'PIL opens only first chanel of TIF image
I'm trying to open (and then process) a 3-channel Tif image (8-bits) created with ImageJ.
im = Image.open('spinal.tif')
im.show()
shows me a png for the first channel
n = np.array(im)
print(n.shape)
gives me (400, 450), thus considers only the first channel
How could I work on the different channels? Many thanks
Info on my tif file from ImageJ:
Title: spinal.tif
Width: 1986.4042 microns (450)
Height: 1765.6926 microns (400)
Size: 527K
Resolution: 0.2265 pixels per micron
Voxel size: 4.4142x4.4142x1 micron^3
ID: -466
Bits per pixel: 8 (grayscale LUT)
Display ranges
1: 0-255
2: 0-255
3: 0-255
Image: 1/3 (c:1/3 - 64_spinal_20x lame2.ndpis #1)
Channels: 3
Composite mode: "grayscale"
The file is temporarily available here : https://filesender.renater.fr/?s=download&token=ab39ca56-24c3-4993-ae78-19ac5cf916ee
Solution 1:[1]
I finally found a way around using the scikit-image library. This opens correctly the 3 channels (matplotlib didn't, nor PIL). Once I have the array, I can go back to PIL using Image.fromarray to resume the processing.
from skimage.io import imread
from PIL import Image
img = imread('spinal.tif')
im_pil = Image.fromarray(img)
im_pil.show()
print(np.array(im_pil).shape)
This shows the composite image, and the correct (400, 450, 3) shape. I can then get the different channels with Image.getchannel(channel) as in :
im_BF = im_pil.getchannel(0)
im_BF.show()
Thank you to the contributors who tried to solve my issue (I saw that the file was downloaded several times) and there might be a better way to process these multiple-channels TIF images with PIL, but this looks like working !
Solution 2:[2]
Your image is not a 3-channel RGB image. Rather, it is 3 separate images, each one a single greyscale channel. You can see that with ImageMagick:
magick identify spinal.tif
spinal.tif[0] TIFF 450x400 450x400+0+0 8-bit Grayscale Gray 545338B 0.000u 0:00.000
spinal.tif[1] TIFF 450x400 450x400+0+0 8-bit Grayscale Gray 0.000u 0:00.000
spinal.tif[2] TIFF 450x400 450x400+0+0 8-bit Grayscale Gray 0.000u 0:00.000
Or with tiffinfo which comes with libtiff:
TIFF Directory at offset 0x8 (8)
Subfile Type: (0 = 0x0)
Image Width: 450 Image Length: 400
Resolution: 0.22654, 0.22654 (unitless)
Bits/Sample: 8
Compression Scheme: None
Photometric Interpretation: min-is-black
Samples/Pixel: 1
Rows/Strip: 400
Planar Configuration: single image plane
ImageDescription: ImageJ=1.53f
images=3
channels=3
mode=grayscale
unit=micron
loop=false
TIFF Directory at offset 0x545014 (850f6)
Subfile Type: (0 = 0x0)
Image Width: 450 Image Length: 400
Resolution: 0.22654, 0.22654 (unitless)
Bits/Sample: 8
Compression Scheme: None
Photometric Interpretation: min-is-black
Samples/Pixel: 1
Rows/Strip: 400
Planar Configuration: single image plane
ImageDescription: ImageJ=1.53f
images=3
channels=3
mode=grayscale
unit=micron
loop=false
TIFF Directory at offset 0x545176 (85198)
Subfile Type: (0 = 0x0)
Image Width: 450 Image Length: 400
Resolution: 0.22654, 0.22654 (unitless)
Bits/Sample: 8
Compression Scheme: None
Photometric Interpretation: min-is-black
Samples/Pixel: 1
Rows/Strip: 400
Planar Configuration: single image plane
ImageDescription: ImageJ=1.53f
images=3
channels=3
mode=grayscale
unit=micron
loop=false
If it is meant to be 3-channel RGB, rather than 3 separate greyscale channels, you need to save it differently in ImageJ. I cannot advise on that.
If you want combine the 3 channels into a single image on the command-line, you can do that with ImageMagick:
magick spinal.tif -combine spinal-RGB.png
If you want to read it with PIL/Pillow, you need to treat it as an image sequence:
from PIL import Image, ImageSequence
with Image.open("spinal.tif") as im:
for frame in ImageSequence.Iterator(im):
print(frame)
which gives this:
<PIL.TiffImagePlugin.TiffImageFile image mode=L size=450x400 at 0x11DB64220>
<PIL.TiffImagePlugin.TiffImageFile image mode=L size=450x400 at 0x11DB64220>
<PIL.TiffImagePlugin.TiffImageFile image mode=L size=450x400 at 0x11DB64220>
Or, if you want to assemble into RGB, something more like this:
from PIL import Image
# Open image and hunt down separate channels
with Image.open("spinal.tif") as im:
R = im.copy()
im.seek(1)
G = im.copy()
im.seek(2)
B = im.copy()
# Merge the three separate channels into single RGB image
RGB = Image.merge("RGB", (R, G, B))
RGB.save('result.png')
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Tilde |
| Solution 2 |

