8

I'm playing around with a camera for a microscope using Micro-Manager 1.4. Using the Python interface, I've managed to access the camera, change exposure time etc, and I can capture individual images.

However, each image is returned as NumPy arrays where each pixel is represented as a single integer, e.g. "7765869". As far as I can find online, this is known as a "BufferedImage" in Java, and it means that the RGB values are encoded as:

BufferedImage = R * 2^16 + G * 2^8 + B

My question is: How can I, using e.g. Numpy or OpenCV, convert this kind of array into a more handy array where each pixel is a RGB triplet of uint8 values? Needless to say, the conversion should be as efficient as possible.

1
  • To expand on the theory behind this a bit, what you have is a linear diophantine equation of the form a * x + b * y + c * z == n, where in our case a = 2**16, b = 2**8, c = 1. Typically, the solutions to these equations involve finding gcd(a, b, c) and hoping it divides n; if it doesn't, then there are no solutions. Given that a solution exists, there are infinitely many solutions. However, we are restricted in this case to find a solution 0 <= x, y, z < 256, so there will be only one solution given that gcd(a, b, c) | n. Commented Oct 17, 2013 at 17:05

4 Answers 4

9

The easiest is to let numpy do the conversion for you. Your numpy array will probably be of type np.uint32. If you view it as an array of np.uint8, you will have an RGB0 format image, i.e. the values of R, G, and B for each pixel, plus an empty np.uint8 following. It's easy to reshape and discard that zero value:

>>> img = np.array([7765869, 16777215], dtype=np.uint32)
>>> img.view(np.uint8)
array([109, 127, 118,   0, 255, 255, 255,   0], dtype=uint8)
>>> img.view(np.uint8).reshape(img.shape+(4,))[..., :3]
array([[109, 127, 118],
       [255, 255, 255]], dtype=uint8)

Best thing is there is no calculation or copying of data, just a reinterpretation of the contents of your original image: I don't think you can get much more efficient than that!

I recall that for some operations OpenCV requires a contiguous array, so you may have to add a .copy() to the end of that expression to really get rid of the column of zeros, not simply ignore it, although this would of course trigger the copy of data that the code above had avoided.

Sign up to request clarification or add additional context in comments.

3 Comments

Works perfectly! Defining "img2" as "img.view(np.uint8).reshape(img.shape+(4,))[..., :3]" and then using "cv2.imwrite" perfectly saves the image. Thanks!
@Bjarke You may want to make sure that you are saving an RGB image, and not a BGR one... It will be dependent on the endianess of your system. If it is wrong, simply stick [::-1] at the end of your definition of img2 and it will reverse the order in which they get read.
@tom10 Yes it's clever, although in all fairness it is someone else's cleverness: I make a living designing printer pipelines, and this kind of byte fiddling is more or less standard procedure in our (HP) products.
2

One way is

Red = BufferedImage / 2**16
Green = (BufferedImage % 2**16) / 2**8
Blue = (BufferedImage % 2**8)

However, I doubt it's the most elegant (Pythonic?) or the fastest way.

Comments

0
rgbs = [((x&0xff0000)>>16,(x&0xff00)>>8,x&0xff) for x in values]

at least I think ...

afaik the formula above can also be written as

BufferedRGB = RED<<16 + GREEN << 8 + BLUE 

red,green,blue = 0xFF,0x99,0xAA
red<<16 + green << 8 + blue  #= 0xFF99AA (buffered into one value)

#apply a bitmask to get colors back
red = (0xFF99AA & 0xFF0000) >> 16 # = 0xFF
green = (0xFF99AA & 0xFF00) >> 8  # = 0x99
blue = 0xFF99AA & 0xFF          # = 0xAA

which is somewhat more readable to me and clear what is going on

Comments

0

The fastest approach would probably be to keep this in numpy:

from numpy import *
x = array([211*2**16 + 11*2**8 + 7])  # test data

b, g, r = bitwise_and(x, 255), bitwise_and(right_shift(x, 8), 255), bitwise_and(right_shift, 16), 255)

print r, g, b
(array([211]), array([11]), array([7]))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.