Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.7k views
in Technique[技术] by (71.8m points)

python - Check if two contours intersect?

I have 2 contours (cont1 and cont2) received from cv2.findContours(). How do I know if they intersect or not? I don't need coordinates, I only need a boolean True or False.

I have attempted different ways and already tried to do a check with

if ((cont1 & cont2).area() > 0):

... but got the error that the array has no method "Area()"

...
cont1array = cv2.findContours(binary1, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[0]
cont2array = cv2.findContours(binary2, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[0]
...

for cont1 in cont1array:
  for cont2 in cont2array:
    print("cont1")
    print(cont1)
    print(type(cont1))
    print("cont2")
    print(cont2)
    print(type(cont2))
>   if cont1 and cont2 intersect: #i dont know how check intersect
      print("yes they intersect")
    else:
      print("no they do not intersect")

# cont1
# [[172 302]
#  [261 301]
#  [262 390]
#  [173 391]]
# <class 'numpy.ndarray'>
# cont2
# [[  0   0]
#  [  0 699]
#  [499 699]
#  [499   0]]
# <class 'numpy.ndarray'>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

enter image description here

Detected Contour

enter image description here

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)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...