Here is my code using Colour to do color calibration. It uses numpy float64 type but how can I convert back to the format that is compatible in openCV, ideally uint8 because Canny only works with uint8?
import colour
import numpy as np
import cv2
IMAGE = cv2.imread('/Users/kelsolaar/Downloads/EKcv1.jpeg')
IMAGE = cv2.cvtColor(IMAGE, cv2.COLOR_BGR2RGB)/255
# Reference values a likely non-linear 8-bit sRGB values.
# "colour.cctf_decoding" uses the sRGB EOTF by default.
REFERENCE_RGB = colour.cctf_decoding(
np.array(
[
[240, 0, 22],
[252, 222, 10],
[30, 187, 22],
[26, 0, 165],
]
)
/ 255
)
colour.plotting.plot_multi_colour_swatches(colour.cctf_encoding(REFERENCE_RGB))
# Measured test values, the image is not properly decoded as it has a very specific ICC profile.
TEST_RGB = np.array(
[
[0.578, 0.0, 0.144],
[0.895, 0.460, 0.0],
[0.0, 0.183, 0.074],
[0.067, 0.010, 0.070],
]
)
corrected = colour.colour_correction(IMAGE, REFERENCE_RGB, TEST_RGB)
colour.plotting.plot_image(
corrected
)
This is some ways I found on stackoverflow but the image in uint8 doesn't look like the corrected image
#Method 1 which works but not uint8.....
img = cv2.cvtColor(corrected.astype(np.float32), cv2.COLOR_RGB2BGR)
# When I convert to unint8, it doesn't look like the original corrected image
# Method 2
corrected *= 255
corrected = corrected.astype(np.uint8)
img = cv2.cvtColor(corrected, cv2.COLOR_RGB2BGR)
# Method 3
img = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8U)
img = img.astype(np.uint8)*255
CodePudding user response:
We use OpenCV in colour-checker-detection which uses colour-science under the hood. Here is our dedicated 8-bit conversion function pasted in its entirety:
def as_8_bit_BGR_image(image: ArrayLike) -> NDArray:
"""
Convert and encodes given linear float *RGB* image to 8-bit *BGR* with
*sRGB* reverse OETF.
Parameters
----------
image
Image to convert.
Returns
-------
:class:`numpy.ndarray`
Converted image.
Notes
-----
- In the eventuality where the image is already an integer array, the
conversion is by-passed.
Examples
--------
>>> from colour.algebra import random_triplet_generator
>>> prng = np.random.RandomState(4)
>>> image = list(random_triplet_generator(8, random_state=prng))
>>> image = np.reshape(image, [4, 2, 3])
>>> print(image)
[[[ 0.96702984 0.25298236 0.0089861 ]
[ 0.54723225 0.43479153 0.38657128]]
<BLANKLINE>
[[ 0.97268436 0.77938292 0.04416006]
[ 0.71481599 0.19768507 0.95665297]]
<BLANKLINE>
[[ 0.69772882 0.86299324 0.43614665]
[ 0.2160895 0.98340068 0.94897731]]
<BLANKLINE>
[[ 0.97627445 0.16384224 0.78630599]
[ 0.00623026 0.59733394 0.8662893 ]]]
>>> image = as_8_bit_BGR_image(image)
>>> image = as_8_bit_BGR_image(image)
>>> print(image)
[[[ 23 137 251]
[167 176 195]]
<BLANKLINE>
[[ 59 228 251]
[250 122 219]]
<BLANKLINE>
[[176 238 217]
[249 253 128]]
<BLANKLINE>
[[229 112 252]
[239 203 18]]]
>>> as_8_bit_BGR_image(image)
>>> as_8_bit_BGR_image(image)
array([[[ 23, 137, 251],
[167, 176, 195]],
<BLANKLINE>
[[ 59, 228, 251],
[250, 122, 219]],
<BLANKLINE>
[[176, 238, 217],
[249, 253, 128]],
<BLANKLINE>
[[229, 112, 252],
[239, 203, 18]]], dtype=uint8)
"""
image = np.asarray(image)[..., :3]
if image.dtype == np.uint8:
return image
return cv2.cvtColor(
cast(NDArray, cctf_encoding(image) * 255).astype(np.uint8),
cv2.COLOR_RGB2BGR,
)
Something worth noting is that in your code above, you apply the correction matrix on IMAGE
which is still non-linearly encoded. You should linearise it with the colour.cctf_decoding
definition before applying the correction then re-encode it for display with the colour.cctf_encoding
definition.