使用Python将颜色图/渐变图应用到图像

问题描述 投票:0回答:4

大多数图像编辑软件都具有渐变图功能。渐变贴图采用给定像素的亮度并根据亮度应用颜色渐变。 Photoshop 和其他软件有办法自动执行此操作,但它们不能完全满足我的要求,所以我认为 Python 可能可以解决这个问题。不幸的是,当我使用 Python 搜索渐变图或颜色图时,我很难理解或应用出现的任何结果。

Gradient maps

我发现的所有潜在解决方案线程都使用了 numpy 或 matplotlib,其中有很多数学线超出了我的想象......我希望得到一些帮助。最初我对处理有一些了解,但我发现使用处理导出大量图像的任务很奇怪而且很棘手。另外,我喜欢 Python,并且想学习如何用它编辑和生成艺术作品。

这就是我现在正在做的事情。

from PIL import Image

myPalette = ['#1A1423', '#684756', '#AB8476']

def colorMap(pixel, palette): 
    # Calculate the brightness of pixel 
    R, G, B = pixel 
    brightness = sum([R, G, B])/3
 
    # Map gradient of colors to brightness
    # ???...
    
    return mappedColor

 
img = Image.open('image_input.png') 
pixels = img.load()
 
for x in range(img.size[0]): 
    for y in range(img.size[1]): 
        pixel = img.getpixel((x, y)) 
        pixels[x, y] = colorMap(pixel, myPalette)
 
img.save('image_output.png')

加载、计算亮度、保存都很简单。我只是不知道如何将调色板的渐变应用于像素。

python image image-processing colors colormap
4个回答
6
投票

您可以使用 ImageMagick 或 PIL/Numpy/OpenCV 轻松完成此操作。

首先是获取颜色图 - 图像右侧下方的垂直条。我没有也不知道 Clip Studio,所以也许它可以让你导出色彩图,或者创建一个灰度渐变并将色彩图应用到它,然后将结果保存为 PNG。就我而言,我将图像加载到 Photoshop 中,剪切出渐变并旋转它,以制作一张完全 256 像素宽 x 1 像素高的图像。放大后是这样的:

颜色图.png

我还从图像的左侧裁剪了你的漩涡状物体 - 请以后单独发布图像。

漩涡.png


现在应用它。首先,只需在终端中使用ImageMagick。我加载了您的漩涡图像并将其分成其组成的 RGB 通道,然后对通道进行平均并应用颜色图,也称为 CLUT“颜色查找表”:

magick swirl.png -channel RGB -separate -evaluate-sequence mean colourmap.png -clut result.png


接下来,与 PIL/Numpy 相同:

#!/usr/bin/env python3

import numpy as np
from PIL import Image

# Load image, make into Numpy array and average RGB channels
im = Image.open('swirl.png').convert('RGB')
na = np.array(im)
grey = np.mean(na, axis=2).astype(np.uint8)
Image.fromarray(grey).save('DEBUG-grey.png')   # DEBUG only

# Load colourmap
cmap = Image.open('colourmap.png').convert('RGB')
# cmap must be resized to have a width of 256
# since grey's scaled from 0-255, so np.take will select from indices 0-255 only
cmap = cmap.resize((256, 1))

# Make output image same height and width as grey image, but 3-channel RGB
result = np.zeros((*grey.shape,3), dtype=np.uint8)

# Take entries from RGB colourmap according to greyscale values in image
np.take(cmap.getdata(), grey, axis=0, out=result)

# Save result
Image.fromarray(result).save('result.png')

您还可以生成分段线性颜色图,如下所示:

 magick -size 160x1 gradient:navy-"rgb(220,110,110)"   \
        -size  60x1 gradient:"rgb(220,110,110)"-yellow \
        -size  35x1 gradient:yellow-white              \
        +append colourmap.png

