可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Does anyone have a method for importing a 16 bit per channel, 3 channel TIFF image in Python?
I have yet to find a method which will preserve the 16 bit depth per channel when dealing with the TIFF format. I am hoping that some helpful soul will have a solution.
Here is a list of what I have tried so far without success and the results:
import numpy as np import PIL.Image as Image import libtiff import cv2 im = Image.open('a.tif') # IOError: cannot identify image file tif = libtiff.TIFF.open('a.tif') im = tif.read_image() # im only contains one of the three channels. im.dtype is uint16 as desired. im = [] for i in tif.iter_images(): # still only returns one channel im = np.array(cv2.imread('a.tif')) # im.dtype is uint8 and not uint16 as desired. # specifying dtype as uint16 does not correct this
So far the only solution I have found is to convert the image to PNG with ImageMagick. Then the bog standard matplotlib.pyplot.imread
reads the PNG file without any problems.
Another problem I have is saving any numpy arrays as 16 bit PNG files which so far has not been straightforward either.
回答1:
It has limited functionality, especially when it comes to writing back to disk non RGB images, but Christoph Gohlke's tifffile
module reads in 3 channel 16-bit TIFFs with no problems, I just tested it:
>>> import tifffile as tiff >>> a = tiff.imread('Untitled-1.tif') >>> a.shape (100L, 100L, 3L) >>> a.dtype dtype('uint16')
And Photoshop reads without complaining what I get from doing:
>>> tiff.imsave('new.tiff', a)
回答2:
The answer by @Jaime works.
In the mean time I managed to also solve the problem using cv2.imread
in OpenCV.
By default cv2.imread
will convert a 16 bit, three channel image in a.tif
to 8 bit as shown in the question.
cv2.imread
accepts a flag after the filename ( cv2.imread(filename[, flags])
) which specifies the colour type of the loaded image cf. the documentation:
- >0 returns a 3 channel colour image. This results in conversion to 8 bit as shown above.
- 0 returns a greyscale image. Also results in conversion to 8 bit.
- returns the image as is. This will return a 16 bit image.
So the following will read the image without conversion:
>>> im = cv2.imread('a.tif', -1) >>> im.dtype dtype('uint16') >>> im.shape (288, 384, 3)
Note that OpenCV returns the R, G and B channels in reverse order so im[:,:,0]
is the B channel, im[:,:,1]
the G channel and im[:,:,2]
is the R channel.
I have also found that cv2.imwrite
can write 16 bit, three channel TIFF files.
>>> cv2.imwrite('out.tif', im)
Checking the bit depth with ImageMagick:
$ identify -verbose out.tif Format: TIFF (Tagged Image File Format) Class: DirectClass Geometry: 384x288+0+0 Resolution: 72x72 Print size: 5.33333x4 Units: PixelsPerInch Type: TrueColor Base type: TrueColor Endianess: MSB Colorspace: sRGB Depth: 16-bit Channel depth: red: 16-bit green: 16-bit blue: 16-bit ....
回答3:
I found an additional alternative to the two methods above.
The scikit-image package can also read 16 bit, three channel TIFF files using both tifffile.py
and FreeImage and specifying them as the plugin to be used.
While reading using tifffile.py
is probably done more simply in the manner shown by @Jaime, I thought I would show how it is used along with scikit-image in case anyone wants to do it in this manner.
For anyone using Ubuntu, FreeImage is available as libfreeimage3
using apt
.
If the tifffile.py
plugin option is used the tifffile.py must be copied to the skimage/io/_plugins directory (f.ex. on Ubuntu the full path in my case was /usr/local/lib/python2.7/dist-packages/skimage/io/_plugins/
).
>>> import skimage.io >>> im = skimage.io.imread('a.tif', plugin='tifffile') >>> im.dtype dtype('uint16') >>> im.shape (288, 384, 3) >>> im = skimage.io.imread('a.tif', plugin='freeimage') >>> im.dtype dtype('uint16') >>> im.shape (288, 384, 3)
Writing TIFF files:
>>> skimage.io.imsave('b.tif', im, plugin='tifffile') >>> skimage.io.imsave('c.tif', im, plugin='freeimage')
Checking the bitdepth of both b.tif
and c.tif
using ImageMagick shows that each channel in both images are 16 bit.
回答4:
For me the previous alternatives did not work. I have used gdal successfully for reading a 16bit images of 1 GB.
You can open an image with something like this:
from osgeo import gdal import numpy as np ds = gdal.Open("name.tif") channel = np.array(ds.GetRasterBand(1).ReadAsArray())
There is a list of supported diver that you can use to write the data.