最近遇到了一个需求,就是对图片进行色彩风格转换,让一个物体可以以各种不同的色彩来呈现。

比如一个红色的苹果,我想把它转化成绿色,这可怎么办呢?本来想的解决方案是先识别边界,然后对边界内区域进行色彩替换或者填充,这样整个流程就分成了两步,首先需要进行边界判断,有了边界之后才能对某些区域颜色进行替换填充,填充的区域还是不规则的,填充的颜色也需要根据实际的情况来变化,同时还要兼顾阴影、高光等等的处理,想想真是头大。

然后我就突然想到了之前学 PS 的时候,曾经做过对某一张图片进行色调替换,我还记得当时调的内容是「色相」,通过调节这个值可以实现各种色调的转换。这之后我就心想,能不能用程序来做这件事呢?

于是我就开始了对图像色彩的一些研究,研究完了之后就实现了用 Python 来更换图片色调的功能,将这篇文章顺便记录下来。

先给大家看看效果吧,就比如我从百度上随便搜一张图,比如热气球吧,是这样子:

原图

我把它转成红色、黄色、蓝色、紫色,基本就是这个样子:

红色风格

黄色风格

绿色图片

蓝色图片

这里的图片都是经过 Python 自动转换算法实现的,主要调节的就是色相。其实代码实现是比较简单的,但在实现之前需要了解一些图像色彩知识。了解了这些之后我们再实现才会更加游刃有余。

下面我们就首先来了解一下图像色彩的基本知识,然后用 Python 实现色调转换算法吧。

RGB

首先让我们来了解下颜色的三原色,RGB。

RGB,其实就是三种颜色,分别代表红色(Red)、绿色(Green)、蓝色(Blue),用这三种原色颜色混合可以表示任意的颜色。RGB 是根据颜色发光的原理来设计的,比如这里有红绿蓝三道光,当三束光混合在一起的时候,其呈现的最终的光效颜色就取决于这三种原色光的强弱了。

• 比如说红光最强,绿光和蓝光几乎没有,那么最后结果肯定呈现为红光了。 • 如果蓝光很弱,红光和绿光非常强,那么结果就是红光和绿光的混合光,也就黄光。 • 如果红绿蓝三种光都非常强,那么就会呈现三种光的混合光,也就是白光。 • 如果三种光都非常弱,那就几乎没有光,自然就是黑色了。

如果大家了解过 RGB 的一些知识的话,想必也见过这张混合光图:

但是这仅仅是一张平面图,并不能很好地体现三原色的混合关系,大家可以看这张图:

实际上可以对 RGB 色值建立一个三维坐标系,坐标原点就在上图中所看不见的那个正方体顶点,像左延伸为 R 红色轴,向右延伸为 B 蓝色轴,向上延伸为 G 绿色轴。

RGB 在进行色彩表示时使用了 256 阶,也就是从 0-255,可以由一个字节来表示。数值越大,RGB 三个轴,每个轴对应的数值越大,就代表其亮度越高,最亮就对应着 255,最暗就对应着 0。三个轴上的三个数字联合起来可以用来表示一个颜色。

例如:

• (255, 255, 255) 就代表 RGB 都是满的,组成白色。 • (255, 255, 0) 就代表 R 红色是满的,G 绿色是满的,B 蓝色是没有的,红色和绿色混合为黄色,所以它就表示黄色。 • (0, 0, 0) 就代表 RGB 都是没有的,呈现黑色。

因此,通过这三个数值,我们就可以实现任何颜色的表示了。

HSV

但了解了 RGB 显然不能应对我们的需求,它和色相也没有什么关系,所以这里我们还需要研究另外一个颜色模型,叫做 HSV。

HSV,又叫做 HSB,其实也是三个参数,分别是色调(Hue)、饱和度(Saturation)、明度(Brightness),在 HSV 中 V 代表 Value,也是明度的意思。通过这三个值,我们同样可以表示任意的颜色。

首先我们看看 HSV (HSB) 颜色模型的坐标轴图吧,它可以用这么一个锥形的坐标来表示:

