【问题标题】:OpenCV findContours - 2.4.5 Heap CorruptionOpenCV findContours - 2.4.5 堆损坏
【发布时间】:2013-05-13 13:23:22
【问题描述】:

我在 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,这对我有用,我得到了预期的结果。

【问题讨论】:

    标签: c++ opencv


    【解决方案1】:

    罪魁祸首是您使用了cv::Mat*new。这是一个坏主意。动态分配cv::Mat 对象是不必要的,而且经常有问题(正如您所发现的)。更好的解决方案是通过值或const 引用传递它们,因为底层图像数据被引用,而cv::Mat 是浅拷贝。

    第一个具体问题是你在CVMatFromUC()中手动分配data成员:

    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() 首先被评估,并隐式转换为 trueCV_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() 的调用和相关的数据副本。但是,我尝试并得到了内存错误,因此可能还有其他问题潜伏在其他地方。

    【讨论】:

    • Err,你对返回类型是正确的。我最初在 Canny(outp, inp) 拥有它,因此 inp 持有边缘图。但是在调试这个的时候,我把它改成了更多的变量,导致返回错误。我实施了你的建议,但我仍然遇到同样的堆损坏。 (在编辑中更新了代码)
    • 好的,需要您的部分建议来解决此问题,但主要问题似乎是我从调试应用程序链接了发布库。
    【解决方案2】:

    -改变findContours如下 findContours(灰色, 轮廓, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

    • 如果它再次不起作用,您的问题可能是未初始化的内存。您可以尝试创建新的 Mat outP2 并将原始的克隆到其中。

    • 然后从以下步骤使用 outP2:

    cv::Canny(*outP2, canny_output, 10.0, 15.0); ... ...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-15
      • 2010-12-07
      • 2011-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多