0

此代码用于从 cam 捕获,然后在每一帧上将其转换为 HSV 图像,然后对其应用颜色分割以找到红色、绿色和蓝色对象,然后找到每个对象的轮廓并将其存储在 CVSeq 中。

代码运行良好,但问题是 10 分钟后它会引发运行时异常,因为尽管我cvClearMemStorage()用来释放内存,但没有内存可以分配给新轮廓。

#include <cv.h>
#include <highgui.h>

CvSeq *contours;
IplImage* frame=0;
CvMemStorage* g_storage;

//This function threshold the HSV image and create a binary image
IplImage* GetThresholdedRedImage(IplImage* imgHSV)
{
       IplImage* imgThresh = cvCreateImage(cvGetSize(imgHSV),IPL_DEPTH_8U, 1);
       cvInRangeS(imgHSV, cvScalar(160,160,60), cvScalar(180,256,256), imgThresh);

       //CvMemStorage* g_storage = cvCreateMemStorage(0);
       cvFindContours( cvCloneImage(imgThresh), g_storage, &contours );
       if( contours )
       {
           cvDrawContours(frame, contours, cvScalar(0, 255, 0), cvScalarAll(255), 100);
           cvClearSeq(contours);

       }

       cvClearMemStorage(g_storage);

       return imgThresh;
}

IplImage* GetThresholdedGreenImage(IplImage* imgHSV)
{
       IplImage* imgThresh=cvCreateImage(cvGetSize(imgHSV),IPL_DEPTH_8U, 1);
       cvInRangeS(imgHSV, cvScalar(38,160,60), cvScalar(75,256,256), imgThresh);

       //CvMemStorage* g_storage = cvCreateMemStorage(0);
       cvFindContours( cvCloneImage(imgThresh), g_storage, &contours );
       if( contours )
       {
           cvDrawContours(frame, contours, cvScalar(0, 255, 255), cvScalarAll(255), 100);
           cvClearSeq(contours);
       }

       cvClearMemStorage(g_storage);

       return imgThresh;
}

IplImage* GetThresholdedBlueImage(IplImage* imgHSV)
{
       IplImage* imgThresh=cvCreateImage(cvGetSize(imgHSV),IPL_DEPTH_8U, 1);
       cvInRangeS(imgHSV, cvScalar(75,160,60), cvScalar(130,256,256), imgThresh);

       //CvMemStorage* g_storage = cvCreateMemStorage(0);
       cvFindContours( cvCloneImage(imgThresh), g_storage, &contours );
       if( contours )
       {
           cvDrawContours(frame, contours, cvScalarAll(255), cvScalarAll(255), 100);
           cvClearSeq(contours);
       }

       cvClearMemStorage(g_storage);

       return imgThresh;
}

int main()
{
      CvCapture* capture =0;

      capture = cvCaptureFromCAM(0);
      if(!capture)
      {
        printf("Capture failure\n");
        return -1;
      }

      //IplImage* frame=0;

      cvNamedWindow("Video");
      cvNamedWindow("Red");
      //cvNamedWindow("Yellow");
      //cvNamedWindow("Orange");
      cvNamedWindow("Green");
      cvNamedWindow("Blue");
      //cvNamedWindow("Violet");
      g_storage = cvCreateMemStorage(0);

      //iterate through each frames of the video
      while(true)
      {

            frame = cvQueryFrame(capture);
            if(!frame) break;

            frame = cvCloneImage(frame);
            cvSmooth(frame, frame, CV_GAUSSIAN,3,3); //smooth the original image using Gaussian kernel

            IplImage* imgHSV = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
            cvCvtColor(frame, imgHSV, CV_BGR2HSV); //Change the color format from BGR to HSV

            IplImage* redImgThresh = GetThresholdedRedImage(imgHSV);
            IplImage* blueImgThresh = GetThresholdedBlueImage(imgHSV);
            IplImage* greenImgThresh = GetThresholdedGreenImage(imgHSV);

            //cvClearSeq(contours);

            cvSmooth(redImgThresh, redImgThresh, CV_GAUSSIAN,3,3); //smooth the binary image using Gaussian kernel
            cvSmooth(blueImgThresh, blueImgThresh, CV_GAUSSIAN,3,3);
            cvSmooth(greenImgThresh, greenImgThresh, CV_GAUSSIAN,3,3);

            cvShowImage("Red", redImgThresh);
            cvShowImage("blue", blueImgThresh);
            cvShowImage("green", greenImgThresh);
            cvShowImage("Video", frame);

            //Clean up used images
            cvReleaseImage(&imgHSV);
            cvReleaseImage(&redImgThresh);
            cvReleaseImage(&blueImgThresh);
            cvReleaseImage(&greenImgThresh);
            cvReleaseImage(&frame);

            //Wait 50mS
            int c = cvWaitKey(10);
            //If 'ESC' is pressed, break the loop
            if((char)c==27 ) break;
      }

      cvDestroyAllWindows() ;
      cvReleaseCapture(&capture);

      return 0;
}
4

