1

I have made an Intensity meter in a pictureBox. For making this intensity meter I have used a picture as Dialer(Dialer.bmp) and making needle using a line. I am doing this using openCV. And changing the needle pointer we have created a thread at form load. And the code is as follows

private: System::Void FocusExposure_Load(System::Object^  sender, System::EventArgs^  e) {
 if(ExposureThreadStatus)
                     th->Abort();
                 th = gcnew Thread(gcnew ThreadStart(this,&FocusExposure::UpdateIntensity)); 
                th->Start();
                ExposureThreadStatus = true;
                }


void UpdateIntensity()
{
Intensity_Values data;
 while(1)
 {

 data = ReadImage(focusBuffer);
    System::Drawing::Bitmap ^bmp=drawImageMeter(data.Max);
     this->pictureBox1->Image =this->pictureBox1->Image->FromHbitmap(bmp->GetHbitmap());
     delete bmp;
     Sleep(1000);                   
 }
}

 System::Drawing::Bitmap^ drawImageMeter(float intensity_value)
{
        IplImage  *Background =cvLoadImage("Dialer.bmp", 1);
        int width,height;
        if(counter==1)
        {
        width=Background->width;
           height=Background->height;
            counter++;
        needle_center.x=width/2;
        needle_center.y=height/2;
        needle_top.x=needle_center.x;
        needle_top.y=needle_center.y-140;
        }
            double const PI = 3.14159265358979323;
           int x1 = needle_top.x; 
           int y1 = needle_top.y;
           int x0=needle_center.x;
           int y0=needle_center.y;
           float angle;
            CurrIntensity = intensity_value;
            angle = CurrIntensity-PreIntensity;
            angle= 0.0703125f * angle;
           // degrees, not radians
           float radians = angle * (PI / 180.0f);   // convert degrees to radians

           if (current_max==1)
            {
                current_max++;
                int N1x1 = needle_top.x; 
                int N1y1 = needle_top.y;
                needle1_top.x = ((N1x1-x0) * cos(radians)) - ((N1y1-y0) * sin(radians)) + x0; 
                needle1_top.y = ((N1x1-x0) * sin(radians)) + ((N1y1-y0) * cos(radians)) + y0;
            }
           needle_top.x = ((x1-x0) * cos(radians)) - ((y1-y0) * sin(radians)) + x0; 
           needle_top.y = ((x1-x0) * sin(radians)) + ((y1-y0) * cos(radians)) + y0;

           cvLine(Background, needle_center, needle1_top, CV_RGB(0, 0, 255), 1, 4, 0);
           cvLine(Background, needle_center, needle_top, CV_RGB(255, 0, 0), 1, 4, 0);
         System::Drawing::Bitmap ^bmp = gcnew System::Drawing::Bitmap(Background->width,Background->height,Background->widthStep,System::Drawing::Imaging::PixelFormat::Format24bppRgb,(System::IntPtr)Background->imageData);
         PreIntensity = CurrIntensity;
         return bmp;

}

This code is working fine and giving output as per my requirement. But The only problem is that when I am opening the form It is giving memory leak. I have seen in task manager and also used Intel Vtune profiler. This profiler is showing Mismatched allocation/deallocation at the following line

IplImage *Background =cvLoadImage("Dialer.bmp", 1);

We need to reload this image because we are drawing the line at the image and when needle pointer has changed it require the Dialer Image without needle.

Can anybody please suggest me any solution to solve this memory leak Issue.

Any help will be appreciated.

karlphillip
  • 92,053
  • 36
  • 243
  • 426
geeta
  • 689
  • 3
  • 17
  • 33
  • What about a cvReleaseImage(&Background)? Sounds like a needed step – Sam Sep 25 '12 at 06:18
  • @vasile Thanks for reply. When I am using cvReleaseImage(&Background) then I am not able to see the Dialer Image on the pictureBox and my application gets suddenly closed. – geeta Sep 25 '12 at 06:56
  • 1
    Because you release the image while you are still using its data packed in bmp. So, my advice is to go back a few steps, and take some lessons on general programming issues, pointers and memory management. Do not take it personally, but you really need it. – Sam Sep 25 '12 at 07:00

1 Answers1

3

It seems that drawImageMeter() is being called more than once. The problem is that each time cvLoadImage() is executed, it allocates space on the HEAP for the pixels. So after displaying the image you should release it with cvReleaseImage() so the data get's freed.

A quick and dirty (and horrible) fix would be to make the variablestatic:

static IplImage* Background =cvLoadImage("Dialer.bmp", 1);

But you should really change the design of your application so Background it's allocated only once. To do that you can either make it global variable and load it on the main() method, or make it a parameter of drawImageMeter():

System::Drawing::Bitmap^ drawImageMeter(IplImage* Background, float intensity_value)
{
   // code
}
Community
  • 1
  • 1
karlphillip
  • 92,053
  • 36
  • 243
  • 426
  • +1; spent hours trying to figure out the cause of memory leaking in my javacpp opencv application. Eventually, I started commenting out all code until literally the first line containing `cvLoadImage()` that was being called in a loop over a large directory of training images.. It was only then that I googled the right words and ended up here. Thank you. – SND Feb 26 '18 at 15:01
  • @SND Glad you found it! – karlphillip Feb 26 '18 at 15:07
  • Same applies to JavaCV in which using `image.release()` doesn't seems to work, but `cvReleaseImage(image)` does. – lepe Aug 01 '18 at 07:57