4

我正在使用 OpenCV 2.4 来计算图像的凸包。

我也在做一些处理以消除图像中的一些噪声,这与问题并不真正相关。

计算convexHull的代码如下:

...
cv::Mat sourceImage; // assume something is already here please
cv::vector<cv::Vec4i> hierarchy;    
std::vector<std::vector<cv::Point> > contours;

cv::findContours( sourceImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE,cv::Point(0, 0));

// Find the convex hull object for each contour
vector<cv::vector<cv::Point> >hull( contours.size() );

for (int i = 0; i < contours.size(); i++)
{
    convexHull( contours[i], hull[i], false );
}
...

拥有convexHull和轮廓我现在想计算hull(s)的convexityDefects,通过查看opencv文档我认为它会是这样的:

cv::Vec4i defects;  
convexityDefects(cv::Mat(contours),  hull, defects);

这样做我得到这个错误:

OpenCV Error: Assertion failed (ptnum > 3) in convexityDefects, file ./opencv/opencv/modules/imgproc/src/contours.cpp, line 1969

关于使用convexityDefects时我做错了什么的任何想法?

Opencv 凸面缺陷文档

提前致谢。

更新

感谢影射的回答,我将主循环代码更新为:

std::vector<Vec4i> defects; 
vector<cv::vector<cv::Point> >hull( contours.size() );

for (int i = 0; i < contours.size(); i++)
{  
    convexHull( contours[i], hull[i], false );
    convexityDefects(contours[i], hull[i], defects[i]);
}

使用它,我现在得到的错误是:

OpenCV Error: Assertion failed (hull.checkVector(1, CV_32S) > 2) in convexityDefects
4

4 回答 4

4

来自 openCV 维基:

查找轮廓的凸面缺陷。

所以你应该将它包含在你的循环中。

std::vector<Vec4i> defects; 
vector<cv::vector<int> >hull( contours.size() );

for (int i = 0; i < contours.size(); i++)
{  
    convexHull( contours[i], hull[i], false );
    convexityDefects(contours[i], hull[i], defects[i]);
}

另外,正如您提到的,在 wiki 中说:

hull – 输出凸包。它是索引的整数向量或点的向量。在第一种情况下,外壳元素是原始数组中凸包点的基于 0 的索引(因为凸包点集是原始点集的子集)。在第二种情况下,包元素是凸包点本身。

于 2012-05-17T05:11:53.710 回答
4

对于那些没有阅读评论或没有看到评论的人,解决方案是使用:

vector<cv::vector<int> >hull;

创建船体而不是:

vector<cv::vector<Point> >hull;

因为convexityDefects 仅适用于存储为一系列索引而不是一系列点的外壳。

可悲的是,这带来了另一个问题,因为 drawContours 仅绘制存储为一系列点而不是一系列索引的轮廓!因此,如果您想在稍后阶段绘制船体,您可能希望在查找船体时创建 2 个商店,一个用于绘图,一个用于从中查找缺陷。类似于以下作品的内容:

  // create storage space
  vector<vector<int> > hullsI(contours.size());
  vector<vector<Point> > hullsP(contours.size());
  vector<vector<Vec4i> > defects(contours.size());

  for(int i = 0; i <contours.size(); ++i){
     //find the hulls
     convexHull(contours[i], hullsI[i], true);
     convexHull(contours[i], hullsP[i], true);
     //find the defects  
     convexityDefects(contours[i], hullsI[i], defects[i]);
     }

使用不同的方法来绘制船体而不是计算两次可能更有效,但这是我看到的最优雅的方法。

此外,我自己(Java 人)仍然掌握 C/C++ 的窍门,但我相信如果您添加using namespace cv到代码的顶部,您可以省去在整个代码中使用 cv:: 的麻烦。

希望我没有踩脚趾影射,如果我有的话,根本不是我的意图。

于 2012-07-06T16:21:15.413 回答
3

我遇到了上面提到的问题,但最后我写了正确的:)

vector<vector<Point>> hull( contours.size() );
vector<vector<int> > hullsI(contours.size());
vector<vector<Vec4i>> convdefect(contours.size());

for( int i = 0; i < contours.size(); i++ )
{ 
    convexHull( Mat(contours[i]), hull[i], false);
    convexHull( Mat(contours[i]), hullsI[i], false);        
    if(hullsI[i].size() > 3 )
        convexityDefects(contours[i],hullsI[i],convdefect[i]);
}
/// Draw contours + hull results
Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
{
    size_t count = contours[i].size();
    if( count <300 )
        continue;

    //Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255));
    drawContours( drawing, contours, i, Scalar(255,0,0), 1, 8, vector<Vec4i>(), 0, Point());
    drawContours( drawing, hull, i, Scalar(0,0,255), 1, 8, vector<Vec4i>(), 0, Point());
}

/// Draw convexityDefects
for( int i = 0; i< contours.size(); i++ )
{
    size_t count = contours[i].size();
    if( count <300 )
        continue;

    vector<Vec4i>::iterator d=convdefect[i].begin();
    while( d!=convdefect[i].end() ) {
        Vec4i& v=(*d);
        int startidx=v[0]; Point ptStart( contours[i][startidx] );
        int endidx=v[1]; Point ptEnd( contours[i][endidx] );
        int faridx=v[2]; Point ptFar( contours[i][faridx] );
        float depth = v[3] / 256;

        line( drawing, ptStart, ptEnd, Scalar(0,255,0), 1 );
        line( drawing, ptStart, ptFar, Scalar(0,255,0), 1 );
        line( drawing, ptEnd, ptFar, Scalar(0,255,0), 1 );
        circle( drawing, ptFar,   4, Scalar(0,255,0), 2 );
        d++;
    }
}
于 2013-01-03T10:37:36.323 回答
2

在向我提出解决方案之前,我一直有同样的错误。contours[i]只需在调用 convexityDefects 之前检查大小

/// Find the convex hull object for each contour
vector<vector<int> > hullsI(contours.size());
vector<vector<Point> > hullsP(contours.size());
vector<vector<Vec4i> > defects(contours.size());

for(int i = 0; i <contours.size(); ++i){
    //find the hulls
    convexHull(contours[i], hullsI[i], false, false);
    convexHull(contours[i], hullsP[i], false, true);
    //find the defects
    if (contours[i].size() >3 )
    {
        convexityDefects(contours[i], hullsI[i], defects[i]);            
    }

}

希望能帮助到你 :)

于 2012-09-11T12:36:24.340 回答