OpenCV example code for find contours: vector deallocation issue

23,455

You're building your application in debug mode and linking against the Multithreaded Debug DLL CRT. Do you know which CRT the OpenCV DLL(s) are linked against? If it's linked against a static CRT it'll fill up the vector with data allocated from a separate heap, which causes an assertion in the Debug CRT you're using.

If you build your application in Release mode you should no longer see the assert, but you might end up leaking memory. The best thing would be to ensure that both your application and the OpenCV DLL(s) are linked against the same Multithreaded DLL CRT.

EDIT: If you can't rebuild OpenCV to use the same CRT as your application you could try telling the linker to use the same CRT version as OpenCV for your application by modifying the application manifest. See How to Enforce C++ compiler to use specific CRT version? for more information on how to do that.

Share:
23,455
ShdNx
Author by

ShdNx

Updated on February 08, 2020

Comments

  • ShdNx
    ShdNx over 4 years

    I'm trying to get started with contour detection in OpenCV 2.4.2. To this end, I set up a project for OpenCV and copied the whole example code found in the documentation. For future reference, here is the code:

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    
    using namespace cv;
    using namespace std;
    
    Mat src; Mat src_gray;
    int thresh = 100;
    int max_thresh = 255;
    RNG rng(12345);
    
    /// Function header
    void thresh_callback(int, void* );
    
    /** @function main */
    int main( int argc, char** argv )
    {
      /// Load source image and convert it to gray
      src = imread( argv[1], 1 );
    
      /// Convert image to gray and blur it
      cvtColor( src, src_gray, CV_BGR2GRAY );
      blur( src_gray, src_gray, Size(3,3) );
    
      /// Create Window
      char* source_window = "Source";
      namedWindow( source_window, CV_WINDOW_AUTOSIZE );
      imshow( source_window, src );
    
      createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh, thresh_callback );
      thresh_callback( 0, 0 );
    
      waitKey(0);
      return(0);
    }
    
    /** @function thresh_callback */
    void thresh_callback(int, void* )
    {
      Mat canny_output;
      vector<vector<Point> > contours;
      vector<Vec4i> hierarchy;
    
      /// Detect edges using canny
      Canny( src_gray, canny_output, thresh, thresh*2, 3 );
      /// Find contours
      findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
    
      /// Draw contours
      Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
      for( int i = 0; i< contours.size(); i++ )
         {
           Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
           drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
         }
    
      /// Show in a window
      namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
      imshow( "Contours", drawing );
    
      contours.clear(); // Error!!
    }
    

    It compiles fine in Visual Studio 11 RC (Windows 7 SP1), but I get an error at the end of the thresh_callback function. Here is the stacktrace:

    msvcr110d.dll!_CrtIsValidHeapPointer(const void * pUserData) Line 2036
    msvcr110d.dll!_free_dbg_nolock(void * pUserData, int nBlockUse) Line 1322
    msvcr110d.dll!_free_dbg(void * pUserData, int nBlockUse) Line 1265
    msvcr110d.dll!operator delete(void * pUserData) Line 54
    std::allocator<cv::Point_<int> >::deallocate(cv::Point_<int> * _Ptr, unsigned int __formal) Line 586
    std::_Wrap_alloc<std::allocator<cv::Point_<int> > >::deallocate(cv::Point_<int> * _Ptr, unsigned int _Count) Line 888
    std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > >::_Tidy() Line 1542
    std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > >::~vector<cv::Point_<int>,std::allocator<cv::Point_<int> > >() Line 901
    std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > >::`scalar deleting destructor'(unsigned int)
    std::allocator<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > >::destroy<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > >(std::<cv::Point_<int>,std::allocator<cv::Point_<int> > > * _Ptr) Line 624
    std::allocator_traits<std::allocator<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > > >::destroy<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > >(std::allocator<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > > & _Al, std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > * _Ptr)758
    std::_Wrap_alloc<std::allocator<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > > >::destroy<std::vector<cv::Point_<int>,std::allocator<cv::Poin> > > >(std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > * _Ptr) Line 909
    std::_Destroy_range<std::_Wrap_alloc<std::allocator<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > > > >(std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > * _First, std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > * _Last, std::_Wrap_alloc<std::allocator<std::vector<cv::Point_<int>,std::allocator<cv::<int> > > > > & _Al, std::_Nonscalar_ptr_iterator_tag __formal) Line 89
    std::_Destroy_range<std::_Wrap_alloc<std::allocator<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > > > >(std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > * _First, std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > * _Last, std::_Wrap_alloc<std::allocator<std::vector<cv::Point_<int>,std::allocator<cv::<int> > > > > & _Al) Line 80
    std::vector<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > >,std::allocator<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> >::_Destroy(std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > * _First, std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > * _Last) Line 1480
    std::vector<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > >,std::allocator<std::vector<cv::Point_<int>,std::allocator<cv::Point_<int> > > > >::c Line 1416
    thresh_callback(int __formal, void * __formal) Line 143
    opencv_highgui242d.dll!icvUpdateTrackbar(CvTrackbar * trackbar, int pos) Line 1938
    opencv_highgui242d.dll!HGToolbarProc(HWND__ * hwnd, unsigned int uMsg, unsigned int wParam, long lParam) Line 1982
    

    (Note that actually I have a slightly modified version of the example code, added a few printf-s, and a contours.clear() call, which is at line 143, and which triggers the vector deallocation [that would happen automatically at the end of the function] which seems to be the source of the problem. The very same issue occurs with the exact example code as well.)

    The problem seems to be with the deallocation of the contours vector. The same occurs if I try to call contours.clear(). I have examined the variable's contents in the VS debugger, but there's nothing unusual as far as I can tell.

    I tried to clear the vector as soon as it was no longer needed (after the for loop), but it didn't help. I also tried to switch the Platform Toolset to Visual Studio 10, which in turn won't even compile with error messages that are beyond me:

    error C1083: Cannot open include file: 'SDKDDKVer.h': No such file or directory (C:\<project path>\targetver.h) (Line 8, Column 1)
    IntelliSense: cannot open source file "SDKDDKVer.h" (C:\<project path>\targetver.h) (Line 8, Column 1)
    IntelliSense: cannot open source file "windows.h" (C:\<opencv path>\build\include\opencv2\core\operations.hpp (Line 83, Column 3)
    

    Any help would be greatly appreciated. Please note that I'm not a C++ programmer: I have very little knowledge, and even less experience with C++ programming and native programming in general.

    Edit: it turns out that the debugger displayed the wrong line as the source of error. I should have seen in the call stack that the problem was with vector >. So the problematic vector is contours, not hierarchy!

    Edit #2: I also tried to reproduce the issue with a minimal code that creates a vector<vector<cv::Point> >, puts some items in it, then clears it, but I couldn't reproduce the problem.

  • ShdNx
    ShdNx almost 12 years
    I downloaded the OpenCV source code, and built it on my machine. I don't know what it's linked against - I didn't change the preset setting. Where can I see this information? I tried to compile and run my application in Release mode, but the problem persists.
  • Michael
    Michael almost 12 years
    Dependency Walker (dependencywalker.com) can show you for a given DLL/EXE which DLLs it has dependencies to. If anything named something like MSVC* pops up in the dependency tree you can compare that against what your application is using. If no such dependency is found, the DLL is probably linked statically against the CRT.
  • Michael
    Michael almost 12 years
    Also, since you mention that you're building OpenCV yourself (also using visual studio?), you could go into the project properties when building OpenCV and make sure you're using the same CRT as for your application (Code Generation -> Runtime Library).
  • ShdNx
    ShdNx almost 12 years
    I checked the dependencies for my exe and the OpenCV dlls, and it turns out that while OpenCV uses MSVCP100D.DLL, my exe uses MSVCP110D.DLL. I guess this comes from OpenCV being built for VS 10 (it uses CMake), while my exe is built in VS 11. I checked the Code Generation -> Runtime Library option, but there's no option to use earlier runtime library, I can just decide between Multi-threaded (Debug)? (DLL)?
  • ShdNx
    ShdNx almost 12 years
    Thank you very much for your help. I fixed the problem by building my application with VS 2010, so that it uses MSVCP100D.DLL by default.
  • memyself
    memyself over 11 years
    @Michael thanks for your post - I was having the same problem and couldn't figure it out! You say you might end up leaking memory. - how can I check whether this might be the case?
  • Michael
    Michael over 11 years
  • cwadding
    cwadding over 11 years
    I was having this problem with a project using gtest and gmock with opencv. Both gtest and gmock used /MT by default when I built it with cmake and opencv used /MD by default for the runtime library. My console app for my test project was setup to use /MT which was conflicting with a dll project compiled using /MD. To resolve the issue I recompiled gtest and gmock to use /MD and changed my console test app so it is also /MD. Everything works great now. At first I tried recompiling opencv to use /MT but this proved to be more painful but in theory that should work as well.