5

I am retrieving a raw image from a camera and the specs of the image are as follows:

  • 80 x 60 resolution
  • 4-bit grayscale

I retrieve the image as a byte array and have an array that is 2400 (1/2 * 80 * 60) bytes long. The next step is to convert the byte array into a Bitmap. I have already used the

BitmapFactory.decodeByteArray(bytes, 0, bytes.length)

but that didn't return a displayable image. I looked at this post and copied the code below into my Android application, but I got a "buffer not large enough for pixels" runtime error.

byte [] Src; //Comes from somewhere...
byte [] Bits = new byte[Src.length*4]; //That's where the RGBA array goes.
int i;
for(i=0;i<Src.length;i++)
{
    Bits[i*4] =
        Bits[i*4+1] =
        Bits[i*4+2] = ~Src[i]; //Invert the source bits
    Bits[i*4+3] = -1;//0xff, that's the alpha.
}

//Now put these nice RGBA pixels into a Bitmap object

Bitmap bm = Bitmap.createBitmap(Width, Height, Bitmap.Config.ARGB_8888);
bm.copyPixelsFromBuffer(ByteBuffer.wrap(Bits));

At the bottom of the thread, the original poster had the same error I currently have. However, his problem was fixed with the code pasted above. Does anyone have any suggestions on how I should convert the raw image or RGBA array into a Bitmap?

Thanks so much!

UPDATE:

I followed Geobits suggestion and this is my new code

byte[]  seperatedBytes = new byte[jpegBytes.length * 8];
for (int i = 0; i < jpegBytes.length; i++) {
    seperatedBytes[i * 8] = seperatedBytes[i * 8 + 1] = seperatedBytes[i * 8 + 2] = (byte) ((jpegBytes[i] >> 4) & (byte) 0x0F);
    seperatedBytes[i * 8 + 4] = seperatedBytes[i * 8 + 5] = seperatedBytes[i * 8 + 6] = (byte) (jpegBytes[i] & 0x0F);
    seperatedBytes[i * 8 + 3] = seperatedBytes[i * 8 + 7] = -1; //0xFF
}

Now, I am able to get a Bitmap using this command

Bitmap bm = BitmapFactory.decodeByteArray(seperatedBytes, 0, seperatedBytes.length);

but the Bitmap has a size of 0KB.

The image I am getting is a raw Image from this camera. Unfortunately, retrieving a pre-compressed JPEG image is not an option becuase I need 4-bit grayscale.

Community
  • 1
  • 1
Ankit Goyal
  • 437
  • 1
  • 7
  • 24

2 Answers2

2

If the image coming in is only in 2400 bytes, that means there are two pixels per byte(4 bits each). You're only giving the byte buffer 2400 * 4 = 9600 bytes when an ARGB_8888 needs 4 bytes per pixel, or 60 * 80 * 4 = 19200.

You need to split each incoming byte into an upper/lower nibble value, then apply that to the following 8 bytes(excluding alpha). You can see this answer for an example of how to split bytes.

Basically:

  • Split incoming byte i into two nibbles, ia and ib
  • Apply ia to outgoing bytes i*8 through (i*8)+2
  • Apply ib to outgoing bytes (i*8)+4 through (i*8)+6
  • Bytes (i*8)+3 and (i*8)+7 are alpha (0xFF)

Once you have the right size byte buffer, you should be able to use decodeByteArry() with no problems.

Community
  • 1
  • 1
