将直角坐标系中的一个圆映射为新坐标系中的一个点,对于原直角坐标系中的每一个圆,可以对应(a, b, r) 这样一个点,这个点即为新三维中的点。
标准法实现步骤:
1.获取原图像的边缘检测图像;
2.设置最小半径、最大半径和半径分辨率等超参数;
3.根据转化后空间的圆心分辨率等信息,设置计数器N(a, b, r);
4.对边缘检测图像的每个白色边缘像素点,其坐标记为(x, y),对于指定的半径r,根据公式 (a-x)^2 + (b-y)^2 = r^2 得到点(a, b)形成的轨迹圆,将轨迹圆经过的计数器N(a, b, r) 加1;
5.如果某个计数器的点数超过设定阈值,则认为存在对应的圆,取出(a, b, r),求出对应的圆方程。
梯度法实现步骤:
1.获取原图像的边缘检测图像;
2.设置最小半径、最大半径和半径分辨率等超参数;
3.计算原图像各点x和y方向的梯度;
4.设置计数器N(a, b);
5.对边缘图像中任意一点p,其梯度为(px, py),由该点p和其梯度决定一条直线,将直线经过的计数器N(a, b)加1。
6.如果某计数器点数超过阈值,则认为存在圆,取出的(a, b)记为圆心,通过不断变换半径,若与边缘图的交集点数超过设定阈值,则认为存在圆,从而获得圆方程。
- import cv2 as cv
- import numpy as np
- import matplotlib.pyplot as plt
-
-
- # 封装图片显示函数
- def image_show(image):
- if image.ndim == 2:
- plt.imshow(image, cmap='gray')
- else:
- image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
- plt.imshow(image)
- plt.show()
-
- # Hough圆检测
-
-
- if __name__ == '__main__':
-
- # 读取灰度图
- img_desk = cv.imread('desk.png')
-
- # 转换为灰度图
- img_gray = cv.cvtColor(img_desk, cv.COLOR_BGR2GRAY)
-
- # 参数设置
- img_dp = 2 # 图像分辨率与累加器分辨率之比,建议范围为1-2
- MinDist = 50 # 两个不同圆圆心之间的距离
- Param1 = 400 # Canny边缘阈值的上限,其下限为上限的1/2
- Param2 = 80 # cv.HOUGH_GRADIENT 方法的累加器阈值,阈值越小,检测的圆越多
- # cv.HOUGH_GRADIENT_ALT 方法中,该参数用于衡量圆的完美度,范围为0-1
- MinRadius = 10 # 最小圆半径
- MaxRadius = 100 # 最大圆半径
-
- # 霍夫圆检测
- circles = cv.HoughCircles(img_gray, cv.HOUGH_GRADIENT, dp=img_dp, minDist=MinDist,
- param1=Param1, param2=Param2, minRadius=MinRadius, maxRadius=MaxRadius)
-
- # 绘制结果
- for (x, y, r) in circles.squeeze():
- cv.circle(img_desk, (int(x), int(y)), int(r), (0, 0, 255), 2)
-
- image_show(img_desk)
- import cv2 as cv
- import numpy as np
- import matplotlib.pyplot as plt
-
-
- # 封装图片显示函数
- def image_show(image):
- if image.ndim == 2:
- plt.imshow(image, cmap='gray')
- else:
- image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
- plt.imshow(image)
- plt.show()
-
-
-
- if __name__ == '__main__':
-
- # 读取灰度图
- img_desk = cv.imread('desk.png')
-
- # 转换为灰度图
- img_gray = cv.cvtColor(img_desk, cv.COLOR_BGR2GRAY)
-
- # 边缘检测
- img_canny = cv.Canny(img_gray, 100, 400)
-
- # 参数设置
- img_dr = 1 # 半径分辨率
- MinRadius = 10 # 最小圆半径
- MaxRadius = 100 # 最大圆半径
- thresh = 80 # 累加的阈值
-
- # 初始化计数器
- height, width = img_gray.shape
- radius = int((MaxRadius - MinRadius) / img_dr) + 1
- N = np.zeros((width, height, radius))
-
- # 获取边缘像素位置
- edge_y, edge_x = np.where(img_canny == 255)
-
- # 循环绘制不同圆
- for (x, y) in zip(edge_x, edge_y):
- for r in range(MinRadius, MaxRadius, img_dr):
-
- # 根据个点绘制不同圆
- circle = np.zeros((height, width), np.uint8)
- cv.circle(circle, (x, y), r, 255, 1)
-
- # 获取不同圆的轨迹位置
- bsi, asi = np.where(circle == 255)
-
- # 将轨迹经过位置计数器累加
- N[asi, bsi, r - MinRadius] += 1
-
- # 显示累加图
- plt.imshow(N[:, :, 50], cmap='jet')
- plt.show()
-
- # 获取圆的位置和半径
- xs, ys, rs = np.where(N > thresh)
-
- # 绘制图上检测的圆
- for (x, y, r) in zip(xs, ys, rs):
- cv.circle(img_desk, (x, y), r, (0, 0, 255), 2)
-
- # 显示结果
- image_show(img_desk)
- import cv2 as cv
- import numpy as np
- import matplotlib.pyplot as plt
-
-
- # 封装图片显示函数
- def image_show(image):
- if image.ndim == 2:
- plt.imshow(image, cmap='gray')
- else:
- image = cv.cvtColor(image, cv.COLOR_BGR2RGB)
- plt.imshow(image)
- plt.show()
-
-
- if __name__ == '__main__':
-
- # 读取灰度图
- img_desk = cv.imread('desk.png')
-
- # 转换为灰度图
- img_gray = cv.cvtColor(img_desk, cv.COLOR_BGR2GRAY)
-
- # 边缘检测
- img_canny = cv.Canny(img_gray, 100, 400)
-
- # 参数设置
- img_dr = 1 # 半径分辨率
- MinRadius = 10 # 最小圆半径
- MaxRadius = 100 # 最大圆半径
- thresh1 = 40 # 累加的阈值
- thresh2 = 90 # 交集的阈值
-
- # 设置直线长度
- height, width = img_canny.shape
- lmax = height + width
-
- # 计算梯度
- Ix = cv.Sobel(img_gray, cv.CV_64F, 1, 0)
- Iy = cv.Sobel(img_gray, cv.CV_64F, 0, 1)
- Ix = Ix / (np.sqrt(Ix**2 + Iy**2) + 1e-5)
- Iy = Iy / (np.sqrt(Ix ** 2 + Iy ** 2) + 1e-5)
-
- # 设置计数器
- N = np.zeros((height, width), np.int32)
-
- # 获取边缘像素位置
- edge_y, edge_x = np.where(img_canny == 255)
-
- # 循环绘制不同直线
- for (x, y) in zip(edge_x, edge_y):
-
- # 获取不同点梯度
- grad_x = Ix[y, x]
- grad_y = Iy[y, x]
-
- # 根据点和梯度绘制直线
- line_sx = int(x + grad_x * lmax)
- line_sy = int(y + grad_y * lmax)
-
- line_ex = int(x - grad_x * lmax)
- line_ey = int(y - grad_y * lmax)
-
- line = np.zeros((height, width), np.uint8)
- cv.line(line, (line_sx, line_sy), (line_ex, line_ey), 255, 1)
-
- # 获取不同圆的轨迹位置
- bsi, asi = np.where(line == 255)
-
- # 将轨迹经过位置计数器累加
- N[bsi, asi] += 1
-
- # 显示累加图
- plt.imshow(N, cmap='jet')
- plt.show()
-
- # 获取圆的位置和半径
- bsi, asi = np.where(N > thresh1)
-
- # 根据已知的圆心绘制不同半径的圆
- cir_abr = []
- for (a, b) in zip(asi, bsi):
- for r in range(MinRadius, MaxRadius, img_dr):
-
- # 绘制不同半径的圆
- circles = np.zeros((height, width), np.uint8)
- cv.circle(circles, (a, b), r, 255, 1)
-
- # 获取绘制圆和边缘图的交集
- intersection = cv.bitwise_and(circles, img_canny)
-
- # 累计交集的点数
- num_sum = (intersection == 255).sum()
-
- # 获取超过阈值的圆心和半径
- if num_sum > thresh2:
-
- cir_abr.append((a, b, r))
-
- # 绘制检测的圆
- for (a, b, r) in cir_abr:
- cv.circle(img_desk, (a, b), r, (0, 0, 255), 2)
-
- # 显示结果
- image_show(img_desk)