介绍

在介绍颜色空间转换之前,先来介绍一下什么是颜色空间。

颜色空间指的是组织颜色的特定方式。我们知道,一种颜色可以由 红、绿、蓝 三种颜色组合出来,这里的 红、绿、蓝 三原色就是一种颜色模型。而这种由三原色组织颜色的方法就是一种颜色空间。任何一种颜色,在颜色空间中,都可以通过一个函数表示出来,在 RGB 模型中,函数的参数就是 R、G、B 三原色。

当然,同一种颜色,在不同的颜色空间中,由于侧重点不同,表现出来的色彩是不一样的。通常的图片是采用的 RGB 三原色来表示的,所以,现在,我们的目的就是将同一幅图片转换成用其他颜色空间来表示。

这篇文章中一共有四张颜色空间的转换:

  • RGB -> YIQ
  • RGB -> HSI
  • RGB -> YCbCr
  • RGB -> XYZ

颜色空间转换的算法及流程

RGB -> YIQ :

先来介绍一下 YIQ 这个颜色空间,百度百科:

YIQ色彩空间属于NTSC系统。这里Y是指颜色的明视度,即亮度。其实Y就是图像灰度值,I和Q都指的是指色调,即描述图像色彩与饱和度的属性。YIQ颜色空间具有能将图像中的亮度分量分离提取出来的优点,并且YIQ颜色空间与RGB颜色空间之间是线性变换的关系,计算量小,聚类特性也比较好,可以适应光照强度不断变化的场合。

首先,需要将读取的 R,G,B 分量进行归一化,归一到 [0,1][0,1][0,1] 区间,然后再利用下面的公式进行计算:

[YIQ]=[0.2990.5870.1140.596−0.274−0.3220.211−0.5230.312][RGB]\begin{bmatrix} Y \\ I \\ Q \\ \end{bmatrix} = \begin{bmatrix} 0.299 & 0.587 & 0.114 \\ 0.596 & -0.274 & -0.322 \\ 0.211 & -0.523 & 0.312 \\ \end{bmatrix} \begin{bmatrix} R \\ G \\ B \\ \end{bmatrix}⎣⎡​YIQ​⎦⎤​=⎣⎡​0.2990.5960.211​0.587−0.274−0.523​0.114−0.3220.312​⎦⎤​⎣⎡​RGB​⎦⎤​

计算完成后,需要将其标准化,即转成 [0,255][0,255][0,255] 区间内。标准化的时候,要将I 和 Q 分量+128。不同的标准可能数值会有一些差异,但不会差别很大。

RGB -> HSI :

HSI 颜色模型介绍:

HSI〔Hue-Saturation-Intensity(Lightness),HSI或HSL〕颜色模型用H、S、I三参数描述颜色特性,其中H定义颜色的波长,称为色调;S表示颜色的深浅程度,称为饱和度;I表示强度或亮度。在HSI颜色模型的双六棱锥表示,I是强度轴,色调H的角度范围为[0,2π],其中,纯红色的角度为0,纯绿色的角度为2π/3,纯蓝色的角度为4π/3。

RGB 转成 HSI 稍微复杂一些,具体步骤如下:

首先,需要将 R、G、B 三种颜色通道进行转换:

r=RR+G+Bg=GR+G+Bb=BR+G+Br = \frac{R}{R + G + B} \ \ \ \ g = \frac{G}{R + G + B} \ \ \ \ b = \frac{B}{R + G + B} r=R+G+BR​    g=R+G+BG​    b=R+G+BB​

然后再进行转换,其中 H 维度需要进行一次判断,具体公式如下:

h=cos⁡−1(0.5⋅[(r−g)+(r−b)][(r−g)2+(r−b)(g−b)]12)h∈[0,π]forb≤gh = \cos^{-1} \left( \frac{0.5\cdot \left[ \left(r - g\right) + \left(r - b\right)\right] } {\left[\left(r - g\right)^2 + \left(r - b \right) \left(g - b \right) \right]^{\frac12}} \right) \ \ \ \ h \in [0, \pi] \ for \ \ b \leq gh=cos−1⎝⎜⎛​[(r−g)2+(r−b)(g−b)]21​0.5⋅[(r−g)+(r−b)]​⎠⎟⎞​    h∈[0,π] for  b≤g

