OpenCV doesn't support reading Tiff image in float format (at least not the standard Python version).
We may use tifffile for reading the image:
import tifffile
...
image = tifffile.imread(filename)
There are multiple ways to enhance the contrast of the image.
Two examples: "Linear stretching" and CLAHE.
Linear stretching (from my following answer):
Find minimal and maximal percentile, and apply linear "stretch" such that low percentile goes to 0, and high_prc percentile goes to 255:
def lin_stretch_img(img, low_prc, high_prc):
lo, hi = np.percentile(img, (low_prc, high_prc)) # Example: 1% - Low percentile, 99% - High percentile
if lo == hi:
return np.full(img.shape, 128, np.uint8) # Protection: return gray image if lo = hi.
stretch_img = (img.astype(np.float32) - lo) * (255/(hi-lo)) # Linear stretch: lo goes to 0, hi to 255.
stretch_img = stretch_img.clip(0, 255).astype(np.uint8) # Clip range to [0, 255] and convert to uint8
return stretch_img
OpenCV CLAHE:
Enhancing the contrast in each block, allows much higher contrast compared to the linear stretching.
Since CLAHE in OpenCV does not support float32, we have to convert the image to uint16 type before applying CLAHE.
image_as_uint16 = cv2.normalize(image, None, 0, 65535, cv2.NORM_MINMAX, cv2.CV_16U) # Convert to uint16 before applying CLAHE
clahe = cv2.createCLAHE(clipLimit=20, tileGridSize=(8, 8))
cl1 = clahe.apply(image_as_uint16) # CLAHE in OpenCV does not support float32 apply CLAHE to the uint16 image.
cl1 = cv2.convertScaleAbs(cl1, alpha=255/65535) # Convert from uint16 to uint8
Code sample:
import os
import cv2
import tifffile
import numpy as np
def lin_stretch_img(img, low_prc, high_prc):
"""
Apply linear "stretch" - low_prc percentile goes to 0,
and high_prc percentile goes to 255.
The result is clipped to [0, 255] and converted to np.uint8
"""
lo, hi = np.percentile(img, (low_prc, high_prc)) # Example: 1% - Low percentile, 99% - High percentile
if lo == hi:
return np.full(img.shape, 128, np.uint8) # Protection: return gray image if lo = hi.
stretch_img = (img.astype(np.float32) - lo) * (255/(hi-lo)) # Linear stretch: lo goes to 0, hi to 255.
stretch_img = stretch_img.clip(0, 255).astype(np.uint8) # Clip range to [0, 255] and convert to uint8
return stretch_img
filename = 'top_high_1493_2065_132_132_0.tiff'
#image = cv2.imread(filename, cv2.IMREAD_GRAYSCALE)
image = tifffile.imread(filename)
alpha = 1.0035
beta = 0
enhanced_image = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)
# Apply "linear stretching" (lower percentile 0.1 goes to 0, and percentile 99.9 to 255).
lin_enhanced_image = lin_stretch_img(image, 0.1, 99.9)
# Normalizing frame to range [0, 65535], and get the result as type uint16. (65535 = 2**16-1)
image_as_uint16 = cv2.normalize(image, None, 0, 65535, cv2.NORM_MINMAX, cv2.CV_16U) # Convert to uint16 before applying CLAHE
clahe = cv2.createCLAHE(clipLimit=20, tileGridSize=(8, 8))
cl1 = clahe.apply(image_as_uint16) # CLAHE in OpenCV does not support float32 apply CLAHE to the uint16 image.
cl1 = cv2.convertScaleAbs(cl1, alpha=255/65535) # Convert from uint16 to uint8
output_filename = os.path.splitext(filename)[0] + '_enhanced.tif'
cv2.imwrite(output_filename, enhanced_image)
cv2.imwrite(os.path.splitext(filename)[0] + '_lin_enhanced.tif', lin_enhanced_image)
cv2.imwrite(os.path.splitext(filename)[0] + '_cl1_enhanced.tif', cl1)
CLAHE output for example:

The contrast is enhanced, but the input image is mainly noise...