For my college project, I need to convert a 4-byte colored png file to a 1-byte colored png file using Keil.
I've converted a png file to a hex file using Python, then loaded a hex file in Keil, progressed the data, and got the output.
In Keil, a hex file with a 4-byte RGBA was changed to a 1-byte RGB(RRR_GGG_BB in each byte) by removing the alpha channel and concatenating 3 or 2 MSB of each color.
Compressing process MUST be done in keil.
So the output hex file has 1-byte RGB data.
I put this data in python, reshape the array, but I can't make it to PNG file.
Here's the code that I tried.
from intelhex import IntelHex
from PIL import Image
import numpy as np
ih = IntelHex()
ih.loadhex('memoutput.hex')
pydict=ih.todict()
rgbcomp = np.fromiter(pydict.values(), dtype=int)
rgbcomp = np.reshape(rgbcomp,(640,960))
img_2 = Image.fromarray(rgbcomp, 'P')
# https://pillow.readthedocs.io/en/stable/handbook/concepts.html#modes
img_2.show()
Each data in rgbcomp array has 1-byte RGB data(R[7:5]+G[7:5]+B[7:6]).
Does anyone knows how to make reshaped array to 256 color PNG using pillow?
It should be look like true-color image converted into 256 color gif image.
Please help.
++ Added at 14:15, May 23, 2024
Here's the file of keil's output memoutput.hex
And also I've almost done that make pltePix - targetting the number of palette, plte - palette that decompose RRRGGGBB to R[7:0], G[7:0], B[7:0]
from intelhex import IntelHex
from PIL import Image
import numpy as np
ih = IntelHex()
ih.loadhex('memoutput.hex')
pydict=ih.todict() #hex to dict
rgbcomp = np.fromiter(pydict.values(), dtype=int) #array of values in dict
uniqRgbComp = np.unique(rgbcomp) #int list of uniq colors
plte = np.zeros((len(uniqRgbComp),3)) #plte(24bit rgb) = uniqRgbComp(8bit rgb)
for i in range(len(uniqRgbComp)):
plte[i] = np.array([ int(uniqRgbComp[i]&0b11100000), int( ((uniqRgbComp[i])&0b00011100) << 3 ), int( (uniqRgbComp[i]&0b00000011) << 6 ) ])
pltePix = np.zeros(len(rgbcomp)) #Pixel data points palette
for i in range(len(rgbcomp)):
pltePix[i] = np.argwhere(uniqRgbComp==rgbcomp[i])[0]
pltePix = np.reshape(pltePix, (640, 960))
The last, I just need to write PNG file using pltePix(pixel data), and plte(palette).
Can I get help to write 1-byte RGB image with these two arrays?
The 256 color image will looks like(generated by photoshop, 3:3:2 color will looks different):
++ Added at 14:50, May 23, 2024
FINALLY I MADE IT!!! Thanks for your all help.
And the code:
from intelhex import IntelHex
from PIL import Image
import numpy as np
# data=[None]*256
# for i in range(256):
# data[i] = i
#data[i] = f'ob{i:08b}'
ih = IntelHex()
ih.loadhex('memoutput.hex')
pydict=ih.todict() #hex to dict
rgbcomp = np.fromiter(pydict.values(), dtype=int) #array of values in dict
uniqRgbComp = np.unique(rgbcomp) #int list of uniq colors
plte = np.zeros((len(uniqRgbComp),3)) #plte(24bit rgb) = uniqRgbComp(8bit rgb)
for i in range(len(uniqRgbComp)):
plte[i] = np.array([ int(uniqRgbComp[i]&0b11100000), int( ((uniqRgbComp[i])&0b00011100) << 3 ), int( (uniqRgbComp[i]&0b00000011) << 6 ) ])
pltePix = np.zeros(len(rgbcomp)) #Pixel data points palette
for i in range(len(rgbcomp)):
pltePix[i] = np.argwhere(uniqRgbComp==rgbcomp[i])[0]
pltePix = np.reshape(pltePix, (640, 960))
im = Image.new(mode="P", size=(960,640))
plte = np.ravel(plte)
plte = np.uint8(plte).tolist()
im.putpalette(plte, rawmode="RGB")
pltePix = np.ravel(pltePix)
im.putdata(pltePix)
im.show()
Thank you for providing your Intel hex file. I converted it to a straight binary file with just 61,4400 bytes (960*640) using:
objcopy --input-target=ihex --output-target=binary image.hex image.bin
objcopy
should be in any compiler toolchain. I actually used Alpine Linux on docker and installed the binutils
package to get it.
You can then do the following:
PIL Image
#!/usr/bin/env python3
import numpy as np
from PIL import Image
# Convert your Intel hex file to 'image.bin' with:
# objcopy --input-target=ihex --output-target=binary image.hex image.bin
# Load binary file and reshape to 960x640
pixels = np.fromfile('image.bin', dtype=np.uint8).reshape((640,960))
# Make into 'PIL Image'
im = Image.fromarray(pixels)
# Generate palette
pal = [ [i & 0x70, (i & 0x1c)<<3, (i & 0x3)<<6] for i in range(256)]
# Flatten palette and push into image and save
flat = [x for xs in pal for x in xs]
im.putpalette(flat)
im.save('result.png')
You should really share your 1-byte RGB file so folks can test their solutions, but I'll try and answer blind.
You have 2 options:
PIL Image
and let PIL deduce a palette for youI think the first option is not "in the spirit" of your assignment, so let's go with the second.
At each pixel location, you will have 1-byte, with a value in the range 0..255. You need to determine what RGB colour that byte must become in order to make a palette. Let's look at the first few:
0 => rgb(0,0,0)
1 => rgb(0,0,64)
2 => rgb(0,0,128)
3 => rgb(0,0,192)
4 => rgb(0,32,0)
So you need something like this to generate your palette.
pal = [ [i & 0x70, (i & 0x1c)<<3, (i & 0x3)<<6] for i in range(256)]
Then you'll need to call putpalette(pal) to force that palette into your P
mode image.
All code sadly untested due to lack of input data in question.