Super fast color transfer between images(图像色彩转换)
translator:aaron-clark-aic
图像转换算法
-
步骤一:输入源图像和目标图像,源图像包含有你想要目标图像上展示的色彩空间。
-
步骤二:将源图像和目标图像都转换为Lab色彩空间。
source = cv.cvtColor(source, cv.COLOR_BGR2LAB).astype("float32") target = cv.cvtColor(target, cv.COLOR_BGR2LAB).astype("float32")
-
步骤三:分割源图像和目标图像的色彩通道。
(l, a, b) = cv.split(target)
-
步骤四:计算两幅图Lab色彩空间每个通道的均值和标准差。
# compute the mean and standard deviation of each channel (l, a, b) = cv.split(image) (lMean, lStd) = (l.mean(), l.std()) (aMean, aStd) = (a.mean(), a.std()) (bMean, bStd) = (b.mean(), b.std())
-
步骤五:目标图像减去目标图像的lab每个通道的均值。
#5 subtract the means from the target image (l, a, b) = cv.split(target) l -= lMeanTar a -= aMeanTar b -= bMeanTar
-
步骤六:按照比例混合色彩通道
#5 subtract the means from the target image (l, a, b) = cv.split(target) l -= lMeanTar a -= aMeanTar b -= bMeanTar #6 scale by the standard deviations l = (lStdTar / lStdSrc) * l a = (aStdTar / aStdSrc) * a b = (bStdTar / bStdSrc) * b
-
步骤七:添加源图像的通道均值到目标图像中
#5 subtract the means from the target image (l, a, b) = cv.split(target) l -= lMeanTar a -= aMeanTar b -= bMeanTar #6 scale by the standard deviations l = (lStdTar / lStdSrc) * l a = (aStdTar / aStdSrc) * a b = (bStdTar / bStdSrc) * b #7 add in the source mean l += lMeanSrc a += aMeanSrc b += bMeanSrc
-
步骤八:过滤掉超过[0,255]范围的值
# clip the pixel intensities to [0, 255] if they fall outside # this range l = np.clip(l, 0, 255) a = np.clip(a, 0, 255) b = np.clip(b, 0, 255)
-
步骤九:合并通道
# merge the channels together and convert back to the RGB color # space, being sure to utilize the 8-bit unsigned integer data # type transfer = cv.merge([l, a, b])
-
步骤十:转换Lab色彩空间到RGB
# merge the channels together and convert back to the RGB color # space, being sure to utilize the 8-bit unsigned integer data # type transfer = cv.merge([l, a, b]) transfer = cv.cvtColor(transfer.astype("uint8"), cv.COLOR_LAB2BGR)
完整代码
# import the necessary packages
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
def color_transfer(source, target):
# convert the images from the RGB to L*ab* color space, being
# sure to utilizing the floating point data type (note: OpenCV
# expects floats to be 32-bit, so use that instead of 64-bit)
source = cv.cvtColor(source, cv.COLOR_BGR2LAB).astype("float32")
target = cv.cvtColor(target, cv.COLOR_BGR2LAB).astype("float32")
# compute color statistics for the source and target images
(lMeanSrc, lStdSrc, aMeanSrc, aStdSrc, bMeanSrc, bStdSrc) = image_stats(source)
(lMeanTar, lStdTar, aMeanTar, aStdTar, bMeanTar, bStdTar) = image_stats(target)
# subtract the means from the target image
(l, a, b) = cv.split(target)
l -= lMeanTar
a -= aMeanTar
b -= bMeanTar
# scale by the standard deviations
l = (lStdTar / lStdSrc) * l
a = (aStdTar / aStdSrc) * a
b = (bStdTar / bStdSrc) * b
# add in the source mean
l += lMeanSrc
a += aMeanSrc
b += bMeanSrc
# clip the pixel intensities to [0, 255] if they fall outside
# this range
l = np.clip(l, 0, 255)
a = np.clip(a, 0, 255)
b = np.clip(b, 0, 255)
# merge the channels together and convert back to the RGB color
# space, being sure to utilize the 8-bit unsigned integer data
# type
transfer = cv.merge([l, a, b])
transfer = cv.cvtColor(transfer.astype("uint8"), cv.COLOR_LAB2BGR)
# return the color transferred image
return transfer
def image_stats(image):
# compute the mean and standard deviation of each channel
(l, a, b) = cv.split(image)
(lMean, lStd) = (l.mean(), l.std())
(aMean, aStd) = (a.mean(), a.std())
(bMean, bStd) = (b.mean(), b.std())
# return the color statistics
return (lMean, lStd, aMean, aStd, bMean, bStd)
image_source = cv.imread(".././img/source.jpg")
image_target = cv.imread(".././img/target.jpg")
image_transfer = color_transfer(image_source,image_target)
fig = plt.figure()
ax = fig.add_subplot(131)
ax.set_title("source")
ax.imshow(image_source[:,:,[2,1,0]])
ax = fig.add_subplot(132)
ax.set_title("target")
ax.imshow(image_target[:,:,[2,1,0]])
ax = fig.add_subplot(133)
ax.set_title("transfer")
ax.imshow(image_transfer[:,:,[2,1,0]])
plt.show()
cv.waitKey(0)