[Python从零到壹] 六十五.图像识别及经典案例篇之图像霍夫变换详解

欢迎大家来到“Python从零到壹”,在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界。所有文章都将结合案例、代码和作者的经验讲解,真心想把自己近十年的编程经验分享给大家,希望对您有所帮助,文章中不足之处也请海涵。Python系列整体框架包括基础语法10篇、网络爬虫30篇、可视化分析10篇、机器学习20篇、大数据分析20篇、图像识别30篇、人工智能40篇、Python安全20篇、其他技巧10篇。您的关注、点赞和转发就是对秀璋最大的支持,知识无价人有情,希望我们都能在人生路上开心快乐、共同成长。

该系列文章主要讲解Python OpenCV图像处理和图像识别知识,前期主要讲解图像处理基础知识、OpenCV基础用法、常用图像绘制方法、图像几何变换等,中期讲解图像处理的各种运算,包括图像点运算、形态学处理、图像锐化、图像增强、图像平滑等,后期研究图像识别、图像分割、图像分类、图像特效处理以及图像处理相关应用。

第一部分作者介绍了图像处理基础知识,第二部分介绍了图像运算和图像增强,接下来第三部分我们将详细讲解图像识别及图像处理经典案例,该部分属于高阶图像处理知识,能进一步加深我们的理解和实践能力。在数字图像处理中,有两个经典的变换被广泛应用——傅里叶变换和霍夫变换。其中,傅里叶变换主要是将时间域上的信号转变为频率域上的信号,用来进行图像除噪、图像增强等处理;霍夫变换主要用来辨别找出物件中的特征,用来进行特征检测、图像分析、数位影像处理等处理。本文主要讲解图像霍夫变换,希望文章对您有所帮助,如果有不足之处,还请海涵。

下载地址:记得点赞喔 O(∩_∩)O

前文赏析:(尽管该部分占大量篇幅,但我舍不得删除,哈哈!)

第一部分 基础语法

第二部分 网络爬虫

第三部分 数据分析和机器学习

第四部分 Python图像处理基础

第五部分 Python图像运算和图像增强

第六部分 Python图像识别和图像高阶案例

第七部分 NLP与文本挖掘

第八部分 人工智能入门知识

第九部分 网络攻防与AI安全

第十部分 知识图谱构建实战

扩展部分 人工智能高级案例

作者新开的“娜璋AI安全之家”将专注于Python和安全技术,主要分享Web渗透、系统安全、人工智能、大数据分析、图像识别、恶意代码检测、CVE复现、威胁情报分析等文章。虽然作者是一名技术小白,但会保证每一篇文章都会很用心地撰写,希望这些基础性文章对你有所帮助,在Python和安全路上与大家一起进步。


一.霍夫变换

霍夫变换(Hough Transform)是一种特征检测(Feature Extraction),被广泛应用在图像分析、计算机视觉以及数位影像处理。 霍夫变换是在1959年由气泡室(Bubble Chamber)照片的机器分析而发明,发明者Paul Hough在1962年获得美国专利。现在广泛使用的霍夫变换是由Richard Duda和Peter Hart在1972年发明,并称之为广义霍夫变换。经典的霍夫变换是检测图片中的直线,之后,霍夫变换不仅能识别直线,也能够识别任何形状,常见的有圆形、椭圆形。1981年,因为Dana H.Ballard的一篇期刊论文“Generalizing the Hough transform to detect arbitrary shapes”,让霍夫变换开始流行于计算机视觉界。

霍夫变换是一种特征提取技术,用来辨别找出物件中的特征,其目的是通过投票程序在特定类型的形状内找到对象的不完美实例。这个投票程序是在一个参数空间中进行的,在这个参数空间中,候选对象被当作所谓的累加器空间中的局部最大值来获得,累加器空间是由计算霍夫变换的算法明确地构建。霍夫变换主要优点是能容忍特征边界描述中的间隙,并且相对不受图像噪声的影响。

最基本的霍夫变换是从黑白图像中检测直线,它的算法流程大致如下:给定一个物件和要辨别的形状的种类,算法会在参数空间中执行投票来决定物体的形状,而这是由累加空间里的局部最大值来决定。假设存在直线公式如(1)所示,其中m表示斜率,b表示截距。

在这里插入图片描述

如果用参数空间表示,则直线为(b, m),但它存在一个问题,垂直线的斜率不存在(或无限大),使得斜率参数m值接近于无限。为此,为了更好的计算,Richard O. Duda和Peter E. Hart在1971年4月,提出了Hesse normal form(Hesse法线式),如公式(2)所示,它转换为直线的离散极坐标公式。