Geobits
  • 22,218
  • 6
  • 59
  • 103
  • Thanks for the response. I tried this and unfortunately it did not work. This is what I have: `byte[] seperatedBytes = new byte[jpegBytes.length * 8]; for (int i = 0; i < jpegBytes.length; i++) { seperatedBytes[i * 8] = seperatedBytes[i * 8 + 1] = seperatedBytes[i * 8 + 2] = seperatedBytes[i * 8 + 3] = (byte) ((jpegBytes[i] >> 4) & (byte) 0x0F); seperatedBytes[i * 8 + 4] = seperatedBytes[i * 8 + 5] = seperatedBytes[i * 8 + 6] = seperatedBytes[i * 8 + 7] = (byte) (jpegBytes[i] & 0x0F); }` – Ankit Goyal Jul 19 '13 at 12:55
  • and then this: `Bitmap bm = BitmapFactory.decodeByteArray(seperatedBytes, 0, seperatedBytes.length);` I saved the .jpg to the Android and it is showing the filesize is 0KB. The array jpegBytes has a length of 2400 and he seperatedBytes array has a length of 19200. – Ankit Goyal Jul 19 '13 at 12:58
  • Is the incoming byte array a JPG? If so, you need to convert it to a bitmap format first. Also, I should have mentioned, bytes 3 and 7 of each group are still alpha, like you were doing before. I don't have any idea why your saved image would have a size of zero bytes, though. You may want to consider adding some of that code into the question as an update. – Geobits Jul 19 '13 at 13:12
  • [This is the datasheet of the camera I am retrieving an image from](http://www.mouser.com/ds/2/451/uCAM-DS-rev7-3555.pdf). Although it can send a JPEG image, I need a 4-bit grayscale image. Also, I changed my code to have bytes 3 and 7 of each group equal Alpha. The updated code is in the "UPDATE" and I still get a Bitmap of size 0KB. – Ankit Goyal Jul 19 '13 at 13:31
  • This might be the problem - the byte array jpegBytes is 2400 bytes long. It is the array of the 4-bit grayscale image transmitted by the camera. Am I properly converting it into an ARGB array in the updated code? – Ankit Goyal Jul 19 '13 at 13:35
  • Oh, that could be the problem. It looks like we're making an `RGBA_8888` when it should be `ARGB_8888` to match the format. Try swapping the first/last bytes of each pixel. That still shouldn't cause a size of 0, though. How are you saving the image? – Geobits Jul 19 '13 at 13:42
  • I am saving the image to the SD card using [this post](http://stackoverflow.com/questions/7887078/android-saving-file-to-external-storage). Also, since I am trying to display a video feed from the camera, I set the Bitmap as the background of my custom SurfaceView, but nothing shows up. I know my SurfaceView works because I had a different camera and I was able to get pictures about every 10 seconds, but not video. The pictures were compressed JPEGs so decodeByteArray worked and I was able to set them as the background of the SurfaceView. – Ankit Goyal Jul 19 '13 at 13:52
  • Also - I swapped the first/last bytes of each pixel, but the image size is still 0. – Ankit Goyal Jul 19 '13 at 13:55
  • Well, it sounds like something more is wrong than just the conversion. I'm not sure what. – Geobits Jul 19 '13 at 14:02
  • Are you confident that decodeByteArray is the way to go? The other post I linked to in the original post used Bitmap.createBitmap(...) and copyPixelsFromBuffer – Ankit Goyal Jul 19 '13 at 14:05
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/33799/discussion-between-ankit-goyal-and-geobits) – Ankit Goyal Jul 19 '13 at 18:31
  • Alright I get an image and display it and it looks like [this](http://i.imgur.com/HzoCRCp.jpg). In this picture, all the colors are very light and I think they are inverted. For example, when I stick a piece of paper in front of the camera, the screen becomes extremely white and when I remove the paper, the screen has splotches of gray. I tried to invert the bitmap using [this method](http://www.androidsnippets.com/how-to-invert-bitmap-color), but it did not work. The image becomes all black and I can't see anything on the screen. Any suggestions? Final stretch!! – Ankit Goyal Jul 23 '13 at 15:55
1

If I understand you correctly you have a byte array, whose bytes contain 2 greyscale values each. I'd say a greyscale value can be considered as a simple intensity value, can't it?

So the first thing you need to do is to seperate your greyscale values into single bytes each, as BitmapFactory.decodeByteArray can probably not handle your "half bytes". This can be easily done by bit-operations. To obtain the first 4-Bit of your byte `0bxxxxxxxx` value you need to right shift 4 times: `0bxxxxxxxx >> 4` which would lead to `0b0000xxxx`. The second value can be obtained by a bitwise or with the pattern `0b00001111`: `0b00001111 ^ 0bxxxxxxxx` wich would lead to `0b0000xxxx`. (for detailed information about bit-operations see here: Bit-Operations)

Those two values can now be stored into a new byte array. If you do this for every pair of half-bytes you'll get an array of full bytes and doubled size at the end.

I'm not sure if this is already enough for 'BitmapFactory.decodeByteArray' or if you have to repeat every byte 4 times for each RGBA-Channel, which would increase the size of your byte-array again by four times of the original size. I hope I did not missunderstand anything and my suggestions helps ;)

  • I have the same problem as the one described above - each image is 0KB. I also decoded the image into an RGBA array following [this post](http://stackoverflow.com/questions/5626795/how-to-get-a-bitmap-from-a-raw-image). Even then, the image is blank. – Ankit Goyal Jul 19 '13 at 13:09