【问题标题】:Estimating the percentage of green in an image估计图像中绿色的百分比
【发布时间】:2021-04-20 19:32:15
【问题描述】:

我正在尝试提出一种算法,通过使用 PIL 遍历像素,为图像中包含的绿色量打分。到目前为止,我已经提出了几种不同的方法,但它们似乎都有缺陷。

第一个将 rgb 中 g 的所有值相加,然后除以所有 3 种颜色的总和。

def percent_green(img_file):
    red = 0
    green = 0
    blue = 0

    img = Image.open(img_file)
    pixels = img.load()
    width, height = img.size
    for x in range(width):
        for y in range(height):
            rgb = pixels[x, y]
            red += rgb[0]
            green += rgb[1]
            blue += rgb[2]

    percent = green / (red + blue + green)
    return percent * 100

此方法成功地根据图像的绿色程度对图像进行排名,但例如仅由 rgb(100, 200, 100) 组成的图像尽管非常绿色,但只能得分 50%。

我想到的另一种方法是简单地确定多少百分比的像素包含的绿色多于红色或蓝色。

def percent_green(img_file):
    img = Image.open(img_file)
    pixels = img.load()
    width, height = img.size
    total_green = 0
    for x in range(width):
        for y in range(height):
            rgb = pixels[x, y]
            if rgb[1] > rgb[0] and rgb[1] > rgb[2]: #if green predominant colour
                total_green += 1


    percent = total_green /(width * height)
    return percent * 100

这个选项的问题是像 rgb(0, 1, 0) 或 rgb(244, 255, 244) 这样的颜色会被视为绿色。理想情况下,我希望通过某种方式对颜色的“绿色”进行排名。

我将非常感谢任何可以提供更好百分比的图像绿色百分比的算法建议。也欢迎任何关于我当前的算法更好或如何改进它们的建议。

【问题讨论】:

  • 一种颜色的“绿色”可以由g / (r + b)之类的东西确定;假设其他两种原色中的更多使颜色看起来不那么绿色。然后只需确定一些阈值来决定一种颜色是否足够绿。
  • “理想情况下,我希望通过某种方式对颜色的“绿色”进行排名。”这实际上是一个颜色理论问题,而不是编程问题。您可能想从这里开始:en.wikipedia.org/wiki/Colorimetry

标签: python image-processing python-imaging-library


【解决方案1】:

一种可能的方法是在 “色相饱和度和值” 色彩空间 HSV colourspace 中查看图像。然后您可以查看色调,看看它是否对应于您要识别的绿色范围。

在链接的 HSV 色轮上,您可以看到红色的色调为 0,绿色为 120,蓝色为 240。但是,PIL 想要将这些值保存在一个范围为 0..255 的无符号 8 位数字中而不是 0..360,因此所有值都按 255/360 缩放。因此,在 PIL 中,红色大约 0,绿色大约 85,蓝色大约 170。

因此,您可以使用以下代码将所有介于 80..90 之间的像素计算为绿色。请注意,在 Python 中迭代像素通常是一个非常糟糕的主意——它很慢——所以我使用 Numpy。如果您不想使用 Numpy,只需像我在下面那样获取 Hue 通道,然后在常规 Python 中迭代计算您想要的范围内的像素:

from PIL import Image
import numpy as np

# Load image and convert to HSV
im = Image.open('bp-1.jpg').convert('HSV')

# Extract Hue channel and make Numpy array for fast processing
Hue = np.array(im.getchannel('H'))

# Make mask of zeroes in which we will set greens to 1
mask = np.zeros_like(Hue, dtype=np.uint8) 

# Set all green pixels to 1
mask[(Hue>80) & (Hue<90)] = 1 

# Now print percentage of green pixels
print((mask.mean()*100)

如果我在他的图像上运行,我得到 4%

而这张图片我得到 31%

如果您只想计算高度饱和的颜色,您也可以提取并考虑饱和度。

【讨论】:

  • @dnobl mask[] 是一个与原始图像大小相同的数组。原始图像中所有为绿色的像素在mask[] 中为1,所有其他像素为零。因此,如果原始图像中的每个像素mask.mean() 将是1。如果原始图像没有绿色像素,则为零。如果一半像素为绿色,则为 0.5。
  • 那么,如果 50% 的像素是绿色的,并且图像的大小为 1M 像素,那么您计算的百分比为(mask.mean() * mask.size) / 100 = (0.5*1M)/100 = 5000?我错过了什么?无论如何,感谢您的详细回复:)
  • @PabloEM 嗯...我想应该是简单的mask.mean() * 100
  • 是的,我想是的!
【解决方案2】:

我今天遇到了完全相同的问题。这是不使用numpy的。相反,我使用列表理解、lambdas、zip。您必须将 RGB 转换为 HSL 颜色空间。

#call it
print(
   is_img_hue_green(
     Image.open(img_file_path)
   )
)

def is_img_hue_green(pil_img):
    #if greater than threshold of 18%
    #green 120 +- 60; values from pillow 0-255
    minvalue = int(60 * 0.708333333)
    maxvalue = int(180 * 0.708333333)
    if img_return_threshold_hsv(pil_img, minvalue,maxvalue) > 0.40 :
        return True
    else:
        return False

def img_return_threshold_hsv(pil_img, min_hue, max_hue):
    hue_band_iterable = list(pil_img.convert( 'HSV' ).getdata(0)) #convert getdata to list
    sat_band_iterable = list(pil_img.convert( 'HSV' ).getdata(1))

    #fill all with 1s, if all 1s Bitwise AND returns 1; if any 0=0
    bitlist = [1 for i in range( pil_img.width * pil_img.height )] #fill with 1s
    func_hue = lambda hue : 1 if hue >= min_hue and hue <= max_hue else 0
    func_sat = lambda sat : 1 if sat >= 50 else 0
    green_mask_h = [func_hue(hue)  for hue in hue_band_iterable ] #1 if True
    green_mask_s = [func_sat(sat) for sat in sat_band_iterable ]

    bitlist = [x & y & z for x, y, z in zip(bitlist, green_mask_h, green_mask_s)]
    #zip returns a tuple (x,y,z) of elements side by side, if all 1 return 1
    return sum(bitlist) / (pil_img.width * pil_img.height)

调整阈值(0.4=40%)和饱和度(50 vs 0-255)

【讨论】:

    猜你喜欢
    • 2023-04-08
    • 2019-03-14
    • 1970-01-01
    • 2014-02-23
    • 2021-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多