查找图像中每个像素最接近的RGB颜色

时间:2020-01-31 16:45:59

标签: python python-3.x numpy python-imaging-library

首先:我是一名编程初学者。 我有一个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 个答案:

答案 0 :(得分:1)

(已更正)您的功能是:

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%。我们可以使用更Python化的方法做得更好吗?

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像素/秒。


使用来自先前问题的随机图像(它使用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像素/秒-比本机(/天真的)实现快 500倍
(超豪华元组到列表来自https://stackoverflow.com/a/3205524