Numpy 8/16/32 bits image data type after cvtColor() conversion to HSV colorspace

后端 未结 1 2112
旧时难觅i
旧时难觅i 2021-01-20 23:17

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.

1条回答
  •  囚心锁ツ
    2021-01-20 23:51

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

    0 讨论(0)
提交回复
热议问题