h=2π−cos⁡−1(0.5⋅[(r−g)+(r−b)][(r−g)2+(r−b)(g−b)]12)h∈[0,π]forb>gh = 2\pi - \cos^{-1} \left( \frac{0.5\cdot \left[ \left(r - g\right) + \left(r - b\right)\right] } {\left[\left(r - g\right)^2 + \left(r - b \right) \left(g - b \right) \right]^{\frac12}} \right) \ \ \ \ h \in [0, \pi] \ for \ \ b > gh=2π−cos−1⎝⎜⎛​[(r−g)2+(r−b)(g−b)]21​0.5⋅[(r−g)+(r−b)]​⎠⎟⎞​    h∈[0,π] for  b>g

s=1−3⋅min(r,g,b)s∈[0,1]s = 1 - 3 \cdot min(r, g, b) \ \ \ s \in [0,1]s=1−3⋅min(r,g,b)   s∈[0,1]

i=R+G+B3⋅255i∈[0,1]i = \frac{R + G + B} { 3 \cdot 255} \ \ \ i \in [0,1]i=3⋅255R+G+B​   i∈[0,1]

计算完成后,再进行转换,转换公式如下:

H=h×180πH = \frac{h \times 180} {\pi}H=πh×180​

S=s×100S = s \times 100S=s×100

I=i×255I = i \times 255I=i×255

这样就算转换成功了,计算稍微复杂一点但也不算太麻烦。最后,记得将 H 维度截断成 [0,255][0,255][0,255] 区间内。

RGB -> YCbCr :

先来看百度百科的介绍:

YCbCr或Y’CbCr有的时候会被写作:YCBCR或是Y’CBCR,是色彩空间的一种,通常会用于影片中的影像连续处理,或是数字摄影系统中。Y’为颜色的亮度(luma)成分、而CB和CR则为蓝色和红色的浓度偏移量成份。Y’和Y是不同的,而Y就是所谓的流明(luminance),表示光的浓度且为非线性,使用伽马修正(gamma correction)编码处理。

这个转换公式比较简单,直接乘上一个转换矩阵再转换一下就可以了:

[YCbCr]=[0128128]+[0.2990.5870.114−0.169−0.3310.50.5−0.419−0.081][RGB]\begin{bmatrix} Y \\ Cb \\ Cr \\ \end{bmatrix} = \begin{bmatrix} 0 \\ 128 \\ 128 \\ \end{bmatrix} + \begin{bmatrix} 0.299 & 0.587 & 0.114 \\ -0.169 & -0.331 & 0.5 \\ 0.5 & -0.419 & -0.081 \\ \end{bmatrix} \begin{bmatrix} R \\ G \\ B \\ \end{bmatrix}⎣⎡​YCbCr​⎦⎤​=⎣⎡​0128128​⎦⎤​+⎣⎡​0.299−0.1690.5​0.587−0.331−0.419​0.1140.5−0.081​⎦⎤​⎣⎡​RGB​⎦⎤​

RGB -> XYZ :

还是先来看看百度百科:

1931CIE-XYZ系统,就是在RGB系统的基础上,用数学方法,选用三个理想的原色来代替实际的三原色,从而将CIE-RGB系统中的光谱三刺激值和色度坐标r、g、b均变为正值。

这个跟 RGB 空间比较相似,计算也比较简单,直接乘上一个转换矩阵,转换公式如下:

[XYZ]=[0.4124530.3575800.1804230.2126710.7151600.0721690.0193340.1191930.950227][RGB]\begin{bmatrix} X \\ Y \\ Z \\ \end{bmatrix} = \begin{bmatrix} 0.412453 & 0.357580 & 0.180423 \\ 0.212671 & 0.715160 & 0.072169 \\ 0.019334 & 0.119193 & 0.950227 \\ \end{bmatrix} \begin{bmatrix} R \\ G \\ B \\ \end{bmatrix}⎣⎡​XYZ​⎦⎤​=⎣⎡​0.4124530.2126710.019334​0.3575800.7151600.119193​0.1804230.0721690.950227​⎦⎤​⎣⎡​RGB​⎦⎤​

实验结果

原始图片 :

RGB -> YIQ :

RGB -> HSI :

RGB -> YCbCr :

RGB -> XYZ :

Python 代码

