opencv-python 霍夫变换

理解霍夫变换的实现
分别使用霍夫线变换和圆变换检测图像中的直线和圆
OpenCV函数:cv2.HoughLines(), cv2.HoughLinesP(), cv2.HoughCircles()

霍夫变换(Hough Transform)
是图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进算法。主要用来从图像中分离出具有某种相同特征的几何形状(如:直线、圆等)。最基本的霍夫变换是从黑白图像中检测直线。

霍夫变换是经典的检测直线的算法。其最初用来检测图像中的直线,同时也可以将其扩展,以用来检测图像中的简单结构。它最初是用于在二值化的图像中进行直线检测的。对于图像中的一条直线,利用直角坐标系,可以用公式表示为:
在这里插入图片描述
如果从k-b参数空间的角度来考虑,则该直线的任意一点(x,y)将变成一个“点”。也就是说,将图像空间中所有的非零像素转换到k-b参数空间,那么它们将聚焦在一个点上,而且参数空间中的一个局部峰值点就很有可能对应着原图像空间的一条直线。不过,由于直线的斜率可能为无穷大,或者无穷小,那么在k-b参数空间就不便于对直线进行描述和刻画。所以,有人提出采用极坐标参数空间进行直线检测。在极坐标系中,直线可以表述为以下形式:
在这里插入图片描述
opencv-python 霍夫变换_第1张图片
上图(a)所示为原始的图像空间中的一个点(x_{0},y_{0}) ;(b)中所示为直角坐标系当中为过同一点的四条直线;

(c)所示为这四条直线在极坐标参数空间可以表示为四个点。

在OpenCV中,支持两种两种不同的霍夫直线变换,the Standard Hough Transform(SHT,标准霍夫变换)和Progressive Probability Hough Transform(PPHT,渐进概率式霍夫变换)。

SHT就是上述的在极坐标空间进行参数表示的方法,而PPHT是SHT的改进,它是在一定的范围内进行霍夫变换,从而减少计算量,缩短计算时间。

在OpenCV中检测直线的函数有cv2.HoughLines()-----(标准霍夫变换),cv2.HoughLinesP()------(渐进概率式霍夫变换)。

(一)标准霍夫变换

函数cv2.HoughLines()返回值实际上是一个二维数据矩阵,表述的就是上述的(\rho ,\theta),其中\rho的单位是像素长度(即直线到图像原点直线的距离,从上述图b中可以看出),\theta的单位是弧度,函数有四个参数输入:

通过调整边缘检测算子Canny阈值参数和标准霍夫变换阈值参数,来获取较好的检测效果。

第一个参数,要检测的二值图(一般是阈值分割或边缘检测后的图)
第二个参数 rho的精确度,值越大,线越多
 第三个参数 theta的精确度,值越小,线越多
第四个参数累加数阈值,值越小,考虑越多的线

# 标准霍夫变换


import cv2
import numpy as np

img = cv2.imread('shudu.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray,50,150)

lines = cv2.HoughLines(edges,0.8,np.pi/180,200)
for line in lines:
    rho,theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a*rho
    y0 = b*rho
    x1 = int(x0 + 1000*(-b))
    y1 = int(y0 + 1000*(a))
    x2 = int(x0 - 1000*(-b))
    y2 = int(y0 - 1000*(a))

    cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)

cv2.imwrite('dst.jpg',img)

检测结果
opencv-python 霍夫变换_第2张图片
(二)渐进概率式霍夫变换

函数cv2.HoughLinesP()是一种概率直线检测,从原理上讲hough变换是一个耗时耗力的算法,尤其是对每一个点的计算,即便经过了canny转换,但有的时候点的数量依然很庞大,这时候采取一种概率挑选机制,不是所有的点都进行计算,而是随机的选取一些点来进行计算,这样的话在阈值设置上也需要降低一些。

与标准霍夫变换函数相比,在参数的输入上多了两个参数:minLineLengh(线的最短长度,比这个线段短的都忽略掉)和maxLineGap(两条直线之间的最大间隔,小于此值,就认为是一条直线)。

这个函数的输出直接是直线点的坐标位置,这样可以省去一系列for循环中的由参数空间到图像的实际坐标点的转换。

# 渐进概率式霍夫变换
img = cv2.imread('house1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 250)
# minLineLength:最短长度阈值,比这个长度短的线会被排除
# maxLineGap:同一直线两点之间的最大距离
lines = cv2.HoughLinesP(edges, 1, np.pi/180, 30, minLineLength=60, maxLineGap=10)
lines = lines[:, 0, :]
for x1, y1, x2, y2 in lines:
    cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 1)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

再进行边缘检测之前如果对图像进行去噪声操作,图像显示的效果将会更好。
(三)利用霍夫变换检测圆环

圆的数学的数学表达式为:

(x-x_{0}){2}+(y-y_{0}){2}=r^{2}

所以一个圆的确定需要三个参数,那么就需要三层循环来实现,从而把图像上的所有点映射到三维空间上。寻找参数空间累加器的最大(或者大于某一阈值)的值。那么理论上圆的检测将比直线更耗时,然而OpenCV对其进行了优化,用了霍夫梯度法。

cv2.HoughCircles(image, method, dp, minDist, circles, param1, param2, minRadius, maxRadius)

参数2:变换方法,一般使用霍夫梯度法,详情:HoughModes
参数3 dp=1:表示霍夫梯度法中累加器图像的分辨率与原图一致
参数4:两个不同圆圆心的最短距离
参数5:param2跟霍夫直线变换中的累加数阈值一样

利用霍夫检测对印章进行定位:

img = cv2.imread('yinzhang.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('img_yuantu', img)
gaussian = cv2.GaussianBlur(gray, (3, 3), 0)
circles1 = cv2.HoughCircles(gaussian, cv2.HOUGH_GRADIENT, 1, 100, param1=100, param2=30, minRadius=15, maxRadius=80)
print(np.shape(circles1))             # hough_gradient 霍夫梯度法
circles = circles1[0, :, :]
circles = np.uint16(np.around(circles))
for i in circles[:]:
    cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 3)
    cv2.circle(img, (i[0], i[1]), 2, (255, 0, 255), 10)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

参考博客:https://blog.csdn.net/qq_40962368/article/details/81950178

你可能感兴趣的:(图此处理)