I have a 4 band multichannel image (TIF) which is an unsigned 16 bit image. I am using the following:
opencv2
python
I have done the following at the beginning of my code
import cv2
When I use
i = cv2.imread('img.tif')
it is reading all the four bands but as UINT8. When I use
i = cv2.imread('img.tif', cv2.CV_16U)
it reads only one channel of the image. What should be done to read all the four channels in 16bit unsigned?
Try passing the flag cv2.IMREAD_ANYDEPTH. The documentation states this flag will:
If set, return 16-bit/32-bit image when the input has the corresponding depth, otherwise convert it to 8-bit.
i = cv2.imread('img.tif', flags=cv2.IMREAD_ANYDEPTH)
If that doesn't work, try the cv2.IMREAD_UNCHANGED flag instead. It's not documented, but it looks like it may also work.
Related
I'm using imageio in Python to read in jpg images and write them as a gif, using something resembling the code below.
import imageio
with imageio.get_writer('mygif.gif', mode='I') as writer:
for filename in framefiles: # iterate over names of jpg files I want to turn into gif frames
frame = imageio.imread(filename)
writer.append_data(frame)
I'm noticing that the image quality in the gifs I produce is quite poor; I suspect this is due to some form of compression. Is there a way to tell imageio not to use any compression? Or maybe a way to do this with opencv instead?
Real problem is that GIF can display only 256 colors (8-bits color) so it has to reduce 24-bits colors (RGB) to 256 colors or it has emulate more colors using dots with different colors - ditherring.
As for options:
Digging in source code I found that it can get two parameters quantizer, palettesize which can control image/animation quality. (There is also subrectangles to reduce file size)
But there are two plugins for GIF which use different modules Pillow or FreeImage and they need different value for quantizer
PIL needs integer 0, 1 or 2.
FI needs string 'wu' or 'nq' (but later it converts it to integer 0 or 1)
They also keep these values in different way so if you want get current value or change it after get_writer() then you also need different code.
You can select module with format='GIF-PIL' or format='GIF-FI'
with imageio.get_writer('mygif.gif', format='GIF-PIL', mode='I',
quantizer=2, palettesize=32) as writer:
print(writer)
#print(dir(writer))
#print(writer._writer)
#print(dir(writer._writer))
print('quantizer:', writer._writer.opt_quantizer)
print('palette_size:', writer._writer.opt_palette_size)
#writer._writer.opt_quantizer = 1
#writer._writer.opt_palette_size = 256
#print('quantizer:', writer._writer.opt_quantizer)
#print('palette_size:', writer._writer.opt_palette_size)
with imageio.get_writer('mygif.gif', format='GIF-FI', mode='I',
quantizer='nq', palettesize=32) as writer:
print(writer)
#print(dir(writer))
print('quantizer:', writer._quantizer)
print('palette_size:', writer._palettesize)
#writer._quantizer = 1
#writer._palettesize = 256
#print('quantizer:', writer._quantizer)
#print('palette_size:', writer._palettesize)
I tried to create animations with different settings but they don't look much better.
I get better result using external program ImageMagick in console/terminal
convert image*.jpg mygif.gif
but still it wasn't as good as video or static images.
You can run it in Python
os.system("convert image*.jpg mygif.gif")
subprocess.run("convert image*.jpg mygif.gif", shell=True)
Or you can try to do it with module Wand which is a wrapper on ImageMagick
Source code: GifWriter in pillowmulti.py and in freeimagemulti.py
* wu - Wu, Xiaolin, Efficient Statistical Computations for Optimal Color Quantization
* nq (neuqant) - Dekker A. H., Kohonen neural networks for optimal color quantization
Doc: GIF-PIL Static and animated gif (Pillow), GIF-FI Static and animated gif (FreeImage)
I have a naive question, but after a long day, I am not still able to get my answer.
I am currently loading my png image using PIL, it works well. However, some of my png
images are 16-bit per pixel. I am trying desperately to query this information, but I am not able to get it, using PIL. Indeed, if I am simply using the file system binary it works.
$ file flower_16b.png
flower_16b.png: PNG image data, 660 x 600, 16-bit/color RGB, non-interlaced
However in my python code:
img = Image.open(filename, "r")
print(img.mode)
I get RGB. Following the documentation PIL RGB means (3x8-bit pixels, true color), it look likes the image has been casted. So does it exist a way to get the depth of an image, using PIL or an other python module ?
PIL/Pillow doesn't support 48-bit images like that. One option might be OpenCV but be aware it comes as BGR not RGB:
import cv2
# Read with whatever bit depth is specified in the image file
BGR = cv2.imread('image.png', cv2.IMREAD_ANYDEPTH|cv2.IMREAD_ANYCOLOR)
# Check dtype and number of channels
print(BGR.dtype, BGR.shape)
dtype('uint16'), (768, 1024, 3)
Another option may be pyvips, which works a slightly different way, but has some good benefits:
import pyvips
im = pyvips.Image.new_from_file('image.png', access="sequential")
print(im)
<pyvips.Image 1024x768 ushort, 3 bands, rgb16>
If you are really, really stuck and can't/won't install OpenCV or pyvips, you have a couple more options with ImageMagick...
You could reduce your 3 RGB channels (16-bits each) to 3 RGB channels (8-bits each) with:
magick input.png PNG24:output.png # then open "output.png" with PIL
Or, you could separate the 3 RGB channels into 3 separate 16-bit files and process them separately with PIL/Pillow:
magick input.png -separate channel-%d.png
and you will get the red channel as a 16-bit image in channel-0.png which you can open with PIL/Pillow, the green as channel-1.png and the blue as channel-2.png
Question
With an image loaded into Python as shown below, how do I know which order the channels are in? (e.g. BGR or RGB)
Code
from PIL import Image
import numpy as np
image_pil = Image.open("Stonehenge.jpg")
image_np = np.array(image_pil)
image_np[0][0]
Result
array([ 52, 123, 155], dtype=uint8)
Specific question
How do I know whether the 52 corresponds to the red channel, the blue channel, or a different channel? Or does this question not make sense on a conceptual level?
Notes
In a similar question for Java instead of Python, one person claims:
If you are reading in the image file, or you have access to the code
that reads in the file, know it is:
BGR order if you used cv2.imread(),
RGB order if you used mpimg.imread(), (assuming import matplotlib.image as mpimg)
If you don't know how the file was opened, the accepted answer
BufferedImage is great for Java.
Since you use PIL and you don't specify any other mode to load the Image with, you get R G B.
You could verify that by checking the "mode" attribute on the Image instance:
image_pil.mode # should return the string 'RGB'
Pillow supports the array interface, via image_pil.__array_interface__ magic method, so when when you create the ndarray numpy just uses that. i.e., it doesn't know anything about the colour channel order. If you have an image file stored as BGR, and you load it like this, you will get blue data in the red channel and vice-versa, and it would look wrong when you display it.
I'm attempting to make a reasonably simple code that will be able to read the size of an image and return all the RGB values. I'm using PIL on Python 2.7, and my code goes like this:
import os, sys
from PIL import Image
img = Image.open('C:/image.png')
pixels = img.load()
print(pixels[0, 1])
now this code was actually gotten off of this site as a way to read a gif file. I'm trying to get the code to print out an RGB tuple (in this case (55, 55, 55)) but all it gives me is a small sequence of unrelated numbers, usually containing 34.
I have tried many other examples of code, whether from here or not, but it doesn't seem to work. Is it something wrong with the .png format? Do I need to further code in the rgb part? I'm happy for any help.
My guess is that your image file is using pre-multiplied alpha values. The 8 values you see are pretty close to 55*34/255 (where 34 is the alpha channel value).
PIL uses the mode "RGBa" (with a little a) to indicate when it's using premultiplied alpha. You may be able to tell PIL to covert the to normal "RGBA", where the pixels will have roughly the values you expect:
img = Image.open('C:/image.png').convert("RGBA")
Note that if your image isn't supposed to be partly transparent at all, you may have larger issues going on. We can't help you with that without knowing more about your image.
I try to apply image filters using python's PIL. The code is straight forward:
im = Image.open(fnImage)
im = im.filter(ImageFilter.BLUR)
This code works as expected on PNGs, JPGs and on 8-bit TIFs. However, when I try to apply this code on 16-bit TIFs, I get the following error
ValueError: image has wrong mode
Note that PIL was able to load, resize and save 16-bit TIFs without complains, so I assume that this problem is filter-related. However, ImageFilter documentation says nothing about 16-bit support
Is there any way to solve it?
Your TIFF image's mode is most likely a "I;16".
In the current version of ImageFilter, kernels can only be applied to
"L" and "RGB" images (see source of ImageFilter.py)
Try converting first to another mode:
im.convert('L')
If it fails, try:
im.mode = 'I'
im = im.point(lambda i:i*(1./256)).convert('L').filter(ImageFilter.BLUR)
Remark: Possible duplicate from Python and 16 Bit Tiff
To move ahead, try using ImageMagick, look for PythonMagick hooks to the program. On the command prompt, you can use convert.exe image-16.tiff -blur 2x2 output.tiff. Didn't manage to install PythonMagick in my windows OS as the source needs compiling.