-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
color.rgb2ycbcr and color.ycbcr2rgb are not mutually inverse #5972
Comments
I suspect there is a bug in ycbcr2rgb. The first thing the function does is subtract 16 or 128 and then it does the conversion which depends on the dtype. If one passes uint8 as input, the initial subtraction is nonsense. If one passes float ranged to 0-1 it is also a nonsense. If one passes float ranged to 255 the initial subtraction works but then the conversion treats the input as 0-1 ranged float which it isn't. Or I may be wrong and don't understand what's going on but someone more knowledgeable please look into it:-) |
Well, most import numpy as np
from skimage import img_as_float
from skimage import color
### First create test data
# Create a uint8 image
rgb_u8 = np.round(np.random.rand(10, 10, 3) * 255).astype('uint8')
# Convert it to float
rgb = img_as_float(rgb_u8) # This image is the target of the loop RGB -> YCbCr -> RGB
### Perform RGB -> YCbCr -> RGB loop
# Convert the both images to YCbCr
ybr_u8 = color.rgb2ycbcr(rgb_u8)
ybr = color.rgb2ycbcr(rgb)
# Convert back both images to RGB
rgb2_u8 = color.ycbcr2rgb(ybr_u8)
rgb2 = color.ycbcr2rgb(ybr)
### Validate the loop
assert np.allclose(rgb, rgb2)
assert np.allclose(rgb, rgb2_u8) In your example print(np.max(np.abs(rgb - skimage.img_as_float(rgb2)))) |
Dear @hookxs, Thanks for reaching out! I just checked and functions
Please try running: import matplotlib.pyplot as plt
import numpy as np
from skimage import color, data, exposure
img = data.colorwheel()
img.dtype # dtype('uint8')
img.max() # 255
ycc = color.rgb2ycbcr(img)
ycc.dtype # dtype('float64')
ycc.min() # 16.0
ycc.max() # 240.0
rgb = color.ycbcr2rgb(ycc)
rgb.dtype # dtype('float64') in range 0 to 1
img_rescaled = exposure.rescale_intensity(img, out_range='float')
np.testing.assert_array_almost_equal(rgb, img_rescaled) With or witout rescaling, both Hope this helps! |
If you don't mind @hookxs, I will convert your issue to discussion 😉 |
comments moved back from the deleted Discussion
|
Description
The colorspace conversion functions
color.rgb2ycbcr
andcolor.ycbcr2rgb
are not mutually inverse. Maybe there is some assumption of the data type and/or input range which is not mentioned in the docs, I don't know. The rgb2ycbcr seems to work fine for both 0-255 uint8 images as well as 0-1 float images, the inverse ycbcr2rgb does not seem to work for either uint8 or float.Way to reproduce
The text was updated successfully, but these errors were encountered: