找到图像中每个像素的最接近的RGB颜色
找到图像中每个像素的最接近的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日
你(修正后)的函数如下所示:
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()
以及测试图片前后:
如果您只对结果感兴趣,请使用图像库允许的任何本机方法。这个短片段使用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)