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

Python 为图像中的每个像素查找最接近的RGB颜色,python,python-3.x,numpy,python-imaging-library,Python,Python 3.x,Numpy,Python Imaging Library,首先:我是一个编程初学者。 我有一个NumPy阵列,每个像素都有RGB数据 im=np.asarray(Image.open('Image.jpg')) 我将每个像素传递给我的getNearestColor函数。Out也是一个numpy数组 范围内x的(len(im)): 对于范围内的y(len(im[x]): 对于范围内的(len(im[x][y]): out[x][y]=getNearestColor(im[x][y]) 然后我在3d RGB系统中计算距离 def getNearestC

首先:我是一个编程初学者。 我有一个NumPy阵列,每个像素都有RGB数据

im=np.asarray(Image.open('Image.jpg'))
我将每个像素传递给我的getNearestColor函数。Out也是一个numpy数组

范围内x的
(len(im)):
对于范围内的y(len(im[x]):
对于范围内的(len(im[x][y]):
out[x][y]=getNearestColor(im[x][y])
然后我在3d RGB系统中计算距离

def getNearestColor(rgb):
a=[]
对于范围内的i(len(rgbValue)):
d=((rgb值[i][0]-rgb[0])*0.3)**2+((rgb值[i][1]-rgb[1])*0.59)**2+((rgb值[i][2]-rgb[2])*0.11)**2
a、 附加(d)
列表.排序(a)
返回[0]
RGB值是一个包含22个RGB值的列表,需要与之进行比较。这太慢了。这也只是给了我距离(d)。它应该会返回rgb值。如何获取最接近的RGB值并使其更快。 我希望一切都可以理解:)

您的(已更正)功能是:

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]]
它返回正确的
rgb值
;现在这是可能的,因为它的索引也存储在
a
中。这是一个公认的粗略时间框架,每秒处理27085像素

一个简单的实现,调整后只记住最近的索引:

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]
没有。使用相同的图像和相同的定时机制,它将下降到33417像素/秒


使用前面问题中的随机图像完成测试程序(它使用PIL加载、访问像素并显示图像,但与距离计算无关):

将计算外包给本机代码,结果好得惊人:18443414像素/秒–比我的本机(/naïve)实现快500倍。

(要列出的超级花哨元组来自)

你确定范围内的i(len(im[x][y])有
吗:
有吗<代码>i未使用。已更改它。。。更好在
getNearestColor
中,每次追加后都要重新排序。但在循环结束后,只需排序一次。然后再一次。。。你根本不需要维护一个列表——你只需要最接近的颜色。@hallozed你最里面的for循环没有任何作用。它只是重复了完全相同的操作
len(im[x][y])
次。实际上,我只排序了一次。这里的格式不对。你想说“你不需要维护一个列表”吗?你太棒了!谢谢!我显然在使用PIL实现。但是因为我正在学习编程,你的答案理解了它背后的概念真是太棒了。但是为什么他们的方法更好/更快呢?@halved:PIL的大部分被编译成机器上的本机可执行代码。在这方面,即使是一个简单的C实现也比Python中的任何东西都要好。(免责声明:您可能注意到我没有使用NumPy进行测试。它可能比我自己的做得更好,但您必须使用Python读写像素,因此它可能仍然没有PIL快。)您能解释一下您为PIL实现做了什么吗?这是做什么的呢?调色板序列必须包含768个整数值,这在某种程度上是这样做的(我假设),但实际发生了什么?你的22种颜色不足以填充3*256个整数值的整个数组。不能用0填充,因为这样调色板将包含第23种颜色。因此,这会将列表复制12次->264 RGB三倍。这太多了,所以再减少一次。(任何进一步的问题最好问一个新的问题,以免我们被指控“聊天”…)
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]]
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()
rgbValues = list(sum(rgbValues, ()))*12
rgbValues = rgbValues[:768]
palimage = Image.new('P', (width, height))
palimage.putpalette(rgbValues)
newimage = image.quantize(palette=palimage)