在这里插入图片描述

其中r是原点到直线上最近点的距离,θ是x轴与连接原点和最近点直线之间的夹角,如图1所示。

在这里插入图片描述

对于点(x0, y0),可以将通过这个点的一族直线统一定义为公式(3)。因此,可以将图像的每一条直线与一对参数(r,θ)相关联,相当于每一对(r0,θ)代表一条通过点的直线(x0, y0),其中这个参数(r,θ)平面被称为霍夫空间。

在这里插入图片描述

然而在实现的图像处理领域,图像的像素坐标P(x, y)是已知的,而(r,θ)是需要寻找的变量。如果能根据像素点坐标P(x, y)值绘制每个(r,θ)值,那么就从图像笛卡尔坐标系统转换到极坐标霍夫空间系统,这种从点到曲线的变换称为直线的霍夫变换。变换通过量化霍夫参数空间为有限个值间隔等分或者累加格子。

当霍夫变换算法开始,每个像素坐标点P(x, y)被转换到(r,θ)的曲线点上面,累加到对应的格子数据点,当一个波峰出现时候,说明有直线存在。如图2所示,三条正弦曲线在平面相交于一点,该点坐标(r0,θ)表示三个点组成的平面内的直线。这就是使用霍夫变换检测直线的过程,它追踪图像中每个点对应曲线间的交点,如果交于一点的曲线的数量超过了阈值,则认为该交点所代表的参数对(r0,θ)在原图像中为一条直线。

在这里插入图片描述

同样的原理,可以用来检测圆,对于圆的参数方程变为如下等式:

在这里插入图片描述

其中(a, b)为圆的中心点坐标,r圆的半径。这样霍夫参数空间就变成一个三维参数空间。给定圆半径转为二维霍夫参数空间,变换相对简单,也比较常用。


二.图像霍夫线变换操作

在OpenCV中,霍夫变换分为霍夫线变换和霍夫圆变换,其中霍夫线变换支持三种不同方法——标准霍夫变换、多尺度霍夫变换和累计概率霍夫变换[3]。

  • 标准霍夫变换主要有HoughLines()函数实现。
  • 多尺度霍夫变换是标准霍夫变换在多尺度下的变换,可以通过HoughLines()函数实现。
  • 累计概率霍夫变换是标准霍夫变换的改进,它能在一定范围内进行霍夫变换,计算单独线段的方向及范围,从而减少计算量,缩短计算时间,可以通过HoughLinesP()函数实现。

在OpenCV 中,通过函数HoughLines()检测直线,并且能够调用标准霍夫变换(SHT)和多尺度霍夫变换(MSHT),其函数原型如下所示:

  • lines = HoughLines(image, rho, theta, threshold[, lines[, srn[, stn[, min_theta[, max_theta]]]]])
    – image表示输入的二值图像
    – lines表示经过霍夫变换检测到直线的输出矢量,每条直线为(r,θ)
    – rho表示以像素为单位的累加器的距离精度
    – theta表示以弧度为单位的累加器角度精度
    – threshold表示累加平面的阈值参数,识别某部分为图中的一条直线时它在累加平面中必须达到的值,大于该值线段才能被检测返回
    – srn表示多尺度霍夫变换中rho的除数距离,默认值为0。粗略的累加器进步尺寸为rho,而精确的累加器进步尺寸为rho/srn
    – stn表示多尺度霍夫变换中距离精度theta的除数,默认值为0,。如果srn和stn同时为0,使用标准霍夫变换
    – min_theta表示标准和多尺度的霍夫变换中检查线条的最小角度。必须介于0和max_theta之间
    – max_theta表示标准和多尺度的霍夫变换中要检查线条的最大角度。必须介于min_theta和π之间

下面的代码是调用HoughLines()函数检测图像中的直线,并将所有的直线绘制于原图像中。

# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
from matplotlib import pyplot as plt
import matplotlib

#读取图像
img = cv2.imread('lines.png')

#灰度变换
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#转换为二值图像
edges = cv2.Canny(gray, 50, 150)

#显示原始图像
plt.subplot(121), plt.imshow(edges, 'gray'), plt.title(u'(a)原始图像')

plt.axis('off')

#霍夫变换检测直线
lines = cv2.HoughLines(edges, 1, np.pi / 180, 160)

#转换为二维
line = lines[:, 0, :] 

