首先,虽然系数对于 sRGB 或 Rec709 是正确的,但要从颜色转换为 Y...
(0.2126*R + 0.7152*G + 0.0722*B)
...他们要求 RGB 通道全部线性化以移除任何伽马编码。
其次,这些是 Rec709 或 sRGB 的系数,但其他色彩空间需要不同的系数。
图书馆
我推荐 KenSolaar 的 ColourScience,这是一个 python 库,可以执行转换为亮度等操作,并使用 numpy 和矢量化数学。
https://github.com/colour-science/colour
转换和跟踪像素值
将 sRGB 像素转换为亮度非常简单:
- 将 sRGB 值解析为离散的 RʹGʹBʹ 值。我们假设是 8 位。
- 分别除以 255.0
- 移除 TRC(又名伽玛)。
- sRGB 和其他几个色彩空间的简单方法是使用 ^2.2 的指数将功率曲线应用于每个 RʹGʹBʹ 通道。
- 然后对亮度 Y 应用系数和总和。
- (0.2126 * R + 0.7152 * G + 0.0722 * B)
将所有这些放在一起:
imgPixel = 0xAACCFF
R = (imgPixel & 0xFF0000) >> 16
G = (imgPixel & 0x00FF00) >> 8
B = (imgPixel & 0x0000FF)
Y = 0.2126*(R/255.0)**2.2 + 0.7152*(G/255.0)**2.2 + 0.0722*(B/255.0)**2.2
这是最简单的,但仍然相当准确,但是一些纯粹主义者可能会建议使用 IEC 指定的 sRGB TRC,它是分段且计算成本更高的:
# Piecewise sRGB TRC to Linear (only red is shown in this example)
if R <= 0.04045:
R / 12.92
else:
(( R + 0.055) / 1.055) ** 2.4
是吗?
下一个问题是,如何确定像素,这只是创建并填充一个列表(数组),其中包含与亮度匹配的像素的坐标和颜色值。
您想将亮度量化回 8 位整数值吗?还是停留在 0.0 到 1.0 并定义一个范围?后者通常最有用,所以让我们这样做。
对于cv2.imread('test.jpg',1),不要将标志设置为 0 — 您将制作自己的灰度并且想要保存颜色像素值,对吗?
因此使用前面的示例,但使用三元分段 TRC 方法并添加一个循环,为找到的像素附加一个数组:
# declare some variables
Llo = 0.18 # Lo luminance range
Lhi = 0.20 # Hi range choosing pixels between here and Lo
results = [[]]
imgPixel = 0x000000
img = cv2.imread('test.jpg',1) # set flag to 1 (or omit) for color — you're going to make your own greyscale.
rows,cols = img.shape
for ir in range(rows):
for ic in range(cols):
imgPixel = img[ir,ic]
R = ((imgPixel & 0xFF0000) >> 16) / 255.0
G = ((imgPixel & 0x00FF00) >> 8 ) / 255.0
B = ((imgPixel & 0x0000FF) ) / 255.0
R = R / 12.92 if R <= 0.04045 else (( R + 0.055) / 1.055) ** 2.4
G = G / 12.92 if G <= 0.04045 else (( G + 0.055) / 1.055) ** 2.4
B = B / 12.92 if B <= 0.04045 else (( B + 0.055) / 1.055) ** 2.4
Y = 0.2126 * R + 0.7152 * G + 0.0722 * B
# If the Y is in range, then append the pixel coordinates and color value to the array
if Y>Llo or Y<Lhi: results.append([ ic, ir, imgPixel ])
# CAVEAT: This code is entered but not tested in Python.
很可能有一种方法可以将其矢量化,因此值得查看我上面链接的颜色科学库,因为它尽可能这样做。