Loading...
墨滴

张春成

2021/06/30  阅读:50  主题:默认主题

配色方法

配色方法

如果你经常纠结于怎么为自己的PPT或其他什么东西配色的话。 本文将介绍一种基于HSV空间的配色方法,也许能解决你的问题。


颜色空间切割

前面几篇文章已经说明了颜色空间的三维空间特性。 我们可以在三维空间中画一条线,并将这条线等分。 等分点,即是得到的配色方案。 如下图所示。

  • 配色方案图
Cut-colorSpace.png
Cut-colorSpace.png

其中,上、下两张子图分别代表在RGBHSV颜色空间中,进行配色分割的方案图。 可以看到,HSV空间中的颜色更加丰富。

绘图样例

下面我们通过一个例子来说明,使用HSV空间进行配色的优势。 我们选取一张典型图片,用我们的颜色方案进行重新渲染。

  • 原始图像
RawImg.png
RawImg.png
  • RGB空间渲染图
RGB-ReFill.png
RGB-ReFill.png
  • HSV空间渲染图
HSV-ReFill.png
HSV-ReFill.png

是不是HSV空间的颜色分配稍微看着顺眼一些?

代码实现

计算过程使用python代码,可以参考我的GITHUB仓库[1]

由于本计算过程较为简单,我们直接列出如下。

  • 引用的包
import cv2
from PIL import Image
import urllib.request
from io import BytesIO

import numpy as np
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
  • 自定义工具
def rnd(a=10, b=20):
    ''' Generate Random Number '''
    return np.random.randint(a, b)

def rect():
    ''' Generate Random Rect '''
    ps = [np.array([00])]
    ps.append(ps[-1] + np.array([rnd(), 0]))
    ps.append(ps[-1] + np.array([0, rnd()]))
    ps.append(ps[-1] + np.array([-rnd(), 0]))

    x0 = rnd(a=10, b=100)
    y0 = rnd(a=10, b=100)

    x = [e[0] + x0 for e in ps]
    y = [e[1] + y0 for e in ps]

    x.append(x[0])
    y.append(y[0])

    return x, y

def rgb2str(rgb):
    ''' Convert RGB to String like #FFFFFF'''
    return '#' + ''.join([hex(int(e)).replace('x''')[-2:] for e in rgb])

def hsv2rgb(hsv):
    ''' Convert Color Array from HSV to RGB '''
    hsv = hsv[np.newaxis, np.newaxis, :].astype(np.uint8)
    return cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR).ravel()

def color_queue(num=15, output_str=True):
    ''' Generate Queue of Colors
    If output_str is True, the RGB Array will be converted into String like #FFFFFF
    '''

    queue_rgb = []
    queue_hsv = []

    threshold = 100**2 + 100**2 + 100**2

    while True:
        kwargs = dict(a=10, b=230)
        r0 = rnd(**kwargs)
        r1 = rnd(**kwargs)
        g0 = rnd(**kwargs)
        g1 = rnd(**kwargs)
        b0 = rnd(**kwargs)
        b1 = rnd(**kwargs)

        if (r0-r1)**2 + (g0-g1)**2 + (b0-b1)**2 > threshold:
            break

    for r, g, b in zip(np.linspace(r0, r1, num), np.linspace(g0, g1, num), np.linspace(b0, b1, num)):
        queue_rgb.append((r, g, b))
        r = r % 180
        queue_hsv.append(hsv2rgb(np.array([r, g, b])))

    if output_str:
        return [rgb2str(e) for e in queue_rgb], [rgb2str(e) for e in queue_hsv]
    else:
        return queue_rgb, queue_hsv

def ravel(d):
    ''' Ravel the 1st and the 2nd Dimensions '''
    s = d.shape
    n = s[0] * s[1]
    d = d.reshape((n, s[2]))
    return d
  • 生成配色方案

# Fetch Image to Get How-Many-Colors We Need
url = 'http://localhost:8000/Colors.png'
req = urllib.request.urlopen(url)
im = Image.open(BytesIO(req.read()))

rgb = np.array(im.convert('RGB'))[:, :2000]
uniques = np.unique(rgb[:, :, 2].ravel())
rgb.shape, uniques.shape, uniques

# Build Color Plan
rgb_data = []
hsv_data = []

rgb_queue, hsv_queue = color_queue(len(uniques), output_str=False)

for rgb_arr, hsv_arr in zip(rgb_queue, hsv_queue):
    x, y = rect()
    rgb_data.append(go.Scatter(x=x, y=y, fillcolor=rgb2str(rgb_arr), fill='toself', line_width=0, opacity=0.5, mode='lines'))
    hsv_data.append(go.Scatter(x=x, y=y, fillcolor=rgb2str(hsv_arr), fill='toself', line_width=0, opacity=0.5, mode='lines'))

fig = make_subplots(rows=2, cols=1, subplot_titles=['RGB''HSV'])

for d in rgb_data:
    fig.add_trace(
        d,
        row=1,
        col=1,
    )

for d in hsv_data:
    fig.add_trace(
        d,
        row=2,
        col=1,
    )

fig.update_layout(dict(
        height=800,
        width=800,
    ))

fig.show()

  • 绘图并重新渲染

# RawImg
img = Image.fromarray(rgb)
img

# ReFill using RGB
rgb1 = rgb.copy()
for j in range(1, len(uniques)):
    rgb1[rgb1[:, :, 2] == uniques[j]] = rgb_queue[j]

img1 = Image.fromarray(rgb1)
img1

# ReFill using HSV
rgb2 = rgb.copy()
for j in range(1, len(uniques)):
    rgb2[rgb2[:, :, 2] == uniques[j]] = hsv_queue[j]

img2 = Image.fromarray(rgb2)
img2

参考资料

[1]

GITHUB仓库: https://github.com/listenzcc/JupyterScripts.git

张春成

2021/06/30  阅读:50  主题:默认主题

作者介绍

张春成