OpenCV Error in Android: Insufficient memory (Failed to allocate) - android

I am using opencv in Android Studio to increase the red color proportion in an image. But when I run the function after about 30 times, the program crashes and shows the error.
OpenCV Error: Insufficient memory(Failed to allocate *****bytes)
I have searched many relating questions and many people say add Mat.release() could solve this problem. I added the Mat.release in my function but it does not help. The program still crashes after I run it over 30 times.
Here is my Code. Does somebody know how to solve this issue?
public void addRedColor(int red){
Mat img = new Mat();
Utils.bitmapToMat(src, img);
List<Mat> bitplane = new ArrayList<>(img.channels());
Core.split(img, bitplanes);
Mat redChannel = new Mat();
Core.add(bitplane.get(0), new Scalar(red), redChannel);
bitplane.set(0, redChannel);
Core.merge(bitplane, img);
// release the Mat
img.release();
bitplane.get(0).release();
bitplane.get(1).release();
bitplane.get(2).release();
redChannel.release();
}

Avoid to waste memory with new Mat and force the garbage collector before the end of the method
System.gc();
System.runFinalization();

Related

Canny Edge Detection (Android OpenCV) app unfortunately stops

#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.Canny_Edge) //Unfortunately stops the app when we use this option {
ImageView i = (ImageView) findViewById(R.id.image_view);
Bitmap bmp =BitmapFactory.decodeResource(getResources(),R.drawable.smiley);
Mat srcMat = new Mat ( bmp.getHeight(), bmp.getWidth(), CvType.CV_8UC3);
Bitmap myBitmap32 = bmp.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(myBitmap32, srcMat);
Mat gray = new Mat(srcMat.size(), CvType.CV_8UC1);
Imgproc.cvtColor(srcMat, gray, Imgproc.COLOR_RGB2GRAY,4);
Mat edge = new Mat();
Mat dst = new Mat();
Imgproc.Canny(gray, edge, 80, 90);
Imgproc.cvtColor(edge, dst, Imgproc.COLOR_GRAY2RGBA,4);
Bitmap resultBitmap = Bitmap.createBitmap(dst.cols(), dst.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(dst, resultBitmap);
i.setImageBitmap(resultBitmap);
}
else if(id == R.id.Sobel) {
ImageView i = (ImageView) findViewById(R.id.image_view);
i.setImageResource(R.drawable.apj);
//some code
}
return super.onOptionsItemSelected(item);
}
In the above code ,Android studio doesn't shows any errors .
But the app unfortunately stops on getting this Canny_Edge option(in the menu).
Why, Can anyone solve this problem.
I have answered a similar question on: https://stackoverflow.com/a/50637228/1693327 but I am unable to comment to the post due to lack of reputation points so I will copy the answer below.
The device should be crashing when it executes the Imgproc.Canny function call.
I believe the app is crashing when it hits the Canny detector because of the wrong type of OpenCV Manager installed on your device, be it version number or central processor instruction set. Checking the correct version should be straightforward. Just go to the OpenCV-android-sdk\apk directory and check for the 3 (x.y.z) numbers after OpenCV_
Checking instruction set of Android devices for Windows
To check the instruction set of your device, navigate to the adb (android debug bridge) directory commonly located at:
C:\Users\<'your username'>\AppData\Local\Android\Sdk\platform-tools
Run the command:
./adb.exe shell cat /proc/cpuinfo
After getting the correct instruction set, navigate back to the OpenCV-android-sdk\apk and locate the correct apk version and instruction set to be installed on your android device.
You can then transfer the apk to your device and install it. Another way I find useful is to navigate to the adb.exe directory and run the command:
./adb.exe install <path to OpenCV-android-sdk>/apk/OpenCV_x.y.z_Manager_x.yz_<platform instruction set>.apk
Apart from the steps above, make sure that you do not have any other environment variables that use other types of OpenCV Manager such as stating a different one in the Application.mk or build.gradle files.
After the steps above, your Canny detector should be able to run on your device without crashing.
Happy Developing :).

Avoiding java.lang.OutOfMemoryError

Hi all I am developing live wallpapers, and I am using lot of bitmaps. I have tested my new live wallpaper for aboute a week, and it was up and runing perfectly, but as soon as I have uploaded it to a market I keep getting this kind of exceptions : java.lang.OutOfMemoryError for both android.graphics.Bitmap.nativeCreate and android.graphics.BitmapFactory.nativeDecodeAsset. I use this kind of lifecycle of an bitmap:
I create a reference like:
Bitmap dark = null;
Bitmap cave = null;
at onCreateEngine I init them like :
cave = BitmapFactory.decodeResource(getResources(), R.drawable.cave);
dark = BitmapFactory.decodeResource(getResources(), R.drawable.dark);
here is where it trows the exception. for these images: . and after all I draw them to an canvas like this:
canvas.save();
canvas.drawBitmap(bg, new Matrix(), new Paint());
canvas.drawBitmap(dark, new Matrix(), new Paint());
canvas.restore();
What Should I do? It is better to load the dark image just one picture and draw it to the canvas width*height times? Or Are there any methods to do? I think recycle or calling onDestroy. But I do not know when to call them because the exceptions are thrown at onCreate.Are the images too big? And why it is working smoothly on my device, and on the other devices it is throwing exceptions? The bitmaps are 1484*1484 dimension big and the clouds are 250*172 dimensional big, should they be in 2^x * 2^x dimension?
Just try to use Memory Optimizer and see where are you creating Memory Leaks. You can use Eclipse Memory Analyzer(MAT) for this. Its a very common problem with using bitmaps. By using BitMaps you need to be extra careful for memory leaks.

