0
votes

I'm creating a app that gets a image from camera (using CameraKit library), process the image and do a OCR Read using Google Vision Api, And get this error:

FATAL EXCEPTION: main Process: com.., PID: 1938 java.lang.OutOfMemoryError: Failed to allocate a 63701004 byte allocation with 16777216 free bytes and 60MB until OOM at dalvik.system.VMRuntime.newNonMovableArray(Native Method) at android.graphics.Bitmap.nativeCreate(Native Method) at android.graphics.Bitmap.createBitmap(Bitmap.java:905) at android.graphics.Bitmap.createBitmap(Bitmap.java:882) at android.graphics.Bitmap.createBitmap(Bitmap.java:849) at com.****.****.Reader.ReaderResultActivity.createContrast(ReaderResultActivity.java:123) at com.*****.****.Reader.ReaderResultActivity.onCreate(ReaderResultActivity.java:47) at android.app.Activity.performCreate(Activity.java:6672) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1140) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2612) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2724) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1473) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6123) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)

ReaderResultActivity Code:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_reader_result);

    ImageView img1 = (ImageView)findViewById(R.id.imageView2);
    ImageView img2 = (ImageView)findViewById(R.id.imageView3);
    ImageView img3 = (ImageView)findViewById(R.id.imageView4);
    TextView scanResults = (TextView)findViewById(R.id.textView);

    //Get bitmap from a static class.
    Bitmap bitmap = Reader.img;

    Bitmap grayScale = toGrayscale(bitmap);
    Bitmap blackWhiteImage = createContrast(grayScale, 50);
    Bitmap invertColor = invertColor(blackWhiteImage);

    //Show process steps
    img1.setImageBitmap(grayScale);
    img2.setImageBitmap(blackWhiteImage);
    img3.setImageBitmap(invertColor);

    TextRecognizer detector = new TextRecognizer.Builder(getApplicationContext()).build();

    try {

        if (detector.isOperational()) {
            Frame frame = new Frame.Builder().setBitmap(invertColor).build();
            SparseArray<TextBlock> textBlocks = detector.detect(frame);
            String blocks = "";
            String lines = "";
            String words = "";
            for (int index = 0; index < textBlocks.size(); index++) {
                //extract scanned text blocks here
                TextBlock tBlock = textBlocks.valueAt(index);
                blocks = blocks + tBlock.getValue() + "\n" + "\n";
                for (Text line : tBlock.getComponents()) {
                    //extract scanned text lines here
                    lines = lines + line.getValue() + "\n";
                    for (Text element : line.getComponents()) {
                        //extract scanned text words here
                        words = words + element.getValue() + ", ";
                    }
                }
            }
            if (textBlocks.size() == 0) {
                scanResults.setText("Scan Failed: Found nothing to scan");
            } else {
                lines = lines.replaceAll("o", "0");
                lines = lines.replaceAll("A", "1");

                scanResults.setText(lines + "\n");
            }
        } else {
            scanResults.setText("Could not set up the detector!");
        }
    } catch (Exception e) {
        Toast.makeText(this, "Failed to load Image", Toast.LENGTH_SHORT)
                .show();
        Log.e("312", e.toString());
    }
}

private Bitmap processImage(Bitmap bitmap){
    Bitmap grayScale = toGrayscale(bitmap);
    Bitmap blackWhiteImage = createContrast(grayScale, 50);
    Bitmap invertColor = invertColor(blackWhiteImage);

    return invertColor;
}
public Bitmap toGrayscale(Bitmap bmpOriginal) {
    int width, height;
    height = bmpOriginal.getHeight();
    width = bmpOriginal.getWidth();

    Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, bmpOriginal.getConfig());
    Canvas c = new Canvas(bmpGrayscale);
    Paint paint = new Paint();
    ColorMatrix cm = new ColorMatrix();
    cm.setSaturation(0);
    ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
    paint.setColorFilter(f);
    c.drawBitmap(bmpOriginal, 0, 0, paint);
    return bmpGrayscale;
}

public static Bitmap createContrast(Bitmap src, double value) {
    // image size
    int width = src.getWidth();
    int height = src.getHeight();
    // create output bitmap
    Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
    // color information
    int A, R, G, B;
    int pixel;
    // get contrast value
    double contrast = Math.pow((100 + value) / 100, 2);

    // scan through all pixels
    for(int x = 0; x < width; ++x) {
        for(int y = 0; y < height; ++y) {
            // get pixel color
            pixel = src.getPixel(x, y);
            A = Color.alpha(pixel);
            // apply filter contrast for every channel R, G, B
            R = Color.red(pixel);
            R = (int)(((((R / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
            if(R < 0) { R = 0; }
            else if(R > 255) { R = 255; }

            G = Color.red(pixel);
            G = (int)(((((G / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
            if(G < 0) { G = 0; }
            else if(G > 255) { G = 255; }

            B = Color.red(pixel);
            B = (int)(((((B / 255.0) - 0.5) * contrast) + 0.5) * 255.0);
            if(B < 0) { B = 0; }
            else if(B > 255) { B = 255; }

            // set new pixel color to output bitmap
            bmOut.setPixel(x, y, Color.argb(A, R, G, B));
        }
    }

    return bmOut;
}

Bitmap invertColor(Bitmap src){
    Bitmap copy = src.copy(src.getConfig(), true);

    for (int x = 0; x < copy.getWidth(); ++x) {
        for (int y = 0; y < copy.getHeight(); ++y) {
            int color = copy.getPixel(x, y);
            int r = Color.red(color);
            int g = Color.green(color);
            int b = Color.blue(color);
            int avg = (r + g + b) / 3;
            int newColor = Color.argb(255, 255 - avg, 255 - avg, 255 - avg);
            copy.setPixel(x, y, newColor);
        }
    }


    return copy;
}

Already try to do this in Manifest

android:largeHeap="true"

But the application just stop running when is on:

ReaderResultActivity.createContrast(ReaderResultActivity.java:123)

The same line that appears on error without the "largeHeap" tag. Just dont know what to do, but i think that has something with all those "Bitmap.CreateBitmap" in every process function. But without doing this, in OCR reading, appear a error saying that the bitmap has a wrong format.

1
largeHeap will not solve the problem . When you get getting image from camera you need to optimize the bitmap before passing it further . Have a look at thisADM
Is your bitmap dimensions (in pixels) is larger than your view's dimensions?Muhammad Babar

1 Answers

2
votes

You are loading three bitmaps in different imageviews without scaling it according to the size you want to show on your UI.

Android devices's camera captures pictures with much higher resolution than the screen density of your device.

Given that you are working with limited memory, ideally you only want to load a lower resolution version in memory. The lower resolution version should match the size of the UI component that displays it. An image with a higher resolution does not provide any visible benefit, but still takes up precious memory and incurs additional performance overhead due to additional on the fly scaling.

You can optimize it by following developer documentation suggestions - https://developer.android.com/topic/performance/graphics/load-bitmap.html