霍夫变换
霍夫直线变换
霍夫直线变换用来做直线检测
绘制经过某点的所有直线的示例代码如下
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
def draw_line():
# 绘制一张黑图
img = np.zeros((500, 500, 1), np.uint8)
# 绘制一个点
cv.line(img, (10, 10), (10, 10), (255), 1)
cv.imshow("line", img)
return img
def hough_lines(img):
rho = 1;
theta = np.pi / 180
threshold = 0
lines = cv.HoughLines(img, rho, theta, threshold)
dst_img = img.copy()
for line in lines[:, 0]:
rho, theta = line
a = np.cos(theta)
b = np.sin(theta)
x = a * rho
y = b * rho
x1 = int(np.round(x + 1000 * (-b)))
y1 = int(np.round(y + 1000 * a))
x2 = int(np.round(x - 1000 * (-b)))
y2 = int(np.round(y - 1000 * a))
cv.line(dst_img, (x1, y1), (x2, y2), (255, 0, 0), 1)
cv.imshow("li", dst_img)
img = draw_line()
hough_lines(img)
cv.waitKey(0)
cv.destroyAllWindows()
案例:寻找棋盘中的直线
示例代码
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
# 1. 将图片以灰度的方式读取进来
img = cv.imread("img/weiqi.jpg", cv.IMREAD_COLOR)
cv.imshow("src", img)
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# cv.imshow("gray",gray_img)
#
flag, thresh_img = cv.threshold(gray_img, 100, 255, cv.THRESH_BINARY_INV)
cv.imshow("thresh_img", thresh_img)
# 3. 霍夫变换
# 线段以像素为单位的距离精度,double类型的,推荐用1.0
rho = 1
# 线段以弧度为单位的角度精度,推荐用numpy.pi/180
theta = np.pi / 180
# 累加平面的阈值参数,int类型,超过设定阈值才被检测出线段,值越大,基本上意味着检出的线段越长,检出的线段个数越少。
threshold = 10
# 线段以像素为单位的最小长度
min_line_length = 25
# 同一方向上两条线段判定为一条线段的最大允许间隔(断裂),超过了设定值,则把两条线段当成一条线段,值越大,允许线段上的断裂越大,越有可能检出潜在的直线段
max_line_gap = 3
lines = cv.HoughLinesP(thresh_img, rho, theta, threshold, minLineLength=min_line_length, maxLineGap=max_line_gap)
dst_img = img.copy()
for line in lines:
x1, y1, x2, y2 = line[0]
cv.line(dst_img, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv.imshow("dst img", dst_img)
cv.waitKey(0)
cv.destroyAllWindows()
霍夫圆
一个圆可以由以下公式表示
其中
是圆心,r是半径。圆环需要3个参数来确定,所以进行圆环检测的累加器必须是三维的,这样效率就会很低,因此OpenCV使用了霍夫梯度法这个巧妙的方法,来使用边界的梯度信息,从而提升计算的效率。
使用步骤:
- 霍夫圆检测对噪声敏感,先对对象做中值滤波
- 检测边缘,先把可能的圆边缘过滤出来
- 根据边缘得到最大概率的圆心,进而得到最佳半径
OpenCV的Logo检测结果:
示例参数以及代码
import cv2
import numpy as np
def hough_circle(img):
img_copy = img.copy()
# 中值滤波降噪
img_copy = cv2.GaussianBlur(img_copy, (3, 3), 0)
img_copy = cv2.medianBlur(img_copy, 5)
gray = cv2.cvtColor(img_copy, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)
"""
@param 8-bit 单通道图片
@param method 检测方法, 当前只有cv2.HOUGH_GRADIENT
@param dp 累加器分辨率和图像分辨率的反比例, 例如:
如果 dp=1 累加器和输入图像分辨率相同.
如果 dp=2 累加器宽高各为输入图像宽高的一半相同.
@param minDist 检测到圆的圆心之间的最小距离。
如果参数太小,除了真实的一个之外,可能错误地检测到多个相邻的圆圈。
如果参数太大,可能会遗漏一些圆
@param param1 参数1。它是两个传递给Canny边缘检测器的较高阈值(较低的阈值是此值的一半)
@param param2 参数2, 它是检测阶段圆心的累加器阈值。
它越小,会检测到更多的假圆圈。较大累加器值对应的圆圈将首先返回。
@param minRadius 最小圆半径.
@param maxRadius 最大圆半径.
如果<=0, 会使用图片最大像素值
如果< 0, 直接返回圆心, 不计算半径
"""
# ../images/coins.jpg
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT,
dp=1,
minDist=50,
param1=160,
param2=50,
minRadius=0,
maxRadius=100)
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# draw the outer circle
cv2.circle(img_copy, (i[0], i[1]), i[2], (0, 255, 0), 2)
# draw the center of the circle
cv2.circle(img_copy, (i[0], i[1]), 2, (0, 0, 255), 3)
cv2.imshow("detected circles", img_copy)
案例:寻找棋盘中的棋子
示例代码
import cv2 as cv
import numpy as np
img = cv.imread("img/weiqi.jpg", cv.IMREAD_COLOR)
cv.imshow("src", img)
# 将图片转成灰色图片
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 霍夫圆形检测
def hough_circle(gray_img):
# 定义检测图像中圆的方法。目前唯一实现的方法是cv2.HOUGH_GRADIENT
method = cv.HOUGH_GRADIENT
# 累加器分辨率与图像分辨率的反比。例如,如果dp = 1,则累加器具有与输入图像相同的分辨率。如果dp = 2,则累加器的宽度和高度都是一半。
dp = 1
# 检测到的圆的圆心之间最小距离。如果minDist太小,则可能导致检测到多个相邻的圆。如果minDist太大,则可能导致很多圆检测不到。
minDist = 20
# param1 Canny算法阈值上线
# param2 cv2.HOUGH_GRADIENT方法的累加器阈值。阈值越小,检测到的圈子越多。
# minRadius : 最小的半径,如果不确定,则不指定
# maxRadius : 最大的半径,若不确定,则不指定
circles = cv.HoughCircles(gray_img, method, dp, minDist=minDist, param1=70, param2=30, minRadius=0, maxRadius=20)
for circle in circles[0, :]:
# 圆心坐标,半径
x, y, r = circle
# 绘制圆心 必须强转成int类型
cv.circle(img, (int(x), int(y)), 2, (0, 255, 0), 1)
# 绘制圆形
cv.circle(img, (int(x), int(y)), int(r), (0, 0, 255), 2)
cv.imshow("result", img)
# 调用函数,寻找霍夫圆
hough_circle(gray_img)
cv.waitKey(0)
cv.destroyAllWindows()
文章出处登录后可见!
已经登录?立即刷新