将图像中的颜色映射到颜色列表中最接近的成员,在 Python 中
Map colors in image to closest member of a list of colors, in Python
我有一个包含 19 种颜色的列表,它是一个大小为 (19,3)
:
的 numpy 数组
colors = np.array([[0, 0, 0],
[0, 0, 255],
[255, 0, 0],
[150, 30, 150],
[255, 65, 255],
[150, 80, 0],
[170, 120, 65],
[125, 125, 125],
[255, 255, 0],
[0, 255, 255],
[255, 150, 0],
[255, 225, 120],
[255, 125, 125],
[200, 100, 100],
[0, 255, 0],
[0, 150, 80],
[215, 175, 125],
[220, 180, 210],
[125, 125, 255]
])
现在我有一个图像(大小为 (1024,1024,3)
的 numpy 数组),其颜色有点接近或等于上面定义的所有颜色。但是,我的程序要求图像只能包含上面的颜色,不能包含附近的颜色,所以我需要将数组中每个像素的颜色转换为 19 种颜色中最接近的颜色。
我在这里看到了一个函数,它可以从一组颜色中找到最接近的颜色,它只使用 Numpy(效果很好):
def closest_color(colors,color):
colors = np.array(colors)
color = np.array(color)
distances = np.sqrt(np.sum((colors-color)**2,axis=1))
index_of_smallest = np.where(distances==np.amin(distances))
smallest_distance = colors[index_of_smallest]
return smallest_distance
使用此功能,我可以从预定义列表中找到最接近单一颜色的颜色,但在我的问题中,我没有想要更改的单一颜色,而是整个图像(1024 x 1024 像素颜色)。利用此函数(或使用任何更好的函数)的最有效方法是什么,它仅使用 numpy 来解决我的问题。我想尽可能减少for循环的数量,因为我总共需要处理30,000张大小为1024 x 1024的图像。
谢谢!
由于您正在计算的是欧几里德距离,因此您可以使用 scipy.spatial.distance.cdist
快速计算每对距离,然后从生成的距离矩阵中选择最接近的颜色:
import numpy as np
import scipy.spatial.distance
np.random.seed(0)
palette = np.array([
[0, 0, 0],
[0, 0, 255],
[255, 0, 0],
[150, 30, 150],
[255, 65, 255],
[150, 80, 0],
[170, 120, 65],
[125, 125, 125],
[255, 255, 0],
[0, 255, 255],
[255, 150, 0],
[255, 225, 120],
[255, 125, 125],
[200, 100, 100],
[0, 255, 0],
[0, 150, 80],
[215, 175, 125],
[220, 180, 210],
[125, 125, 255]
])
data = np.random.randint(256, size=(10, 3))
closest_idx = scipy.spatial.distance.cdist(data, palette).argmin(1)
data_in_palette = palette[closest_idx]
print(*zip(data, data_in_palette), sep='\n')
# (array([172, 47, 117]), array([150, 30, 150]))
# (array([192, 67, 251]), array([255, 65, 255]))
# (array([195, 103, 9]), array([150, 80, 0]))
# (array([211, 21, 242]), array([255, 65, 255]))
# (array([36, 87, 70]), array([ 0, 150, 80]))
# (array([216, 88, 140]), array([200, 100, 100]))
# (array([ 58, 193, 230]), array([ 0, 255, 255]))
# (array([ 39, 87, 174]), array([125, 125, 125]))
# (array([ 88, 81, 165]), array([125, 125, 125]))
# (array([25, 77, 72]), array([ 0, 150, 80]))
我们可以使用 Cython-powered kd-tree
for quick nearest-neighbor lookup 从而实现我们的 classification/bucketing -
from scipy.spatial import cKDTree
# Input image : img
out_img = colors[cKDTree(colors).query(img,k=1)[1]]
该问题不仅要求找到最近的邻居(其他答案提供),而且还要求如何有效地应用超过 30000 张图像的交换。
性能提升:
不是计算每个图像的每个像素的距离 (30000*1024*1024 = 31457280000),而是为调色板上的每种可能颜色计算一次映射。
然后使用该映射交换像素。
import numpy as np
import itertools as it
import scipy.spatial.distance
palette = np.array([[0, 0, 0],
[0, 0, 255],
[255, 0, 0],
[150, 30, 150],
[255, 65, 255],
[150, 80, 0],
[170, 120, 65],
[125, 125, 125],
[255, 255, 0],
[0, 255, 255],
[255, 150, 0],
[255, 225, 120],
[255, 125, 125],
[200, 100, 100],
[0, 255, 0],
[0, 150, 80],
[215, 175, 125],
[220, 180, 210],
[125, 125, 255]
])
valueRange = np.arange(0,256)
allColors = np.array(list(it.product(valueRange,valueRange,valueRange)))
mapping = scipy.spatial.distance.cdist(allColors, palette).argmin(1)
另外推荐
的讲座
我有一个包含 19 种颜色的列表,它是一个大小为 (19,3)
:
colors = np.array([[0, 0, 0],
[0, 0, 255],
[255, 0, 0],
[150, 30, 150],
[255, 65, 255],
[150, 80, 0],
[170, 120, 65],
[125, 125, 125],
[255, 255, 0],
[0, 255, 255],
[255, 150, 0],
[255, 225, 120],
[255, 125, 125],
[200, 100, 100],
[0, 255, 0],
[0, 150, 80],
[215, 175, 125],
[220, 180, 210],
[125, 125, 255]
])
现在我有一个图像(大小为 (1024,1024,3)
的 numpy 数组),其颜色有点接近或等于上面定义的所有颜色。但是,我的程序要求图像只能包含上面的颜色,不能包含附近的颜色,所以我需要将数组中每个像素的颜色转换为 19 种颜色中最接近的颜色。
我在这里看到了一个函数,它可以从一组颜色中找到最接近的颜色,它只使用 Numpy(效果很好)
def closest_color(colors,color):
colors = np.array(colors)
color = np.array(color)
distances = np.sqrt(np.sum((colors-color)**2,axis=1))
index_of_smallest = np.where(distances==np.amin(distances))
smallest_distance = colors[index_of_smallest]
return smallest_distance
使用此功能,我可以从预定义列表中找到最接近单一颜色的颜色,但在我的问题中,我没有想要更改的单一颜色,而是整个图像(1024 x 1024 像素颜色)。利用此函数(或使用任何更好的函数)的最有效方法是什么,它仅使用 numpy 来解决我的问题。我想尽可能减少for循环的数量,因为我总共需要处理30,000张大小为1024 x 1024的图像。
谢谢!
由于您正在计算的是欧几里德距离,因此您可以使用 scipy.spatial.distance.cdist
快速计算每对距离,然后从生成的距离矩阵中选择最接近的颜色:
import numpy as np
import scipy.spatial.distance
np.random.seed(0)
palette = np.array([
[0, 0, 0],
[0, 0, 255],
[255, 0, 0],
[150, 30, 150],
[255, 65, 255],
[150, 80, 0],
[170, 120, 65],
[125, 125, 125],
[255, 255, 0],
[0, 255, 255],
[255, 150, 0],
[255, 225, 120],
[255, 125, 125],
[200, 100, 100],
[0, 255, 0],
[0, 150, 80],
[215, 175, 125],
[220, 180, 210],
[125, 125, 255]
])
data = np.random.randint(256, size=(10, 3))
closest_idx = scipy.spatial.distance.cdist(data, palette).argmin(1)
data_in_palette = palette[closest_idx]
print(*zip(data, data_in_palette), sep='\n')
# (array([172, 47, 117]), array([150, 30, 150]))
# (array([192, 67, 251]), array([255, 65, 255]))
# (array([195, 103, 9]), array([150, 80, 0]))
# (array([211, 21, 242]), array([255, 65, 255]))
# (array([36, 87, 70]), array([ 0, 150, 80]))
# (array([216, 88, 140]), array([200, 100, 100]))
# (array([ 58, 193, 230]), array([ 0, 255, 255]))
# (array([ 39, 87, 174]), array([125, 125, 125]))
# (array([ 88, 81, 165]), array([125, 125, 125]))
# (array([25, 77, 72]), array([ 0, 150, 80]))
我们可以使用 Cython-powered kd-tree
for quick nearest-neighbor lookup 从而实现我们的 classification/bucketing -
from scipy.spatial import cKDTree
# Input image : img
out_img = colors[cKDTree(colors).query(img,k=1)[1]]
该问题不仅要求找到最近的邻居(其他答案提供),而且还要求如何有效地应用超过 30000 张图像的交换。
性能提升:
不是计算每个图像的每个像素的距离 (30000*1024*1024 = 31457280000),而是为调色板上的每种可能颜色计算一次映射。
然后使用该映射交换像素。
import numpy as np
import itertools as it
import scipy.spatial.distance
palette = np.array([[0, 0, 0],
[0, 0, 255],
[255, 0, 0],
[150, 30, 150],
[255, 65, 255],
[150, 80, 0],
[170, 120, 65],
[125, 125, 125],
[255, 255, 0],
[0, 255, 255],
[255, 150, 0],
[255, 225, 120],
[255, 125, 125],
[200, 100, 100],
[0, 255, 0],
[0, 150, 80],
[215, 175, 125],
[220, 180, 210],
[125, 125, 255]
])
valueRange = np.arange(0,256)
allColors = np.array(list(it.product(valueRange,valueRange,valueRange)))
mapping = scipy.spatial.distance.cdist(allColors, palette).argmin(1)
另外推荐