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

13 浏览
0 Comments

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

我正在使用 NumPy 进行图像处理。我将图像加载到数组中,并获取每个像素的“最近”颜色,如下所示:

# rgbValues is a global list with 22 RGB values
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]
im = np.asarray(Image.open('image.jpg'))
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])

如何获取 out 中实际的 RGB 值,而不是距离?如何提高代码的性能?

admin 更改状态以发布 2023年5月24日
0
0 Comments

你(修正后)的函数如下所示:

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%。我们能否用更Pythonic的方法做得更好呢?

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

0