# -*- coding: UTF-8 -*-
import numpy as np
import math
# YIQ 变换
def imgTranYIQ(r, g, b) :matrix_tran = np.array([[0.299, 0.587, 0.114], \[0.596, -0.274, -0.322], \[0.211, -0.523, 0.312]])Y = []I = []Q = []for row in range(len(r)) :Y_row = []I_row = []Q_row = []for col in range(len(r[row])) :Y_row.append(matrix_tran[0][0] * r[row][col] + matrix_tran[0][1] * g[row][col] + matrix_tran[0][2] * b[row][col])I_row.append(matrix_tran[1][0] * r[row][col] + matrix_tran[1][1] * g[row][col] + matrix_tran[1][2] * b[row][col])Q_row.append(matrix_tran[2][0] * r[row][col] + matrix_tran[2][1] * g[row][col] + matrix_tran[2][2] * b[row][col])Y.append(Y_row)I.append(I_row)Q.append(Q_row)# 标准化return Y, I, Q# HSI 变换
def imgTranHSI(R, G, B) :# 变化后的 g, b, rg = []b = []r = []for row in range(len(R)) :r_row = []g_row = []b_row = []for col in range(len(R[row])) :g_value = G[row][col]b_value = B[row][col]r_value = R[row][col]rgb_sum = g_value + b_value + r_valueif rgb_sum == 0 :b_row.append(0)g_row.append(0)r_row.append(0)else :b_row.append(b_value / rgb_sum)g_row.append(g_value / rgb_sum)r_row.append(r_value / rgb_sum)b.append(b_row)g.append(g_row)r.append(r_row)# 计算 H、S、I三维通道H = []S = []I = []for row in range(len(r)) :H_row = []S_row = []I_row = []for col in range(len(r[row])) :r_value = r[row][col]g_value = g[row][col]b_value = b[row][col]# 计算 H_row_valuesqrt_value = (r_value - g_value) * (r_value - g_value) + (r_value - b_value) * (g_value - b_value)sqrt_value = math.sqrt(sqrt_value)son_value = 0.5 * (r_value - g_value + r_value - b_value)if sqrt_value == 0 :H_row_value = 0else :acos_value = son_value / sqrt_valueif acos_value > 1 :acos_value = 1elif acos_value < -1 :acos_value = -1H_row_value = math.acos(acos_value)if b[row][col] <= g[row][col] :H_row.append(H_row_value)else :H_row.append(math.pi * 2 - H_row_value)# 存储 S_row、I_rowS_row.append(1 - 3 * min(r_value, g_value, b_value))I_row.append((R[row][col] + G[row][col] + B[row][col]) / (3 * 255))H.append(H_row)S.append(S_row)I.append(I_row)return H, S, I# YCbCr 变换
def imgTranYCbCr(R, G, B) :matrix_tran = np.array([[0.299, 0.587, 0.114], \[-0.169, -0.331, 0.5], \[0.5, -0.419, -0.081]])Y = []Cb = []Cr = []for row in range(len(R)) :Y_row = []Cb_row = []Cr_row = []for col in range(len(R[row])) :Y_row.append(matrix_tran[0][0] * R[row][col] + matrix_tran[0][1] * G[row][col] + matrix_tran[0][2] * B[row][col])Cb_row.append(matrix_tran[1][0] * R[row][col] + matrix_tran[1][1] * G[row][col] + matrix_tran[1][2] * B[row][col] + 128)Cr_row.append(matrix_tran[2][0] * R[row][col] + matrix_tran[2][1] * G[row][col] + matrix_tran[2][2] * B[row][col] + 128)Y.append(Y_row)Cb.append(Cb_row)Cr.append(Cr_row)# 标准化return Y, Cb, Cr# XYZ 变换
def imgTranXYZ(R, G, B) :matrix_tran = np.array([[0.412453, 0.357580, 0.180423], \[0.212671, 0.715160, 0.072169], \[0.019334, 0.119193, 0.950227]])X = []Y = []Z = []for row in range(len(R)) :X_row = []Y_row = []Z_row = []for col in range(len(R[row])) :X_row.append(matrix_tran[0][0] * R[row][col] + matrix_tran[0][1] * G[row][col] + matrix_tran[0][2] * B[row][col])Y_row.append(matrix_tran[1][0] * R[row][col] + matrix_tran[1][1] * G[row][col] + matrix_tran[1][2] * B[row][col])Z_row.append(matrix_tran[2][0] * R[row][col] + matrix_tran[2][1] * G[row][col] + matrix_tran[2][2] * B[row][col])X.append(X_row)Y.append(Y_row)Z.append(Z_row)return X, Y, Z

调用代码:
需要注意的是,这里我读取的是 bmp 文件,由于实验的要求,读取文件是我自己写的。其实可以直接调用 opencv 的库函数 利用 imread() 来读取。

