0

试图弄清楚如何完成这项任务:我想根据亮度选择图像的像素,然后获取这些像素的 rgb 值。

我最初的想法是使用 OpenCV 在图像的灰度上制作直方图:

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

但我不知道如何确定直方图特定箱中的像素在图像中的位置?

或者,我找到了这个公式来获得亮度:

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

所以我想我可以用这个公式迭代图像中的任何像素,并抓住那些与我选择的亮度级别相匹配的像素?

有没有更好的方法在 Python 中实现这一点?

4

1 回答 1

2

First, while the coefficients are correct for sRGB or Rec709, to convert from color to Y...

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

...they require that the RGB channels are all linearized to remove any gamma encoding.

Second, these are the coefficients for Rec709 or sRGB, but other colorspaces require different coefficients.

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.

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

Conversion and tracking pixel values

Converting an sRGB pixel to luminance is straight forward:

  1. Parse the sRGB value into discrete RʹGʹBʹ values. We'll assume 8bit.
  2. Divide each individually by 255.0
  3. Remove the TRC (aka 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.
  4. Then apply coefficients and sum for Luminance Y.
    • (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:

# 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? Or stay in a 0.0 to 1.0 and define a range? 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?

So using the earlier example but with a ternary piecewise TRC method and adding a loop that appends an array for the found pixels:

          # 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 and 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.

于 2021-10-11T02:13:53.107 回答