pythonopencv

How to read and enhance contrast of 32bit .tiff image using opencv2 in python coding?


As I tried to code the opencv2 to read the tiff image file, It show up

OpenCV TIFF: TIFFRGBAImageOK: Sorry, can not handle images with 32-bit samples

I should expect that the opencv will read the file and process it with enhance contrast a bit.

here is the code:

import os
import cv2

input_folder = 'path'
output_folder = 'path'

# Loop through all TIFF files in the input folder
for filename in os.listdir(input_folder):
    if filename.endswith('.tiff'):
        image = cv2.imread(os.path.join(input_folder, filename), cv2.IMREAD_GRAYSCALE)

        alpha = 1.0035
        beta = 0
        enhanced_image = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)

        output_filename = os.path.splitext(filename)[0] + '_enhanced.tif'
        cv2.imwrite(os.path.join(output_folder, output_filename), enhanced_image)

For the image tiff file, i have upload Here and please use ImageJ to view it.

Update (1), I have tried How do you read a 32-bit TIFF image in python? But it seem have another error which is this

can't open/read file: check file path/integrity

Followed by

cv2.error: OpenCV(4.7.0) D:\a\opencv-python\opencv-python\opencv\modules\imgcodecs\src\loadsave.cpp:783: error: (-215:Assertion failed) !_img.empty() in function 'cv::imwrite'


Solution

  • 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.


    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:
    enter image description here
    The contrast is enhanced, but the input image is mainly noise...