Weird issue with OpenCV drawContours on android

I stumbled upon a weird problem with OpenCV drawContours on android.
Sometimes, (without apparent pattern) function drawContours produces this:
drawContours http://img17.imageshack.us/img17/9031/screenshotgps.png
while it should obviously produce just the white part.
To put it in context:
I detect edges using canny algorithm and then I find contours with
Imgproc.findContours(dil, contours, dummy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
Then i select several contours that fit some requirements and I add them to a list:
List<MatOfPoint> goodContours = new ArrayList<MatOfPoint>();
After that I randomly select one contour and I draw it (filled with white) on mat and convert it to android Bitmap:
Mat oneContour = new Mat(orig.rows(), orig.cols(), CvType.CV_8UC1);
int index = (int) (Math.random() * goodContours.size());
Imgproc.drawContours(oneContour, goodContours, index, new Scalar(255, 255, 255), -1);
Bitmap oneContourBitmap = Bitmap.createBitmap(oneContour.cols(), oneContour.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(oneContour, oneContourBitmap);
Most of the times I get what I expect: white patch on a pure black background, but sometimes I get the above. I'm totally at a loss here. I suspect there could be some memory leakage but I try hard to release all Mat's immediately after they are of no use anymore (I also tried to release them at the end of a function where it all happens but without effect) but I'm unable to pinpoint the source of the problem.
Has anyone had similar issues?
I first discovered this on OpenCV 2.4.0 but it stays the same on 2.4.3.
Any suggestion is appreciated.

Explicitly releasing Mat with opencv 2.0

I'm working on a program where we do some image processing of full quality camera photos using the Android NDK. So, obviously memory usage is a big concern.
There are times where I don't need the contents of a Mat anymore - I know that it'll be released automatically when it goes out of scope, but is there a good way of releasing it earlier, so I can reduce the memory usage?
It's running fine on my Galaxy S II right now, but obviously that is not representative of the capabilities of a lot of the older phones around!
If you have only one matrix pointing to your data, you can do this trick:
Mat img = imread("myImage.jpg");
// do some operations
img = Mat(); // release it
If more than one Mat is pointing to your data, what you should do is to release all of them
Mat img = imread("myImage.jpg");
Mat img2 = img;
Mat roi = img(Rect(0,0,10,10));
// do some operations
img = Mat(); // release all of them
img2 = Mat();
roi = Mat();
Or use the bulldozer approach: (Are you sure? this sounds like inserting bugs in your code )
Mat img = imread("myImage.jpg");
Mat img2 = img;
Mat roi = img(Rect(0,0,10,10));
// do some operations
char* imgData = (char*)img.data;
free[] imgData;
imshow("Look, this is called access violation exception", roi);
Mat::release() should do the trick.
cf.: OpenCV Memory Management Documentation

android - rendering bitmaps from native code - nativeCreate bitmaps are not cleanedup from memory

I am streaming a video in android and I decode frames in native code and then copy the pixels to a bitmap, then display the bitmap in Java using canvas.unlockandpost with a while loop for all the bitmaps.
Everything is fine, but the streaming of bitmaps is very slow and causes a crash. I only see a message on logcat saying that "low memory no more background processes".
I see on the allocation table from eclipse, that the bitmaps that I created are not getting deleted from memory, even though, I am overwritng the pixels everytime. Is there any way I can clean up the memory it is keeping.
My code is as follows.
C Code :
AndroidBitmapInfo info;
void* pixels;
int ret;
if ((ret =AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
}
memcpy(pixels, pictureRGB, 480*320);
AndroidBitmap_unlockPixels(env, bitmap);
Java Code
Bitmap mBitmap = Bitmap.createBitmap(480, 320, Bitmap.Config.RGB_565);
renderbitmap(mBitmap, 0);
canvas.drawBitmap(mBitmap, 0, 0, null);
The code shown in your question is missing some critical parts to fully understand your problem, but it sounds like you're creating a new bitmap for every frame. Since Android only allows for about 16MB of allocations for each Java VM, your app will get killed after about 52 frames. You can create a bitmap once and re-use it many times. To be more precise, you are creating a bitmap (Bitmap.CreateBitmap), but not destroying it (Bitmap.recycle). That would solve your memory leak, but still would not be the best way to handle it. Since the bitmap size doesn't change, create it once when your activity starts and re-use it throughout the life of your activity.

Categories

Resources