Avoiding memory leaks while using vector<Mat> - opencv

I am trying to write a code that uses opencv Mat objects it goes something like this
Mat img;
vector<Mat> images;
for (i = 1; i < 5; i++)
{
img.create(h,w,type) // h,w and type are given correctly
// input an image from somewhere to img correctly.
images.push_back(img);
img.release()
}
for (i = 1; i < 5; i++)
images[i].release();
I however still seem to have memory leakage can anyone tell me why it is so?
I thought that if the refcount of a mat object = 0 then the memory should be automatically deallocated

You rarely need to call release explicitly, since OpenCV Mat objects take automatically care of internal memory.
Also take care that Mat copy just copies creates a new header pointing to the same data. If the original Mat goes out of scope you are left with an invalid matrix. So when you push the image into the vector, use a deep copy (clone()) to avoid that it the image into the vector becomes invalid.
Since you mentioned:
I have a large 3D image stored in a Mat object. I am running over it using for loops. creating a 2D mat called "image" putting the slices into image, pushing back image to vector images. releasing the image. And later doing a for loop on the images vector releasing all the matrices one by one.
You can store all slices into the vector with the following code. To release the images in the vector, just clear the vector.
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
using namespace std;
int main()
{
// Init the multidimensional image
int sizes[] = { 10, 7, 5 };
Mat data(3, sizes, CV_32F);
randu(data, Scalar(0, 0, 0), Scalar(1,1,1));
// Put slices into images
vector<Mat> images;
for (int z = 0; z < data.size[2]; ++z)
{
// Create the slice
Range ranges[] = { Range::all(), Range::all(), Range(z, z + 1) };
Mat slice(data(ranges).clone()); // with clone slice is continuous, but still 3d
Mat slice2d(2, &data.size[0], data.type(), slice.data); // make the slice a 2d image
// Clone the slice into the vector, or it becomes invalid when slice goes of of scope.
images.push_back(slice2d.clone());
}
// You can deallocate the multidimensional matrix now, if needed
data.release();
// Work with slices....
// Release the vector of slices
images.clear();
return 0;
}

Please try this code, which is basically what you do:
void testFunction()
{
// image width/height => 80MB images
int size = 5000;
cv::Mat img = cv::Mat(size, size, CV_8UC3);
std::vector<cv::Mat> images;
for (int i = 0; i < 5; i++)
{
// since image size is the same for i==0 as the initial image, no new data will be allocated in the first iteration.
img.create(size+i,size+i,img.type()); // h,w and type are given correctly
// input an image from somewhere to img correctly.
images.push_back(img);
// release the created image.
img.release();
}
// instead of manual releasing, a images.clear() would have been enough here.
for(int i = 0; i < images.size(); i++)
images[i].release();
images.clear();
}
int main()
{
cv::namedWindow("bla");
cv::waitKey(0);
for(unsigned int i=0; i<100; ++i)
{
testFunction();
std::cout << "another iteration finished" << std::endl;
cv::waitKey(0);
}
std::cout << "end of main" << std::endl;
cv::waitKey(0);
return 0;
}
After the first call of testFunction, memory will be "leaked" so that the application consumes 4 KB more memory on my device. But not more "leaks" after additional calls for me...
So this looks like your code is ok and the "memory leak" isn't related to that matrix creation and releasing, but maybe to some "global" things happening within the openCV library or C++ to optimize future function calls or memory allocations.

I encountered same problems when iterate openCV mat. The memory consumption can be 1.1G, then it stopped by warning that no memory. In my program, there are macro #define new new(FILE, LINE), crashed with some std lib. So I deleted all Overloading Operator about new/delete. When debugging, it has no error. But when it runs, I got "Debug Assertion Failed! Expression: _pFirstBlock == pHead". Following the instruction
Debug Assertion Error in OpenCV
I changed setting from MT (Release)/MTd (Debug)to
Project Properties >> Configuration Properties >> C/C++ >> Code Generation and changing the Runtime Library to:
Multi-threaded Debug DLL (/MDd), if you are building the Debug version of your code.
Multi-threaded DLL(/MD), if you are building the Release version of your code.
The memory leak is gone. The memory consumption is 38M.

Related

Using Ptr<IplImage> in OpenCv causes memory exception

