gpt4 book ai didi

python - 在圆内寻找轮廓

转载 作者:行者123 更新时间:2023-12-02 17:06:52 25 4
gpt4 key购买 nike

我正在尝试编写一个程序来检测圆形镜头上的直线切割,如图像左侧所示:

enter image description here

现在,我尝试使用 Canny 边缘检测、霍夫线变换和 findContour 单独分离线,但我没有成功。

我还尝试通过首先检测镜头的外圆并在 ROI(检测到的圆)内执行轮廓搜索来检测线条,但我在镜头上得到随机线条,但不是我想要的输出。

最佳答案

因此,首先我想指出您的图像非常嘈杂。这意味着仅仅通过寻找轮廓或边缘或线条可能会因为噪音而不起作用。这使得任务非常困难。如果您正在寻找一种使此类任务自动化的方法,我建议您努力寻找合适的照明(我认为经典的圆顶灯就足够了),因为它会在图像上产生更少的噪音(更少的反射.. .),因此制作这样的算法会更容易。

话虽如此。我举了一个例子来说明我将如何尝试完成这样的任务。请注意,此解决方案可能不适用于其他图像,但在此示例中,结果非常好。它也许会给你一个关于如何解决这个问题的新观点。

首先,在使用 OTSU 阈值将图像转换为二进制之前,我会尝试执行直方图均衡。之后,我将对图像执行打开(腐 eclipse 后膨胀):

enter image description here

之后,我会在最大轮廓上制作一个边界框。使用 x,y,h,w 我可以计算边界框的中心,该中心将作为我要创建的 ROI 的中心。在图像的副本上画一个半径略小于 w/2 的圆,并在半径等于 w/2 的新蒙版上画一个圆。然后执行按位运算:

enter image description here

现在您有了 ROI,并且必须再次对其进行阈值化以使边界没有噪声并搜索轮廓:

enter image description here

现在您可以看到您有两个轮廓(内部和外部)。所以现在你可以提取镜头被切割的区域。您可以通过计算内轮廓和外轮廓的每个点之间的距离来做到这一点。两点之间的距离公式是sqrt((x2-x1)^2 + (y2-y2)^2) .阈值这个距离,以便如果距离小于某个整数,并在图像上的这两个点之间画一条线。我用蓝线画了距离。之后将图像转换为 HSV 颜色空间并再次使用按位运算对其进行掩码,因此剩下的就是那些蓝线:

enter image description here

再次执行 OTSU 阈值并选择最大的轮廓(那些蓝线)并通过轮廓拟合一条线。在原图上画线,你会得到最终结果:

enter image description here

示例代码:

import cv2
import numpy as np

### Perform histogram equalization and threshold with OTSU.
img = cv2.imread('lens.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
equ = cv2.equalizeHist(gray)
_, thresh = cv2.threshold(equ,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)

### Perform opening (erosion followed by dilation) and search for contours.
kernel = np.ones((2,2),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
_, contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)

### Select the biggest one and create a bounding box.
### This will be used to calculate the center of your ROI.
cnt = max(contours, key=cv2.contourArea)

### Calculate x and y of the center.
x,y,w2,h2 = cv2.boundingRect(cnt)
center_x = int(x+(w2/2))
center_y = int(y+(h2/2))

### Create the radius of your inner circle ROI and draw it on a copy of the image.
img2 = img.copy()
radius = int((w2/2)-20)
cv2.circle(img2,(center_x,center_y), radius, (0,0,0), -1)

### Create the radius of your inner circle ROI and draw it on a blank mask.
radius_2 = int(w2/2)
h,w = img.shape[:2]
mask = np.zeros((h, w), np.uint8)
cv2.circle(mask,(center_x,center_y), radius_2, (255,255,255), -1)

### Perform a bitwise operation so that you will get your ROI
res = cv2.bitwise_and(img2, img2, mask=mask)

### Modify the image a bit to eliminate noise with thresholding and closing.
_, thresh = cv2.threshold(res,190,255,cv2.THRESH_BINARY)
kernel = np.ones((3,3),np.uint8)
closing = cv2.morphologyEx(thresh,cv2.MORPH_CLOSE,kernel, iterations = 2)

### Search for contours again and select two biggest one.
gray = cv2.cvtColor(closing,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
area = sorted(contours, key=cv2.contourArea, reverse=True)
contour1 = area[0]
contour2 = area[1]

### Iterate through both contours and calculate the minimum distance.
### If it is less than the threshold you provide, draw the lines on the image.
### Forumula is sqrt((x2-x1)^2 + (y2-y2)^2).
for i in contour1:
x = i[0][0]
y = i[0][1]
for j in contour2:
x2 = j[0][0]
y2 = j[0][1]
dist = np.sqrt((x2-x)**2 + (y2-y)**2)
if dist < 12:
xy = (x,y)
x2y2 = (x2,y2)
line = (xy,x2y2)
cv2.line(img2,xy,x2y2,(255,0,0),2)
else:
pass

### Transform the image to HSV colorspace and mask the result.
hsv = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV)
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
mask = cv2.inRange(hsv, lower_blue, upper_blue)
res = cv2.bitwise_and(img2,img2, mask= mask)

### Search fot contours again.
gray = cv2.cvtColor(res,cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
_, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt = max(contours, key=cv2.contourArea)

### Fit a line through the contour and draw it on the original image.
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
left = int((-x*vy/vx) + y)
right = int(((w-x)*vy/vx)+y)
cv2.line(img,(w-1,right),(0,left),(0,0,255),2)

### Display the result.
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

关于python - 在圆内寻找轮廓,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52777567/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com