简体   繁体   中英

How to find a specific point on a contour in opencv/python

I have used opencv to create some contours, and I need to identify a specific point on a contour, which is usually the innermost point of a 'V' shape. In the attached image, the point I want to identify is shown by the green arrows.

例

On the left is an easy case, where identification can be done (for example) by computing a convex hull of the contour, and then finding the point furthest from the hull.

However, on the right of the attached image is a much more difficult case, where instead of 1 contour, I get several, and the nice 'V' shape is not present, making it impossible to identify the innermost point of the 'V'. As shown by the red dotted line, one solution might be to extrapolate the higher contour until it intersects with the lower one. Does anyone know how I might go about this? Or have a better solution?

For the record I have tried:

  • dilation/erosion (works when multiple contours are close together, otherwise not)

  • hough transform p (tends to mislocate the target point)

Any pointers would be hugely appreciated.

This solution will work for the two images that you provided. This should also be a good solution for all other images that have a similar coloration and a 'v' shape (or at least a partial 'v' shape) that points to the right.

Let's take a look at the easier image first. I started by segmenting the image using color spaces.

# 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)

色彩空间

Next, I found the mid_point where there was an equal amount of white above and below that row.

# 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

Then, I floodfilled the image starting at the midpoint: 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

Now that I have the floodfilled image, I know the point that I am looking for is the gray pixel that is the closest to the right side of the image.

# 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

The result:

RESULT1

Now for the harder image. In the image on the right, the 'v' does not fully connect:

不连接

To close the 'v', I iteratively dilated the mask checked if it connected:

# 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

扩张

This is the resulting output:

OUTPUT2

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM