OpenCV findContours - 2.4.5堆损坏 [英] OpenCV findContours - 2.4.5 Heap Corruption

查看:393
本文介绍了OpenCV findContours - 2.4.5堆损坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个堆损坏发生与100%确定的findContours函数。当我不使用它,一切正常。

  unsigned char * UCFromMatUC(cv :: Mat& input)
{
int size = input.size.p [0] * input.size.p [1];
unsigned char * result = new unsigned char [size];
memcpy(result,input.data,size);
return result;
}

unsigned char * CannyEdgeCV(unsigned char * input,int width,int height)
{
std :: vector< std :: vector< cv: :Point> >轮廓;
std :: vector< cv :: Vec4i>层次;

cv :: RNG rng(12345);

cv :: Mat inp(cv :: Size(width,height),CV_8UC1,input);
cv :: Mat canny_output;
cv :: Mat outp;
cv :: blur(inp,outp,cv :: Size(3,3));
cv :: Canny(outp,canny_output,4.0,8.0);
if(canny_output.type()!= CV_8UC1){
return NULL;
}

cv :: findContours(canny_output,contour,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,cv :: Point(0,0));
cv :: Mat drawing = cv :: Mat :: zeros(canny_output.size(),CV_8UC3);
for(int i = 0; i {
cv :: Scalar color = cv :: Scalar(rng.uniform(0,255), (0,255),均匀(0,255));
drawContours(drawing,contour,i,color,2,8,hierarchy,0,cv :: Point());
}

cv :: imwrite(contours.jpg,drawing);

unsigned char * result = UCFromMatUC(canny_output);

返回结果;
}

本来我只使用canny edge贴图,测试轮廓功能的结果。



Canny Edge工作正常,我得到一个预期的图像,但findContours(代码和注释版本中的一个)失败,堆溢出错误。是什么原因导致的?



这是CannyEdgeCV()的入口点,并以640x480 8位灰色图像调用。



编辑:更新的代码。



编辑2:当我试图创建一个最小的例子来重现这个,我的代码失败甚至imread(imagename.bmp );这是很奇怪,所以我开始调查可能会导致这种情况。现在有人写了一个相应的SO问题,你不能混合调试/释放模式库,所以如果你在调试,你必须使用调试DLL,这对我工作,我得到预期的结果。

解决方案

主要原因是您使用 cv :: Mat * new 。这是一个坏主意。动态分配 cv :: Mat 对象是不必要且经常有问题的(如您所发现的)。更好的解决方案是通过值或 const 引用传递它们,因为底层图像数据被引用, cv :: Mat 中手动分配数据成员。 $ c> CVMatFromUC()

  resultMat-> data = input 

你不应该这样做。 cv :: Mat 有其他成员也引用数据位置,你要求麻烦。如果你需要为外部数据创建一个 cv :: Mat 头,你应该创建一个 cv :: Mat 因此:

  cv :: Mat inp(cv :: Size(width,height),CV_8UC1,input); //创建cv :: Mat头,没有内存复制

$ c> canny_output 不正确。 !canny_output.type()首先计算,并隐式转换为 true CV_8UC1 。所以表达式总是 true 。您想要的条件是: canny_output.type()!= CV_8UC1



CVMatFromUC()函数是不必要的。您的函数的改进版本如下:

  uchar * CannyEdgeCV(uchar * input,int width,int height)
{
std :: vector< std :: vector< cv :: Point> >轮廓;
std :: vector< cv :: Vec4i>层次;

cv :: Mat inp(cv :: Size(width,height),CV_8UC1,input); //创建cv :: Mat头,没有内存复制
cv :: Mat canny_output;
cv :: Mat outp;
cv :: blur(inp,outp,cv :: Size(3,3));

cv :: Canny(outp,canny_output,10.0,15.0);
if(canny_output.type()!= CV_8UC1){
return NULL;
}

cv :: findContours(canny_output,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);
// cv :: findContours(canny_output,contour,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_SIMPLE,cv :: Point(0,0));

unsigned char * result = UCFromMatUC(& inp);
return result;
}



我应该注意看起来 CannyEdgeCV 返回它接收到的相同数据,因此可以完全删除对 UCFromMatUC()和相关数据副本的调用。但是,我试图并得到内存错误,所以可能会有其他问题潜伏在其他地方。


I have a heap corruption happening with 100% certainty on the findContours function. When I do not use it, everything works fine.

unsigned char* UCFromMatUC(cv::Mat& input)
{
    int size = input.size.p[0] * input.size.p[1];
    unsigned char* result = new unsigned char[size];
    memcpy(result, input.data, size);
    return result;
}

unsigned char* CannyEdgeCV(unsigned char* input, int width, int height)
{
    std::vector<std::vector<cv::Point> > contours;
    std::vector<cv::Vec4i> hierarchy;

    cv::RNG rng(12345);

    cv::Mat inp(cv::Size(width, height), CV_8UC1, input);
    cv::Mat canny_output;
    cv::Mat outp;
    cv::blur(inp, outp, cv::Size(3,3));
    cv::Canny(outp, canny_output, 4.0, 8.0);
    if(canny_output.type()!=CV_8UC1){
        return NULL;
    }

    cv::findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );
    cv::Mat drawing = cv::Mat::zeros( canny_output.size(), CV_8UC3 );
    for( int i = 0; i< contours.size(); i++ )
    {
        cv::Scalar color = cv::Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
        drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, cv::Point() );
    }

    cv::imwrite( "contours.jpg", drawing );

    unsigned char* result = UCFromMatUC(canny_output);

    return result;
}   

