我正在尝试提出一种算法,通过使用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)之类的颜色将被视为绿色。理想情况下,我希望以某种方式对颜色的“绿色”进行排名。
对于算法的任何建议,我都将不胜感激,因为它可以给出更好的图像绿色程度百分比。也欢迎就我当前使用哪种算法更好或如何改进它们提出任何建议。
答案 0 :(得分:2)
一种可能的方法是使用“色相饱和度和值” 色彩空间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()*mask.size)/100)
如果在他的图像上运行,我将获得4%
与此图像相比,我得到31%
如果您只想计算高度饱和的颜色,也可以提取并考虑饱和度。
答案 1 :(得分:1)
我今天遇到了完全相同的问题。这是不使用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)