简体   繁体   English

在 Python 中根据亮度获取像素的 RGB 值

[英]Getting RGB Values of Pixels Based on Luminance in Python

Trying to figure out how to accomplish this task: I'd want to select pixels of an image based on luminance, and then grab the rgb values of those pixels.试图弄清楚如何完成这项任务:我想 select 基于亮度的图像像素,然后获取这些像素的 rgb 值。

My initial thought was to use OpenCV to make a histogram on the greyscale of the image:我最初的想法是使用 OpenCV 在图像的灰度上制作直方图:

img = cv2.imread('test.jpg',0)
hist = cv2.calcHist([img],[0],None,[256],[0,256])

but I wasn't sure how to then identify where those pixels in a particular bin of my histogram are in the image?但我不知道如何确定直方图特定箱中的像素在图像中的位置?

Alternatively I found this formula to get luminance:或者,我找到了这个公式来获得亮度:

(0.2126*R + 0.7152*G + 0.0722*B)

So I guess I could iterate over ever pixel in the image with that formula and grab the ones that match my chosen luminance level?所以我想我可以用这个公式迭代图像中的任何像素,并抓住那些与我选择的亮度级别相匹配的像素?

Is there a better way to accomplish this in Python?在 Python 中是否有更好的方法来实现这一点?

First, while the coefficients are correct for sRGB or Rec709, to convert from color to Y...首先,虽然系数对于 sRGB 或 Rec709 是正确的,但要从颜色转换为 Y...

    (0.2126*R + 0.7152*G + 0.0722*B)

...they require that the RGB channels are all linearized to remove any gamma encoding. ...他们要求 RGB 通道全部线性化以消除任何伽马编码。

Second, these are the coefficients for Rec709 or sRGB, but other colorspaces require different coefficients.其次,这些是 Rec709 或 sRGB 的系数,但其他色彩空间需要不同的系数。

A Library图书馆

I recommend KenSolaar's ColourScience, a python library that can do things like convert to a luminance, and uses numpy and vectorized math.我推荐 KenSolaar 的 ColourScience,这是一个 python 库,可以执行转换为亮度等操作,并使用 numpy 和矢量化数学。

https://github.com/colour-science/colour https://github.com/colour-science/colour

Conversion and tracking pixel values转换和跟踪像素值

Converting an sRGB pixel to luminance is straight forward:将 sRGB 像素转换为亮度很简单:

  1. Parse the sRGB value into discrete RʹGʹBʹ values.将 sRGB 值解析为离散的 RʹGʹBʹ 值。 We'll assume 8bit.我们假设8位。
  2. Divide each individually by 255.0分别除以 255.0
  3. Remove the TRC (aka gamma).移除 TRC(又名 gamma)。
    • The simple way for sRGB and several other colorspaces is to apply a power curve to each RʹGʹBʹ channel using an exponent of ^2.2. sRGB 和其他几个色彩空间的简单方法是使用 ^2.2 的指数对每个 RʹGʹBʹ 通道应用功率曲线。
  4. Then apply coefficients and sum for Luminance Y.然后对亮度 Y 应用系数和总和。
    • (0.2126 * R + 0.7152 * G + 0.0722 * B) (0.2126 * R + 0.7152 * G + 0.0722 * B)

Putting all that together:把所有这些放在一起:

    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 

That's the simplest while still being reasonably accurate, however some purists might suggest using the IEC specified sRGB TRC, which is piecewise and computationally more expensive:这是最简单的,但仍然相当准确,但是一些纯粹主义者可能会建议使用 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

Y Not?为什么不呢?

The next question was, how to determine the pixels, and that's just creating and populating a list (array) with the coordinates and color value for pixels that match the luminance.下一个问题是,如何确定像素,这只是创建和填充一个列表(数组),其中包含与亮度匹配的像素的坐标和颜色值。

Do you want to quantize back to 8 bit integer values for the luminance?您想将亮度量化回 8 位 integer 值吗? Or stay in a 0.0 to 1.0 and define a range?还是停留在 0.0 到 1.0 并定义一个范围? The later is usually most useful, so let's do that.后者通常是最有用的,所以让我们这样做。

For cv2.imread('test.jpg',1) don't set the flag to 0 — you're going to make your own greyscale and you want to save the color pixel values, correct?对于cv2.imread('test.jpg',1)不要将标志设置为 0 - 你要制作自己的灰度并且要保存颜色像素值,对吗?

So using the earlier example but with a ternary piecewise TRC method and adding a loop that appends an array for the found pixels:因此,使用前面的示例,但使用三元分段 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.

There's very likely a way to vectorize this, so worth it to look at the colour-science library I linked above as it does so where possible.很可能有一种方法可以对其进行矢量化,因此值得查看我上面链接的颜色科学库,因为它尽可能这样做。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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