简体   繁体   中英

OpenCV 'cvtColor' changes color and saturation when executed multiple times (python)

I am using OpenCV's function cv2.cvtColor to modify an image in steps:

  • I convert the original BGR image to HSV color format.
  • I do some computation on HSV image.
  • I convert back the HSV image to BGR color format.

Eventually, the converstion BGR-to-HSV and HSV-to-BGR is not prefectly dual and some (random) pixels see variations in their H and S values.

Here what I mean:

import cv2
import numpy as np


# Load image
original_img = cv2.imread('img.png')
img = original_img.copy()


# Convert image multiple times
for ii in range(50):
    img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    img = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)

    print(f'\niter {ii+1}')
    print(f'H sum: {np.sum(img_hsv[:,:,0])}')
    print(f'S sum: {np.sum(img_hsv[:,:,1])}')
    print(f'V sum: {np.sum(img_hsv[:,:,2])}')


# Display images (resize for convenience)
cv2.imshow('original', cv2.resize(original_img, tuple([s*3 for s in img.shape[:2]])))
cv2.imshow('converted', cv2.resize(img, tuple([s*3 for s in img.shape[:2]])))

cv2.waitKey(0)
cv2.destroyAllWindows()

Original (left) vs converted (right):

原始图像 转换后的图像

As you may notice, there are a bunch of pixels that becomes reddish and with an increasing saturation. Also, H and S channels change as (sum of values):

iter 1
H sum: 862253
S sum: 1470471
V sum: 1028930

iter 2
H sum: 847617
S sum: 1511497
V sum: 1028930

...

iter 49
H sum: 796974
S sum: 1570406
V sum: 1028930

iter 50
H sum: 796974
S sum: 1570412
V sum: 1028930

Python 3.8.3 | OpenCV 4.5.1

Because the images are 8-bit, there is loss of data in each iteration. See convertion between HSV and RGB . For example, saturation is chroma (max - min) over maximum component. When it is converted to HSV, the saturation value will be quantized between 0 to 255. As a side note, the maximum hue value in OpenCV is 180.

Instead of using uchar , performing convertions with floating point images prevents the loss. I changed your code with .astype(np.float32) and the result is the same in each iteration.

H sum: 1739456.625
S sum: 5764.1796875
V sum: 1028930.0

Edited code:

import cv2
import numpy as np


# Load image
original_img = cv2.imread('img.png').astype(np.float32)
img = original_img.copy()


# Convert image multiple times
for ii in range(50):
    img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    img = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)

    print(f'\niter {ii+1}')
    print(f'H sum: {np.sum(img_hsv[:,:,0])}')
    print(f'S sum: {np.sum(img_hsv[:,:,1])}')
    print(f'V sum: {np.sum(img_hsv[:,:,2])}')


# Display images (resize for convenience)
cv2.imshow('original', cv2.resize(original_img, tuple([s*3 for s in img.shape[:2]])).astype(np.uint8))
cv2.imshow('converted', cv2.resize(img, tuple([s*3 for s in img.shape[:2]])).astype(np.uint8))

cv2.waitKey(0)
cv2.destroyAllWindows()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM