How to efficiently read a Bitmap object into a two-dimensional integer array?

I need to read the entirety of a Bitmap object into a 2-dimensional integer array in my Android application.

Currently, I am reading each pixel individually, one at a time, like so:

for (int y = 0; y < coverImageHeight; y++)
{
    for (int x = 0; x < coverImageWidth; x++)
    {
        coverImageIntArray[x][y] = coverImageBitmap.getPixel(x, y);
    }
}

However, this takes a really long time on large images (about 15 seconds).

Is there a way to do it all in one fell swoop for better efficiency?

Upvotes: 7

Views: 3953

Answers (3)

Wacov
Wacov

Reputation: 422

I'm not familiar with Android dev, but typically for image objects you're able to just grab a reference or copy of some underlying buffer. This buffer is usually 1D, but you should be able to covert it fairly easily. In your case, for grabbing the pixels, there's a function getPixels which looks perfect.

int[] coverImageIntArray1D = new int[coverImageWidth * coverImageHeight]
coverImageBitmap.getPixels(coverImageIntArray1D, 0, coverImageWidth,
    0, 0, coverImageWidth, coverImageHeight)
// coverImageIntArray1D should now contain the entire image's pixels

FYI, you can index into this type of 1D array using 2D indices:

int pixel = coverImageIntArray1D[x + y*coverImageWidth]

Which will give you the pixel at [x][y]. So you can still use it in a 2D manner without performing an inefficient transformation.

Upvotes: 7

linkD
linkD

Reputation: 141

Instead of using a two-dimensional array, consider using a little bit of for-loop logic and a one-dimensional array with

void getPixels (int[] pixels, 
                int offset, 
                int stride, 
                int x, 
                int y, 
                int width, 
                int height)

This approach should be much more performant than trying to split a one-dimensional array up into two-dimensional arrays, since you'd be converting the pixel data, which seems to be internally stored as int[], to an int[][], only to simplify your logic slightly.

int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
for (int row = 0; row < bitmap.getHeight(); row++)
    for (int column = 0; column < bitmap.getWidth(); column++)
        Color color = Color.valueOf(pixels[row * bitMap.getWidth() + column]);

Have a look at the Android Developers reference for Bitmap.getPixels(int[], int, int, int, int, int, int) and Color.valueOf(int) (to extract single color components, Color.alpha(int), Color.red(int), Color.green(int) and Color.blue(int) respectively).

Upvotes: 0

Arjun Panickssery
Arjun Panickssery

Reputation: 183

I just checked an old project I did involving OCR, and I used the method you present in your answer. My images were only 28x28 pixels, though.

It's likely that using getPixels() is faster.

See void getPixels (int[] pixels, int offset, int stride, int x, int y, int width, int height)

The code might look like

bitmap.getPixels(intArray, 0, bmp.getWidth(), 0, 0, bmp.getWidth(), bmp.getHeight());  

This will copy the bitmap Color values into the int array.

Upvotes: 1

Related Questions