如何从颜色字典快速更改图像中的像素?

Ank*_*wal 1 opencv python-imaging-library python-3.x

我有一个图像,我想从颜色图中更改图像中的所有颜色,例如。{(10,20,212):(60,40,112)...}

目前,我正在读取图像 OpenCV,然后遍历图像数组并更改每个像素,但这非常慢。

有什么办法可以更快地做到这一点吗?

Mar*_*ell 7

我对这个问题提供两个答案。这个答案更基于 PIL/Pillow ,另一个更基于OpenCV。结合我的其他答案阅读此答案,并可能混合搭配。

您可以使用调色板来完成。如果您不熟悉调色图像,而不是在每个像素位置都有一个 RGB 值,您可以在多达 256 种颜色的调色板中使用一个简单的 8 位索引。

因此,我们可以做的是将您的图像加载为 PIL 图像,并将其量化为您拥有的一组输入颜色。然后每个像素将具有地图中颜色的索引。然后只需将调色板替换为您想要映射到的颜色。

#!/usr/bin/env python3

import numpy as np
from PIL import Image

def QuantizeToGivenPalette(im, palette):
    """Quantize image to a given palette.

    The input image is expected to be a PIL Image.
    The palette is expected to be a list of no more than 256 R,G,B values."""

    e = len(palette)
    assert e>0,    "Palette unexpectedly short"
    assert e<=768, "Palette unexpectedly long"
    assert e%3==0, "Palette not multiple of 3, so not RGB"

    # Make tiny, 1x1 new palette image
    p = Image.new("P", (1,1))

    # Zero-pad the palette to 256 RGB colours, i.e. 768 values and apply to image
    palette += (768-e)*[0]
    p.putpalette(palette)

    # Now quantize input image to the same palette as our little image
    return im.convert("RGB").quantize(palette=p)

# Open input image and palettise to "inPalette" so each pixel is replaced by palette index
# ... so all black pixels become 0, all red pixels become 1, all green pixels become 2...
im = Image.open('image.png').convert('RGB')

inPalette = [
    0,0,0,    # black
    255,0,0,  # red
    0,255,0,  # green
    0,0,255,  # blue
    255,255,255 # white
    ]
r = QuantizeToGivenPalette(im,inPalette)

# Now simply replace the palette leaving the indices unchanged
newPalette = [
    255,255,255,  # white
    0,255,255,    # cyan
    255,0,255,    # magenta
    255,255,0,    # yellow
    0,0,0         # black
    ]

# Zero-pad the palette to 256 RGB colours, i.e. 768 values
newPalette += (768-len(newPalette))*[0]

# And finally replace the palette with the new one
r.putpalette(newPalette)

# Save result
r.save('result.png')
Run Code Online (Sandbox Code Playgroud)

输入图像

在此处输入图片说明

输出图像

在此处输入图片说明

因此,要使用将旧颜色值映射到新颜色值的字典来具体执行您所要求的操作,您需要初始化字典oldPalette和字典newPalette

关键词:Python、PIL、枕头、图像、图像处理、量化、量化、特定调色板、给定调色板、指定调色板、已知调色板、重新映射、重新映射、颜色映射、映射。

这里这里有一些关于调色图像的有用词。


Mar*_*ell 6

我对这个问题提供两个答案。这个答案更基于OpenCV,另一个更基于 PIL/Pillow。结合我的其他答案阅读此答案,并可能混合搭配。

您可以使用 Numpy'slinalg.norm()来查找颜色之间的距离,然后argmin()选择最近的。然后,您可以使用 LUT “查找表”根据图像中的现有值查找新值。

#!/usr/bin/env python3

import numpy as np
import cv2

def QuantizeToGivenPalette(im, palette):
    """Quantize image to a given palette.

    The input image is expected to be a Numpy array.
    The palette is expected to be a list of R,G,B values."""

    # Calculate the distance to each palette entry from each pixel
    distance = np.linalg.norm(im[:,:,None] - palette[None,None,:], axis=3)

    # Now choose whichever one of the palette colours is nearest for each pixel
    palettised = np.argmin(distance, axis=2).astype(np.uint8)

    return palettised

# Open input image and palettise to "inPalette" so each pixel is replaced by palette index
# ... so all black pixels become 0, all red pixels become 1, all green pixels become 2...
im=cv2.imread("image.png",cv2.IMREAD_COLOR)

inPalette = np.array([
   [0,0,0],             # black
   [0,0,255],           # red
   [0,255,0],           # green
   [255,0,0],           # blue
   [255,255,255]],      # white
   dtype=np.uint8)

r = QuantizeToGivenPalette(im,inPalette)

# Now make LUT (Look Up Table) with the 5 new colours
LUT = np.zeros((5,3),dtype=np.uint8)
LUT[0]=[255,255,255]  # white
LUT[1]=[255,255,0]    # cyan
LUT[2]=[255,0,255]    # magenta
LUT[3]=[0,255,255]    # yellow
LUT[4]=[0,0,0]        # black

# Look up each pixel in the LUT
result = LUT[r]

# Save result
cv2.imwrite('result.png', result)
Run Code Online (Sandbox Code Playgroud)

输入图像

在此处输入图片说明

输出图像

在此处输入图片说明

关键词:Python、PIL、枕头、图像、图像处理、量化、量化、特定调色板、给定调色板、指定调色板、已知调色板、重新映射、重新映射、颜色图、映射、LUT、linalg.norm。