作者:Adrian Rosebrock
编译:Color Space
导读
本文主要介绍如何在两个图像之间实现颜色迁移的功能。给定任意两个图像,一个源图像,一个目标图像,然后可以将源图像的颜色空间迁移到目标图像。
算法实现与步骤
算法实现:通过分别利用L*a*b颜色空间以及每个L*、a*和b*通道的均值和标准差来实现颜色迁移。
实现步骤:
(1)输入源图像和目标图像。源图像包含你希望目标图像模仿的颜色空间,在本页中,左侧日落图像
是source, 中间是target, 右侧是source应用与target的结果;
(2)将源图像和目标图像都转换到Lab颜色空间。Lab颜色空间模拟感知均匀性,其中颜色量的微小变化也应该产生颜色重要性的相对相等的变化。L*a*b* 颜色空间比标准 RGB 颜色空间在模仿人类如何解释颜色方面做得更好,并且如您所见,非常适合颜色转移。
(3)将源图像和目标图像都做通道分离。
(4)计算source和target图像的每个 L*a*b* 通道的平均值和标准偏差。
(5)目标图像通道分离为L,a,b后,每个通道减去对应通道的均值
(6)target图像每个通道的标准偏差除以源图像对应通道标准偏差,再乘以对应通道图像对目标图像通道进行缩放。
(7)添加 L*a*b* 通道的均值source。
(8)裁剪任何超出范围[0, 255] 的值。(注意:这一步不是原始论文的一部分。由于 OpenCV 处理颜色空间转换的方式,我添加了它。如果你要在不同的语言/库中实现这个算法,你要么必须执行颜色空间转换自己,或了解进行转换的库是如何工作的)。
(9)将通道重新合并在一起。
(10)从L*a*b*空间转换回RGB色彩空间。
实现代码与效果
Python OpenCV代码:
代码语言:javascript复制# 导入需要的包
import numpy as np
import cv2
import sys
def color_transfer(source, target):
# 将源图像和目标图像从BGR颜色空间转到Lab颜色通道
# 确保使用OpenCV图像为32位浮点类型数据
source = cv2.cvtColor(source, cv2.COLOR_BGR2LAB).astype("float32")
target = cv2.cvtColor(target, cv2.COLOR_BGR2LAB).astype("float32")
# 计算源图像和目标图像的颜色统计信息(每个通道的均值和标准差)
# L通道均值、标准差,a通道均值、标准差,b通道均值、标准差
(lMeanSrc, lStdSrc, aMeanSrc, aStdSrc, bMeanSrc, bStdSrc) = image_stats(source)
(lMeanTar, lStdTar, aMeanTar, aStdTar, bMeanTar, bStdTar) = image_stats(target)
# 从目标图像中减去均值
(l, a, b) = cv2.split(target)
l -= lMeanTar
a -= aMeanTar
b -= bMeanTar
# 按标准差缩放(scale_rate = 目标图像标准差/源图像标准差)
l = (lStdTar / lStdSrc) * l
a = (aStdTar / aStdSrc) * a
b = (bStdTar / bStdSrc) * b
# 加入源图像对应通道的均值
l = lMeanSrc
a = aMeanSrc
b = bMeanSrc
# 如果像素强度超出范围,则将像素强度剪裁为[0, 255]范围
l = np.clip(l, 0, 255)
a = np.clip(a, 0, 255)
b = np.clip(b, 0, 255)
# 将通道合并在一起并转换回BGR颜色空间,确保确保使用 8 位无符号整数数据类型
transfer = cv2.merge([l, a, b])
transfer = cv2.cvtColor(transfer.astype("uint8"), cv2.COLOR_LAB2BGR)
# 返回颜色迁移后的图像
return transfer
def image_stats(image):
# 计算每个通道的均值和标准差
(l, a, b) = cv2.split(image)
(lMean, lStd) = (l.mean(), l.std())
(aMean, aStd) = (a.mean(), a.std())
(bMean, bStd) = (b.mean(), b.std())
# 返回颜色统计信息
return (lMean, lStd, aMean, aStd, bMean, bStd)
if __name__ == '__main__':
src = cv2.imread('./0.jpg')
target = cv2.imread('./2.jpg')
if src is None or target is None:
print('图像加载失败,请检查图片路径!')
else:
cv2.imshow('src',src)
cv2.imshow('target', target)
dst = color_transfer(src, target)
cv2.imshow('result', dst)
cv2.waitKey()
cv2.destroyAllWindows()
运行效果:
用PyQt5加个UI,选择自己的图片进行测试:
处理前:
处理后: