1

我有一个运行良好的 c++-cli/opencv 程序,但它的一部分存在内存泄漏。我包括了内存泄漏最多的部分。我已经修复了轮廓 0 和轮廓 1 中的泄漏,这将内存泄漏减少了 1/3,但是仍然存在泄漏。有没有办法仍然减少内存泄漏?谢谢。

// capture video frame and convert to grayscale
     const int nFrames0 = (int) cvGetCaptureProperty( capture0 , CV_CAP_PROP_FRAME_COUNT ); 
     printf("LICENSECOUNT=%d\n",nFrames0);
     img = cvQueryFrame( capture0 );

     IplImage* frame1;
     cvReleaseImage(&frame1);
     frame1=cvCreateImage(cvSize(img->width,img->height),img->depth, 1 );
     cvConvertImage(img, frame1,0);

// create blank images for storing
     cvReleaseImage(&img00);
     img00=cvCreateImage(cvSize(img->width,img->height),img->depth, 3 );
     cvReleaseImage(&img10);
     img10=cvCreateImage(cvSize(img->width,img->height),img->depth, 1 );
     cvReleaseImage(&img20);
     img20=cvCreateImage(cvSize(img->width,img->height),img->depth, 1 );
     cvReleaseImage(&img30);
     img30=cvCreateImage(cvSize(img->width,img->height),img->depth, 1 );
     cvReleaseImage(&imggray1);
     imggray1=cvCreateImage(cvSize(img->width,img->height),img->depth, 1 );
     cvReleaseImage(&imgdiff);
     imgdiff=cvCreateImage(cvSize(img->width,img->height),img->depth, 1 );
     cvReleaseImage(&imgco);
     imgco=cvCreateImage(cvSize(img->width,img->height),img->depth, 1 );

     int flagp=1;
     int licf=0;


    CvSeq *contour0; 
CvSeq* result0;

storage0 = cvCreateMemStorage(0); 



     CvRect r0;
//skip a few frames 
      for (int i=0;i<cf1-1;i++)

     img = cvQueryFrame( capture0 );

// go through all frames to find frames that contain square with certain dimension
     while ( key != 'q')
     {
         img = cvQueryFrame( capture0 );
              if( !img ) break;

        cvConvertImage(img,img00,0);    

          cvSetImageROI(img,cvRect(0,img->height-35,img->width,35));
          cvZero(img);
          cvResetImageROI(img);


          cvConvertImage(img, img10,0);
          cvConvertImage(img, img20,0);
          cvConvertImage(img, imggray1,0);

       int flagp=1;

       cvAbsDiff(img10,frame1,imgdiff);
           cvThreshold(imgdiff, imgdiff,60,255,CV_THRESH_BINARY);


     mem0 = cvCreateMemStorage(0);


     CvSeq *ptr,*polygon;

 //vary threshold levels for segmentation 
     for (int thr=1;thr<11;thr++)

     {
         // do morphology if segmentation does not work
         if (thr==10)
         {

          cvEqualizeHist( img20, img10 );
          cvSetImageROI(img10,cvRect(0,0,20,img->height));
          cvZero(img10);
          cvResetImageROI(img10);
          cvMorphologyEx(img20,img10,img20,cvCreateStructuringElementEx(20,10,10,5,CV_SHAPE_RECT,NULL),CV_MOP_TOPHAT,1);

  IplImage  *frame_copy1 = 0; 
  frame_copy1 = cvCreateImage(cvSize(img10->width,img10->height),IPL_DEPTH_16S,1 ); 
  cvSobel(img10,frame_copy1,1,0,3); 
  cvConvertScaleAbs(frame_copy1, img10, 1, 0);
  cvSetImageROI(img10,cvRect(0,0,20,img->height));
  cvZero(img10);
  cvResetImageROI(img10);

  cvSetImageROI(img10,cvRect(img->width-20,0,20,img->height));
  cvZero(img10);
  cvResetImageROI(img10);


cvMorphologyEx(img10,img10,img20,cvCreateStructuringElementEx(16,5,8,3,CV_SHAPE_RECT,NULL),CV_MOP_CLOSE,1);




cvThreshold(img10,img10,180,255,CV_THRESH_BINARY | CV_THRESH_OTSU);

cvErode(img10,img10,cvCreateStructuringElementEx(10,5,5,2,CV_SHAPE_RECT,NULL),1);
cvErode(img10,img10,cvCreateStructuringElementEx(5,10,2,5,CV_SHAPE_RECT,NULL),1);

cvDilate(img10,img10,cvCreateStructuringElementEx(5,10,2,5,CV_SHAPE_RECT,NULL),1);
cvDilate(img10,img10,cvCreateStructuringElementEx(10,5,5,2,CV_SHAPE_RECT,NULL),1);

cvErode(img10,img10,cvCreateStructuringElementEx(10,5,5,2,CV_SHAPE_RECT,NULL),2);
cvDilate(img10,img10,cvCreateStructuringElementEx(10,5,5,2,CV_SHAPE_RECT,NULL),1);


         }

  //segmenation
         else 


             {
  cvThreshold(img20,img10,thr*255/11,255,CV_THRESH_BINARY);

    cvDilate(img10,img10,cvCreateStructuringElementEx(10,5,5,2,CV_SHAPE_RECT,NULL),1);
cvDilate(img10,img10,cvCreateStructuringElementEx(20,30,10,15,CV_SHAPE_RECT,NULL),1);

    }

   //trim the sides of the image

cvSetImageROI(img10,cvRect(0,0,20,img->height));
cvZero(img10);
cvResetImageROI(img10);

cvSetImageROI(img10,cvRect(img->width-20,0,20,img->height));
cvZero(img10);
cvResetImageROI(img10);


cvReleaseImage(&imgco);

imgco = cvCloneImage(img10); 


///find contours to find squares with certain dimension
cvRelease((void**)&contour0);
int Nc0;
Nc0= cvFindContours(imgco, storage0, &contour0, sizeof (CvContour), 
             CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); 


float k;
int white=0;

while( contour0 )

{

r0 = cvBoundingRect(contour0, 0);
double s,t;
if( ((r0.width*r0.height)>2000 ||  (r0.width*r0.height && thr==10)>1000) && (r0.width*r0.height) < 40000 && (float(r0.width)/float(r0.height))>1.7 && (float(r0.width)/float(r0.height))<5   )  
{

    k=0.8;
if (thr==10 && licf<2)
    k=0.6       ;

   cvSetImageROI(img10,r0);

cc=cvCountNonZero(img10);


cvResetImageROI(img10);

//if area of contour is a percentage of area of rectangle surrounding contour
if (cc>k*r0.width*r0.height && (cvCountNonZero(imgdiff)>10000))
    {   

cvSetImageROI(img,cvRect(0,img->height-35,img->width,35));
cvSet(img, cvScalar(255,255,255));
cvResetImageROI(img);

      //process the image contained inside the contour area 
cvSetImageROI(img,cvRect(r0.x-5,r0.y-10,r0.width+10,r0.height+20));

img30 = cvCreateImage( cvGetSize( img), IPL_DEPTH_8U, 1);  

         cvCvtColor( img, img30, CV_RGB2GRAY );  

         IplImage* img_temp=cvCreateImage(cvSize(2*r0.width,2*r0.height+20),img->depth, 1 );
         IplImage* img_tempo=cvCreateImage(cvSize(2*r0.width,2*r0.height+20),img->depth, 1 );


         cvResize(img30,img_tempo);


CvMemStorage *storage1; 
    CvSeq *contour1; 
    CvSeq* result1;

    storage1 = cvCreateMemStorage(0); 
    CvRect r1;

    //segment inside squares check if square contains letters or numbers with certain dimension

    for (int th=20;th<200;th+=5)

 {
    cvThreshold(img_tempo, img_temp, th, 255, CV_THRESH_BINARY);
    cvThreshold(img_temp, img_temp, 0, 255, CV_THRESH_BINARY_INV);           

    {
cvErode(img_temp,img_temp);


cvDilate(img_temp,img_temp);
cvErode(img_temp,img_temp);

    }

    cvResize(img_temp,img30);

    cvRelease((void**)&contour1);


    int Nc=cvFindContours(img30, storage1, &contour1, sizeof (CvContour), 
             CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE) ;

    int count =0 ;

    while( contour1)


        {

            r1 = cvBoundingRect(contour1, 0);

            int s_y1av=0;
            int s_y2av=0;
            int s_x1av=0;


        {


        int s_x1=r1.x; 

        int s_y1=r1.y;

        float width1=r1.width;

        float height1=r1.height;

        float ratio1= width1/height1;


        //if contours match certain dimensions

        if(ratio1>0.05 && ratio1<1 && height1>0.3*r0.height && width1>0.05*r0.width && width1<0.3*r0.width && width1*height1>60 && width1*height1<2000)

        {  
            count+=1;

        }

        s_y1av=s_y1;
        s_y2av=s_y1+height1;

        }
        contour1=contour1->h_next;
        }

            //if there are more than 3 letters/numbers and less than 9  
        if (count>=3 && count<9)
            {
                th=200;
                thr=11;
                if (thr!=10)
                licf=1;

                if (a)
                {
                cvNamedWindow( "license", 1 );
                cvShowImage( "license", img00 );
                cvWaitKey(1);
                }       


    int jpeg_params[] = { CV_IMWRITE_JPEG_QUALITY, 80, 0 };
    CvMat* buf0 = cvEncodeImage(".jpeg", img00, jpeg_params);
    int img_sz=buf0->width*buf0->height;
    array <Byte>^ hh = gcnew array<Byte> (img_sz);
    Marshal::Copy( (IntPtr)buf0->data.ptr, hh, 0, img_sz );


    if(!myResult->TryGetValue("PLATE", thisList4))
        {
            thisList4 = gcnew List<array<Byte>^>();
            myResult->Add("PLATE", thisList4);}

    thisList4->Add(hh);



             }
        cvResetImageROI(img);

            }

       }



         }

contour0=contour0->h_next;
}


     }



     }
