7

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?

3 Answers3

7

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.

Community
  • 1
  • 1
Wacov
  • 400
  • 2
  • 9
  • Hmm... so by using `getPixels()`, the importing into a 1D array is *extremely* fast (less than a second), however I'm having some serious problems converting the 1D array to a 2D array. I've tried two of the answers in the link that you provided, but both of them rotate the image by 90 degrees, and one rotates it and also introduces vertical artifacts. If you could help me with a 1D --> 2D conversion method that actually works properly, I'll gladly accept & upvote your answer :) – You'reAGitForNotUsingGit Apr 14 '17 at 23:38
  • Now that I think about it, it's actually a pain (and very inefficient) to convert to what you want, since the image data is stored row-by-row but an [x][y] array stores data column-by-column - that's why you were finding things got rotated. It's probably a good idea to rethink your data structure! I've added a note to show how you can use the 1D array with 2D indices. If you're really set on the 2D array, you could just reconstruct it using that notation and your original loops. – Wacov Apr 15 '17 at 02:05
  • Yeah, I guess I'll try rewriting the array code to be YX instead of XY and see if that fixes the rotation. – You'reAGitForNotUsingGit Apr 29 '17 at 02:56
  • 1
    Okay, I fixed it and and there was a massive speed boost! Thanks so much! – You'reAGitForNotUsingGit May 01 '17 at 01:04
1

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.

0

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).

linkD
  • 121
  • 13