色调,Hue,它是一种角度度量,就是图中 Hue 所示的角度,绕圆锥体一周。它的值是从红色开始逆时针方向计算的,红色是 0,绿色是 120,蓝色为 240,形成一个红绿蓝三原色组成的色带。

饱和度,Saturation,它是图中 Saturation 所示的方向,由最上面圆的圆心向外扩散。它表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为 0,饱和度达到最高。通常取值范围为 0-100,值越大,颜色越饱和。也就是说图中,圆心处饱和度为 0,越靠近边,饱和度越高,最高达到 100。

明度,Brightness,它表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关,对于物体色,此值和物体的透射比或反射比有关。通常取值范围为 0-100,0 对应黑色,100 对应白色。

另外大家如果用到取色板的话,它是这样子的:

你可以看到左边有个大的矩形,右边有个竖直的彩虹带。 由于刚才所说的圆锥坐标不好表示,在调色板里面就把圆锥坐标拆成了两部分。

• 右边的彩虹带就可以选择色调 Hue,拖动彩虹带的箭头位置就可以调整 Hue 的值。 • 左边的正方形就和饱和度 Saturation、明度 Brightness 有关,横坐标表示饱和度 Saturation,纵坐标表示 Brightness,从左到右,饱和度 Saturation 变高,从下到上,明度 Brightness 变高。 • 左下角,由于饱和度 Saturation 和明度 Brightness 都为 0,就呈现黑色。 • 左上角,由于饱和度 Saturation 为 0,所以相当于没有颜色,颜色最浅,但是它的明度 Brightness 达到了最高,所以它就显示没有颜色的明度最高的色,即白色。 • 右上角,由于饱和度 Saturation 和明度 Brightness 都为最高,那就显示最纯的 Hue 值。

这也就是 HSB 颜色模型的原理。

同样地,我们可以用 HSB 的三个值来表示任意的颜色,因此 HSB 也成为表示颜色的基本标准之一。

HSB 和 RGB 的转换

HSB 和 RGB 都能表示一个颜色,它们之间也是可以相互转换的,可以一一对应。

他们之间的转换逻辑这里就不再专门对其公式展开详解了,公式总结如下:

RGB to HSB

HSV to RGB

大家如果感兴趣想要研究的话也可以去:https://www.rapidtables.com/convert/color/hsv-to-rgb.html 来了解一下详情,这里还有详细的转换表格以及实时转换实现。

另外对于它们之间的转换算法,很多库都已经封装好了。我们可以直接调用,比如 Python 中的 colorsys 模块,就实现了 rgb_to_hsv 和 hsv_to_rgb 算法,我们也可以直接使用。

色调转换

了解了以上内容之后,我们就可以使用程序来实现色调转换了。相比我们已经知道应该改什么内容了,那就是修改 HSV 中的 H 值,通过不同的 H 值我们就可以将图片转换为不同的色调了。

具体思路是怎样的呢:

• 首先获取图像每个像素的的 RGB 色值。 • 将 RGB 色值转化为 HSV 色值。 • 调整 HSV 色值中的 H。 • 将 HSV 色值转回 RGB 色值。 • 输出图像。

一共就是这么五步,这里的两个转换色值的操作我们就可以借助于 colorsys 模块。另外需要安装一个 pillow 模块:

pip3 install pillow

安装完毕之后,我们准备任意一张图片,然后实现上面的五个步骤。

最终的代码实现如下:

 

import colorsys

from PIL import Image

# 输入文件

filename = 'input.jpg'

# 目标色值

target_hue = 0

# 读入图片,转化为 RGB 色值

image = Image.open(filename).convert('RGB')

# 将 RGB 色值分离

image.load()

r, g, b = image.split()

result_r, result_g, result_b = [], [], []

# 依次对每个像素点进行处理

for pixel_r, pixel_g, pixel_b in zip(r.getdata(), g.getdata(), b.getdata()):

# 转为 HSV 色值

h, s, v = colorsys.rgb_to_hsv(pixel_r / 255., pixel_b / 255., pixel_g / 255.)

# 转回 RGB 色系

rgb = colorsys.hsv_to_rgb(target_hue, s, v)