2 回答 2

0

我不喜欢的代码的一部分是:

frame = cvCloneImage(frame);
...
cvReleaseImage(&frame);

由于,从highgui.h

 /* Just a combination of cvGrabFrame and cvRetrieveFrame
 !!!DO NOT RELEASE or MODIFY the retrieved frame!!!      */
 CVAPI(IplImage*) cvQueryFrame( CvCapture* capture );

我建议使用不同的指针来检索图像并将其克隆到这个。

IplImage* tempFrame = cvCloneImage(frame);
frame = cvCloneImage(tempFrame);
...
cvReleaseImage(&frame);

另请阅读:OpenCV 简介

请参阅使用视频序列部分。

于 2013-02-21T21:19:06.447 回答
0

如果您使用 MSVC 编译此...

main()在包含您的入口点的同一文件中包含以下代码行:

#if _DEBUG
#   define _CRTDBG_MAP_ALLOC
#   include <stdlib.h>
#   include <crtdbg.h>
#endif

然后,在main()函数的最顶部,包括以下内容:

_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

这将告诉 VC 运行时动态监视应用程序中的资源泄漏。
编译并运行您的应用程序,然后在几秒钟左右后退出它。

如果您查看输出窗口,您应该会看到一些类似于以下内容的行:

Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

这里的兴趣点是{18} normal block,它是内存分配数和块类型。查看列表中的第一个分配编号,并将其复制下来。

现在,就在您在函数中编写_CrtSetDbgFlag()的位置下方main(),粘贴以下内容:

_CrtSetBreakAlloc(18); // Where `18` is the memory allocation number

如果您再次编译并运行,您的项目应该在分配该内存块的位置中断。如果它在代码的未知部分中中断,您可以检查“调用堆栈”窗口以将其追溯到您编写的代码。

您应该使用此信息来了解哪些对象需要被释放,并让您大致了解在哪里这样做。只需重复此过程,直到不再检测到泄漏。

所有这些信息以及更多信息都可以通过MSDN 中的Memory Leak Detection and Isolation找到。

如果您正在为 UNIX 编译...

检查此线程以获取更多信息。

现在,就如何解除分配而言...

好吧,这实际上取决于分配的内容(以及确切的分配方式)。
在 的情况下CvSeq,您通常根本不需要释放它,因为它(似乎)由 OpenCV 管理,直到cvReleaseMemStorage被调用。由于我在您发布的代码中的任何地方都没有看到对此方法的调用,因此这可能会导致您的资源泄漏......

因此,我敦促您按照上述步骤自行确定代码是否在cvCreateMemStorage. 如果是这样,请确保在cvReleaseMemStorage完成使用后包含对的调用。

另一方面,cvClearMemStorage描述如下: “该函数
存储的顶部(可用空间边界)重置为最开始。此函数不会释放任何内存。如果存储有父存储,则该函数将所有块返回到父母。”

您是否可能混淆了这两个功能?

于 2013-05-24T04:29:46.367 回答