这使得三个段各具有线性渐变:

  • 160x1 海军蓝到鲑鱼色,
  • 60x1 鲑鱼色至黄色和
  • 35x1 黄色至白色

然后将它们附加在一起。


如果将颜色图的所有段设置为相同的长度,您将得到不同的解释:

magick -size 85x1 \
   gradient:navy-"rgb(220,110,110)"   \
   gradient:"rgb(220,110,110)"-yellow \
   gradient:yellow-white +append -resize 256x1\! colourmap.png

这导致了这个:


1
投票

诀窍是定义一个映射表,将颜色与 [0, 255] 范围内的每个灰度值相关联(在您的情况下,您甚至可以通过不取平均值来映射 [0, 255 x 3])。

现在要获得平滑的效果,需要定期更改颜色成分。选项是无限的。这是一个典型的例子:


1
投票

这里有两种方法,一种使用Matplotlib,一种仅使用OpenCV

方法#1:

OpenCV
+
matplotlib.pyplot.get_cmap

我们首先将图像加载为灰度。默认情况下,OpenCV 将图像读取为 3 通道、8 位 BGR。我们可以使用

cv2.imread()
cv2.IMREAD_GRAYSCALE
参数直接将图像加载为灰度图像,或者使用
cv2.cvtColor()
cv2.COLOR_BGR2GRAY
参数将 BGR 图像转换为灰度图像。加载图像后,我们将此灰度图像放入 Matplotlib 中以获得热图图像。 Matplotlib 返回 RGB 格式,因此我们必须转换回 Numpy 格式并切换到 BGR 色彩空间以便与 OpenCV 一起使用。这是使用
inferno
颜色图的示例。请参阅在 Matplotlib 中选择颜色图,了解可用的内置颜色图,具体取决于您所需的用例。

输入图像

->
热图图像

代码

import matplotlib.pyplot as plt
import numpy as np
import cv2

image = cv2.imread('1.png', 0)
colormap = plt.get_cmap('inferno')
heatmap = (colormap(image) * 2**16).astype(np.uint16)[:,:,:3]
heatmap = cv2.cvtColor(heatmap, cv2.COLOR_RGB2BGR)

cv2.imshow('image', image)
cv2.imshow('heatmap', heatmap)
cv2.waitKey()

方法#2:

cv2.applyColorMap()

我们可以使用OpenCV内置的热图功能。这是使用

cv2.COLORMAP_HOT
热图

的结果

代码

import cv2

image = cv2.imread('1.png', 0)
heatmap = cv2.applyColorMap(image, cv2.COLORMAP_HOT)

cv2.imshow('heatmap', heatmap)
cv2.waitKey()

注意: 虽然 OpenCV 的内置实现简短而快速,但我建议使用方法#1,因为有更大的颜色图选择。 Matplotlib 拥有数百种不同的颜色图,并允许您创建自己的自定义颜色图,而 OpenCV 只有 12 种可供选择。这是内置的 OpenCV 颜色图选择:


0
投票

我知道你说过你不想要 matplotlib,但我认为你不需要数学线来让它工作。我用自己的 PNG 进行了测试,希望它也适用于您的。这是一个很大程度上借鉴了本文档的示例。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap

# Read PNG and take average:
img = plt.imread('image_input.png')
Z = img.mean(-1)

#   Kestrel
color_list = [np.array([207,117,80])/255,
              np.array([219,179,127])/255,
              np.array([248,249,251])/255,
              np.array([185,191,205])/255,
              np.array([88,104,127])/255]

cmap_name = 'Kestrel'
N_bin=100
# Create the colormap
cmap = LinearSegmentedColormap.from_list(cmap_name, color_list, N=N_bin)
# Fewer bins will result in "coarser" colomap interpolation
fig, ax = plt.subplots()
im = ax.imshow(Z, cmap=cmap)
fig.colorbar(im, ax=ax)

plt.show()
© www.soinside.com 2019 - 2024. All rights reserved.