pixel_r, pixel_g, pixel_b = [int(x * 255.) for x in rgb]

# 每个像素点结果保存

result_r.append(pixel_r)

result_g.append(pixel_g)

result_b.append(pixel_b)

r.putdata(result_r)

g.putdata(result_g)

b.putdata(result_b)

# 合并图片

image = Image.merge('RGB', (r, g, b))

# 输出图片

image.save('output.png')

具体的实现在代码注释里面已经很清楚了。

在这里我们将 target_hue 定义为 0。通过前文我们知道,Hue 为 0 代表红色,120 代表绿色,240 代表蓝色。我们可以自定义 0-355 这 360 个数值,实现不同的色调转换。

如果想输出其他颜色的图片,就把 target_hue 这个值改一下就好了。

看看最后的运行效果,输入是一张原图:

所以最后的输出效果就是如下的结果:

如果将代码中的 target_hue 值进行更改,就会呈现不同的颜色风格了,就像文中开头所示的一样。

比如把飞猪的 Logo 由黄色变为红色,都是可以做到的:

处理透明像素

上面的算法仅仅考虑了 RGB,如果有些图包含了透明像素,上面的程序对于透明像素是无法处理的,最后输出的结果会带有某种颜色的背景。

对于透明像素的处理,我们可以增加一个维度的值,就是 A,即 Alpha 透明度。

所以使用 RGBA 和 HSV 的转换我们就可以实现透明像素的处理了,代码实现如下:

 

import colorsys

from PIL import Image

# 输入文件

filename = 'input.png'

# 目标色值

target_hue = 0

# 读入图片,转化为 RGB 色值

image = Image.open(filename).convert('RGBA')

# 将 RGB 色值分离

image.load()

r, g, b, a = image.split()

result_r, result_g, result_b, result_a = [], [], [], []

# 依次对每个像素点进行处理

for pixel_r, pixel_g, pixel_b, pixel_a in zip(r.getdata(), g.getdata(), b.getdata(), a.getdata()):

# 转为 HSV 色值

h, s, v = colorsys.rgb_to_hsv(pixel_r / 255., pixel_b / 255., pixel_g / 255.)

# 转回 RGB 色系

rgb = colorsys.hsv_to_rgb(target_hue, s, v)

pixel_r, pixel_g, pixel_b = [int(x * 255.) for x in rgb]

# 每个像素点结果保存

result_r.append(pixel_r)

result_g.append(pixel_g)

result_b.append(pixel_b)

result_a.append(pixel_a)

r.putdata(result_r)

g.putdata(result_g)

b.putdata(result_b)

a.putdata(result_a)

# 合并图片

image = Image.merge('RGBA', (r, g, b, a))

# 输出图片

image.save('output.png')

在这里就是增加了对透明像素的处理,在图像 convert 和 merge 的时候都使用 RGBA 模式,就可以保留原有图片中的透明像素了。

以上便是使用 Python 程序自动调整色调的实现。

其他应用

另外对于图像调色的应用还有很多,比如我们可以不直接指定 Hue 的值,而是将 Hue 的值在原来的基础上增加或减少,则可以实现彩虹变色,如:

原图是这样子:

经过处理之后我们可以得到这样的效果:

这样我们使用程序处理出各种风格的好看的照片了,是不是很有意思呢?

