简体   繁体   English

估计图像中绿色的百分比

[英]Estimating the percentage of green in an image

I'm trying to come up with an algorithm to give images a score for the amount of green that they contain by iterating through the pixels using PIL.我正在尝试提出一种算法,通过使用 PIL 遍历像素来为图像所包含的绿色量提供分数。 I have come up with a few different methods so far but they all seem flawed.到目前为止,我已经提出了几种不同的方法,但它们似乎都有缺陷。

The first one sums all of the values of g in rgb and divides it but the total of all 3 colours.第一个将 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

This method succeeds at ranking images by how green they are but an image composed of just rgb(100, 200, 100) for example would only score 50% despite being very green.这种方法成功地根据图像的绿色程度对图像进行了排序,但仅由 rgb(100, 200, 100) 组成的图像尽管非常绿色,但只能获得 50% 的分数。

The other method I have thought of is simply determining what percentage of pixels contain more green than red or blue.我想到的另一种方法是简单地确定包含比红色或蓝色更多的绿色像素的百分比。

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

The problem with this option is that colours like rgb(0, 1, 0) or rgb(244, 255, 244) would be counted as green.这个选项的问题是像 rgb(0, 1, 0) 或 rgb(244, 255, 244) 这样的颜色会被算作绿色。 I would ideally like some way to rank the "greenness" of a colour.理想情况下,我希望以某种方式对颜色的“绿色”进行排名。

I would be very grateful for any suggestions of algorithms which can give a better percentage of how green an image is.我将非常感谢任何算法建议,这些建议可以更好地说明图像的绿色程度。 Any suggestions on which of my current algorithms is better or how to improve them are also welcome.也欢迎任何关于我目前的算法更好或如何改进它们的建议。

One potential way is to look at the image in "Hue Saturation and Value" colourspace HSV colourspace .一种可能的方法是在“色相饱和度和值”色彩空间HSV 色彩空间中查看图像。 Then you can look at the Hue and see if it corresponds to the range of greens you want to identify.然后您可以查看色相,看看它是否与您要识别的绿色范围相对应。

On the linked HSV colour wheel, you can see Reds have a Hue of 0, Greens are 120 and Blues are 240. However, PIL wants to save those values in an unsigned 8-bit number with a range 0..255 rather than 0..360, so all the values are scaled by 255/360.在链接的 HSV 色轮上,您可以看到红色的色调为 0,绿色为 120,蓝色为 240。但是,PIL 希望将这些值保存在一个范围为 0..255 而不是 0 的无符号 8 位数字中..360,因此所有值都按 255/360 缩放。 So, in PIL, Reds come out around 0, Greens come out at around 85 and Blues come out at around 170.因此,在 PIL 中,红队的得分约为 0,绿队的得分约为 85,蓝队的得分约为 170。

So you could count all pixels that fall between 80..90 as green with the code below.因此,您可以使用以下代码将所有介于 80..90 之间的像素计数为绿色。 Note that it is generally a really bad idea to iterate over pixels in Python - it is dog slow - so I use Numpy.请注意,在 Python 中迭代像素通常是一个非常糟糕的主意 - 它很慢 - 所以我使用 Numpy。 If you don't want to use Numpy, just get the Hue channel like I do below and iterate over the pixels counting the ones in the range you want in regular Python:如果您不想使用 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)

If I run that on his image, I get 4%如果我在他的图像上运行它,我会得到 4%

在此处输入图片说明

Whereas with this image I get 31%而有了这张图片,我得到了 31%

在此处输入图片说明

You could extract and consider the Saturation too, if you wanted to only count highly saturated colours.如果您只想计算高度饱和的颜色,您也可以提取并考虑饱和度。

I had the exact same problem today.我今天遇到了完全相同的问题。 Here is it without using numpy.这是不使用numpy的。 Instead I use list comprehension,lambdas,zip.相反,我使用列表理解、lambdas、zip。 You have to convert RGB to HSL color space.您必须将 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)

Play around with the threshold(0.4=40%) and saturation level(50 vs 0-255)玩转阈值(0.4=40%)和饱和度(50 vs 0-255)

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

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