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