我在findContours函数上100%确定地发生了堆损坏。当我不使用它时,一切正常。
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;
}
最初我只使用了canny边缘图,但后来我想测试轮廓功能的结果。
Canny Edge工作正常,我按预期得到了一个图像,但是findContours(代码和注释版本中的一个)都因堆损坏错误而失败。是什么原因造成的?
这是CannyEdgeCV()的入口点,使用640x480 8位灰度图像调用。
编辑:更新的代码。
Edit2:当我尝试创建一个最小的例子来重现这个时,我的代码甚至在imread(“imagename.bmp”)失败了;这真的很奇怪,所以我开始调查可能导致这种情况的原因。现在有人写了一个相应的SO问题,你不能混合调试/发布模式库,所以如果你在调试,你必须使用调试DLL,现在对我有用,我得到了预期的结果。
答案 0 :(得分:3)
主要罪魁祸首是您使用cv::Mat*
和new
。这是一个坏主意。动态分配cv::Mat
个对象是不必要的,并且经常会出现问题(正如您所发现的那样)。更好的解决方案是按值或const
引用传递它们,因为基础图像数据已重新计算,cv::Mat
被浅层复制。
第一个具体问题是您在data
中手动分配CVMatFromUC()
成员:
resultMat->data = input
你不应该这样做。 cv::Mat
还有其他成员也引用了数据位置,而您却遇到了麻烦。如果您需要为外部数据创建cv::Mat
标头,则应创建cv::Mat
,如下所示:
cv::Mat inp(cv::Size(width, height), CV_8UC1, input); //Create cv::Mat header, no memory copied
此外,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> > 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;
}
我应该注意,CannyEdgeCV
似乎返回了它收到的相同数据,因此可以完全删除对UCFromMatUC()
的调用和关联的数据副本。但是,我尝试了内存错误,因此潜伏在其他地方可能存在其他问题。
答案 1 :(得分:0)
- 更改findContours如下 findContours(灰色,轮廓,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE);
如果它再次不起作用,你的问题可能是未初始化的内存。您可以尝试创建新的Mat outP2并将原始的一个克隆到此。
然后使用以下步骤中的outP2:
cv :: Canny(* outP2,canny_output,10.0,15.0); ... ...