#将检测的线在极坐标中绘制 
for rho,theta in line[:]: 
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a * rho
    y0 = b * rho
    print(x0, y0)
    x1 = int(x0 + 1000 * (-b))
    y1 = int(y0 + 1000 * (a))
    x2 = int(x0 - 1000 * (-b))
    y2 = int(y0 - 1000 * (a))
    print(x1, y1, x2, y2)
    #绘制直线
    cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 1)

#设置字体
matplotlib.rcParams['font.sans-serif']=['SimHei']

#显示处理图像
plt.subplot(122), plt.imshow(img, 'gray'), plt.title('(b)结果图像')

plt.axis('off')
plt.show()

输出结果如图3所示,第一幅图为原始图像,第二幅检测出的直线。

在这里插入图片描述

使用该方法检测大楼图像中的直线如图4所示,可以发现直线会存在越界的情况。

在这里插入图片描述

前面的标准霍夫变换会计算图像中的每一个点,计算量比较大,另外它得到的是整条线(r,θ),并不知道原图中直线的端点。接下来使用累计概率霍夫变换,它是一种改进的霍夫变换,调用HoughLinesP()函数实现。

  • lines = HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]])
    – image表示输入的二值图像
    – lines表示经过霍夫变换检测到直线的输出矢量,每条直线具有4个元素的矢量,即(x1, y1)和(x2, y2)是每个检测线段的端点
    – rho表示以像素为单位的累加器的距离精度
    – theta表示以弧度为单位的累加器角度精度
    – threshold表示累加平面的阈值参数,识别某部分为图中的一条直线时它在累加平面中必须达到的值,大于该值线段才能被检测返回
    – minLineLength表示最低线段的长度,比这个设定参数短的线段不能被显示出来,默认值为0
    – maxLineGap表示允许将同一行点与点之间连接起来的最大距离,默认值0

下面的代码是调用HoughLinesP()函数检测图像中的直线,并将所有的直线绘制于原图像中。

# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
from matplotlib import pyplot as plt
import matplotlib

#读取图像
img = cv2.imread('judge.png')

#灰度转换
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#转换为二值图像
edges = cv2.Canny(gray, 50, 200)

#显示原始图像
plt.subplot(121), plt.imshow(edges, 'gray'), plt.title(u'(a)原始图像')
plt.axis('off')

#霍夫变换检测直线
minLineLength = 60
maxLineGap = 10
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 30, minLineLength, maxLineGap)

#绘制直线
lines1 = lines[:, 0, :]
for x1,y1,x2,y2 in lines1[:]:
    cv2.line(img, (x1,y1), (x2,y2), (255,0,0), 2)

res = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

#设置字体
matplotlib.rcParams['font.sans-serif']=['SimHei']

#显示处理图像
plt.subplot(122), plt.imshow(res), plt.title('(b)结果图像')
plt.axis('off')
plt.show()

输出结果如图5所示,图(a)为原始图像,图(b)检测出的直线,它有效地提取了线段的起点和终点。

在这里插入图片描述


三.图像霍夫圆变换操作

霍夫圆变换的原理与霍夫线变换很类似,只是将线的(r,θ)二维坐标提升为三维坐标,包括圆心点(x_center,y_center,r)和半径r,其数学形式如公式(5)。

在这里插入图片描述

从而一个圆的确定需要三个参数,通过三层循环实现,接着寻找参数空间累加器的最大(或者大于某一阈值)的值。随着数据量的增大,导致圆的检测将比直线更耗时,所以一般使用霍夫梯度法减少计算量。在OpenCV中,提供了cv2.HoughCircles()函数检测圆,其原型如下所示:

  • circles = HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]])
    – image表示输入图像,8位灰度单通道图像
    – circles表示经过霍夫变换检测到圆的输出矢量,每个矢量包括3个元素,即(x, y, radius)
    – method表示检测方法,包括HOUGH_GRADIENT值
    – dp表示用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,允许创建一个比输入图像分辨率低的累加器
    – minDist表示霍夫变换检测到的圆的圆心之间的最小距离
    – param1表示参数method设置检测方法的对应参数,对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示传递给Canny边缘检测算子的高阈值,而低阈值为高阈值的一半,默认值100
    – param2表示参数method设置检测方法的对应参数,对当前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值,它越小,将检测到更多根本不存在的圆;它越大,能通过检测的圆就更接近完美的圆形
    – minRadius表示圆半径的最小值,默认值为0
    – maxRadius表示圆半径的最大值,默认值0

下列代码是检测图像中的圆。

# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
from matplotlib import pyplot as plt
import matplotlib

#读取图像
img = cv2.imread('test.png')

#灰度转换
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

