How to increase memory available to OpenCV - c++

I have a problem with OpenCV.
I need to read from memory, rotate, resize and save some images.
It happens in a thread in 32-bit app (sadly, there is limitation, due to 3rd party library, that doesn't support 64-bit).
My code looks like this:
void processImage(std::vector<char> data)
{
cv::Mat image = cv::imdecode(data, cv::IMREAD_UNCHANGED);
cv::rotate(image, image, image_rotation_);
cv::imwrite(path_.toStdString(), image);
QString preview_path = path_.replace(path_.section("/",-1),"Previews/"+path_.section("/",-1));
cv::resize(image, image, cv::Size(preview_size_.width(), preview_size_.height()));
cv::imwrite(preview_path.toStdString(), image);
image.release();
}
But it crashes on 1st to 3rd pass of imread with message
OpenCV: terminate handler is called! The last OpenCV error is:
OpenCV(3.4.7) Error: Insufficient memory (Failed to allocate 150962688 bytes) in OutOfMemoryError, file C:\opencv-3.4.7\modules\core\src\alloc.cpp, line 72
My app uses around 500Mb of memory and there is about 40% of physical memory free.
Is there any way to resolve such problem or maybe I'm doing something wrong?

Related

Slow shared memory access via pointer

So, here is a setup:
My piece of software processes an image, captured from a device with a camera.
The device runs Linux on top of RTOS and has ARM cpu. A separate process manages image capturing. It uses shared memory and cyclic buffer. My piece of software gets (unsigned char *), I wrap it using openCV cv::Mat using .data attribute. Image sizes are predefined and known.
Turns out processing this cv::Mat is very very slow. Simple cv::resize takes much more time than resize on image loaded from the disk. I mean much more, like x10 more time.
What is the best way to wrap data pointer with cv::Mat? What could be an issue of slow memory access?
I'm sorry for such a scarce description of my problem. Also we have some other piece of software that works fast with this pointer. (Can't look into source code).
Code example:
cv::Mat Frame(480, 640, CV_8UC1);
cv::Mat transformFrame(unsigned char *frame) {
Frame.data = frame;
cv::Mat res;
cv::resize(Frame, res, cv::Size(240, 320), cv::INTER_LINEAR);
return res;
}
cv::resize works very slow if src is cv::Mat wrapped around pointer to shared memory and relatively fast with loaded image from disk.

Capture image frames from Kinect and save to Hard drive

My aim is to capture all the frames (RGB) from Kinect at 30 fps and save them to my hard drive. For doing this I took the following approach.
Get the frames from Kinect and store them in an array buffer. Since writing to disk (using imwrite()) takes a bit of time and I may miss some frames while doing so, so instead of directly saving them to the disk, I store them in an array. Now, I have another parallel thread that accesses this array and writes the individual frames to the disk as images.
Now I have used a static array of size 3000 and type Mat. This will suffice since I need to store frames for 1.5 minute videos (1.5 minutes = 2700 frames). I have declared the array as follows :
#define NUM_FRAMES 3000
Mat rgb[NUM_FRAMES];
I have already tested this limit by reading images and saving them to the array using the following code :
for(int i=0; i<NUM_FRAMES; i++)
{
Mat img = imread("image.jpg", CV_LOAD_IMAGE_COLOR);
rgb[i] = img;
imshow("Image", img);
cvWaitKey(10);
}
The above code executed flawlessly.
But one problem is that the code I am using for capturing image using Kinect, captures the image in an IplImage. Thus I need to convert the image to cv::Mat format before using it. I convert it using the following command:
IplImage* color = cvCreateImageHeader(cvSize(COLOR_WIDTH, COLOR_HEIGHT), IPL_DEPTH_8U, 4);
cvSetData(color, colorBuffer, colorLockedRect.Pitch); // colorBuffer and colorLockedRect.Pitch is something that Kinect uses. Not related to OpenCv
rgb[rgb_read++] = Mat(color, FLAG);
Now here lies my problem. Whenever I am setting #define FLAG true, it causes memory leaks and gives me OpenCv Error: Insufficient memory (failed to allocate 1228804 bytes) error.
But if I use #define FLAG false it works correctly, but the frames that I am getting is erroneous as shown below. They are three consecutive frames.
I was moving around my arm and the image got cut in between as can be seen from above.
Can someone please point out the reason for this weird behavior or any other alternate way of obtaining the desired result. I have been struggling with this since a few days now. Please ask for if any further clarifications are required.
I am using OpenCV 2.4.8, Kinect SDK for Windows version-1.8.0 and Microsoft Visual Studio 2010.
Also can someone please explan to me the role of the CopyData parameter in Mat::Mat. I have already gone through this link, but still it's not completely clear. Maybe that's why I could not solve the above error in the first place since it's working is not very clear.
Thanks in advance.
first, do not use IplImages, stick with cv::Mat, please.
the equivalent code for that would be:
Mat img_borrowed = Mat( height, width, CV_8U4C, colorBuffer, colorLockedRect.Pitch );
note, that this does not do any allocation on its own, it's still the kinect's pixels, so you will have to clone() it:
rgb[rgb_read++] = img_borrowed.clone();
this is the same as setting the flag in your code above to 'true'. (deep-copy the data)
[edit] maybe it's a good idea to skip the useless 4th channel (also less mem required), so , instead of the above you could do:
cvtColor( img_borrowed, rgb[rgb_read++], CV_BGRA2BGR); // will make a 'deep copy', too.
so, - here's the bummer: if you don't save a deep-copy in your array, you'll end up with garbled (and all the same!) images, probably even with undefined behaviour due to the locking/unlocking of the kinect buffer, if you do copy it (and you must), you will need a lot of memory.
unlikely, that you can keep 3000 *1024*786*4 = 9658368000 bytes in memory, you'll have to cut it down one way or another.

