OpenCV findContours - 2.4.5堆损坏 [英] OpenCV findContours - 2.4.5 Heap Corruption
问题描述
我有一个堆损坏发生与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 $第一个具体问题是您在<$ c>中手动分配
:数据
成员。 $ 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屋!