问题

上图是一幅红色树林的图像,左下图是一个蔬菜的图像。

目标:将蔬菜图像的颜色组成换成树林图像的颜色组成。

要求:通过算法完成两个图像之间颜色的映射。

分析

下述出自论文**《图像处理中的颜色传递算法_李雅娜》**:

原文链接:图像处理中的颜色传递算法 - 中国知网 (cnki.net)

由于目前图像采用的颜色空间主要为 RGB 空间,但 RGB 颜色空间的各分量之间存在着相关性,这就意味着如果改变一个像素颜色外观的话,必须改变所有的颜色通道,这使得颜色更改过程变得极为复杂。而后 Ruderman 等人基于人类视觉对图像数据的感知研究,提出了lαβ 颜色空间,与 RGB 及其他颜色空间不同的是在 lαβ 颜色空间中通道间数据的相关性最小,从而可在不同的通道独立地进行统计信息的传递。

查阅论文,得知

故,我们需要的操作如下:

  1. 把源图片和目标图片由RGB转换为Lab颜色空间

  2. 分别两个计算各个通道的均值和方差,假设s_mean、t_mean、s_std、s_std 分别为源图像和目标图像Lab下某一通道的均值和方差

  3. 对源图像的每一通道的每个像素点作运算(设p为对应像素值):p = (p - s_mean) * (t_std / s_std) + t_mean

  4. 把图像由Lab空间转换成RGB空间

  5. 对转换回的RGB图像作越界检测矫正处理

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import numpy as np
import cv2
import os


def get_mean_and_std(x):
# 计算矩阵的均值和标准差 以Mat形式返回
x_mean, x_std = cv2.meanStdDev(x)
# print(x_mean, x_std) 均为3*1的矩阵

# 将矩阵进行连接 转换成 2*3的矩阵 方便操作
x_mean = np.hstack(np.around(x_mean, 2))
# print(x_mean)
x_std = np.hstack(np.around(x_std, 2))
# print(x_std)
return x_mean, x_std

print("==读取源图片==")
s = cv2.imread('source.jpg')
s = cv2.cvtColor(s, cv2.COLOR_BGR2LAB)
print("==读取目标图片==")
t = cv2.imread('target.jpg')
t = cv2.cvtColor(t, cv2.COLOR_BGR2LAB)

print("==计算源图片的均值和标准差==")
s_mean, s_std = get_mean_and_std(s)
print("==计算目标图片的均值和标准差==")
t_mean, t_std = get_mean_and_std(t)

height, width, channel = s.shape
# print(height, width, channel)
# 385 383 3 (1*3)
for i in range(0, height):
for j in range(0, width):
for k in range(0, channel):
x = s[i, j, k]
# 归一化处理
x = ((x-s_mean[k]) * (t_std[k] / s_std[k])) + t_mean[k]
# 返回最接近的整数
x = round(x)
# 越界矫正
x = 0 if x < 0 else x
x = 255 if x > 255 else x
s[i, j, k] = x

s = cv2.cvtColor(s, cv2.COLOR_LAB2BGR)
print("==保存转换好的图片==")
cv2.imwrite('result.jpg', s)

结果

sourcetargetresult