问题
上图是一幅红色树林的图像,左下图是一个蔬菜的图像。
目标:将蔬菜图像的颜色组成换成树林图像的颜色组成。
要求:通过算法完成两个图像之间颜色的映射。
分析
下述出自论文**《图像处理中的颜色传递算法_李雅娜》**:
原文链接:图像处理中的颜色传递算法 - 中国知网 (cnki.net)
由于目前图像采用的颜色空间主要为 RGB 空间,但 RGB 颜色空间的各分量之间存在着相关性,这就意味着如果改变一个像素颜色外观的话,必须改变所有的颜色通道,这使得颜色更改过程变得极为复杂。而后 Ruderman 等人基于人类视觉对图像数据的感知研究,提出了lαβ 颜色空间,与 RGB 及其他颜色空间不同的是在 lαβ 颜色空间中通道间数据的相关性最小,从而可在不同的通道独立地进行统计信息的传递。
查阅论文,得知
故,我们需要的操作如下:
- 把源图片和目标图片由RGB转换为Lab颜色空间
- 分别两个计算各个通道的均值和方差,假设
s_mean、t_mean、s_std、s_std
分别为源图像和目标图像Lab下某一通道的均值和方差 - 对源图像的每一通道的每个像素点作运算(设p为对应像素值):
p = (p - s_mean) * (t_std / s_std) t_mean
- 把图像由Lab空间转换成RGB空间
- 对转换回的RGB图像作越界检测矫正处理
代码
代码语言:javascript复制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)