检查两个轮廓是否相交?

时间:2019-04-11 21:26:37

标签: python opencv opencv-contour

我从cont1收到2个轮廓(cont2cv2.findContours())。我怎么知道它们是否相交?我不需要坐标,只需要布尔TrueFalse

我尝试了不同的方式,并且已经尝试通过

进行检查
if ((cont1 & cont2).area() > 0):

... 但是出现了数组没有方法“ 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'>

2 个答案:

答案 0 :(得分:3)

一旦有了cv2.findContours()的两个轮廓,就可以使用按位的AND操作来检测相交。具体来说,我们可以使用np.logical_and()。想法是为每个轮廓创建两个单独的图像,然后对它们使用逻辑AND操作。具有正值(1True)的任何点都是交点。因此,由于您只想获取是否存在相交的布尔值,因此我们可以检查相交的图像以查看是否存在单个正值。本质上,如果整个数组为False,则轮廓之间就没有交集。但是,如果只有一个True,则轮廓会接触并因此相交。

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

示例

原始图片

enter image description here

检测到的轮廓

enter image description here

我们现在将两个检测到的轮廓传递给函数并获得此交集:

[[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]]

我们检查intersection数组是否存在True。我们将在轮廓相交处获得True1,在轮廓不相交处获得False0

return intersection.any()

因此我们获得

  

错误

完整代码

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)

答案 1 :(得分:3)

天真无邪的答案是可行的,但在性能方面却受到影响,如示例中那样,它创建了3个图像副本来绘制轮廓,因此执行时间很慢。

我的替代答案如下;

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