为啥opencv会找到轮廓的边界点,无序且不完整?

Posted

技术标签:

【中文标题】为啥opencv会找到轮廓的边界点,无序且不完整?【英文标题】:Why opencv finds the contours' border-points, disordered and uncompleted?为什么opencv会找到轮廓的边界点,无序且不完整? 【发布时间】:2014-07-03 00:41:14 【问题描述】:

我想写一个程序,可以用C++的opencv纠正答题卡。

但是当我使用cvFindContours() 时,轮廓的边界点还没有完全找到。

我的意思是,我没有封闭对象。 (我使用cvDilatecvErode,不知道它们的真正功能,但是扩张省略了一些轮廓并腐蚀添加了一些额外的、不需要的轮廓)

更大的问题是我想在每个轮廓中找到一个中心点(将答案的位置与预定义的左侧和向下侧边栏进行比较),但是有些轮廓不是对称的,所以中心点的位置并不完全在中间。

看左边的黑色图片,在第二个轮廓中,检测到了一些底部的点,但没有检测到顶部的点。

cvCvtColor(pic, blackpic, CV_BGR2GRAY);
cvResize(blackpic, src0);
cvSmooth(src0, src0, CV_GAUSSIAN, 3, 3);
cvThreshold(src0, src, 140, 255, CV_THRESH_BINARY);


//Find Contour
CvMemStorage* st = cvCreateMemStorage();
CvSeq* first_contour = NULL;
cvFindContours(src, st, &first_contour, sizeof(CvContour), CV_RETR_LIST);

vector <vector <CvPoint> > cont;
vector <CvPoint> dot;

for (CvSeq* s = first_contour; s != NULL; s = s->h_next)
    if (s -> total > C_MIN_SIZE && cvContourArea(s) > C_MIN_AREA)
    
        cont.push_back(vector <CvPoint>()); //convert seq to vector
        CvPoint c = cvPoint(0,0);
        for (int i = 0; i < s -> total; i++)
        
            CvPoint* p = CV_GET_SEQ_ELEM(CvPoint, s, i);
            cont.back().push_back(*p);
            CV_IMAGE_ELEM(test, uchar, p -> y, p -> x) = 255; //drawing each contour's point
            c.x += p -> x; //find the center point by average
            c.y += p -> y;
        
        c.x = floor(c.x / s -> total);
        c.y = floor(c.y / s -> total);
        dot.push_back(c);
    

虽然我使用的是 C++,但我使用了 cv::Mat 和 cv::Point(C++ 结构)的 IplImage* 和 CvPoint(opencv 的 c 结构),如果可能,请不要使用 Mat 和 C++ 模式。

我不明白,当我通过cvDrawContours() 绘制轮廓时,轮廓是完全绘制的,但是当我亲自迭代轮廓的点并逐点绘制它们时,似乎大多数都是未检测到!

【问题讨论】:

findContours 有不同的方式来表示轮廓。一种方法(默认)是仅保存“一些”点并通过假设直线在它们之间进行插值。最有可能的是,drawContours 会填充这些线条,但您不会。在 C++ 中保存所有点,使用方法CV_CHAIN_APPROX_NONE。根据docs.opencv.org/modules/imgproc/doc/… C 语法使用完全相同的参数。 我想,默认情况下所有的点都被存储了。谢谢 + 为什么你们 *** 的成员只是喜欢具有特殊问题的问题,而您几乎不理解他们的标题? “所有简单的问题都会被否决”我认为这一定是您在 *** 中的首要原则。我搜索,尝试了几个小时,然后感到困惑!所以我有权利提问!但是你认为我的问题不是计算机行业的史诗,所以让我们立即投反对票! 【参考方案1】:

对于您的第一个问题,您可以在 Internet 上找到数以千计的链接来解释 Erode, Dilate 和所有其他基本图像处理支柱,花点时间阅读文档,不要跳过步骤。

第二个问题:

我不确定您对轮廓中心的期望是什么?你认为你会在这些椭圆的中心有一个点吗?不,这永远不会发生,如果是这样,恭喜图像处理历史上的这一大堆!

我建议做的是解决您的问题的简单操作:

    找到轮廓(就像你现在做的那样) 计算每个轮廓的中心 当您将答案与中心位置进行比较时,不要使用a == b 进行比较,因为这永远不会发生!相反,使用距离(阈值)的比较来确保您的软件的运行

例子:

bool correct;
CvPoint answer, center;
double distance = sqrt((answer.X - center.X)^2 + (answer.Y - center.Y)^2); // Euclidean distance

// judge using this distance 

if (distance <= 5)    // here you select the number as you (want) i gave example 5

    correct = true; // correct answer :)

祝你好运

【讨论】:

我没有复制代码的下一行,在这些行中,我不是通过 == 来精确比较这些点,而是使用“8 像素”范围比较它们。 感谢您告诉我无法找到确切的中心。

以上是关于为啥opencv会找到轮廓的边界点,无序且不完整?的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV实战(15)——轮廓检测详解

opencv 9 -- 轮廓 近似方法

opencv 9 -- 轮廓 近似方法

python-opencv轮廓基本绘制

opencv 9 -- 轮廓 找 和 画

opencv如何读取多边形区域内的像素值?