Считайте пиксели разного цвета - Python - PullRequest
0 голосов
/ 26 мая 2018

Я нашел этот код здесь, но все, что он делает, считает черный и красный, и это будет работать только с черно-красным изображением.

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 голосов
/ 27 мая 2018

Ответ Пола более элегантный, но, в принципе, я думаю, что вы можете решить его, определив функцию, которая дает вам "расстояние" между любыми двумя цветами RGB примерно так:

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 , чтобы переназначить цвета в вашем новомизображение для тех, кто находится в вашем «эталонном» изображении, которое вы делаете так в командной строке:

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

, как показано в мой другой ответ здесь .Так что в Python вы можете сделать это с помощью вызова system() или с помощью модуля subprocess:

cmd="https://stackoverflow.com/a/38328879/2836621"
system(cmd)
0 голосов
/ 26 мая 2018

Вы должны будете определить свои цветовые группы.Я бы порекомендовал использовать 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, но вы можете использовать любое число, которое вам нравится (вы простонадо придумать имена для всех них).Черное и белое не работают хорошо, потому что мы смотрим на оттенки.Для захвата черного и белого также используйте «значение» и «насыщенность», то есть:

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 цвета - серый.Я обычно нахожу hsv более понятным, чем rgb.

0 голосов
/ 26 мая 2018

Вот подход, использующий 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, «Аква»: 0, «Аквамарин»: 0, «Лазурный»: 0, «Бежевый»: 27, «Бисквит»: 0, «Черный»: 88584, «Бланчедальмонд»: 0, «Синий»: 0,'blueviolet': 0, 'brown': 0, 'burlywood': 76, 'cadetblue': 0, 'chartreuse': 0, 'chocolate': 0, 'коралл': 0, 'cornflowerblue': 0, 'cornsilk': 0,' малиновый ': 0,' голубой ': 0,' darkblue ': 0,' darkcyan ': 0,' darkgoldenrod ': 0,' darkgray ': 0,' darkgreen ': 4148,' darkgrey ':71985, 'darkkhaki': 32907, 'darkmagenta': 0, 'darkolivegreen': 90899, 'darkorange': 0, 'darkorchid': 0, 'darkred': 0, 'darksalmon': 0, 'darkseagreen': 30171,'darkslateblue': 134, 'darkslategray': 108608, 'darkslategrey': 0, 'darkturquoise': 0, 'darkviolet': 0, 'deeppink': 0, 'deepskyblue': 0, 'dimgray': 0, 'dimgrey': 108318,' dodgerblue ': 0,' firebrick ': 0,' floralwhite ': 0,' forestgreen ': 1,' fuchsia ': 0,' gainsboro': 10438, «призрачный белый»: 736, «золотой»: 0, «золотой стержень»: 0, «серый»: 0, «зеленый»: 0, «зеленый желто»: 0, «серый»: 79835, «медовая роса»:0, «hotpink»: 0, «indianred»: 0, «индиго»: 0, «слоновая кость»: 0, «хаки»: 1056, «лаванда»: 4650, «lavenderblush»: 46, «lawngreen»: 0,«лимончифон»: 0, «голубой»: 3, «светлый»: 0, «светлый»: 0, «светло-золотой»: 0, «светло-серый»: 11905, «светло-зеленый»: 2323, «светло-серый»: 0, «лайтпинк»': 0,' lightsalmon ': 0,' lightseagreen ': 0,' lightskyblue ': 0,' lightslategray ': 0,' lightslategrey ': 31920,' lightsteelblue ': 3590,' lightyellow ': 0,' lime ':0, «салатовый»: 0, «льняной»: 46, «пурпурный»: 0, «темно-бордовый»: 0, «медиумаквамарин»: 0, «медиумблю»: 0, «средний орхидея»: 0, «медиумурпуль»: 15,'mediumseagreen': 0, 'mediumslateblue': 0, 'mediumspringgreen': 0, 'mediumturquoise': 0, 'mediumvioletred': 0, 'midnightblue': 54, 'mintcream': 0, 'mistyrose': 19, 'moccasin': 0,' navajowhite ': 0,' navy ': 0,' oldlace ': 0,' olive ': 0,' olivedrab ': 30828,' orange ': 0,' orangered ': 0,' orchid': 0,' palegoldenrod ': 1499,' palegreen ': 285,' paleturquoise ': 0,' palevioletred ': 0,' papayawhip ': 0,' peachpuff ': 0,' peru ': 21,' pink ':0, «слива»: 0, «пудрово-голубой»: 0, «фиолетовый»: 0, «rebeccapurple»: 0, «красный»: 0, «rosybrown»: 2831, «royalblue»: 0, «saddlebrown»: 0,'salmon': 0, 'sandybrown': 0, 'seagreen': 0, 'seashell': 0, 'sienna': 5, 'silver': 35951, 'skyblue': 0, 'slateblue': 0, 'slategray': 7836,' slategrey ': 0,' snow ': 18,' springgreen ': 0,' steelblue ': 0,' tan ': 3925,' teal ': 0,' thistle ': 10274,' tomato ':0, «бирюзовый»: 0, «фиолетовый»: 0, «пшеница»: 21, «белый»: 3, «белый дым»: 834, «желтый»: 0, «желто-зеленый»: 9292, «нет совпадения»: 0}

Вывод только с основными цветами:

{'red': 0, 'green': 403561, 'blue': 3262, 'black': 153782, 'yellow': 225827,'no match': 0}

Исходное изображение:

enter image description here

Версия с уменьшенным цветом:

enter image description here

Версия базового цвета:

enter image description here

0 голосов
/ 26 мая 2018

Если он выполняет только красный и черный, вы можете просто проверить, является ли значение красного меньше или равным 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
...