void hello(Mat original)
{
Mat a=original.clone();
Ptr<IplImage> b = &a.operator IplImage();
return;
}
This function will cause a memory exception. Beause I have to use an old funciton which parameter is IplImage*, I transform the Mat into Ptr and cause memory exception. The above function is just a simplified version.
From OpenCV doc
The operator creates the IplImage header for the matrix without copying the underlying data. You should make sure than the original matrix is not deallocated while the IplImage header is used.
You can pass the reference of the returned header to a function that accepts an IplImage*, likevoid foo(IplImage* img) in the code below):
#include <opencv2\opencv.hpp>
using namespace cv;
void foo(IplImage* img)
{
// Set to blue
cvSet(img, Scalar(255,0,0));
}
int main()
{
// Small green image
Mat3b img(10, 10, Vec3b(0, 255, 0));
{
// Doesn't modify original image
Mat mat = img.clone();
IplImage ipl = mat;
foo(&ipl);
// ipl and mat are blue now
// img is still green
}
{
// Modify original image
IplImage ipl = img;
foo(&ipl);
// ipl and img are blue now
}
// img is blue
return 0;
}
Ptr<T> is a template class thats performs automatic destruction of the wrapped object pointer (see the official documentation for more information about it).
In your code snippet, both a and b are local variables inside the function hello, so they will be destroyed when this function returns and in the reverse order of construction, so a will be destroyed after the destruction of b.
The memory exception could occur because both variables (a and b) refer to the same memory area: in fact, the function Mat::operator IplImage does not copy the underlying data of the Mat object, but creates the IplImage header for these matrix data.
So when the Mat destructor will try to destroy the object a, the portion of memory dedicated to the underlying data will already have been deallocated by b.

OpenCV VideoCapture reading issue

