tifffile in Python not writing 16bit tiff - python

I had a look for duplicates but I'm not sure similar questions had the answer...
I'm using tifffile in Python to read a multipage tiff (16 bit), take the first channel page/channel, blur it and save it as a 16 bit tiff.
import os
import matplotlib.pyplot as plt
import tifffile as tiff
from scipy import misc
tiff_list = []
for i in files_list[0]:
tiff_list.append(tiff.imread('/filepath_to_tiff_folder/'+i))
blurred_list = []
for i in tiff_list:
blurred_list.append(ndimage.gaussian_filter(i[0], sigma=3))
for i,v in enumerate(blurred_list):
misc.imsave('/filepath/testblur2/'+str(files_list[0][i])+'_Brightfield_Blur.tif', v)
Here, files_list is just a list of the file names of the tiffs.
The above code works absolutely fine for blurring and saving the tiff, but it saves it as 8 bit instead.
Is there something in the above I can add to keep it 16 bit or do I have to use another method?

You are using scipy, not tifffile, to save the images.
Use tifffile.imsave to save 16-bit images, e.g.:
from glob import glob
from scipy import ndimage
from tifffile import imread, imsave
for filename in glob('*.tif'):
i = imread(filename)
i = ndimage.gaussian_filter(i[0], sigma=3)
imsave('blurred_' + filename, i)

Related

How to convert multiple mha images to nii

I would like to convert about 300 .mha images into .nii format. Which are under subfolders . I have successfully converted one image but in order to go each folder and convert, its a tidious task. Please suggest me code that is functioning with sitk library
import SimpleITK as sitk
import matplotlib.pyplot as plt
import numpy as np
import os
OUTPUT_DIR = '/home/user/Downloads/'
Image = sitk.ReadImage('Input dir')
print(Image.GetPixelIDTypeAsString())
sitk.WriteImage(Image, os.path.join(OUTPUT_DIR, 'Flair.nii'))
Use python's os.walk method to get all the files in a directory tree. Then select out only the ones with the '.mha' suffix.
Here's an example of how it works:
https://www.tutorialspoint.com/python/os_walk.htm
Or you can try and decipher the os library documentation:
https://docs.python.org/3/library/os.html

How convert image to an array in python

I want to convert image (.jpg) to binary array. Because I have to use this array to my scrambler operating on it saved in file. Which library and and functions should I use?
You should take a look at the openCV library.
import cv2
img = cv2.imread('image.jpg', flags=cv2.IMREAD_COLOR)
You can use the python library: PIL & numpy. Click here to learn more about image handling in python.
import numpy
import PIL
img = PIL.Image.open("foo.jpg").convert("L")
imgarr = numpy.array(img)
You can use this code to convert your image to array
# Import the necessary libraries
from PIL import Image
from numpy import asarray
# load the image and convert into
# numpy array
img = Image.open('test.jpg')
arraydata = asarray(img)
# data
print(arraydata)

Get information of multipage tiff image (I;16) with python

I am working with images from a multispectral camera and after doing some processing I have 16 bits multipage image with 6 bands in tiff format. Now, I need to get information of each layer through python code, so I used:
from __future__ import division
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
files = os.listdir('my directory')
for file in files:
I = Image.open(os.path.join('my directory', "image.tif"))
plt.imshow(np.asarray(I))
plt.show()
print (I.size, I.mode, I.format)
band1 = np.asarray(I,dtype=np.uint16)
A = np.asarray(I,dtype=np.float32)
I can read the image but I cannot find the information of the six different layers and actually, I am not sure from which band the values of "A" are. The image is too big to upload it, but I can try to share it if it´s necessary. Thanks.

Read 16-bit PNG image file using Python

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

scikit-image save image to a bytestring

I'm using scikit-image to read an image:
img = skimage.io.imread(filename)
After doing some manipulations to img, I'd like to save it to an in-memory file (a la StringIO) to pass off to another function, but it looks like skimage.io.imsave requires a filename, not a file handle.
I'd like to avoid hitting the disk (imsave followed by read from another imaging library) if at all possible. Is there a nice way to get imsave (or some other scikit-image-friendly function) to work with StringIO?
Update: 2020-05-07
We now recommend using the imageio library for image reading and writing. Also, with Python 3, StringIO changes to BytesIO:
from io import BytesIO
import imageio
buf = BytesIO()
imageio.imwrite(buf, image, format='png')
scikit-image stores images as numpy arrays, therefore you can use a package such as matplotlib to do so:
import matplotlib.pyplot as plt
from StringIO import StringIO
s = StringIO()
plt.imsave(s, img)
This may be worth adding as default behaviour to skimage.io.imsave, so if you want you can also file an issue at https://github.com/scikit-image/scikit-image.

Categories