Python 估计图像中绿色的百分比

Python 估计图像中绿色的百分比,python,image-processing,python-imaging-library,Python,Image Processing,Python Imaging Library,我试图提出一种算法,通过使用PIL对像素进行迭代,为图像包含的绿色量打分。到目前为止,我提出了几种不同的方法,但它们似乎都有缺陷 第一种方法将rgb中g的所有值相加并将其除,但不包括所有3种颜色的总和 def%绿色(img\u文件): 红色=0 绿色=0 蓝色=0 img=Image.open(img\u文件) 像素=img.load() 宽度、高度=img.size 对于范围内的x(宽度): 对于范围内的y(高度): rgb=像素[x,y] 红色+=rgb[0] 绿色+=rgb[1] 蓝色+=

我试图提出一种算法,通过使用PIL对像素进行迭代,为图像包含的绿色量打分。到目前为止,我提出了几种不同的方法,但它们似乎都有缺陷

第一种方法将rgb中g的所有值相加并将其除,但不包括所有3种颜色的总和

def%绿色(img\u文件):
红色=0
绿色=0
蓝色=0
img=Image.open(img\u文件)
像素=img.load()
宽度、高度=img.size
对于范围内的x(宽度):
对于范围内的y(高度):
rgb=像素[x,y]
红色+=rgb[0]
绿色+=rgb[1]
蓝色+=rgb[2]
百分比=绿色/(红色+蓝色+绿色)
收益率*100
该方法成功地根据图像的绿色程度对图像进行排序,但例如,仅由rgb(100200100)组成的图像即使非常绿色,也只能获得50%的分数

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

def%绿色(img\u文件):
img=Image.open(img\u文件)
像素=img.load()
宽度、高度=img.size
总绿色=0
对于范围内的x(宽度):
对于范围内的y(高度):
rgb=像素[x,y]
如果rgb[1]>rgb[0]和rgb[1]>rgb[2]:#如果绿色为主色
总绿色+=1
百分比=总绿色/(宽度*高度)
收益率*100

此选项的问题在于,rgb(0,1,0)或rgb(24425244)等颜色将被计为绿色。理想情况下,我想用某种方法对一种颜色的“绿色度”进行排名


我将非常感谢任何算法的建议,这些算法可以更好地反映图像的绿色程度。欢迎就我当前的算法中的哪一种更好或如何改进它们提出任何建议。

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

在链接的HSV色轮上,您可以看到红色的色调为0,绿色为120,蓝色为240。但是,PIL希望将这些值保存在范围为0..255而不是0..360的无符号8位数字中,因此所有值都按255/360进行缩放。所以,在皮尔,红色在0分左右,绿色在85分左右,蓝色在170分左右

因此,您可以使用下面的代码将介于80到90之间的所有像素计算为绿色。请注意,在Python中对像素进行迭代通常是一个非常糟糕的主意——速度非常慢——因此我使用Numpy。如果您不想使用Numpy,只需像我下面所做的那样获取色调通道,并在像素上迭代,计算常规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)
从PIL导入图像
将numpy作为np导入
#加载图像并转换为HSV
im=Image.open('bp-1.jpg')。convert('HSV'))
#提取色调通道并制作Numpy阵列以实现快速处理
色调=np.array(im.getchannel('H'))
#制作零掩码,在其中我们将绿色设置为1
掩码=np.zeros_like(色调,dtype=np.uint8)
#将所有绿色像素设置为1

蒙版[(色调>80)&(色调我今天遇到了完全相同的问题。这里是不使用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)

#叫它
印刷品(
是绿色的吗(
Image.open(img\u文件\u路径)
)
)
def为色调绿色(pil):
#如果大于18%的阈值
#绿色120+-60;数值从0-255
最小值=整数(60*0.708333333)
maxvalue=int(180*0.708333333)
如果img\u返回\u阈值\u hsv(pil\u img,minvalue,maxvalue)>0.40:
返回真值
其他:
返回错误
def图像返回阈值hsv(图像、最小色调、最大色调):
hue_band_iterable=list(pil_img.convert('HSV').getdata(0))#将getdata转换为list
sat\u band\u iterable=list(pil\u img.convert('HSV').getdata(1))
#如果所有1都是按位的,则用1s填充all并返回1;如果有0=0
位列表=[1表示范围内的i(pil_img.width*pil_img.height)]#用1s填充
func_色调=lambda色调:如果色调>=最小色调且色调=50,则为1,否则为0
绿色遮罩(h)=[func(色调)表示色调带中的色调(色调)]#如果为真,则为1
绿色面罩=[sat波段sat的功能(sat)]
位列表=[x&y&z代表zip中的x、y、z(位列表、绿色掩码、绿色掩码)]
#如果所有1个元素都返回1,zip将并排返回元素的元组(x、y、z)
返回和(位列表)/(桩号宽度*桩号高度)

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

颜色的“绿色度”可以通过以下方式确定:
g/(r+b)
;假设其他两个原色中的更多原色使颜色看起来不那么绿。然后确定一些阈值,决定颜色是否足够绿。“理想情况下,我想用某种方法对颜色的“绿色”进行排序。”这实际上是一个颜色理论问题,而不是编程问题。您可能想从这里开始:@dnobl
mask[]
是一个与原始图像大小相同的数组。原始图像中的所有绿色像素都是
mask[]
中的
1
所有其他像素都是零。因此,如果原始图像中的每个像素
mask.mean()
将为
1
。如果原始图像没有绿色像素,则为零。如果一半像素为绿色,则为0.5。因此,如果50%的像素为绿色,且图像大小为1M像素,则计算百分比为
(mask.mean()*mask.size)/100=(0.5*1M)/100=5000
?我遗漏了什么?无论如何,谢谢你的详细回答:)@PabloEM Mmmm…我想应该是简单的
mask.mean()*100
是的,我想是的!