2
votes

I need to convert a 2-dimensional 24bit rgb- matrix with Python 3.6

[[rr11gg11bb11, rr12gg12bb12,..  ..,rr1mgg1mbb1m],
.
.
 [rri1gg11bb11, rr12ggi2bb12,..  ..,rr1mgg1mbb1m]
.
.
 [rrn1ggn1bbn1, rrn2ggn2bbn2,.. ..,rrmnggmnbbmn]]

into an image of the format tif, png and jpg.

I've also got the matrix in form of a file

image.bin.

From this binary file I can whatch the image with the help of a RAW Pixel Viewer:

http://rawpixels.net/ 

I have found the PIL library, but I didn't find any method to build an image object out of these data. How can I do that? I use Python 3.6.

Now I've tried the following:

im = Image.frombuffer('RGB', (self.width, self.height), self.matrix, 'raw', 
'RGB', 0, 1)              
logger.info("image object created.")
im.save('result.png')
logger.info("image saved as result.png")

But I get the message:

TypeError: a bytes-like object is required, not 'list'

Now I've found out that I must convert the object into a bytearray:

 npm = np.array(self.matrix)
 arr = bytearray(npm)
 print(arr)
 im = Image.frombuffer('RGB', (self.width, self.height), arr, 'raw', 
'RGB', 0, 1)        

The conversion just works, when I use 'L', or 'RGBA', but not with 'RGB'. Strangely in this case it refuses a bytearray object.

1
Look here... stackoverflow.com/a/58075903/2836621 You will need 'RGB' rather than 'L'.Mark Setchell
@MarkSetchell The ba seems to be my Matrix. So I've done the following:Uwe_98
Don't put code in comments area. Either add it to your question if it doesn't work, or add it as an answer if it does. Then accept it as correct and grab the points:-)Mark Setchell
@MarkSetchell Ok, I've done so. But it doesn't create the image. I thought I don't have to make the 1st step shown in Your link, because the matrix I've already got.Uwe_98

1 Answers

3
votes

Updated Answer

So, essentially, you don't have a Numpy array, but you have a list of lists wherein each element is a single 24-bit number that represents an RGB triplet RGB888.

So, I can make a representation of your list like this:

f=[ 
[0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0x000000,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF],
[0xFFFFFF,0xFFFFFF,0xFFFFFF,0x000000,0x000000,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF],
[0xFFFFFF,0xFFFFFF,0x000000,0xFFFFFF,0x000000,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF],
[0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0x000000,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF],
[0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0x000000,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF,0xFFFFFF]
] 

So, I can make that into a Numpy array of uint32 elements like this:

na = np.array(f).astype(np.uint32) 

And then make an RGB array that PIL will like using:

h,w = 5,10
RGB=np.zeros((h,w,3),dtype=np.uint8)

Then I just have to shift and copy the triplets into the right places:

RGB[:,:,0] = na>>16            # Take red from top
RGB[:,:,1] = (na>>8) & 0xff    # Take green from middle
RGB[:,:,2] = na & 0xff         # Take blue from bottom

Now I can make a PIL image from that RGB array and save it to disk:

pIm = Image.fromarray(RGB).save('result.png')

Original Answer

Let's create a file of test data with ImageMagick. First as a PNG, just so you can see it:

magick -size 640x480 gradient:magenta-yellow image.png

enter image description here

And now the same thing again, but this time as RGB888 to match your file:

magick -size 640x480 gradient:magenta-yellow -depth 8 rgb:image.bin

Now:

from PIL import Image

# Open the file and read contents into "data"
with open('image.bin','rb') as f: 
    data = f.read() 

# Convert that into PIL Image
im = Image.frombuffer('RGB', (640, 480), data, 'raw', 'RGB', 0, 1)

# Save
im.save('result.png')

You could equally let Numpy read the file and then convert the result to a PIL Image:

import numpy as np

im = Image.fromarray(np.fromfile('image.bin',dtype=np.uint8).reshape(480,640,3))

If you want to check your binary file actually contains what you think it contains, you can also convert it to a PNG with ImageMagick to test it. Say you think the file is 640 pixels wide by 480 pixels tall and RGB888, you can ask ImageMagick to make it into a PNG with:

magick -depth 8 -size 640x480 RGB:<YOURFILENAME> image.png

Or, if you think it is a single 16-bit, single channel greyscale image with a 128 byte header that you want to ignore:

magick -depth 16 -size 640x480+128 GRAY:<YOURFILENAME> image.png

Keywords: Raw, raw image, binary file, image, image processing, Python, ImageMagick, convert.