4

3 回答 3

1

较新的 OpenCV C++ 接口会自动为您处理内存 - 分配和解除分配。您应该查看 samples/cpp 文件夹中的示例并将其作为模型。

有了它,您可以忘记内存泄漏。

使用新界面编写的部分代码将如下所示

VideoCapture cap("SomeVideo.avi");
if(!cap.isOpen())
    return 0;

const int nFrames = cap.get(CV_CAP_PROP_FRAME_COUNT );
...
cv::Mat img;
cap >> img;

您应该记住,所有以 cv.. 开头的函数和数据类型,例如 CvSeq,都来自 C 接口,并且在 C++ 中有更好的对应物。

例如:

  • IplImage -> cv::Mat
  • CvPoint -> cv::Point
  • CvSeq -> std::vector<>

等。新界面中的大多数功能保持相同的名称,只是没有“cv”。我在上面写了该规则的主要例外情况。

顺便说一句,您的某些操作似乎是多余的或效率低下的。您应该仔细查看其中哪些是需要的,并重用一些矩阵,以最小化内存分配。

于 2012-07-23T18:15:03.767 回答
1

使用一些内存泄漏检测工具,例如 Valgrind 可能是有用的,也是开始调试的好方法。

于 2012-07-23T17:39:22.170 回答
0

我建议看一下 C++11 中新改进的智能指针。它不会提供自动 garbaje 收集,但至少它处理了 C++ 内存管理的痛苦。您还可以查看 JavaCV,它只是一个包装器,但消除了内存泄漏的一些痛苦。

如果您没有使用最新的 C++ 标准,请查看 autoptr。如果不是,则可能是 OpenCV 的错误。

于 2012-07-23T17:43:59.303 回答