我正在使用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 );
}
...
同时拥有凸壳和轮廓我现在想要计算船体的凸度缺陷,通过查看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
关于使用凸度缺陷时我做错了什么的任何想法?
Opencv convexityDefects documentation
提前致谢。
更新
感谢Innuendo回答我将主循环代码更新为:
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
答案 0 :(得分:4)
来自openCV wiki:
找出轮廓的凸性缺陷。
所以你应该把它包含在循环中。
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]);
}
另外,如你所说,维基说:
船体 - 输出凸包。它是索引的整数向量 或点矢量。在第一种情况下,船体元件是基于0的 原始阵列中凸包点的索引(自集合以来) 凸壳点的数量是原始点集的子集。在里面 第二种情况,船体元素是凸壳本身。
答案 1 :(得分:4)
对于那些没有阅读评论或没有看到评论的人,解决方案是使用:
vector<cv::vector<int> >hull;
创建船体而不是:
vector<cv::vector<Point> >hull;
因为凸度缺陷仅适用于作为一系列索引而非一系列点存储的外壳。
遗憾的是,这会产生另一个问题,因为drawContours只绘制存储为一系列Points的轮廓而不是一系列索引!因此,如果您想在以后阶段绘制船体,您可能需要在找到船体时创建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]);
}
使用不同的方法绘制船体而不是计算它们两次可能更有效,但这是我看到的最优雅的方式。
此外,我自己仍然掌握着C / C ++(Java家伙),但我相信如果你将using namespace cv
添加到代码顶部,你可以节省整个代码中的cv ::。
希望我没有踩过Innuendo,如果我有的话,根本不是我的意图。
答案 2 :(得分:2)
我一直有同样的错误,直到解决方案呈现给我。在调用convexityDefects
之前,只需检查contours[i]
的大小
/// 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]);
}
}
希望有所帮助:)
答案 3 :(得分:2)
我遇到了上面提到的问题,但最后我写了正确的问题:)
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++;
}
}