Найти ближайший цвет RGB для каждого пикселя в изображении - PullRequest
0 голосов
/ 31 января 2020

Прежде всего: я начинающий программист. У меня есть массив NumPy с данными RGB для каждого пикселя.

im = np.asarray(Image.open('image.jpg'))

Я передаю каждый пиксель своей функции getNearestColor. Out также является массивом numpy.

for x in range(len(im)):
    for y in range(len(im[x])):
        for _ in range(len(im[x][y])):
            out[x][y] = getNearestColor(im[x][y])

Затем я вычисляю расстояние в системе 3d RGB.

def getNearestColor(rgb):
    a = []
    for i in range(len(rgbValues)):
        d = ((rgbValues[i][0]-rgb[0])*0.3)**2 + ((rgbValues[i][1]-rgb[1])*0.59)**2 + ((rgbValues[i][2]-rgb[2])*0.11)**2
        a.append(d)
    list.sort(a)
    return a[0]

rgbValues ​​- это список с 22 значениями RGB, к которым нужно сравнивать. ЭТО МЕДЛЕННО. Также это только возвращает мне расстояние (d). Это должно вернуть мне значение RGB. Как я могу вернуть ближайшее значение RGB и сделать его намного быстрее. Надеюсь все было понятно :)

1 Ответ

1 голос
/ 31 января 2020

Ваша (исправленная) функция:

def findNearest(rgb):
    a = []
    for i in range(len(rgbValues)):
        d = ((rgbValues[i][0]-rgb[0])*0.3)**2 + ((rgbValues[i][1]-rgb[1])*0.59)**2 + ((rgbValues[i][2]-rgb[2])*0.11)**2
        a.append([d,i])
    list.sort(a)
    return rgbValues[a[0][1]]

Возвращает правильный rgbValues; теперь это возможно, потому что его индекс также сохраняется в a. Это - по общепринятым временным рамкам - обрабатывает около 27,085 пикселей в секунду.

Простая реализация, настроенная на запоминание только ближайшего индекса:

def findNearest(rgb):
    dist = ((rgbValues[0][0]-rgb[0])*0.3)**2 + ((rgbValues[0][1]-rgb[1])*0.59)**2 + ((rgbValues[0][2]-rgb[2])*0.11)**2
    index = 0
    for i in range(1,len(rgbValues)):
        d = ((rgbValues[i][0]-rgb[0])*0.3)**2 + ((rgbValues[i][1]-rgb[1])*0.59)**2 + ((rgbValues[i][2]-rgb[2])*0.11)**2
        if d < dist:
            dist = d
            index = i
    return rgbValues[index]

уже работает намного лучше: 37,175 пикселей в секунду улучшение скорости на 37%. Можем ли мы добиться большего успеха с более подходом Pythoni c?

def findNearest(rgb):
    dist = [(((rgbValues[i][0]-rgb[0])*0.3)**2 + ((rgbValues[i][1]-rgb[1])*0.59)**2 + ((rgbValues[i][2]-rgb[2])*0.11)**2,i) for i in range(22)]
    return rgbValues[min(dist)[1]]

Нет. С тем же изображением и тем же механизмом синхронизации оно уменьшается до 33 417 пикселей / сек c.


Завершите тестовую программу, используя случайное изображение из предыдущего вопроса (для загрузки используется доступ PIL, доступ пикселей и отображают изображение, но это не относится к расчетам расстояний):

import random
from PIL import Image
from time import time

def findNearest_org(rgb):
    a = []
    for i in range(len(rgbValues)):
        d = ((rgbValues[i][0]-rgb[0])*0.3)**2 + ((rgbValues[i][1]-rgb[1])*0.59)**2 + ((rgbValues[i][2]-rgb[2])*0.11)**2
        a.append([d,i])
    list.sort(a)
    return rgbValues[a[0][1]]

def findNearest_raw(rgb):
    dist = ((rgbValues[0][0]-rgb[0])*0.3)**2 + ((rgbValues[0][1]-rgb[1])*0.59)**2 + ((rgbValues[0][2]-rgb[2])*0.11)**2
    index = 0
    for i in range(1,len(rgbValues)):
        d = ((rgbValues[i][0]-rgb[0])*0.3)**2 + ((rgbValues[i][1]-rgb[1])*0.59)**2 + ((rgbValues[i][2]-rgb[2])*0.11)**2
        if d < dist:
            dist = d
            index = i
    return rgbValues[index]

def findNearest_list(rgb):
    dist = [(((rgbValues[i][0]-rgb[0])*0.3)**2 + ((rgbValues[i][1]-rgb[1])*0.59)**2 + ((rgbValues[i][2]-rgb[2])*0.11)**2,i) for i in range(22)]
    return rgbValues[min(dist)[1]]

image = Image.open('output-2.png')
pixels = image.load()
width, height = image.size

rgbValues = [tuple(random.randrange(0,256) for _ in range(3)) for _ in range(22)]

start = time()
for y in range(height):
    for x in range(width):
        # fetch the rgb value
        color = pixels[x,y]
        # replace with nearest
        pixels[x,y] = findNearest_list (color)
print ('pixels/sec:', (width*height)/(time()-start))

image.show()

и тестовые изображения до и после:

test image before

test image after

Если вас интересуют только результаты, используйте любой родной метод, который позволяет ваша библиотека изображений. Этот короткий фрагмент, использующий собственные PIL quantize

rgbValues = list(sum(rgbValues, ()))*12
rgbValues = rgbValues[:768]
palimage = Image.new('P', (width, height))
palimage.putpalette(rgbValues)
newimage = image.quantize(palette=palimage)

, переносит вычисления в собственный код, и результаты выглядят ошеломительно лучше: 18 443 414 пикселей / сек c - колоссальное * В 1038 * 500 раз быстрее , чем моя нативная (/ naive) реализация.
(Hyper-fancy touple-to-list происходит из { ссылка })

...