What is the way to convert RGB images to RGBA in python using OpenCV? My requirements are specific as I am trying to display an image on E-Paper Display. I need to convert an image to 16 bit RGBA. The code that I have written is converting the image but it's coming as all black. I have tried with convert 1 bit deep images to RGBA? NumPy convert 8-bit to 16/32-bit image these solutions as well. I have to use GMU image editor on Linux to convert it manually then it works. Since I am trying to open a pdf and convert each page as an image to display it on E-Paper Diaplay. I can't go that way.
i = cv2.imread(FNAME, cv2.IMREAD_UNCHANGED)
img = np.array(i, dtype=np.uint16)
img *= 256
filename = 'khrgb.png'
cv2.imwrite(filename, img)
use cv2.cvtColor
rgba=cv2.cvtColor(i,cv2.COLOR_BGR2RGBA)
I try to read a TIFF file with pillow/PIL (7.2.0) in Python (3.8.3), e.g. this image.
The resulting file seems to be corrupted:
from PIL import Image
import numpy as np
myimage = Image.open('moon.tif')
myimage.mode
# 'L'
myimage.format
# 'TIFF'
myimage.size
# (358, 537)
# so far all good, but:
np.array(myimage)
# shows only zeros in the array, likewise
np.array(myimage).sum()
# 0
It doesn't seem to be a problem of the conversion to numpy array only, since if I save it to a jpg (myimage.save('moon.jpg')) the resulting jpg image has the appropriate dimensions but is all black, too.
Where did I do wrong or is it a bug?
I am not an expert in coding but i had same problem and found the TIFF file has 4 layers. R, G ,B and Alpha. When you convert it using PIL it is black.
try to view the image as plt.imshow(myimage[:, :, 0])
you could also remove the Alpha layer by saving the read image ( i used plt.imread('image')) and then saving it as image=image[:,:,3]. Now its a RGB image.
I don't know if i answered your question, but i felt this info might be of help.
For my current task, I need to convert a 24 color bmp, to a 16 color bmp file. and Print the image in the pdf file. I tired using the PIL module,but it didn't helped me.
from PIL import Image
path = r'C:\Display_Icon_Testing\Captured_Images\Impl_Modulation_Screen.bmp'
im = Image.open(path)
print im
im1 = Image.open(path).convert('P')
print im1
please help me with this.
The code below will read an image in any format that PIL understands, convert it to 16 colors, and save it as a PDF file. By default, PIL uses Floyd-Steinberg dithering to improve the image quality when converting a 24 bit image to a palette-based image.
I'm using the Pillow fork of PIL, since the original PIL is no longer maintained, but this code should work properly on original PIL or Pillow.
from PIL import Image
iname = 'test.bmp'
oname = 'test.pdf'
img = Image.open(iname)
newimg = img.convert(mode='P', colors=16)
newimg.save(oname)
I'm trying to read a PNG image file written in 16-bit data type. The data should be converted to a NumPy array. But I have no idea how to read the file in '16-bit'. I tried with PIL and SciPy, but they converted the 16-bit data to 8-bit when they load it. Could anyone please let me know how to read data from a 16-bit PNG file and convert it to NumPy array without changing the datatype?
The following is the script that I used.
from scipy import misc
import numpy as np
from PIL import Image
#make a png file
a = np.zeros((1304,960), dtype=np.uint16)
a[:] = np.arange(960)
misc.imsave('16bit.png',a)
#read the png file using scipy
b = misc.imread('16bit.png')
print "scipy:" ,b.dtype
#read the png file using PIL
c = Image.open('16bit.png')
d = np.array(c)
print "PIL:", d.dtype
I'd recommend using opencv:
pip install opencv-python
and
import cv2
image = cv2.imread('16bit.png', cv2.IMREAD_UNCHANGED)
in contrast to OpenImageIO, opencv could be installed from pip
The time, required to read a single 4000x4000 png is about the same as PIL, but PIL uses more CPU and requires additional time to convert data back to uint16.
I have the same problem here. I tested it even with 16 bit images i created by my own. All of them were opened correctly when i loaded them with the png package. Also the output of 'file ' looked okay.
Opening them with PIL always led to 8-bit numpy-arrays.
Working with Python 2.7.6 on Linux btw.
Like this it works for me:
import png
import numpy as np
reader = png.Reader( path-to-16bit-png )
pngdata = reader.read()
px_array = np.array( map( np.uint16, pngdata[2] )
print( px_array.dtype )
Maybe someone can give more information under which circumstances the former approach worked? (as this one is pretty slow)
Thanks in advance.
The simplest solution I've found:
When I open a 16 bit monochrome PNG Pillow it doesn't open correctly as I;16 mode.
Image.mode is opened as I (32 bits)
So, the best way to convert to numpy array. It is dtype="int32" so we will convert it to dtype="uint16".
import numpy as np
from PIL import Image
im = Image.fromarray(np.array(Image.open(name)).astype("uint16"))
print("Image mode: ", im.mode)
Tested in Python 3.6.8 with Pillow 6.1.0
This happens because PIL does not support 16-bit data, explained here: http://effbot.org/imagingbook/concepts.htm
I use a work around using the osgeo gdal package (which can read PNG).
#Import
import numpy as np
from osgeo import gdal
#Read in PNG file as 16-bit numpy array
lon_offset_px=0
lat_offset_px=0
fn = 'filepath'
gdo = gdal.Open(fn)
band = gdo.GetRasterBand(1)
xsize = band.XSize
ysize = band.YSize
png_array = gdo.ReadAsArray(lon_offset_px, lat_offset_px, xsize, ysize)
png_array = np.array(png_array)
This will return
png_array.dtype
dtype('uint16')
A cleaner way I found is using the skimage package.
from skimage import io
im = io.imread(jpg)
Where 'im' will be a numpy array.
Note: I haven't tested this with PNG but it works with TIFF files
I'm using png module:
At first install png by:
>pip install pypng
Then
import png
import numpy as np
reader = png.Reader('16bit.png')
data = reader.asDirect()
pixels = data[2]
image = []
for row in pixels:
row = np.asarray(row)
row = np.reshape(row, [-1, 3])
image.append(row)
image = np.stack(image, 1)
print(image.dtype)
print(image.shape)
Another option to consider, based on Mr. Fridy's answer, is to load it using pypng like this:
import png
pngdata = png.Reader("path/to/16bit.png").read_flat()
img = np.array(pngdata[2]).reshape((pngdata[1], pngdata[0], -1))
You can install pypng using pip:
pip install pypng
The dtype from png.Reader.read_flat() is correctly uint16 and the reshaping of the np.ndarray puts it into (height, width, channels) format.
I've been playing with this image using PIL version 5.3.0:
it reads the data just fine:
>>> image = Image.open('/home/jcomeau/Downloads/grayscale_example.png')
>>> image.mode
'I'
>>> image.getextrema()
(5140, 62708)
>>> image.save('/tmp/test.png')
and it saves in the right mode, however the contents are not identical:
jcomeau#aspire:~$ diff /tmp/test.png ~/Downloads/grayscale_example.png
Binary files /tmp/test.png and /home/jcomeau/Downloads/grayscale_example.png differ
jcomeau#aspire:~$ identify /tmp/test.png ~/Downloads/grayscale_example.png
/tmp/test.png PNG 85x63 85x63+0+0 16-bit sRGB 6.12KB 0.010u 0:00.000
/home/jcomeau/Downloads/grayscale_example.png PNG 85x63 85x63+0+0 16-bit sRGB 6.14KB 0.000u 0:00.000
however, image.show() always converts to 8-bit grayscale, clamped at 0 and 255. so it's useless for seeing what you've got at any stage of the transformation. while I could write a routine to do so, and perhaps even monkeypatch .show(), I just run the display command in another xterm.
>>> image.putdata([n - 32768 for n in image.getdata()])
>>> image.getextrema()
(-27628, 29940)
>>> image.save('/tmp/test2.png')
note that converting to mode I;16 doesn't help:
>>> image.convert('I;16').save('/tmp/test3.png')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/jcomeau/.local/lib/python2.7/site-packages/PIL/Image.py", line 1969, in save
save_handler(self, fp, filename)
File "/home/jcomeau/.local/lib/python2.7/site-packages/PIL/PngImagePlugin.py", line 729, in _save
raise IOError("cannot write mode %s as PNG" % mode)
IOError: cannot write mode I;16 as PNG
You can also use the excellent OpenImageIO library's Python API.
import OpenImageIO as oiio
img_input = oiio.ImageInput.open("test.png") # Only reads the image header
pix = img_input.read_image(format="uint16") # Reads the pixels into a Numpy array
OpneImageIO is used extensively in the VFX industry, so most Linux distros come with a native package for it. Unfortunately the otherwise excellent documentation is in PDF format (I personally prefer HTML), look for it in /usr/share/doc/OpenImageIO.
imageio library supports 16bit images:
from imageio import imread, imwrite
import numpy as np
from PIL import Image
#make a png file
a = np.arange(65536, dtype=np.uint16).reshape(256,256)
imwrite('16bit.png',a)
#read the png file using imageio
b = imread('16bit.png')
print("imageio:" ,b.dtype)
#imageio: uint16
#read the png file using PIL
c = Image.open('16bit.png')
d = np.array(c)
print("PIL:", d.dtype)
# PIL: int32
Using imagemagick:
>> identify 16bit.png
16bit.png PNG 256x256 256x256+0+0 16-bit Grayscale Gray 502B 0.000u 0:00.000
I suspect your "16 bit" PNG is not 16-bit. (if you're on Linux or Mac you could run file 16bit.png and see what it says)
When I use PIL and numpy I get a 32-bit array with 16-bit values in it:
import PIL.Image
import numpy
image = PIL.Image.open('16bit.png')
pixel = numpy.array(image)
print "PIL:", pixel.dtype
print max(max(row) for row in pixel)
the output is:
PIL: int32
65535
I need to show a background to a matplotlib plot using ax.imshow(). The background images that I will be using are GIF-images. Despite having PIL installed, the following code results in an error complaining that the Python Image Library (PIL) is not installed (which it is):
from pylab import imread
im_file = open("test.gif")
im_obj = imread(im_file)
Reading the image using PIL directly works better:
from PIL import Image
import numpy
img = Image.open("test.gif")
img_arr = asarray(img.getdata(), dtype=numpy.uint8)
However, when reshaping the array, the following code does not work:
img_arr = img_arr.reshape(img.size[0], img.size[1], 3) #Note the number 3
The reason is that the actual color information is contained in a color table accessed through img.getcolors() or img.getpalette().
Converting all the images to PNG or another suitable format that results in RGB images when opening them with imread() or Image.open() is not an option. I could convert the images when needed using PIL but I consider that solution ugly. So the question is as follows: Is there a simple and fast (the images are 5000 x 5000 pixels) way to convert the GIF images to RGB (in RAM) so that I can display them using imshow()?
You need to convert the GIF to RGB first:
img = Image.open("test.gif").convert('RGB')
See this question: Get pixel's RGB using PIL