Convert 16-bit Tiff image to 8-bit RGB

Viewed 11220

I'm dealing with some satellite images, consisting of 16-bit .tiff images. The color is encoded as 16-bit per channel. I would like to know how I can convert these images to normal 8-bit RGB for further CNN processing.

I have tried OpenCV (cv2.read('file',-1)) and PIL (read('file')), but these two packages cannot recognize and read 16-bit tiff images.

3 Answers

Generally, when you want to read or write images in Python — of any bit-depth and format — it is best to use ImageIO. As the name suggests, its singular goal is to input/output images. Only caveat: It may ignore the image's meta data. That is: It may not deal correctly with images defining a color space other than the standard sRGB, or it might fail to preserve the image's intended orientation.

You would read in the image, say example.tif, like so:

import imageio
image = imageio.imread('example.tif')

As for the conversion, that's just basic math. The data structure in which you'll receive the pixel data is a NumPy array. Introspect image.shape and image.dtype. You should expect your images to have a shape of (y, x, 3), where y is the number of pixels in the vertical, x in the horizontal direction, and 3 represents the three color channels: red, green, blue. Its dtype (data type) should be uint16, meaning unsigned 16-bit integers.

Side note: As there are three color channels, each sampled with a 16-bit resolution, the color depth of the image is more commonly described as "48 bits" (per pixel).

16-bit integer numbers range between 0 and 65535 (= 216−1). They need to be coerced to the 8-bit range: 0 to 255 (= 28−1). So divide by 256 (= 28):

image = image / 256

This will yield an array of floating-point pixel values. Its data type must be explicitly cast to 8-bit integer in order to drop any fractions.

image = image.astype('uint8')

Equivalently, and more efficiently, you may also bit-shift the 16-bit values 8 bits to the right:

image = (image >> 8).astype('uint8')

This makes the conversion faster (by a factor of 2 or so on modern hardware) as it skips the floating-point operations.

Then, either use the final image array for further processing, or save it to a new file:

imageio.imwrite('example.png', image)

If all you want is to convert, your .tiff file's color space to RGB. Then Try:-

from PIL import Image

img = Image.open(r"Path_to_tiff_image")
img = img.convert("RGB")
img.save(r"path_of_destination_image")

The above code, first opens a .tiff image, then changes its color mode to RGB. And then saves it to the destination location.

Hey I used tifffile to handle the file and a calculation that I've found in a different thread here for rescaling the 16-bit image to 8-bit.

import numpy as np
import tifffile as tif
import cv2

image = tif.imread('/home/trance/test.tiff')

# Rescale 16-bit to 8-bit
img_rescaled = 255 * (image - image.min()) / (image.max() - image.min())

# Colourising image and saving it with opencv
img_col = cv2.applyColorMap(img_rescaled.astype(np.uint8), cv2.COLORMAP_INFERNO)
cv2.imwrite('/home/trance/test.png', img_col)
 
Related