#显示原始图像
plt.subplot(121), plt.imshow(gray, 'gray'), plt.title(u'(a)原始图像')
plt.axis('off')

#霍夫变换检测圆
circles1 = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param2=30)
print(circles1)

#提取为二维
circles = circles1[0, :, :]

#四舍五入取整
circles = np.uint16(np.around(circles))

#绘制圆
for i in circles[:]: 
    cv2.circle(img, (i[0],i[1]), i[2], (255,0,0), 5) #画圆
    cv2.circle(img, (i[0],i[1]), 2, (255,0,255), 10) #画圆心

#设置字体
matplotlib.rcParams['font.sans-serif']=['SimHei']
plt.subplot(122), plt.imshow(img), plt.title('(b)结果图像')
plt.axis('off')
plt.show()

输出结果如图6所示,图(a)为原始图像,图(b)检测出的圆形,它有效地提取了圆形的圆心和轮廓。

在这里插入图片描述

使用下面的函数能有效提取人类眼睛的轮廓,核心函数如下:

circles1 = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20,
                            param1=100, param2=30,
                            minRadius=160, maxRadius=300)

输出结果如图7所示,它提取了三条圆形接近于人体的眼睛。

在这里插入图片描述

图7中显示了三条曲线,通过不断优化最大半径和最小半径,比如将minRadius设置为160,maxRadius设置为200,将提取更为精准的人体眼睛,如图8所示。

在这里插入图片描述


四.总结

本章主要讲解霍夫变换。霍夫变换主要用来辨别找出物件中的特征,包括提取图像中的直线和圆,调用cv2.HoughLines()、cv2.HoughLinesP()和cv2.HoughCircles()实现。希望对大家有所帮助,这也将为后续图像识别和目标检测提供帮助。

感谢在求学路上的同行者,不负遇见,勿忘初心。图像处理系列主要包括三部分,分别是:

在这里插入图片描述

在这里插入图片描述

请添加图片描述

转眼就过年了,2022年简单总结:很多遗憾,很多不足,勉强算是分秒必争,只争朝夕,但愧对家人,陪伴太少,论文、科研、分享和家庭都做得不好,这一年勉强给个65分吧。最最感恩的永远是女神,回家的感觉真好,平平淡淡,温温馨馨,虽然这辈子科研、事业和职称上没有太大的追求,和大佬们的差距如鸿沟,但能做自己喜欢的事,爱自己喜欢的人,每天前进一小步(人生勿比),一家人健康幸福,足矣。小珞珞是真的逗,陪伴的感觉真好,女神是真的好,爱你们喔,晚安娜继续加油!

在这里插入图片描述

参考文献:

  • [1]冈萨雷斯著. 数字图像处理(第3版)[M]. 北京:电子工业出版社,2013.
  • [2]阮秋琦. 数字图像处理学(第3版)[M]. 北京:电子工业出版社,2008.
  • [3]毛星云,冷雪飞. OpenCV3编程入门[M]. 北京:电子工业出版社,2015.
  • [4]张铮,王艳平,薛桂香等. 数字图像处理与机器视觉——Visual C++与Matlab实现[M]. 北京:人民邮电出版社,2014.
  • [5]Eastmount. [Python图像处理] 三十二.傅里叶变换(图像去噪)与霍夫变换(特征识别)万字详细总结[EB/OL]. (2020.12.02). https://blog.csdn.net/Eastmount/article/details/ 110487868.
  • [6]百度百科. 霍夫变换[EB/OL]. (2018-11-21). https://baike.baidu.com/item/霍夫变换/4647236.
  • [7]yuyuntan. 经典霍夫变换(Hough Transform)[EB/OL]. (2018-04-29). https://blog.csdn.net/yuyuntan/article/details/80141392.
  • [8]g20040733. 霍夫变换[EB/OL]. (2016-12-07). https://blog.csdn.net/g200407331/article/details/53507784.
  • [9]我i智能. Python下opencv使用笔记(十一)(详解hough变换检测直线与圆)[EB/OL]. (2015-07-23). https://blog.csdn.net/on2way/article/details/47028969.
  • [10]ex2tron. Python+OpenCV教程17:霍夫变换[EB/OL]. (2018-01-10). https://www.jianshu.com/p/34d6dc466e81.
  • [11]Daetalus. OpenCV-Python教程(9、使用霍夫变换检测直线)[EB/OL]. (2013-07-12). https://blog.csdn.net/sunny2038/article/details/9253823.

猜你喜欢

转载自blog.csdn.net/Eastmount/article/details/129326878