OpenCV检测轮廓相交

Posted

技术标签:

【中文标题】OpenCV检测轮廓相交【英文标题】:OpenCV detect contours intersection 【发布时间】:2011-12-18 14:28:57 【问题描述】:

我有 2 个轮廓 A 和 B,我想检查它们是否相交。 A 和 B 都是 cv::Point 类型的向量,并且具有不同的大小

为了检查交叉点,我试图做一个 bitwise_and。这是抛出异常,因为输入的大小不同。我该如何解决 ?

编辑:

所附图片应该可以更好地了解该问题。汽车由蓝色轮廓跟踪,障碍物由粉红色轮廓跟踪。我需要检查十字路口。

【问题讨论】:

【参考方案1】:

一种简单但可能不是最有效 (??) 的方法是使用 drawContours 创建两张图像:一张是汽车的轮廓,另一张是障碍物的轮廓。

然后and它们在一起,任何仍然为正的点都将是交点。

一些伪代码(我使用 Python 接口,因此无法正确理解 C++ 语法,但它应该足够简单,您可以转换):

import numpy as np # just for matrix manipulation, C/C++ use cv::Mat
# find contours.
contours,h = findContours( img, mode=RETR_LIST, method=CHAIN_APPROX_SIMPLE )
# Suppose this has the contours of just the car and the obstacle.

# create an image filled with zeros, single-channel, same size as img.
blank = np.zeros( img.shape[0:2] )

# copy each of the contours (assuming there's just two) to its own image. 
# Just fill with a '1'.
img1 = drawContours( blank.copy(), contours, 0, 1 )
img2 = drawContours( blank.copy(), contours, 1, 1 )

# now AND the two together
intersection = np.logical_and( img1, img2 )

# OR we could just add img1 to img2 and pick all points that sum to 2 (1+1=2):
intersection2 = (img1+img2)==2

如果我查看intersection,我会得到一个图像,轮廓相交处为 1,其他地方为 0。

或者,您可以使用drawContours( blank.copy(), contours, 0, 1, thickness=-1 ) 填充整个 轮廓(不仅是轮廓,还填充内部),然后intersection 图像将包含轮廓之间的交叉区域.

【讨论】:

如何使用imshow()查看路口,在使用imshow显示路口时,获取到黑色图片。但是当打印交点时,如所描述的观察到的和零。是否有任何工作可以可视化交叉路口 @Saikrishna 使用灰度值。如果是为了可视化,请在 20... 处绘制轮廓,这是可见但不饱和的。路口会更亮(40 或更多) 我认为在只绘制​​轮廓边界的情况下,有必要使用4-连通线而不是8-连通线,因为否则可能会错过某些具有特定相交角度的2条对角线的交点。跨度> 当一个轮廓包含另一个轮廓时,第一个解决方案也不会检测到这种情况。 drawContours不是只填大纲吗?所以你会得到轮廓之间的交叉点?我必须添加cv2.FILLED 作为参数:img2 = cv2.drawContours(blank.copy(), contours, 0, 1, cv2.FILLED)【参考方案2】:

如果您首先使用几乎任何您能想到的一致排序标准对向量进行排序,那么您可以直接在向量上使用std::set_intersection。如果轮廓与图像大小相比较短,这可能比接受的答案更快。

【讨论】:

这对于“压缩”轮廓是错误的,两个轮廓即使没有公共顶点也可能相交。 @user202729 是的。对于非压缩的 8 连接轮廓也是如此。但不适用于 4 连接。【参考方案3】:

我发现Clipper 库对于这些用途非常有用。 (将cv::Point 的向量转换为 Clipper Path 对象很简单。)

【讨论】:

【参考方案4】:

C++ 测试代码,基于 math.coffee 的回答:

    vector< Point> merge_contours(vector <Point>& contour1, vector <Point>& contour2, int type)
    // get work area        
    Rect work_area = boundingRect( contour1 ) | boundingRect( contour2 );        
    
    Mat merged = Mat::zeros(work_area.size(), CV_8UC1);        
    Mat contour1_im = Mat::zeros(work_area.size(), CV_8UC1);
    Mat contour2_im = Mat::zeros(work_area.size(), CV_8UC1);
    
    //draw
    vector<vector<Point> > shifted1;
    shifted1.push_back(shift_contour(contour1, work_area.tl()));
    drawContours( contour1_im, shifted1, -1, 255, -1);
    vector<vector<Point> > shifted2;
    shifted2.push_back(shift_contour(contour2, work_area.tl()));
    drawContours( contour2_im, shifted2, -1, 255, -1);
    
    //imshow("contour1 debug", contour1_im);
    //imshow("contour2 debug", contour2_im);        
    
    if( type == 0 )
        // intersect
        bitwise_or( contour1_im, contour2_im, merged);
    else
        // unite
        bitwise_and( contour1_im, contour2_im, merged);        
    //imshow("merge contour debug", merged);
    
    // find
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    findContours(merged,contours,hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
    
    if(contours.size() > 1)
        printf("Warn: merge_contours has output of more than one contours.");
    
    
    return shift_contour(contours[0], work_area.tl() * -1);        

【讨论】:

以上是关于OpenCV检测轮廓相交的主要内容,如果未能解决你的问题,请参考以下文章

OPENCV图像轮廓检测

OpenCV轮廓检测

OpenCV-Python实战(11)——OpenCV轮廓检测相关应用

OpenCV-Python实战(10)——详解 OpenCV 轮廓检测

使用openCV进行边缘检测二值化轮廓轮廓检测BGR灰度图二值化,专栏:各种openCV实践的案例

图像轮廓检测错误:OpenCV、C++