转自知乎:https://zhuanlan.zhihu.com/p/267832794,仅供学习。
利用一张图片的颜色去修改另一张图片的颜色风格。
原理是利用颜色空间的正交化
,即更改某个颜色,不会影响到其它属性。这里的色彩迁移的论文则是使用了LAB空间
(RGB颜色空间是非正交化空间
)。
这里使用python3.7.6+opencv4.4.0实现。
选用优化后的算法效率提升很大。
img=cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
图像的均值和方差
:(1) : 源图像的LAB分别进行零均值和单位方差化
x_mean, x_std = cv2.meanStdDev(img)
x_mean = np.hstack(np.around(x_mean, 2))
x_std = np.hstack(np.around(x_std, 2))
(2) 然后归一化后的原图像各通道乘以目标色图像的LAB各通道方差,再加上目标色图像的LAB各通道均值
height, width, channel = img.shape
for i in range(0, height):
for j in range(0, width):
for k in range(0, channel):
x = sc[i, j, k]
x = ((x - s_mean[k]) * (t_std[k] / s_std[k])) + t_mean[k]
# round or +0.5
x = round(x)
# boundary check
x = 0 if x < 0 else x
x = 255 if x > 255 else x
sc[i, j, k] = x
(3).最后再将图像转换为RGB格式:
cv2.cvtColor(res, cv2.COLOR_LAB2BGR)
下面演示颜色迁移效果:
def get_mean_and_std(img):
x_mean, x_std = cv2.meanStdDev(img)
x_mean = np.hstack(np.around(x_mean, 2))
x_std = np.hstack(np.around(x_std, 2))
return x_mean, x_std
def color_transfer(sc, dc):
sc = cv2.cvtColor(sc, cv2.COLOR_BGR2LAB)
s_mean, s_std = get_mean_and_std(sc)
dc = cv2.cvtColor(dc, cv2.COLOR_BGR2LAB)
t_mean, t_std = get_mean_and_std(dc)
height, width, channel = sc.shape
for i in range(0, height):
for j in range(0, width):
for k in range(0, channel):
x = sc[i, j, k]
x = ((x - s_mean[k]) * (t_std[k] / s_std[k])) + t_mean[k]
# round or +0.5
x = round(x)
# boundary check
x = 0 if x < 0 else x
x = 255 if x > 255 else x
sc[i, j, k] = x
dst = cv2.cvtColor(sc, cv2.COLOR_LAB2BGR)
return dst
sc = cv2.imread("sc.bmp", 1)
dc = cv2.imread("sc.bmp", 1)
dst = color_transfer(sc, dc)
cv2.imshow("dst", dst)
cv2.waitKey()
后由小伙伴优化了算法,经测试速度灰常快,感谢这位小伙伴:
import cv2
import numpy as np
import time
def get_mean_and_std(img):
x_mean, x_std = cv2.meanStdDev(img)
x_mean = np.hstack(np.around(x_mean, 2))
x_std = np.hstack(np.around(x_std, 2))
return x_mean, x_std
def color_transfer(sc, dc):
sc = cv2.cvtColor(sc, cv2.COLOR_BGR2LAB)
s_mean, s_std = get_mean_and_std(sc)
dc = cv2.cvtColor(dc, cv2.COLOR_BGR2LAB)
t_mean, t_std = get_mean_and_std(dc)
img_n = ((sc-s_mean)*(t_std/s_std))+t_mean
np.putmask(img_n, img_n > 255, 255)
np.putmask(img_n, img_n < 0, 0)
dst = cv2.cvtColor(cv2.convertScaleAbs(img_n), cv2.COLOR_LAB2BGR)
return dst
sc = cv2.imread("s1.bmp", 1)
dc = cv2.imread("t1.jpg", 1)
dst = color_transfer(sc, dc)
cv2.imshow("dst", dst)
cv2.waitKey()
参考大佬的python源代码:https://github.com/chia56028/Co