【问题标题】:Changing RGB values of a picture to closest predefined RGB values将图片的 RGB 值更改为最接近的预定义 RGB 值
【发布时间】:2020-09-04 18:03:21
【问题描述】:

所以我有一个预定义的调色板,我想用它为图片着色。 我正在研究如何做到这一点,到目前为止发现了这一点。

import scipy.spatial as sp
import matplotlib.pyplot as plt
import cv2
import numpy

avg = image.open("sourcefile.png")

#Color palette I would ike to use

main_colors = [(100, 100, 100),
               (204, 0, 0),
               (0, 174, 0),
               (102, 51, 153),
               (255, 102, 0),
               (0, 0, 155)]

h, w, bpp = numpy.shape(avg)

# Change colors of each pixel
for py in range(0, h) :
    for px in range(0, w):
        input_color = avg[py][px][0], avg[py][px][1], avg[py][px][2]
        tree = sp.KDTree(main_colors)
        distance, result = tree.query(input_color)
        nearest_color = main_colors[result]

        avg[py][px][0] = nearest_color[0]
        avg[py][px][1] = nearest_color[1]
        avg[py][px][2] = nearest_color[2]

# show image
plt.figure()
plt.axis("off")
plt.imshow(avg)

我相信,我真的很接近解决方案,但是,我似乎做不到。有人可以帮我调试吗? 我一直收到这个,我不知道如何解决这个问题

 File "/Average Pictures.py", line 22, in <module>
    input_color = avg[py][px][0], avg[py][px][1], avg[py][px][2]
TypeError: 'Image' object is not subscriptable

看了@Quang Hong 的评论后,我也修改了代码:

import scipy.spatial as sp
import matplotlib.pyplot as plt
import cv2
import numpy 

...
...
...


# Blending loaded Images
avg = Image.open(imlist[0])
for i in range(1, N):
    img = Image.open(imlist[i])
    avg = Image.blend(avg, img, 1.0 / float(i + 1))

avg1 = Image.new("RGB", avg.size)
avg1 = asarray(avg1)

main_colors =numpy.array([(100, 100, 100), 
               (204, 0, 0),  
               (0, 174, 0),  
               (102, 51, 153),
               (255, 102, 0), 
               (0, 0, 155),
               ])

main_colors = numpy.array(main_colors)
dist_mat = sp.distance_matrix(avg1.reshape(-1,3), main_colors)
color_idx = dist_mat.argmax(axis=1)

nearest_colors = main_colors[color_idx].reshape(avg1.shape)

fig, axes = plt.subplots(1, 2)
axes[0].imshow(avg)  # original image
axes[1].imshow(nearest_colors)  # nearest_color
plt.show()

但是现在的问题是,它没有输出正确的图像。

有人可以帮忙吗? 对不起,我是一个绝对的菜鸟。

【问题讨论】:

标签: python python-3.x numpy scipy


【解决方案1】:

我会使用distance_matrix 计算像素/参考颜色之间的距离,然后使用argmin 提取颜色:

# sample image
np.random.seed(1)
avg = np.random.randint(0,255, (10,10,3), dtype=np.uint8)

# in your code, make sure `avg` is an np array
# you can use `cv2.imread` for that purpose, not the BGR color space
# for example
# avg = cv2.imread('image.png')
# agv = cv2.cvtColor(avg, cv2.BGR2RGB) # convert to RGB

# convert main_colors to np array for indexing
main_colors = np.array(main_colors)

# compute the distance matrix
dist_mat = distance_matrix(avg.reshape(-1,3), main_colors)

# extract the nearest color by index
color_idx = dist_mat.argmax(axis=1)

# build the nearest color image with indexing
nearest_colors = main_colors[color_idx].reshape(avg.shape)

# plot
fig, axes = plt.subplots(1,2)
axes[0].imshow(avg)             # original image
axes[1].imshow(nearest_colors)  # nearest_color
plt.show()

输出:

【讨论】:

  • 使用这几行代码后,输出不正确。我已经更新了我的代码。你能再看看吗?
  • avg1 = Image.new("RGB", avg.size) 你为什么要这样做? avg1 只是一个黑色的单色图像,当然你会得到一个单色最近的图像。
  • 哦,是的,没错。我试图先将图片转换为RGB图片,然后将其转换为数组。否则我该怎么做?
  • 我不熟悉Image。你试过opencv 代码吗?
  • 我解决了 RGB 的问题。我遇到的问题很简单。我在代码的第一次迭代中使用了argmax 而不是argmin。因此,输出是一张与其最不相似的图片。将其更改为 argmaxargmin 给了我正确的图片。
猜你喜欢
  • 2011-05-27
  • 2010-12-07
  • 1970-01-01
  • 2017-10-26
  • 2018-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多