Check if two contours intersect?

前端 未结 2 1153
忘掉有多难
忘掉有多难 2020-12-21 03:40

I have 2 contours (cont1 and cont2) received from cv2.findContours(). How do I know if they intersect or not? I don\'t need coordinate

相关标签:
2条回答
  • 2020-12-21 04:11

    Once you have the two contours from cv2.findContours(), you can use a bitwise AND operation to detect intersection. Specifically, we can use np.logical_and(). The idea is to create two separate images for each contour and then use the logical AND operation on them. Any points that have a positive value (1 or True) will be points of intersection. So since you're only looking to obtain a boolean value of whether there is intersection, we can check the intersected image to see if there is a single positive value. Essentially, if the entire array is False then there was no intersection between the contours. But if there is a single True, then the contours touched and thus intersect.

    def contourIntersect(original_image, contour1, contour2):
        # Two separate contours trying to check intersection on
        contours = [contour1, contour2]
    
        # Create image filled with zeros the same size of original image
        blank = np.zeros(original_image.shape[0:2])
    
        # Copy each contour into its own image and fill it with '1'
        image1 = cv2.drawContours(blank.copy(), contours, 0, 1)
        image2 = cv2.drawContours(blank.copy(), contours, 1, 1)
    
        # Use the logical AND operation on the two images
        # Since the two images had bitwise and applied to it,
        # there should be a '1' or 'True' where there was intersection
        # and a '0' or 'False' where it didnt intersect
        intersection = np.logical_and(image1, image2)
    
        # Check if there was a '1' in the intersection
        return intersection.any()
    

    Example

    Original Image

    Detected Contour

    We now pass the two detected contours to the function and obtain this intersection array:

    [[False False False ... False False False]
     [False False False ... False False False]
     [False False False ... False False False]
     ...
     [False False False ... False False False]
     [False False False ... False False False]
     [False False False ... False False False]]
    

    We check the intersection array to see if True exists. We will obtain a True or 1 where the contours intersect and False or 0 where they do not.

    return intersection.any()
    

    Thus we obtain

    False

    Full code

    import cv2
    import numpy as np
    
    def contourIntersect(original_image, contour1, contour2):
        # Two separate contours trying to check intersection on
        contours = [contour1, contour2]
    
        # Create image filled with zeros the same size of original image
        blank = np.zeros(original_image.shape[0:2])
    
        # Copy each contour into its own image and fill it with '1'
        image1 = cv2.drawContours(blank.copy(), contours, 0, 1)
        image2 = cv2.drawContours(blank.copy(), contours, 1, 1)
    
        # Use the logical AND operation on the two images
        # Since the two images had bitwise AND applied to it,
        # there should be a '1' or 'True' where there was intersection
        # and a '0' or 'False' where it didnt intersect
        intersection = np.logical_and(image1, image2)
    
        # Check if there was a '1' in the intersection array
        return intersection.any()
    
    original_image = cv2.imread("base.png")
    image = original_image.copy()
    
    cv2.imshow("original", image)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    cv2.imshow("gray", gray)
    blurred = cv2.GaussianBlur(gray, (5,5), 0)
    cv2.imshow("blur", blurred)
    threshold = cv2.threshold(blurred, 60, 255, cv2.THRESH_BINARY)[1]
    cv2.imshow("thresh", threshold)
    
    contours = cv2.findContours(threshold.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # Depending on OpenCV version, number of arguments return by cv.findContours 
    # is either 2 or 3
    contours = contours[1] if len(contours) == 3 else contours[0]
    
    contour_list = []
    for c in contours:
        contour_list.append(c)
        cv2.drawContours(image, [c], 0, (0,255,0), 2)
    
    print(contourIntersect(original_image, contour_list[0], contour_list[1]))
    cv2.imshow("contour", image)
    cv2.waitKey(0)
    
    0 讨论(0)
  • 2020-12-21 04:25

    The answer by nathancy works, but suffers on the performance side where as in the example creates 3 copies of the image to draw the contours thus, is sluggish when it comes to execution time.

    My alternative answer is as below;

    def contour_intersect(cnt_ref,cnt_query, edges_only = True):
    
        intersecting_pts = []
    
        ## Loop through all points in the contour
        for pt in cnt_query:
            x,y = pt[0]
    
            ## find point that intersect the ref contour
            ## edges_only flag check if the intersection to detect is only at the edges of the contour
    
            if edges_only and (cv2.pointPolygonTest(cnt_ref,(x,y),True) == 0):
                intersecting_pts.append(pt[0])
            elif not(edges_only) and (cv2.pointPolygonTest(cnt_ref,(x,y),True) >= 0):
                intersecting_pts.append(pt[0])
    
        if len(intersecting_pts) > 0:
            return True
        else:
            return False
    
    0 讨论(0)
提交回复
热议问题