如何将Python色彩校准后的float64图像转为OpenCV兼容的uint8格式
正确将Colour库校正后的float64图像转为OpenCV兼容的uint8格式
问题根源
Colour库输出的corrected是线性RGB空间的float64数据,而OpenCV的uint8图像默认遵循sRGB的非线性伽马编码规则。直接缩放或归一化会跳过sRGB的颜色编码步骤,导致显示时颜色失真。
正确转换步骤
要保持校正后的图像外观一致,必须先将线性RGB转换为sRGB编码空间,再进行格式转换:
- 使用
colour.cctf_encoding()对校正后的线性RGB数据应用sRGB的EOTF(伽马编码),得到非线性的sRGB浮点数据 - 将编码后的sRGB值缩放到0-255范围,转换为uint8类型
- 转换为OpenCV所需的BGR格式
完整代码示例
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_RGB = colour.cctf_decoding( np.array( [ [240, 0, 22], [252, 222, 10], [30, 187, 22], [26, 0, 165], ] ) / 255 ) 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) # 正确的转换流程 # 1. 把线性RGB编码为sRGB非线性空间 srgb_corrected = colour.cctf_encoding(corrected) # 2. 缩放并转换为uint8 srgb_corrected_uint8 = (srgb_corrected * 255).astype(np.uint8) # 3. 转为OpenCV的BGR格式 cv2_img = cv2.cvtColor(srgb_corrected_uint8, cv2.COLOR_RGB2BGR) # 现在可以正常用于Canny边缘检测 edges = cv2.Canny(cv2_img, 100, 200) cv2.imshow('Corrected Image', cv2_img) cv2.imshow('Edges', edges) cv2.waitKey(0) cv2.destroyAllWindows()
错误方法分析
- 方法2错误:直接对线性RGB乘255转uint8,没有做伽马编码。OpenCV显示uint8图像时会默认按sRGB伽马曲线解码,相当于对线性数据额外做了一次伽马校正,导致图像整体偏暗、颜色失真。
- 方法3错误:
cv2.normalize会强制把图像的像素值范围拉伸到0-255,破坏了色彩校准后的绝对颜色值,导致颜色偏离预期。
内容的提问来源于stack exchange,提问作者user16971617
相关产品推荐
相关产品推荐