This will probably be a dumb question, but i really can't figure it out.
First of all: sorry for the vague title, i'm not really sure about how to describe my problem in a couple of words.
I'm using OpenCV 2.4.3 in MS Visual Studio, C++. I'm using the VideoCapture interface for capturing frames from my laptop webcam.
What my program should do is:
Loop on different poses of the user, for each pose:
wait that the user is in position (a getchar() waits for an input that says "i'm in position" by simply hitting enter)
read the current frame
extract a region of intrest from that frame
save the image in the ROI and then label it
Here is the code:
int main() {
Mat img, face_img, img_start;
Rect *face;
VideoCapture cam(0);
ofstream fout("dataset/dataset.txt");
if(!fout) {
cout<<"Cannot open dataset file! Aborting"<<endl;
return 1;
}
int count = 0; // Number of the (last + 1) image in the dataset
// Orientations are: 0°, +/- 30°, +/- 60°, +/-90°
// Distances are just two, for now
// So it is 7x2 images
cam.read(img_start);
IplImage image = img_start;
face = face_detector(image);
if(!face) {
cout<<"No face detected..? Aborting."<<endl;
return 2;
}
// Double ROI dimensions
face->x = face->x-face->width / 2;
face->y = face->y-face->height / 2;
face->width *= 2;
face->height *=2;
for(unsigned i=0;i<14;++i) {
// Wait for the user to get in position
getchar();
// Get the face ROI
cam.read(img);
face_img = Mat(img, *face);
// Save it
stringstream sstm;
string fname;
sstm << "dataset/image" << (count+i) << ".jpeg";
fname = sstm.str();
imwrite(fname,face_img);
//do some other things..
What i expect from it:
i stand in front of the camera when the program starts and it gets the ROI rectangle using the face_detector() function
when i'm ready, say in pose0, i hit enter and a picture is taken
from that picture a subimage is extracted and it is saved as image0.jpeg
loop this 7 times
What it does:
i stand in front of the camera when the program starts, nothing special here
i hit enter
the ROI is extracted not from the picture taken in that moment, but from the first one
At first, i used img in every cam.capture(), then i changed the first one in cam.capture(img_start) but that didn't help.
The second iteration of my code saves the image that should have been saved in the 1st, the 3rd iteration the one that should have been saved in the 2nd and so on.
I'm probably missing someting important from the VideoCapture, but i really can't figure it out, so here i am.
Thanks for any help, i really appreciate it.
The problem with your implementation is that the camera is not running freely and capturing images in real time. When you start up the camera, the videocapture buffer is filled up while waiting for you to read in the frames. Once the buffer is full, it doesn't drop old frames for new ones until you read and free up space in it.
The solution would be to have a separate capture thread, in addition to your "process" thread. The capture thread keeps reading in frames from the buffer whenever a new frame comes in and stores it in a "recent frame" image object. When the process thread needs the most recent frame (i.e. when you hit Enter), it locks a mutex for thread safety, copies the most recent frame into another object and frees the mutex so that the capture thread continues reading in new frames.
#include <iostream>
#include <stdio.h>
#include <thread>
#include <mutex>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
void camCapture(VideoCapture cap, Mat* frame, bool* Capture){
while (*Capture==true) {
cap >> *frame;
}
cout << "camCapture finished\n";
return;
}
int main() {
VideoCapture cap(0); // open the default camera
if (!cap.isOpened()) // check if we succeeded
return -1;
Mat *frame, SFI, Input;
frame = new Mat;
bool *Capture = new bool;
*Capture = true;
//your capture thread has started
thread captureThread(camCapture, cap, frame, Capture);
mtx.lock();
imshow(*frame,current_frame);
mtx.unlock();
//Terminate the thread
mtx.lock();
*Capture = false;
mtx.unlock();
captureThread.join();
return 0;
}
This is the code that I wrote from the above advice. I hope someone can get help from this.
When you are capturing the image continuously, no captured frame will be stored in the opencv buffer, such that there will be no lag in streaming.
If you take screenshot/capture image with some time gap inbetween, the captured image will be first stored in the opencv buffer, after that the image is retrieved from the buffer.
When the buffer is full, when you are calling captureObject >> matObject, the last frame from the image is returned, not the current frame in the capturecard/webcam.
So only you are seeing a lag in your code. This issue can be resolved by taking screenshot based on the frames per second (fps) value of the webcam and time taken to capture the screenshot.
The time taken to read frame from buffer is very less, Measure the time taken to take the screenshot. If it is lesser than the fps we can assume that is read from buffer else it means it is captured from webcam.
Sample Code:
For capturing a recent screenshot from webcam.
#include <opencv2/opencv.hpp>
#include <time.h>
#include <thread>
#include <chrono>
using namespace std;
using namespace cv;
int main()
{
struct timespec start, end;
VideoCapture cap(-1); // first available webcam
Mat screenshot;
double diff = 1000;
double fps = ((double)cap.get(CV_CAP_PROP_FPS))/1000;
while (true)
{
clock_gettime(CLOCK_MONOTONIC, &start);
//camera.grab();
cap.grab();// can also use cin >> screenshot;
clock_gettime(CLOCK_MONOTONIC, &end);
diff = (end.tv_sec - start.tv_sec)*1e9;
diff = (diff + (end.tv_nsec - start.tv_nsec))*1e-9;
std::cout << "\n diff time " << diff << '\n';
if(diff > fps)
{
break;
}
}
cap >> screenshot; // gets recent frame, can also use cap.retrieve(screenshot);
// process(screenshot)
cap.release();
screenshot.release();
return 0;
}

Multiple Face Detection

I have a code in OpenCV (in C++) which uses "haarcascade_mcs_upperbody.xml" to detect upper body.
It detects single upper body. How can I make it detect multiple upper bodies.
I think CV_HAAR_FIND_BIGGEST_OBJECT is detecting only the biggest object. But I am not knowing how to solve this issue
The code goes like this:
int main(int argc, const char** argv)
{
CascadeClassifier body_cascade;
body_cascade.load("haarcascade_mcs_upperbody.xml");
VideoCapture captureDevice;
captureDevice.open(0);
Mat captureFrame;
Mat grayscaleFrame;
namedWindow("outputCapture", 1);
//create a loop to capture and find faces
while(true)
{
//capture a new image frame
captureDevice>>captureFrame;
//convert captured image to gray scale and equalize
cvtColor(captureFrame, grayscaleFrame, CV_BGR2GRAY);
equalizeHist(grayscaleFrame, grayscaleFrame);
//create a vector array to store the face found
std::vector<Rect> bodies;
//find faces and store them in the vector array
body_cascade.detectMultiScale(grayscaleFrame, faces, 1.1, 3,
CV_HAAR_FIND_BIGGEST_OBJECT|CV_HAAR_SCALE_IMAGE, Size(30,30));
//draw a rectangle for all found faces in the vector array on the original image
for(int i = 0; i < faces.size(); i++)
{
Point pt1(bodies[i].x + bodies[i].width, bodies[i].y + bodies[i].height);
Point pt2(bodies[i].x, bodies[i].y);
rectangle(captureFrame, pt1, pt2, cvScalar(0, 255, 0, 0), 1, 8, 0);
}
//print the output
imshow("outputCapture", captureFrame);
//pause for 33ms
waitKey(33);
}
return 0;
}
It seems there is some inconsistency in your code, since face_cascade is not defined anywhere, but I assume its type is CascadeClassifier.
detectMultiScale stores all detected objects in the faces vector. Are you sure it contains only one object?
Try removing the CV_HAAR_FIND_BIGGEST_OBJECT flag, because you want all objects to be detected, and not only the biggest one.
Also, make sure you set the minSize and maxSize parameters correctly (see documentation), since those parameters determine the minimal and maximal detectable object sizes.

Memory Leak while using CvSeq in cvFindContours

I am new to OpenCV and i faced some problem while using it.
Currently i am work on Binary Partitioning Tree (BPT) algorithm. Basically I need split the image into many regions, and based on some parameter. 2 regions will merged and form 1 new region, which consists of these 2 regions.
I managed to get initial regions by using cvWatershed. I also created a vector to store these regions, each in 1 vector block. However, I get memory leak when I tried to move the contour information into vector. It says, memory leak.
for (int h = 0; h <compCount; h++) // compCount - Amount of regions found through cvWaterShed
{
cvZero(WSRegion); // clears out an image, used for painting
Region.push_back(EmptyNode); // create an empty vector slot
CvScalar RegionColor = colorTab[h]; // the color of the region in watershed
for (int i = 0; i <WSOut->height; i++)
{
for (int j = 0; j <WSOut->width; j++)
{
CvScalar s = cvGet2D(WSOut, i, j); // get pixel color in watershed image
if (s.val[0] == RegionColor.val[0] && s.val[1] == RegionColor.val[1] && s.val[2] == RegionColor.val[2])
{
cvSet2D(WSRegion, i, j, cvScalarAll(255)); // paint the pixel to white if it has the same color with the region[h]
}
}
}
MemStorage = cvCreateMemStorage(); // create memory storage
cvFindContours(WSRegion, MemStorage, &contours, sizeof(CvContour), CV_RETR_LIST);
Region[h].RegionContour = cvCloneSeq(contours); // clone and store in vector Region[h]
Region[h].RegionContour->h_next = NULL;
}
Is it any ways I can solve this problem? Or is there any alternative that I do not need to create a new memory storage for every region vector? Thank You in advance
You should create the memory storage only once before the loop, cvFindContours can use that, and after the loop you should release the storage with:
void cvReleaseMemStorage(CvMemStorage** storage)
You can also take a look here for the CvMemStorage specification :
http://opencv.itseez.com/modules/core/doc/dynamic_structures.html?highlight=cvreleasememstorage#CvMemStorage
EDIT:
Your next problem is with cvCloneSeq(). Here are some specifications for it:
CvSeq* cvCloneSeq(const CvSeq* seq, CvMemStorage* storage=NULL )
Parameters:
seq – Sequence
storage – The destination storage block to hold the new sequence header and the copied data, if any. If it is NULL, the function uses the storage block containing the input sequence.
As you can see if you don't specify a different memory storage, it will clone the sequence in the same memory block as the input. When you are releasing the memory storage after the loop you are also releasing the last contour and it's clone that you pushed in the list.

Flicker removal using OpenCV?

I am a newbie to openCV. I have installed the opencv library on a ubuntu system, compiled it and trying to look into some image/video processing apps in opencv to understand more.
I am interested to know if OpenCV library has any algorithm/class for removal flicker in captured videos? If yes what document or code should I should look deeper into?
If openCV does not have it, are there any standard implementations in some other Video processing library/SDK/Matlab,.. which provide algorithms for flicker removal from video sequences?
Any pointers would be useful
Thank you.
-AD.
I don't know any standard way to deflicker a video.
But VirtualDub is a Video Processing software which has a Filter for deflickering the video. You can find it's filter source and documents (algorithm description probably) here.
I wrote my own Deflicker C++ function. here it is. You can cut and paste this code as is - no headers needed other than the usual openCV ones.
Mat deflicker(Mat,int);
Mat prevdeflicker;
Mat deflicker(Mat Mat1,int strengthcutoff = 20){ //deflicker - compares each pixel of the frame to a previously stored frame, and throttle small changes in pixels (flicker)
if (prevdeflicker.rows){//check if we stored a previous frame of this name.//if not, theres nothing we can do. clone and exit
int i,j;
uchar* p;
uchar* prevp;
for( i = 0; i < Mat1.rows; ++i)
{
p = Mat1.ptr<uchar>(i);
prevp = prevdeflicker.ptr<uchar>(i);
for ( j = 0; j < Mat1.cols; ++j){
Scalar previntensity = prevp[j];
Scalar intensity = p[j];
int strength = abs(intensity.val[0] - previntensity.val[0]);
if(strength < strengthcutoff){ //the strength of the stimulus must be greater than a certain point, else we do not want to allow the change
//value 25 works good for medium+ light. anything higher creates too much blur around moving objects.
//in low light however this makes it worse, since low light seems to increase contrasts in flicker - some flickers go from 0 to 255 and back. :(
//I need to write a way to track large group movements vs small pixels, and only filter out the small pixel stuff. maybe blur first?
if(intensity.val[0] > previntensity.val[0]){ // use the previous frames value. Change it by +1 - slow enough to not be noticable flicker
p[j] = previntensity.val[0] + 1;
}else{
p[j] = previntensity.val[0] - 1;
}
}
}
}//end for
}
prevdeflicker = Mat1.clone();//clone the current one as the old one.
return Mat1;
}
Call it as: Mat= deflicker(Mat). It needs a loop, and a greyscale image, like so:
for(;;){
cap >> frame; // get a new frame from camera
cvtColor( frame, src_grey, CV_RGB2GRAY ); //convert to greyscale - simplifies everything
src_grey = deflicker(src_grey); // this is the function call
imshow("grey video", src_grey);
if(waitKey(30) >= 0) break;
}

Resources