前言
前段时间,在深度学习领域不是有个比较火的方向叫风格迁移的嘛,对于我这种不喜欢深度学习那种不稳定结果的人来说,还是想看看传统图像处理领域有什么类似的技术,发现了一个颜色迁移的算法,很久前的论文了。
国际惯例,参考博客:
- 原论文《color transfer between images》
- 大佬的python实现
- 大佬的matlab实现
- 知乎解析《Color transfer between images》
理论与对应代码复现
这篇文章的用途在于:利用一张图片的颜色去矫正领一张图片,比如你在昏暗的场景下拍了一张图,但是你发现有一张类似的图颜色非常好,你就可以用这个颜色好的图去矫正你拍的这张昏色图。
正如之前所写的关于颜色协调模型的博客一样,这篇论文也是在某种颜色空间去调整色彩,这个颜色空间通常要求正交化,即更改某个颜色,不会影响到其它属性。颜色协调模型使用的HSV
颜色空间,而这篇色彩迁移的论文则是使用了LαβL\alpha \betaLαβ空间。都不使用RGB
颜色空间的原因就是它并非正交化空间,作者观察到,当蓝色通道值比较大的时候,红色和绿色通道值也很大,由此证明RGB
是互相影响的。
RGB转换为lab方法
lαβl\alpha\betalαβ颜色空间最小化了各通道之间的联系,而且这个颜色空间是对数空间,意味着一阶近似值即通道强度变化同样能够被检测到。
文章介绍了一种方法通过LMS
锥形空间,将RGB
颜色转换到lαβl\alpha\betalαβ颜色空间。
将RGB
转换到LMS
空间包括两个步骤:
-
将
RGB
转换为XYZ三刺激值(tristimulus values
)
注:关于这个tristimulus values
网上有介绍,也是代表图像颜色的三个主分量Tristimulus system, a system for visually matching a colour under standardized conditions against the three primary colours—red, green, and blue; the three results are expressed as X, Y, and Z, respectively, and are called tristimulus values.
作者基于
XYZitu601-1 (D65)
转换标准,做了一次优化,使得转换矩阵的每行加和为1,这一小步骤的公式表示为
[XYZ]=[0.51410.32390.16040.26510.67020.06410.02410.12880.8444][RGB]\begin{bmatrix} X\\Y\\Z \end{bmatrix}= \begin{bmatrix} 0.5141& 0.3239& 0.1604\\ 0.2651& 0.6702& 0.0641\\ 0.0241& 0.1288& 0.8444 \end{bmatrix}\begin{bmatrix} R\\G\\B \end{bmatrix} ⎣⎡XYZ⎦⎤=⎣⎡0.51410.26510.02410.32390.67020.12880.16040.06410.8444⎦⎤⎣⎡RGB⎦⎤ -
获取到
XYZ
值以后,直接利用下式转换到LMS
空间
[LMS]=[0.38970.6890−0.0787−0.22981.18340.04640.00000.00001.0000][XYZ]\begin{bmatrix} L\\M\\S \end{bmatrix}= \begin{bmatrix} 0.3897& 0.6890& -0.0787\\ -0.2298& 1.1834& 0.0464\\ 0.0000& 0.0000& 1.0000 \end{bmatrix}\begin{bmatrix} X\\Y\\Z \end{bmatrix} ⎣⎡LMS⎦⎤=⎣⎡0.3897−0.22980.00000.68901.18340.0000−0.07870.04641.0000⎦⎤⎣⎡XYZ⎦⎤
最终这一步使用公式表示就很简单了,上面两个矩阵相乘,然后取个对数代表对数空间:
[LMS]=log{[0.38110.57830.04020.19670.72440.07820.02410.12880.8444][RGB]}\begin{bmatrix} L\\M\\S \end{bmatrix}=\log\left\{ \begin{bmatrix} 0.3811& 0.5783& 0.0402\\ 0.1967& 0.7244& 0.0782\\ 0.0241& 0.1288& 0.8444 \end{bmatrix}\begin{bmatrix} R\\G\\B \end{bmatrix}\right\} ⎣⎡LMS⎦⎤=log⎩⎨⎧⎣⎡0.38110.19670.02410.57830.72440.12880.04020.07820.8444⎦⎤⎣⎡RGB⎦⎤⎭⎬⎫
接下来作者所说的Ruderman
介绍了LMS
到lαβl\alpha\betalαβ空间的转换方法
[lαβ]=[130001600012][11111−21−10][LMS]\begin{bmatrix} l\\\alpha\\\beta \end{bmatrix}= \begin{bmatrix} \frac{1}{\sqrt3}& 0& 0\\ 0& \frac{1}{\sqrt6}& 0\\ 0& 0& \frac{1}{\sqrt2} \end{bmatrix}\begin{bmatrix} 1& 1& 1\\ 1& 1& -2\\ 1& -1& 0 \end{bmatrix}\begin{bmatrix} L\\M\\S \end{bmatrix} ⎣⎡lαβ⎦⎤=⎣⎢⎡310006100021⎦⎥⎤⎣⎡11111−11−20⎦⎤⎣⎡LMS⎦⎤
作者说如果将LMS分别当做红绿蓝,那么lll代表消色差通道(achromatic channel
),β\betaβ代表黄蓝通道,β\betaβ代表红绿通道。
代码实现如下:
def RGB2LAB(rgb):# RGB to LMScvt_mat = np.array([[0.3811,0.5783,0.0402],[0.1967,0.7244,0.0782],[0.0241,0.1288,0.8444]])lms = np.zeros_like(rgb)for i in range(rgb.shape[0]):for j in range(rgb.shape[1]):lms[i,j,...] = np.dot(cvt_mat,rgb[i,j,...])lms[lms==0]=1lms = np.log10(lms)# LMS to lablms_lab_mat1 = np.array([[1.0/np.sqrt(3.0),0,0],[0,1.0/np.sqrt(6.0),0],[0,0,1.0/np.sqrt(2.0)]])lms_lab_mat2 = np.array([[1,1,1],[1,1,-2],[1,-1,0]])lms_lab_mat = np.dot(lms_lab_mat1 , lms_lab_mat2)lab = np.zeros_like(lms)for i in range(lms.shape[0]):for j in range(lms.shape[1]):lab[i,j,...] = np.dot(lms_lab_mat,lms[i,j,...])return lab
颜色迁移
这一步就不用公式写了,具体意思就是先将源图像的均值和方差变换到目标颜色图像的均值和方差;就纯数学的方法;分两步:
- 源图像的lαβl\alpha\betalαβ分别进行零均值和单位方差化
- 然后归一化后的原图像各通道乘以目标色图像的lαβl\alpha\betalαβ各通道方差,再加上目标色图像的lαβl\alpha\betalαβ各通道均值
这样新的源图像的均值和方差就是目标色图像的均值和方差了。
代码实现如下:
def shift_channel(sc,dc):# dst image's color to soure images_mean = np.mean(sc)d_mean = np.mean(dc)s_std = np.std(sc)d_std = np.std(dc)shift_sc = (sc-s_mean)/s_std * d_std + d_meanreturn shift_sc
lab转换回RGB
这一步作者没做过多说明,直接给出了两个式子
[LMS]=10[11111−11−20][330006600022][lαβ]\begin{bmatrix} L\\M\\S \end{bmatrix}= 10^{ \begin{bmatrix} 1& 1& 1\\ 1& 1& -1\\ 1& -2& 0 \end{bmatrix} \begin{bmatrix} \frac{\sqrt3}{3}& 0& 0\\ 0& \frac{\sqrt6}{6}& 0\\ 0& 0& \frac{\sqrt2}{2} \end{bmatrix}\begin{bmatrix} l\\\alpha\\\beta \end{bmatrix}} ⎣⎡LMS⎦⎤=10[11111−21−10]⎣⎢⎡330006600022⎦⎥⎤[lαβ]
[RGB]=[4.4679−3.58730.1193−1.21862.3809−0.16240.0497−0.24391.2045][LMS]\begin{bmatrix} R\\G\\B \end{bmatrix}= \begin{bmatrix} 4.4679& -3.5873& 0.1193\\ -1.2186& 2.3809& -0.1624\\ 0.0497& -0.2439& 1.2045 \end{bmatrix}\begin{bmatrix} L\\M\\S \end{bmatrix} ⎣⎡RGB⎦⎤=⎣⎡4.4679−1.21860.0497−3.58732.3809−0.24390.1193−0.16241.2045⎦⎤⎣⎡LMS⎦⎤
直接在代码里面码公式就行了。
代码实现如下:
def LAB2RGB(lab):#lab to lmslab_lms_mat1 = np.array([[1,1,1],[1,1,-1],[1,-2,0]])lab_lms_mat2 = np.array([[np.sqrt(3.0)/3.0,0,0],[0,np.sqrt(6.0)/6.0,0],[0,0,np.sqrt(2.0)/2.0]])lab_lms_mat = np.dot(lab_lms_mat1,lab_lms_mat2)lms = np.zeros_like(lab)for i in range(lab.shape[0]):for j in range(lab.shape[1]):lms[i,j,...] = np.dot(lab_lms_mat,lab[i,j,...])lms = 10**lms# lms to rgb lms_rgb_mat = np.array([[4.4679,-3.5873,0.1193],[-1.2186,2.3809,-0.1624],[0.0497,-0.2439,1.2045]])rgb = np.zeros_like(lms)for i in range(lms.shape[0]):for j in range(lms.shape[1]):rgb[i,j,...] = np.dot(lms_rgb_mat,lms[i,j,...])rgb = np.clip(rgb,0.0,1.0)return rgb
最终效果如图所示:
后记
继颜色协调模型后的又一篇好玩的关于图像处理的论文复现。
完整的python
脚本实现放在微信公众号的简介中描述的github中,有兴趣可以去找找,同时文章也同步到微信公众号中,有疑问或者兴趣欢迎公众号私信。