一、什么是风格迁移?
所谓的迁移比较简单,即输入包含两个图片,一张source图片,一张target图片,风格迁移的目的是将source图片上面的色彩迁移到target图像中,从而形成一张新的图片,它在现实场景中具有较多的应用,比较经典的应用是手机照相机中的滤镜。下面展示了一张样例图片。
二、风格迁移算法实现步骤
- 步骤1-输入source和target图像。源图像包含希望目标图像模拟的颜色空间。在上面的实例中,左侧的日落图像是源图像,中间的图像是目标图像,右侧的图像是应用于目标的源的颜色空间;
- 步骤2-将source图像和target图像转换为LAB*颜色空间。LAB颜色空间模型的感知均匀性,其中少量的颜色值变化也应产生相对相等的颜色重要性变化。LAB颜色空间在模仿人类如何解释颜色方面比标准的RGB颜色空间做得更好,正如您将要看到的,它在颜色转换方面具有很好的效果;
- 步骤3-将source图像和target图像的通道划分开来;
- 步骤4-计算source图像和target图像的每个LAB*通道的平均值和标准偏差;
- 步骤5-从目标通道中减去目标图像的LAB*通道的平均值;
- 步骤6-按目标图像的标准偏差除以源图像的标准偏差,再乘以目标通道的比例缩放目标通道;
- 步骤7-加上source图像的LAB*通道的均值;
- 步骤8-将处理后的值变换到[0,255]的范围内;
- 步骤9-将source图像和target图像的通道合并起来;
- 步骤10-从LAB颜色空间变换回RGB空间。
三、风格迁徙算法代码实现
# coding=utf-8
# 导入python包
import cv2
import argparse
import numpy as np
def color_transfer(source, target):
# 从RGB空间转换到LAB空间中
source = cv2.cvtColor(source, cv2.COLOR_BGR2LAB).astype("float32")
target = cv2.cvtColor(target, cv2.COLOR_BGR2LAB).astype("float32")
# 计算source和target图像的统计信息,即均值和方差等
(lMeanSrc, lStdSrc, aMeanSrc, aStdSrc, bMeanSrc, bStdSrc) = image_stats(source)
(lMeanTar, lStdTar, aMeanTar, aStdTar, bMeanTar, bStdTar) = image_stats(target)
# 将目标图像的L、a、b通道划分开来并减去对应的均值
(l, a, b) = cv2.split(target)
l -= lMeanTar
a -= aMeanTar
b -= bMeanTar
# 分别对L、a、b通道进行标准化操作
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)
# 将L、a、b通道合并起来并将其转化回RGB颜色空间
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__':
ap = argparse.ArgumentParser()
ap.add_argument("-s", "--source", required = True, help = "Path to the source image")
ap.add_argument("-t", "--target", required = True, help = "Path to the target image")
args = vars(ap.parse_args())
source = cv2.imread(args["source"])
target = cv2.imread(args["target"])
taransform = color_transfer(source, target)
source1 = cv2.resize(source, target.shape[0:2])
target1 = cv2.resize(target, target.shape[0:2])
taransform1 = cv2.resize(taransform, target.shape[0:2])
result = np.hstack([source1, target1, taransform1])
cv2.imwrite("transform4.png", result)
cv2.imshow("transform", result)
cv2.waitKey(0)
四、代码运行流程
- 步骤1-打开一个cmd界面;
- 步骤2-cd /d xxx 切换到代码所在的路径,xxx表示代码的具体路径;
- 步骤3-python color_transform.py -s source.jpg -t target.jpg 执行代码,默认会保存结果到当前路径中。
五、风格迁徙算法效果展示与分析
上图展示了该算法的风格迁移效果。每一行表示一个测试样本,第1行表示的是source图像,其主要提供色彩空间信息;第2列表示的是target图像,其主要提供内容;第3列表示风格迁徙的结果,即将source的风格迁徙到target中,形成了一幅新的图像,这个效果其实就类似于美颜工具中的滤镜,哈哈,看了这篇文章你也能自己开发一个自己的滤镜库啦。
六、思维扩展
该算法是思路是2001年提出的,整个算法具有速度快和效果好的优点,该算法具有一个缺点,即它依赖于全局颜色统计,因此具有相似像素强度值的大区域会显著影响平均值(从而影响整体颜色传递)。为了很好的解决这个缺点,我们可以从以下的两个方面进行改进。
- 改进思路1-计算源图像在一个较小的感兴趣区域(ROI)中的平均值和标准偏差,你希望模拟其颜色,而不是使用整个图像。采用这种方法将使您的平均值和标准偏差更好地表示您想要使用的颜色空间。
- 改进思路2-将k-均值聚类算法应用到这两个图像中。你可以对LAB*颜色空间中每个图像的像素强度进行聚类,然后使用欧几里得距离确定两个图像之间最相似的质心。然后只计算每个区域内的统计信息。同样,这将使平均值和标准偏差产生更“局部”的影响,并有助于缓解全球统计数据的过度表示问题。当然,缺点是这种方法明显较慢,因为你现在已经添加了一个昂贵的集群步骤。
参考资料
注意事项
[1] 如果您对AI、自动驾驶、AR、ChatGPT等技术感兴趣,欢迎关注我的微信公众号“AI产品汇”,有问题可以在公众号中私聊我!
[2] 该博客是本人原创博客,如果您对该博客感兴趣,想要转载该博客,请与我联系(qq邮箱:1575262785@qq.com),我会在第一时间回复大家,谢谢大家的关注.
[3] 由于个人能力有限,该博客可能存在很多的问题,希望大家能够提出改进意见。
[4] 如果您在阅读本博客时遇到不理解的地方,希望您可以联系我,我会及时的回复您,和您交流想法和意见,谢谢。
[5] 本文测试的图片可以通过关注微信公众号AI产品汇之后找我索取!
[6] 本人业余时间承接各种本科毕设设计和各种小项目,包括图像处理(数据挖掘、机器学习、深度学习等)、matlab仿真、python算法及仿真等,有需要的请加QQ:1575262785详聊!!!