计算不同颜色的像素 - Python

时间:2018-05-26 17:07:54

标签: python image python-imaging-library pillow

我在这里找到了这个代码,但它只是计算黑色和红色,这只适用于黑色和红色图像。

from PIL import Image
im = Image.open('oh.png')

black = 0
red = 0

for pixel in im.getdata():
    if pixel == (0, 0, 0, 255): # if your image is RGB (if RGBA, (0, 0, 0, 255) or so
        black += 1
    else:
        red += 1
print('black=' + str(black)+', red='+str(red))

我如何能够检查不同的颜色而不是如此精确,例如黑色可以是(0,0,0)到(40,40,40)。

这可能太多了,请让我知道。 谢谢:))

4 个答案:

答案 0 :(得分:1)

这是一种使用KDTree进行有效最近颜色查找的方法。请注意,虽然KDTrees可能非常先进,但使用它们实际上非常简单。

import numpy as np
from matplotlib import colors
from scipy.spatial import cKDTree as KDTree
from scipy.misc import face

REDUCED_COLOR_SPACE = True

# borrow a list of named colors from matplotlib
if REDUCED_COLOR_SPACE:
    use_colors = {k: colors.cnames[k] for k in ['red', 'green', 'blue', 'black', 'yellow', 'purple']}
else:
    use_colors = colors.cnames

# translate hexstring to RGB tuple
named_colors = {k: tuple(map(int, (v[1:3], v[3:5], v[5:7]), 3*(16,)))
                for k, v in use_colors.items()}
ncol = len(named_colors)

if REDUCED_COLOR_SPACE:
    ncol -= 1
    no_match = named_colors.pop('purple')
else:
    no_match = named_colors['purple']

# make an array containing the RGB values 
color_tuples = list(named_colors.values())
color_tuples.append(no_match)
color_tuples = np.array(color_tuples)

color_names = list(named_colors)
color_names.append('no match')

# get example picture
img = face()

# build tree
tree = KDTree(color_tuples[:-1])
# tolerance for color match `inf` means use best match no matter how
# bad it may be
tolerance = np.inf
# find closest color in tree for each pixel in picture
dist, idx = tree.query(img, distance_upper_bound=tolerance)
# count and reattach names
counts = dict(zip(color_names, np.bincount(idx.ravel(), None, ncol+1)))

print(counts)

import pylab

pylab.imshow(img)
pylab.savefig('orig.png')
pylab.clf()
pylab.imshow(color_tuples[idx])
pylab.savefig('minimal.png' if REDUCED_COLOR_SPACE else 'reduced.png')

使用完整的matplotlib命名颜色空间输出:

{' aliceblue':315,' antiquewhite':0,' aqua':0,'海蓝宝石':0,&# 39; azure':0,'米色':27,' bisque':0,' black':88584,' blanchedalmond' :0,'蓝':0,' blueviolet':0,'布朗':0,' burlywood':76,&#39 ; cadetblue':0,'黄绿色':0,'巧克力':0,'珊瑚':0,' cornflowerblue': 0,' cornsilk':0,' crimson':0,' cyan':0,' darkblue':0,' darkcyan':0,' darkgoldenrod':0,' darkgray':0,' darkgreen':4148,' darkgrey':71985 ,' darkkhaki':32907,' darkmagenta':0,' darkolivegreen':90899,' darkorange':0,' darkorchid& #39;:0,'黑暗':0,' darksalmon':0,' darkseagreen':30171,' darkslateblue':134, ' darkslategray':108608,' darkslategrey':0,' darkturquoise':0,' darkviolet':0, ' deeppink':0,' deepskyblue':0,' dimgray':0,' dimgrey':108318,' dodgerblue&# 39;:0,'耐火砖':0,' floralwhite':0,' forestgreen':1,' fuchsia':0,& #39; gainboro':10438,' ghostwhite':736,' gold':0,' goldenrod':0,' grey&#39 ;:0,'绿色':0,' greenyellow':0,' grey':79835,' honeydew':0,&# 39; hotpink':0,' indianred':0,' indigo':0,'象牙':0,' khaki' :1056,'薰衣草':4650,' lavenderblush':46,' lawngreen':0,' lemonchiffon':0,&#39 ;浅蓝色':3,' lightcoral':0,' lightcyan':0,' lightgoldenrodyellow':0,' lightgray': 11905,' lightgreen':2323,' lightgrey':0,' lightpink':0,' lightsalmon':0,' lightseagreen':0,' lightskyblue':0,' lightslategray':0,' lightslategrey':31920 ,' lightsteelblue':3590,' lightyellow':0,' lime':0,' limegreen':0,'亚麻& #39;:46,' magenta':0,' maroon':0,' mediumaquamarine':0,' mediumblue':0, ' mediumorchid':0,' mediumpurple':15,' mediumseagreen':0,' mediumslateblue':0,' mediumspringgreen&# 39;:0,' mediumturquoise':0,' mediumvioletred':0,' midnightblue':54,' mintcream':0,& #39; misyrose':19,' moccasin':0,' navajowhite':0,'海军':0,' oldlace&#39 ;:0,'橄榄':0,' olivedrab':30828,'橙':0,' orangered':0,&# 39;兰花':0,' palegoldenrod':1499,' palegreen':285,' paleturquoise':0,' palevioletred' :0,' papayawhip':0,' peachpuff':0,'秘鲁':21,'粉红色':0,&#39 ;李子':0,'粉蓝':0,'紫':0,' rebeccapurple': 0,' red':0,' rosybrown':2831,' royalblue':0,' saddlebrown':0,'鲑鱼':0,' sandybrown':0,' seagreen':0,'贝壳':0,' sienna':5 ,'银':35951,' skyblue':0,' slateblue':0,' slategray':7836,' slategrey& #39;:0,' snow&#39 ;: 18,' springgreen':0,' steelblue':0,' tan':3925, ' teal':0,'蓟':10274,'番茄':0,'绿松石':0,'紫&# 39;:0,'小麦':21,'白色':3,'白色':834,'黄色':0,& #39; yellowgreen':9292,' no match':0}

仅使用基本颜色输出:

{' red':0,' green':403561,' blue':3262,' black':153782,&# 39;黄色':225827,'不匹配':0}

原始图片:

enter image description here

减少颜色版本:

enter image description here

基本颜色版本:

enter image description here

答案 1 :(得分:0)

如果它只做红色&黑色,你可以检查红色值是否小于或等于40.

if pixel[0] <= 40:

修改

colors = {}

for pixel in im.getdata():
    r = pixel[0]
    g = pixel[1]
    b = pixel[2]

    color = ''
    brightness = ''
    avg = (r + g + b) / 3

    if avg < 40 then brightness = 'black'
    else if avg < 80 then brightness = 'dark'
    else if avg > 220 then brightness = 'white'
    else if avg > 150 then brightness = 'light'

    if avg / r > 0.9 then hue = 'red'
    else if avg / r > 0.8 and avg / g > 0.6 then hue = 'orange'
    else if avg / r > 0.7 and avg / g > 0.7 then hue = 'yellow'
    else if avg / g > 0.8 and avg / r > 0.6 then hue = 'lime'
    else if avg / g > 0.9 then hue = 'green'
    else if avg / g > 0.7 and avg / b > 0.7 then hue = 'cyan'
    else if avg / b > 0.9 then hue = 'blue'
    else if avg / b > 0.8 and avg / r > 0.6 then hue = 'indigo'
    else if avg / b > 0.7 and avg / r > 0.7 then hue = 'magenta'

    color = brightness + hue
    if color not in colors:
        colors[color] = 1
    else
        colors[color] = colors[color] + 1

答案 2 :(得分:0)

您必须定义颜色桶。我建议使用hsv色彩空间。

from PIL import Image
import colorsys
im = Image.open('download.png')

NUM_BUCKETS = 6 # Just for example
colour_counts = [0] * NUM_BUCKETS

for pixel in im.getdata():
    hue, saturation, value = colorsys.hsv_to_rgb(pixel[0], pixel[1], pixel[2])
    hue_bucket = hue * NUM_BUCKETS // 255 # Using python3 to get an int
    colour_counts[hue_bucket] += 1

colour_names = ["red", "yellow", "green", "cyan", "blue", "magenta"]
for name, count in [x for x in zip(colour_names, colour_counts)]:
    print("{n} = {c}".format(n=name, c=count))

因此,这只是将颜色空间划分为6,但您可以使用任何您喜欢的数字(您只需要考虑所有这些数字的名称)。黑人和白人不能很好地工作,因为我们正在看色调。要捕捉黑白,也要使用&#34;值&#34;和&#34;饱和&#34;,即:

for pixel in im.getdata():
        hue, saturation, value = colorsys.hsv_to_rgb(pixel[0], pixel[1], pixel[2])
        if value < 32: # It's very dark
            blacks += 1
        elif saturation < 32 and value > 224: # it's basically white
            whites += 1
        else: # if it fails both of those, we can call it a colour
            hue_bucket = hue * NUM_BUCKETS // 255 # Using python3 to get an int
            colour_counts[hue_bucket] += 1

黑色的特点是低value。白色具有高value和低saturation。低saturation颜色为灰色。我通常认为hsvrgb更容易理解。

答案 3 :(得分:0)

保罗的答案更优雅,但基本上我认为你可以通过定义一个函数来解决它,它可以在任何两种RGB颜色之间提供&#34;距离&#34; 像这样:

def distance(col1, col2):
    (r1,g1,b1) = col1
    (r2,g2,b2) = col2
    return (r1 - r2)**2 + (g1 - g2) ** 2 + (b1 - b2) **2

现在,您需要做的只是(伪代码):

load your pre-existing reference colours into a list
load your new image
for each pixel in new image
    # Calculate distance from this pixel to first one in reference list
    mindist=distance(this pixel, first pixel in reference colours)
    nearest=first pixel in reference colours
    # Now see if any other colour in reference list is closer
    for index=1 to number of colours in reference list
        d=distance(this pixel, reference list[index])
        if d < mindist:
           mindist=d
           nearest=reference list[index]
    end
    replace pixel with nearest one from reference list as determined above
end

我还在学习Python,所以我对上述内容的翻译可能不是最优的,但它确实有效!

#!/usr/local/bin/python3
from PIL import Image
import numpy as np

# Calculate distance in RGB space between two RGB pixels
def distance(col1, col2):
    r1,g1,b1 = col1
    r2,g2,b2 = col2
    return (r1 - r2)**2 + (g1 - g2) ** 2 + (b1 - b2) **2

# All colours in the image will be forced to nearest one in this list
refColours=(
      [[255,   0,   0],    # red
       [  0, 255,   0],    # green
       [  0,   0, 255],    # blue
       [255, 255,   0],    # yellow
       [  0, 255, 255],    # cyan
       [255,   0, 255],    # magenta
       [  0,   0,   0],    # black
       [255, 255, 255]])   # white

# Load your new image and note its width and height
im = Image.open('colorwheel.png')
imrgb = im.convert("RGB")
(w,h)=im.size[0],im.size[1]

# Make a buffer for our output pixels
px=np.zeros(w*h,dtype=np.uint8)
idx=0

for pixel in list(imrgb.getdata()):
   # Calculate distance from this pixel to first one in reference list
   mindist = distance([pixel[0],pixel[1],pixel[2]],refColours[0])
   nearest = 0
   # Now see if any other colour in reference list is closer
   for index in range(1,len(refColours)):
       d=distance([pixel[0],pixel[1],pixel[2]],refColours[index])
       if d < mindist:
          mindist=d
          nearest=index
   # Set output pixel to nearest
   px[idx]=nearest
   idx += 1

# Reshape our output pixels to match input image
px=px.reshape(w,h)
# Make output image from our pixels
outimg=Image.fromarray(px).convert('P')
# Put our palette of favourite colours into the output image
palette=[item for sublist in refColours for item in sublist]
outimg.putpalette(palette)
outimg.save("result.png")

所以,我从colorwheel.png开始:

enter image description here

并以此结束:

enter image description here

当然,像我在评论中建议的那样,更简单的解决方案是使用像 ImageMagick 这样的工具将新图像中的颜色重新映射到您的&#34;参考&#34;中的颜色。图像,你在命令行上这样做:

convert colorwheel.png +dither -remap colormap.png result.png

my other answer here所示。所以在Python中,您可以使用system()调用或使用subprocess模块执行此操作:

cmd="https://stackoverflow.com/a/38328879/2836621"
system(cmd)