我自己写的读文件的代码在这篇博客里:Python读取并解析 bmp 文件。这里就不细说了。

# -*- coding: UTF-8 -*-
import numpy as np
import sys
from ReadBMPFile import ReadBMPFile
import cv2
import math
import colorSpaceConversionfilePath = sys.argv[1]
# 读取 BMP 文件
bmpFile = ReadBMPFile(filePath)
# R, G, B 三个通道 [0, 255]
R = bmpFile.R
G = bmpFile.G
B = bmpFile.B
# 变化后的 g, b, r  [0, 1]
g = []
b = []
r = []
for row in range(len(R)) :r_row = []g_row = []b_row = []for col in range(len(R[row])) :r_row.append(R[row][col] / 255)g_row.append(G[row][col] / 255)b_row.append(B[row][col] / 255)r.append(r_row)g.append(g_row)b.append(b_row)# YIQ
y, i, q = colorSpaceConversion.imgTranYIQ(r, g, b)
# 标准化 B、G、R 的值
for row in range(len(y)) :for col in range(len(y[row])) :y[row][col] = np.int8(y[row][col] * 255)i[row][col] = np.int8(i[row][col] * 255 + 128)q[row][col] = np.int8(q[row][col] * 255 + 128)
y = np.array(y, dtype = np.uint8)
i = np.array(i, dtype = np.uint8)
q = np.array(q, dtype = np.uint8)
merged = cv2.merge([y, i, q]) #合并R、G、B分量 默认顺序为 B、G、R
cv2.imshow("YIQ",merged)
cv2.imwrite(filePath.split("/")[-1].split(".")[0] + "-1160300426-YIQ.bmp", merged)# HSI
h, s, i = colorSpaceConversion.imgTranHSI(R, G, B)
# 标准化 B、G、R 的值
for row in range(len(h)) :for col in range(len(h[row])) :h[row][col] = np.int8(h[row][col] * 180 / math.pi)s[row][col] = np.int8(s[row][col] * 100)i[row][col] = np.int8(i[row][col] * 255)
h = np.array(h, dtype = np.uint8)
s = np.array(s, dtype = np.uint8)
i = np.array(i, dtype = np.uint8)
merged = cv2.merge([h, s, i]) #合并R、G、B分量 默认顺序为 B、G、R
cv2.imshow("HSI",merged)
cv2.imwrite(filePath.split("/")[-1].split(".")[0] + "-1160300426-HSI.bmp", merged)# YCbCr
y, Cb, Cr = colorSpaceConversion.imgTranYCbCr(R, G, B)
y_arr = np.array(y, dtype = np.uint8)
Cb_arr = np.array(Cb, dtype = np.uint8)
Cr_arr = np.array(Cr, dtype = np.uint8)
merged = cv2.merge([y_arr, Cb_arr, Cr_arr]) #合并R、G、B分量 默认顺序为 B、G、R
cv2.imshow("YCbCr",merged)
cv2.imwrite(filePath.split("/")[-1].split(".")[0] + "-1160300426-YCbCr.bmp", merged)# XYZ
x, y, z = colorSpaceConversion.imgTranXYZ(R, G, B)
x_arr = np.array(x, dtype = np.uint8)
y_arr = np.array(y, dtype = np.uint8)
z_arr = np.array(z, dtype = np.uint8)
merged = cv2.merge([x_arr, y_arr, z_arr]) #合并R、G、B分量 默认顺序为 B、G、R
cv2.imshow("XYZ",merged)
cv2.imwrite(filePath.split("/")[-1].split(".")[0] + "-1160300426-XYZ.bmp", merged)cv2.waitKey(0)

总结

这次的实验还是挺简单的,主要纠结的地方还是颜色空间的转换矩阵和转换方式有不同的标准,没有统一,因此不知道用哪个。总体的思路还是很清晰的。

最后,附上 github 的项目地址:实验四-图像颜色空间转换

