python - 圆识别和通过在同一垂直线上的圆画线
问题描述
我有一个简单的图像,大约有 15 个随机放置的圆圈。我的任务是识别圆圈,然后通过位于同一垂直线上的圆圈画一条直线。我仍然是 OpenCV 的初学者。
我最初尝试确定圆圈的位置并使用以下代码:
image = cv2.imread('circle', 0)
img = cv2.medianBlur(image,5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(image,cv2.HOUGH_GRADIENT,
1,20,param1=40,param2=20,minRadius=0,maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
cv2_imshow(cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()`
这是我得到的输出,对我来说没有任何意义:
请帮助识别圆圈并在圆圈中画一条直线。
编辑:输入图像如下所示:
解决方案
看看您的输入图像,我怀疑任何圆圈的中心都具有相同的x
坐标。tol
这就是为什么,我将在我的解决方案中设置一个公差,在允许的x
坐标范围内。然后通过这些x
坐标的平均值绘制最后一条线。
一般做法如下:
- 逆二进制阈值图像,请参见
cv2.threshold
和ThresholdTypes
,以在黑色背景上有白色圆圈,并消除可能的 JPG 伪影。 - 找到极端的外部轮廓,参见
cv2.findContours
和RetrievalModes
。 - 使用 找到最小包围区域的圆的中心和半径
cv2.minEnclosingCircle
。 x
如上所述,通过在公差范围内匹配坐标找到垂直线。
这是代码:
import cv2
import numpy as np
from skimage import io # Only needed for web grabbing images, use cv2.imread for local images
# Read image from web
img = cv2.cvtColor(io.imread('https://i.imgur.com/VQ5Ri0W.jpg'), cv2.COLOR_RGB2BGR)
# Convert image to grayscale for further processing; inverse binary threshold (also to get rid of JPG artifacts)
_, gray = cv2.threshold(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY), 240, 255, cv2.THRESH_BINARY_INV)
# Find only external contours
contours, _ = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
n = len(contours)
# Get center coordinates and radii of all circles (converted to int)
circles = [cv2.minEnclosingCircle(cnt) for cnt in contours]
centers = np.array([np.int32(np.round(circ[0])) for circ in circles])
# Find vertical lines within tolerance; calculate mean
tol = 10
x_match = np.array([np.abs(centers[:, 0] - cent[0]) < tol for cent in centers])
lines_global = []
for i in np.arange(n):
lines_local = []
lines_local.append(i)
for j in np.arange(i+1, n):
if (x_match[i, j]):
lines_local.append(j)
if (len(lines_local) > 1):
lines_global.append(np.int32(np.round(np.mean(centers[lines_local, 0]))))
for j in lines_local:
for k in lines_local:
x_match[j, k] = False
x_match[k, j] = False
# Draw lines
for line in lines_global:
cv2.line(img, (line, 0), (line, img.shape[0]), (0, 255, 0), 2)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
当前输出如下所示:
您可以设置tol = 0
为仅获取精确的x
坐标匹配,但如最初所述,对于给定的图像,您不会找到任何两个圆圈。
希望有帮助!