I\'m converting an image from RGB to HSV representation by using cv2.cvtColor
. But when converting the resulting image of np.float32
dtype to np.
The difference arises not because of a decrease of accuracy when converting to integers. Actually, the problem is that you expect the HSV to work equivalently to the RGB representation. But whereas all components in an RGB triple are between 0 and 1 when represented as a float32, this no longer holds true for HSV triples. For HSV the second and third component (namely S and V) are still between 0 and 1 but the first component, H(ue), is an angle between 0 and 360 (see the documentation of cv2.cvtColor).
This is problematic for both, your conversion as well as cv2.imshow()
which expects three components between 0 and 1 as well. While your conversion results in an overflow when you cast the dtype to np.uint8
after multiplying all values with 65535. After reading the documentation of cv2.imshow one might expect the same result for the internal conversion when calling cv2.imshow
but as imshow
interprets the passed array as an RGB image it does simply reduce all values that are bigger than 1 to 1.
If you manually do the same before your conversion, you will get the same image three times:
import cv2
import numpy as np
im = cv2.imread(r'C:\Users\310293649\Desktop\photo.png')
cv2.namedWindow('im', cv2.WINDOW_NORMAL)
cv2.imshow('im', im)
#Conversion from 8uint to float32 before cvtColor()
im = im.astype(np.float32) #Cast Image data type
im /= 255. #Scale value to float32 range 0-1
#Colour Space Conversion to HSV
im = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)
cv2.namedWindow('im1', cv2.WINDOW_NORMAL)
cv2.imshow('im1', im)
im[:, :, 0] = np.where(im[:, :, 0]>1.0, 1.0, im[:, :, 0])
im *= 65535 #Scale value to uint16 range 0-65535
im = im.astype(np.uint16) #Cast Image data type
cv2.namedWindow('im2', cv2.WINDOW_NORMAL)
cv2.imshow('im2', im)
#Conversion from uint16 to uint8
im = im*(255./65535) #Scale value to uint8 range 0-255
im = im.astype(np.uint8) #Cast Image data type
cv2.namedWindow('im3', cv2.WINDOW_NORMAL)
cv2.imshow('im3', im)
This will give the same image for np.float32
, np.uint16
, and np.uint8
:
(Funnily, cv2.imwrite
does not seem to do the same conversion, as one gets a different result for the np.float32
version.)