图像颜色空间转换—— Python 实现相关推荐

  1. opencv 图像颜色空间转换和特定颜色物体追踪

    颜色空间转换 HSV简介 HSV是一个常用于颜色识别的模型,相比BGR更易区分颜色.H表示色调(Hue),S表示饱和度(Saturation),V表示明度(Value). OpenCV中色调H范围为[ ...

  2. 图像颜色空间转换-CSC

    由于从事数字图像处理工作,常常要做颜色空间(如RGB.YUV.YCbCr.HSI).色域(BT.601.BT.709.BT.2020)的转换.之前一直没有弄明白YUV和YCbCr的差异,也没有深究.来 ...

  3. 图像颜色空间转换--RGB to Lαβ

    Lαβ 空间是作者在文章<color transfer between images>中于2001年提出来的,该空间相比于RGB空间的优点是三通道相关性很小,缺点是计算量稍大,RGB转到L ...

  4. Opencv_03 图像色彩空间转换

    文章目录 一. 色彩空间介绍 ① RGB/BGR色彩空间 ② 为什么Opencv中采用的是BGR ③ HSV色彩空间 二.色彩空间转换 ① cvtColor()函数原型 ② 颜色空间转换案例 一. 色 ...

  5. python 图像数据类型及颜色空间转换

    一.图像数据类型及转换 在skimage中,一张图片就是一个简单的numpy数组,数组的数据类型有很多种,相互之间也可以转换.这些数据类型及取值范围如下表所示: Data type Range uin ...

  6. Python+Opencv图像处理新手入门教程(二):颜色空间转换,图像大小调整,灰度直方图

    一步一步来吧 上一节:Python+Opencv图像处理新手入门教程(一):介绍,安装与起步 1.什么是图像 对于计算机而言,图像的本质是一个由像素点构成的矩阵. 例如我们用肉眼很容易分辨一辆汽车的后 ...

  7. python浮点型数据怎么显示为图片_python数字图像处理(4):图像数据类型及颜色空间转换...

    一.图像数据类型及转换 在skimage中,一张图片就是一个简单的numpy数组,数组的数据类型有很多种,相互之间也可以转换.这些数据类型及取值范围如下表所示: Data typeRange uint ...

  8. 颜色空间转换及切割车牌(python)

    如愿 一.前置准备 二.颜色空间转换 2.1 转为灰度图片 三.切割车牌 四.总结 五.参考资料 一.前置准备 软件及使用库 python 3.8.12 opencv 3.4.11 图片 二.颜色空间 ...

  9. 02 数字图像技术——颜色空间转换与颜色空间分割实验结果与分析——python

    04 数字图像技术--图像特征提取之实验结果与分析 03 数字图像技术--频域滤波实验结果与分析 02 数字图像技术--颜色空间转换与颜色空间分割实验结果与分析 01 数字图像基本操作--图像采样.量 ...

最新文章

  1. 在Spring.Net中对于NHibernate.Caches.Prevalence的使用
  2. [perl]Wide character in print报错
  3. 敏捷开发原则与实践(二)
  4. DL之随机性:理解和探究采用深度学习算法预测时导致多次运行结果不一致的问题
  5. 统计一段英文中单词的个数c语言,C语言统计一篇英文短文中单词的个数实例代码...
  6. collections 使用教程
  7. jquery easyui 表单结合对话框
  8. 在php定界符中,PHP中的定界符 - ho俊的个人空间 - OSCHINA - 中文开源技术交流社区...
  9. Python常用的几种数据结构-链表,数组,字典
  10. Rhythmbox中文乱码解决办法
  11. 在家登录学校图书馆知网
  12. 中国地图及各省市县地图json下载地址
  13. 腿抖在饮食上需要注意什么?
  14. [SWPUCTF 2021 新生赛]babyrce
  15. 5G千兆工业路由器 poe供电
  16. Win10,Win11系统安全中心提醒“找到可能不需要的应用”弹窗,如何关闭?
  17. MTK Secure Boot 2.1详细配置方案-终极版
  18. ThinkSNS团队衍生产品你知道几个?
  19. 基于Arduino IDE开发的ESP8266(ESP-12F)项目4 ——中断及高级输入输出
  20. 如何排序10亿个数--外排小试

热门文章

  1. java反射学习(适合新人)
  2. java硬件对接经验总结
  3. Hadoop 3.0 Erasure Coding 纠删码功能预分析
  4. Linux virtual filesystem switch I 磁盘相关概念以及知识
  5. 免费舆情监测软件有哪些功能
  6. vue引用import“@/路径“ 有下划线并且 crtl+鼠标无法点进去
  7. CAD菜单栏不见了怎么办,怎么调出来?
  8. Gaza Cybergang在移动端对阿拉伯语地区的攻击事件
  9. 百度百科怎么修改词条内容?
  10. python:共轭梯度法(以希尔伯特矩阵为例)