Search code examples
pythonimageopencvcompressionpca

Python OpenCV cannot display image correctly after transformation


Today I was trying to compress the image below, using sklearn's PCA algorithm in Python.

Baby Yoda Image that was tried to be compressed

Because the image is RGB (3 channels), I first reshaped the image, so that it becomes 2D. Then, I applied the PCA algorithm on the data to compress the image. After the image was compressed, I inversed the PCA transformation and reshaped the approximated (decompressed) image back to its original shape.

However, when I tried to display the approximated image I got this weird result here:

enter image description here

While the image is stored correctly with the cv2.imwrite function, OpenCV fails to display the image correctly using cv2.imshow. Do You have any idea why this might be happening?

My code is below:

from sklearn.decomposition import PCA
import cv2
import numpy as np

image_filepath = 'baby_yoda_image.jpg'

# Loading image from disk.
input_image = cv2.imread(image_filepath)
height = input_image.shape[0]
width = input_image.shape[1]
channels = input_image.shape[2]

# Reshaping image to perform PCA.
print('Input image shape:', input_image.shape)
#--- OUT: (533, 800, 3)

reshaped_image = np.reshape(input_image, (height, width*channels))
print('Reshaped Image:', reshaped_image.shape)
#--- OUT: (533, 2400)

# Applying PCA transformation to image. No whitening is applied to prevent further data loss.
n_components = 64
whitening = False
pca = PCA(n_components, whitening)
compressed_image = pca.fit_transform(reshaped_image)

print('PCA Compressed Image Shape:', compressed_image.shape)
#--- OUT: (533, 64)
print('Compression achieved:', np.around(np.sum(pca.explained_variance_ratio_), 2)*100, '%')
#--- OUT: 97.0 %    

# Plotting images.
approximated_image = pca.inverse_transform(compressed_image)
approximated_original_shape_image = np.reshape(approximated_image, (height, width, channels))

cv2.imshow('Input Image', input_image)
cv2.imshow('Compressed Image', approximated_original_shape_image)
cv2.waitKey()

Thanks in advance.


Solution

  • Finally, I found a solution to this problem, thanks to @fmw42 . After the transformation, there were negative values in the pixels and also values that exceeded 255.

    Luckily, OpenCV does take care of this problem with this line of code:

    approximated_uint8_image = cv2.convertScaleAbs(approximated_original_shape_image)