Originally I was only using the canny edge map, but later on I wanted to test the results of the contour functionality.

The Canny Edge works fine, and I get an image as expected, but the findContours (both the one in code and the commented version) fail with a heap corruption error. What causes this?

The entry point for this is the CannyEdgeCV(), and is called with a 640x480 8bit grey image.

Edit: updated code.

Edit2: when I tried to create a minimal example to reproduce this, my code failed at even imread("imagename.bmp"); which was really odd, so I began investigating what might cause this. Now someone else wrote in a corresponding SO question that you cannot mix debug / release mode libraries, so if you are in debug, you have to use debug DLLs, and that worked for me now, I get the expected results.

解决方案

The main culprit is your use of cv::Mat* and new. This is a Bad Idea. It is unnecessary and often problematic (as you have discovered) to dynamically allocate cv::Mat objects. A better solution is to pass them by value or const reference, since the underlying image data is refcounted, and cv::Mat are shallow copied.

The first specific problem is that you manually assign the data member in CVMatFromUC():

resultMat->data = input

You should not do this. cv::Mat has other members which also reference the data location, and you are asking for trouble. If you need to create a cv::Mat header for external data, you should create a cv::Mat like so:

cv::Mat inp(cv::Size(width, height), CV_8UC1, input);   //Create cv::Mat header, no memory copied

Also, your type check for canny_output is incorrect. !canny_output.type() is evaluated first, and implicitly converts to true, as does CV_8UC1. So the expression is always true. The condition you want is: canny_output.type() != CV_8UC1

Given this, it turns out that the CVMatFromUC() function is unnecessary. An improved version of your function follows:

uchar* CannyEdgeCV(uchar* input, int width, int height)
{
    std::vector<std::vector<cv::Point> > contours;
    std::vector<cv::Vec4i> hierarchy;

    cv::Mat inp(cv::Size(width, height), CV_8UC1, input);   //Create cv::Mat header, no memory copied
    cv::Mat canny_output;
    cv::Mat outp;
    cv::blur(inp, outp, cv::Size(3,3));

    cv::Canny(outp, canny_output, 10.0, 15.0);
    if(canny_output.type()!=CV_8UC1){
        return NULL;
    }

cv::findContours(canny_output, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
//cv::findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) );

    unsigned char* result = UCFromMatUC(&inp);
    return result;
}

I should note that it appears that CannyEdgeCV returns the same data that it receives, so it may be possible to remove the call to UCFromMatUC() and the associated data copy entirely. However, I tried and got memory errors, so there might be other problems lurking elsewhere.

这篇关于OpenCV findContours - 2.4.5堆损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