如何在OpenCV/Python中找到轮廓上的特定点

3
我使用opencv创建了一些轮廓,需要确定轮廓上特定的点,通常是“V”形的最内部点。在附加的图片中,我想要确认的点由绿色箭头指示。
在左侧是一个简单的情况,可以通过计算轮廓的凸包,然后找到距离凸包最远的点来完成标识。但是,在右侧的图像中,遇到更困难的情况,我得到了多个轮廓,并且漂亮的“V”形不再存在,这使得无法确定“V”形的最内部点。如红色虚线所示,一个解决方案可能是将较高的轮廓外推直到与较低的轮廓相交。有人知道我该如何做吗?或者有更好的解决方案吗?
记录一下,我已经尝试过:
- 膨胀/腐蚀(当多个轮廓靠近时有效,否则无效) - Hough变换p(容易误判目标点)
任何指导都会非常感激。
1个回答

1
这个解决方案适用于您提供的两张图片。对于所有具有类似颜色和指向右侧的“v”形状(或至少部分“v”形状)的其他图像,这也应该是一个很好的解决方案。
首先让我们看一下更简单的图像。我通过使用颜色空间对图像进行了分割。
# Convert frame to hsv color space
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Define range of pink color in HSV
(b,r,g,b1,r1,g1) = 0,0,0,110,255,255
lower = np.array([b,r,g])
upper = np.array([b1,r1,g1])
# Threshold the HSV image to get only pink colors
mask = cv2.inRange(hsv, lower, upper)

color spaces

接下来,我找到了mid_point,即在该行上方和下方都有相等数量的白色像素。
# Calculate the mid point
mid_point = 1
top, bottom = 0, 1
while top < bottom:
    top = sum(sum(mask[:mid_point, :]))
    bottom = sum(sum(mask[mid_point:, :]))
    mid_point += 1

然后,我从中点开始填充图像:

bg = np.zeros((h+2, w+2), np.uint8)

kernel = np.ones((k_size, k_size),np.uint8)  
cv2.floodFill(mask, bg, (0, mid_point), 123)

floodfilled

现在我有了洪水填充图像,我知道我要找的点是最靠近图像右侧的灰色像素。
# Find the gray pixel that is furthest to the right
idx = 0
while True:
    column = mask_temp[:,idx:idx+1]
    element_id, gray_px, found = 0, [], False
    for element in column:
        if element == 123:
            v_point = idx, element_id
            found = True
        element_id += 1
    # If no gray pixel is found, break out of the loop
    if not found: break
    idx += 1

结果:

result1

现在是较难的图像。 在右侧的图像中,“v”未完全连接:

does not connect

为了关闭 'v' 字形,我迭代地膨胀掩码并检查它是否连接:
# Flood fill and dilate loop
k_size, iters = 1, 1
while True:
    bg = np.zeros((h+2, w+2), np.uint8)
    mask_temp = mask.copy()    
    kernel = np.ones((k_size, k_size),np.uint8)    
    mask_temp = cv2.dilate(mask_temp,kernel,iterations = iters)
    cv2.floodFill(mask_temp, bg, (0, mid_point), 123)
    cv2.imshow('mask', mask_temp)
    cv2.waitKey()
    k_size += 1
    iters += 1
    # Break out of the loop of the right side of the image is black
    if mask_temp[h-1,w-1]==0 and mask_temp[1, w-1]==0: break

dilation

这是最终的输出:

output2


非常感谢!对于更难处理的图像,膨胀的效果是将目标点向左推得比实际位置稍微远一些,但我认为我可以根据膨胀迭代次数轻松地进行补偿。再次感谢您的辛勤工作和出色的解决方案。 - ennjaycee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接