Memory Leak in OpenCV Set Size

I am finding a memory leak in this simple OpenCV code:
VideoCapture* capture = new VideoCapture(0);
Mat frame;
while (true) {
capture->set( CV_CAP_PROP_FRAME_WIDTH, 1600 );
capture->set(CV_CAP_PROP_FRAME_HEIGHT, 1200 );
capture->read(frame);
}
This is the whole code. Every time through the while loop, several MB are leaked. I have tried frame.release() just after the read, but it doesn't help. Removing the set-size lines fixes the problem, but in my real code I want to vary the size, so that isn't a solution. It is getting the image at the correct size.
Am I doing something stupid?
By the way, I am using a Logitech B910 webcam.
Thanks!
Do you need to change the readout size on every frame?
Once it is set the camera will produce the same size until you reset it

OpenCV: Memory leak when writing video from webcam using cvWriteFrame

I want to record video from webcam using opencv.
I put the following code inside a timer event handler function, which is called each 50 ms
IplImage *image = cvQueryFrame(camera);
IplImage *resizeImage = cvCreateImage( size, 8, 3);
cvResize(image, resizeImage);
cvWriteFrame(writer, resizeImage );
With writer is created using cvCreateVideoWriter, and the video is created when I call cvReleaseVideoWriter(&writer)
The problem is I can not release memory allocated by cvWriteFrame until cvReleaseVideoWriter is called. That makes a big issue when I need record a long time video.
How can I handle this situation?
I suppose that the best solution in your case (if you don't want to modify OpenCV code), is to write several video files.
As I can suppose, each frame is grabbed to RAM as is without any compressing. So, you can calculate a number of frames before amount of allocated memory exceed a particular size. Then you finish writing to file and start a new one.

loadRawData Memory issue in ogre while load opencv frames

I am capturing images in real time using OpenCV, and I want to show these images in the OGRE window as a background. So, for each frame the background will change.
I am trying to use MemoryDataStream along with loadRawData to load the images into an OGRE window, but I am getting the following error:
OGRE EXCEPTION(2:InvalidParametersException): Stream size does not
match calculated image size in Image::loadRawData at
../../../../../OgreMain/src/OgreImage.cpp (line 283)
An image comes from OpenCV with a size of 640x480 and frame->buffer is a type of Mat in OpenCV 2.3. Also, the pixel format that I used in OpenCV is CV_8UC3 (i.e., each pixel is 8-bits and each pixel contains 3 channels ( B8G8R8 ) ).
Ogre::MemoryDataStream* videoStream = new Ogre::MemoryDataStream((void*)frame->buffer.data, 640*480*3, true);
Ogre::DataStreamPtr ptr(videoStream,Ogre::SPFM_DELETE);
ptr->seek(0);
Ogre::Image* image = new Ogre::Image();
image->loadRawData(ptr,640, 480,Ogre::PF_B8G8R8 );
texture->unload();
texture->loadImage(*image)
Why I always getting this memory error?
Quick idea, maybe memory 4-byte alignment issues ?
see Link 1 and
Link 2
I'm not an Ogre expert, but does it work if you use loadDynamicImage instead?
EDIT : Just for grins try using the Mat fields to setup the buffer:
Ogre::Image* image = new Ogre::Image();
image->loadDynamicImage((uchar*)frame->buffer.data, frame->buffer.cols, frame->buffer.rows, frame->buffer.channels(), Ogre::PF_B8G8R8);
This will avoid copying the image data, and should let the Mat delete it's contents later.
I had similar problems to get image data into OGRE, in my case the data came from ROS (see ros.org). The thing is that your data in frame->buffer is not RAW, but has a file header etc.
I think my solution was to search the data stream for the beginning of the image (by finding the appropriate indicator in the data block, e.g. 0x4D 0x00), and inserting the data from this point on.
You would have to find out were in your buffer the header ends and where your data begins.