Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 检查两个轮廓是否相交?_Python_Opencv_Opencv Contour - Fatal编程技术网

Python 检查两个轮廓是否相交?

Python 检查两个轮廓是否相交?,python,opencv,opencv-contour,Python,Opencv,Opencv Contour,我有两个轮廓(cont1和cont2)是从cv2.findContours()收到的。我怎么知道它们是否相交?我不需要坐标,我只需要一个布尔值True或False 我尝试过不同的方法,并且已经尝试过与 if ((cont1 & cont2).area() > 0): 。。。 但是得到的错误是数组没有方法“Area()” 。。。 cont1array=cv2.findContentours(二进制1,cv2.RETR\u列表,cv2.CHAIN\u近似值\u简单)[0] cont2

我有两个轮廓(
cont1
cont2
)是从
cv2.findContours()
收到的。我怎么知道它们是否相交?我不需要坐标,我只需要一个布尔值
True
False

我尝试过不同的方法,并且已经尝试过与

if ((cont1 & cont2).area() > 0):
。。。 但是得到的错误是数组没有方法“Area()”

。。。
cont1array=cv2.findContentours(二进制1,cv2.RETR\u列表,cv2.CHAIN\u近似值\u简单)[0]
cont2array=cv2.findContentours(二进制2,cv2.RETR\u列表,cv2.CHAIN\u近似值\u简单)[0]
...
对于cont1阵列中的cont1:
对于cont2阵列中的cont2:
打印(“续1”)
印刷品(续1)
打印(类型(续1))
打印(“续二”)
印刷品(续二)
打印(类型(续2))
>如果cont1和cont2相交:#我不知道如何检查相交
打印(“是的,它们相交”)
其他:
打印(“不,它们不相交”)
#cont1
# [[172 302]
#  [261 301]
#  [262 390]
#  [173 391]]
# 
#cont2
# [[  0   0]
#  [  0 699]
#  [499 699]
#  [499   0]]
# 

一旦从
cv2.findContours()
获得两条等高线,就可以使用按位
操作来检测交点。具体来说,我们可以使用。其思想是为每个轮廓创建两个单独的图像,然后对其使用逻辑
操作。任何具有正值(
1
True
)的点都将是交点。因此,由于您只希望获得是否存在交点的布尔值,我们可以检查相交图像以查看是否存在单个正值。基本上,如果整个阵列为
False
,则轮廓之间没有相交。但如果只有一个
为真
,则轮廓会接触,从而相交

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()
def ccw(A,B,C):
    return (C[1]-A[1]) * (B[0]-A[0]) > (B[1]-A[1]) * (C[0]-A[0])

def contour_intersect(cnt_ref,cnt_query):

    ## Contour is a list of points
    ## Connect each point to the following point to get a line
    ## If any of the lines intersect, then break

    for ref_idx in range(len(cnt_ref)-1):
    ## Create reference line_ref with point AB
        A = cnt_ref[ref_idx][0]
        B = cnt_ref[ref_idx+1][0] 
    
        for query_idx in range(len(cnt_query)-1):
            ## Create query line_query with point CD
            C = cnt_query[query_idx][0]
            D = cnt_query[query_idx+1][0]
        
            ## Check if line intersect
            if ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D):
                ## If true, break loop earlier
                return True

    return 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 False]]
我们检查
交叉点
数组以查看
True
是否存在。我们将在轮廓相交处获得
True
1
,在轮廓不相交处获得
False
0

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)

nathancy的答案是可行的,但在性能方面会受到影响,如示例中所示,创建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
编辑

测试此代码后,意识到当轮廓没有两个相似点时,此检查失败。因此,我重写了检查两条等高线相交的算法

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()
def ccw(A,B,C):
    return (C[1]-A[1]) * (B[0]-A[0]) > (B[1]-A[1]) * (C[0]-A[0])

def contour_intersect(cnt_ref,cnt_query):

    ## Contour is a list of points
    ## Connect each point to the following point to get a line
    ## If any of the lines intersect, then break

    for ref_idx in range(len(cnt_ref)-1):
    ## Create reference line_ref with point AB
        A = cnt_ref[ref_idx][0]
        B = cnt_ref[ref_idx+1][0] 
    
        for query_idx in range(len(cnt_query)-1):
            ## Create query line_query with point CD
            C = cnt_query[query_idx][0]
            D = cnt_query[query_idx+1][0]
        
            ## Check if line intersect
            if ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D):
                ## If true, break loop earlier
                return True

    return False

您可以使用边界矩形作为第一个粗糙而廉价的步骤,然后再进行细化。我会在单个遮罩图像上绘制每个填充轮廓并计算遮罩交点,但这可能太慢了。在现实世界中,两个不同的轮廓永远不会相交(请参见,例如)。在计算机的近似计算中,一些轮廓可能相交,但其有用性取决于具体情况。你能多说一点你正在试图解决的潜在问题吗?这可能会让人们提供更多有用的答案。这里有一张儿童游戏的图片(如乐透网格)。在游戏中,他们把筷子放在图片上(像冰激凌棒一样)。我需要确定哪些细胞在棍子下面。cont1是这个游戏网格中所有单元格的轮廓(在它们被放在棍子上之前)。cont2是图片中所有木棒的轮廓。在代码中,我做了一个检查:如果单元的轮廓与棒的轮廓交叉,则单元被棒闭合。因此,我需要知道如何确定两个等高线相交的事实。因为在本文中,每个等高线都只是一个点向量,所以在将它们转换为集合(例如,如中所述)后,您能否找到两个点向量的交点?您可以在交叉点处
返回True
或者更简单地
返回交叉点。any()
谢谢,它似乎可以工作,但是如果一个电路位于另一个电路内,然后我得到了一个错误的答案,我会推荐这个答案,而不是选择的答案,因为这会带来巨大的性能提升。这只适用于
cnt\u查询
角位于
cnt\u ref
区域内的情况。必须在cnt_查询中使用
cv2.CHAIN_APPROX_NONE
参数才能使其正常工作。@justas建议使用cv2.CHAIN_APPROX_,以便减少处理轮廓时的内存占用,如本文所强调的