天天看点

使用Python,OpenCV实现图像之间超快速的颜色转移

图像之间超快速的颜色转移

    • 1. 效果图
    • 2. 步骤
    • 3. 改进算法的方法
    • 4. 源码
    • 参考
目标:源图像与目标图像,转移源图像的色彩空间到目标图像,生成一张新的图像;

有关如何在两个图像之间转移颜色,有俩种方式,

  • (1)基于直方图的方法,该方法旨在平衡三种“类型”的颜色:相等,过多和不足。 该方法获得了良好的结果-但以速度为代价。使用此算法将要求您对源图像中的每个像素执行查找,这将随着图像尺寸的增加而变得非常昂贵。
  • (2)仅使用图像通道的均值和标准差的颜色转移算法。没有复杂的代码。没有计算直方图。只是简单的统计……这种方法甚至可以轻松处理巨大的图像。

1. 效果图

输入源图像和目标图像。源图像包含期待目标图像模仿的色彩空间。

在下图中,左侧的蓝色梦幻水母是我的源,中间的红色水母是我的目标图像,而右侧的图像是将左图色彩应用于目标图像的色彩空间。

2019年中秋节青岛海洋世界里拍的水母图,把梦幻的蓝色(左图)应用于目标烈焰红(中间图),合成独特的水母“红”(右边图);

使用Python,OpenCV实现图像之间超快速的颜色转移

水母2:左图的色彩应用于目标图梦幻的水母图,得到右边的结果图(有点像拍出来的骨片的色彩);

使用Python,OpenCV实现图像之间超快速的颜色转移

水母转换图3:左图 + 中间图 = 右图(结果是比较仙的浅紫色~~~)

使用Python,OpenCV实现图像之间超快速的颜色转移

2. 步骤

  1. 输入来源和目标图像。源图像包含您希望目标图像模仿的色彩空间。在此页顶部的图中,左侧的水母图像是我的源,中间的图像是我的目标,而右侧的图像是应用到目标的源的色彩空间。
  2. 将源图像和目标图像都转换为L * a * b *颜色空间。 L * a * b *颜色空间模拟了感知均匀性,其中颜色值的微小变化也应该在颜色重要性上产生相对相等的变化。与标准RGB颜色空间相比,L * a * b *颜色空间在模仿人类如何解释颜色方面做得好得多,并且您将看到,它在颜色转移方面效果很好。
  3. 分割源和目标图像的颜色通道值。
  4. 为源图像和目标图像计算每个L * a * b *通道的平均值和标准差。
  5. 从目标通道中减去目标图像的L * a * b *通道的平均值。
  6. 按目标的标准偏差除以源的标准偏差再乘以目标通道的比例来缩放目标通道。
  7. 为源图像添加L * a * b 通道的均值。
  8. 裁剪掉[0,255]范围之外的所有值。
  9. 将通道颜色值合并在一起。
  10. 从L * a * b 空间转换回RGB颜色空间。

3. 改进算法的方法

该算法非常快,有一个缺点——它依赖于全局颜色统计信息,因此像素强度值相似的大区域会极大地影响平均值(进而影响总体颜色传递)。

为了解决这个问题,有两个解决方案:

  • (1)计算要模拟颜色的较小关注区域(ROI)中的源图像的均值和标准偏差,而不是使用整个图像。采用这种方法将使您的均值和标准差更好地表示您要使用的色彩空间。
  • (2)将k均值应用于两个图像。可以在L * a * b *颜色空间中的每个图像的像素强度上聚类,然后使用欧几里德距离确定最相似的两个图像之间的质心。

    然后,仅计算每个区域内的统计信息。同样,这将使您的平均数和标准差更具“局部”效果,并有助于减轻全局统计数据的过分表达问题。当然,缺点是这种方法的速度要慢得多,因为添加了昂贵的聚类步骤。

4. 源码

用到了 color_transfer模块的方法,可通过 pip install color_transfer 安装
# USAGE
# python example.py --source images/01.jpg --target images/02.jpg -o images/01_02.jpg

import argparse

import cv2
# 导入必要的类
from color_transfer import color_transfer


def show_image(title, image, width=300):
    # resize图像以使得图像具有固定的大小,以便整个屏幕都可以展示
    r = width / float(image.shape[1])
    dim = (width, int(image.shape[0] * r))
    resized = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)

    # 展示缩放后的图像
    cv2.imshow(title, resized)

# 构建命令行参数及解析
# --source 源图像
# --target 目标图像
# --output 是否输出转换后的图像,此为其路径
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")
ap.add_argument("-o", "--output", help="Path to the output image (optional)")
args = vars(ap.parse_args())

# 加载图像
source = cv2.imread(args["source"])
target = cv2.imread(args["target"])

# 转移源图像的色彩分配 到 目标图像
transfer = color_transfer(source, target)

# 检测是否保存输出图像
if args["output"] is not None:
    cv2.imwrite(args["output"], transfer)

# 展示图像
show_image("Source", source)
show_image("Target", target)
show_image("Transfer", transfer)
cv2.waitKey(0)
           

参考

  • https://www.pyimagesearch.com/2014/06/30/super-fast-color-transfer-images/

继续阅读