一波骚操作,用 Python 给照片换颜色相关推荐

  1. Python骚操作:Python控制Excel实现自动化办公!

    Python骚操作:Python控制Excel实现自动化办公! 1.安装 Python骚操作:Python控制Excel实现自动化办公! 2.操作一个简单的Excel文档 操作注释及代码: Pytho ...

  2. Python骚操作:Python控制Excel实现自动化办公

    点击上方"Python高校",关注 文末干货立马到手 1.安装 2.操作一个简单的Excel文档 操作注释及代码: 操作完成后,数据存储结果如下: 3. 操作简单Excel文档并添 ...

  3. python换照片底色_详解Python给照片换底色(蓝底换红底)

    现在网上出现了很多在线换底色的网页版工具是这么做的呢?其实用Python就可以实现. 环境要求 Python3 numpy函数库 opencv库 安装 下载适应版本的numpy函数库,我电脑是WIN1 ...

  4. 骚操作之Python微信远程控制摄像头!然后嘿嘿嘿!

    盯着电脑工作大半天了,有点疲劳,想想同样苦逼盯着电脑的女朋友,就想逗逗她缓解一下疲劳. 于是一时手痒,开始了新一轮的骚操作,用Python基于itchat实现微信控制电脑打开摄像头拍摄当前电脑的使用者 ...

  5. 这帮吃货程序猿,给阿里食堂来了一波骚操作

    我叫宋爽,在别人眼里,我是一个程序猿. 别的程序猿,喜欢摁键盘,我嘛,就喜欢吃. 有一次,去医院体检,拿到CT片的我,看着自己的脊椎骨,脑子中一直在想:啊!什么时候去吃顿羊蝎子! 身为吃货的我,最近和 ...

  6. python会员折扣_Python骚操作 | 用python爆破某会员网站

    早上照例闲逛,发现简书出了个很有意思的作者,ID叫做爷是奥巴马,发的文章也是不同凡响,上来就对别人家网站玩爆破... -------------------------------- 暑假在家上网,q ...

  7. hle机器人_Theshy败FPX后首玩诺手,踢爆HLE上单!最后一波骚操作扭转定乾坤

    3月3号LPL赛区赛程是IG对阵FPX,两者都是强队,但没想到S8全球总冠军队伍竟然被FPX打败了,让一追二!在第二场比赛中,Theshy突发奇想,自信的锁下诺手!但被对面打野疯狂针对,自身不但没有打 ...

  8. mysql中in查询效率低的替代方法_一波骚操作,我把 SQL 执行效率提高了 10,000,000 倍...

    场景 我用的数据库是mysql5.6,下面简单的介绍下场景 课程表: 数据100条 学生表: 数据70000条 学生成绩表SC 数据70w条 查询目的:查找语文考100分的考生 查询语句: selec ...

  9. 骚操作!Python查看微信共同好友

    点击上方"涛哥聊Python",选择"星标"公众号 重磅干货,第一时间送达 来源:TEDxPY 总有思路清奇的朋友存在,想实现查看微信共同好友: 由于之前分享的 ...

最新文章

  1. 2017年5个最佳网络监控工具 你知道哪些
  2. Oracle11G_逻辑备份
  3. linux java多线程_Java多线程从简单到复杂
  4. php $_server[remote_addr];,php – 如何伪造$_SERVER [‘REMOTE_ADDR’]变量?
  5. Flink本地安装教程
  6. 音视频编解码技术(二):AAC 音频编码技术
  7. MYMPS蚂蚁分类信息系统源码,5.9E多城市全开源版本
  8. linux centos无线网卡驱动安装,CentOS 无线网卡驱动安装
  9. 三月主题读书整理——整理收纳,过心动生活
  10. Arduino小白的学习历程
  11. 数据仓库之数据及预处理
  12. js中的设计模式之中介者模式
  13. PostGreSQL语法及高级功能(2022-06-08补充中)
  14. Flume-----八种采集方案
  15. JavaScript代码压缩工具UglifyJS和Google Closure Compiler的基本用法
  16. C# 高级开发应用:GPS+北斗 antenna 实现精准定位 C#实现
  17. mysql 查询当前时间一个月以内的数据
  18. 外贸轻工工艺行业管理解决方案丨汇信
  19. 算法创作|质数计数问题解决方法
  20. Win11桌面贴纸功能怎么开启?

热门文章

  1. 飞机绕地飞行一周问题
  2. 几组数据的相关性python_属狗的几月出生最好
  3. 自学SpringBoot之国际化配置相关的坑
  4. 编程基础 二进制 解密
  5. day_29 HTML基础
  6. 基于模型预测人工势场的船舶运动规划方法,考虑复杂遭遇场景下的COLREG(Matlab代码实现)
  7. zan-ajax的使用方式
  8. 拙作《Delphi精要》目录,即将由电子工业出版社出版 (转)
  9. (五)汇编实现流水灯
  10. RabbitMQ 通俗易懂 简单开发(一)