Opencv如何转换图片格式(颜色空间)

1 Opencv中常见的颜色空间

1.1 . BGR(Blue-Green-Red):即蓝绿红色,是最常用的颜色空间,OpenCV中默认的颜色空间。与RGB仅顺序不同。

  • BGR的用途:在显示器上显示的颜色。
  • BGR的优点:简单、直观。
  • BGR的缺点:不能反映颜色的饱和度和明度。

1.2 . HSV(Hue-Saturation-Value):色调饱和度明度。

HSV色彩空间是一种常用的色彩模型,它模仿了人类对颜色的感知方式。HSV代表的是色调(Hue)、饱和度(Saturation)和明度(Value),这三个组成部分构成了HSV色彩空间的基本特性。下面是对HSV色彩空间特点的详细介绍:

  1. 色调 (Hue):

    • 色调表示颜色的基本类型,如红色、绿色、蓝色等。
    • 在HSV模型中,色调是一个角度值,范围通常是0°到360°,其中0°和360°表示红色,120°表示绿色,240°表示蓝色。
    • 色调通常用来描述颜色的“纯度”或“色相”。
  2. 饱和度 (Saturation):

    • 饱和度表示颜色的强度或纯度。
    • 在HSV模型中,饱和度是一个百分比值,范围从0%到100%,其中0%表示灰色,100%表示完全饱和的颜色。
    • 饱和度越高,颜色看起来越鲜艳;饱和度越低,颜色越接近灰色。
  3. 明度 (Value):

    • 明度表示颜色的亮度或暗度。
    • 在HSV模型中,明度也是一个百分比值,范围从0%到100%,其中0%表示黑色,100%表示最亮的颜色。
    • 明度的变化不会改变颜色的基本色调。
  • HSV色彩空间更适合于颜色识别和图像分割等任务,因为它的明度概念更接近于颜色的最大亮度。

1.3 . HLS(Hue-Lightness-Saturation):色调亮度饱和度。

  • 与HSV色彩空间相比,HLS色彩空间中的亮度(Lightness)属性是颜色的平均亮度,即颜色中最亮部分和最暗部分的平均值。这意味着当亮度变化时,颜色的明暗程度会改变,但色调和饱和度保持不变。

    • HLS色彩空间则更适合于需要调整图像整体亮度的情况,因为它考虑的是颜色的平均亮度。

1.4 . YCrCb(Luma-Chroma-Cr-Cb):亮度、色度、红色差、蓝色差。

YCrCb色彩空间是一种广泛使用的色彩模型,尤其在数字图像和视频处理中非常常见。它是由YUV色彩空间演变而来的一种形式,通常用于视频编码标准,如JPEG和MPEG。

  • YCrCb色彩空间是一种常用的色彩模型,它将RGB色彩模型中的RGB三个分量分别映射到Y(亮度)、Cr(红色差)、Cb(蓝色差)三个分量。
  1. 亮度与色差分离

    • YCrCb色彩空间将亮度(Y)与色差(Cr和Cb)分离,这有助于减少图像的数据量,因为人眼对亮度的敏感度远高于对色差的敏感度。
    • 在视频压缩技术中,这种分离可以允许对亮度分量和色差分量采用不同的采样率,从而降低数据传输的带宽需求。
  2. 色彩模型转换

    • YCrCb色彩空间可以从RGB色彩空间转换而来,转换公式如下:

      $$

 \begin{align*}
 Y &= 0.299R + 0.587G + 0.114B \\
 Cr &= (R - Y) \times 0.713 + 128 \\
 Cb &= (B - Y) \times 0.564 + 128
 \end{align*}


$$
  • 其中,R、G、B 分别表示红、绿、蓝三个颜色分量,Y、Cr、Cb 分别表示亮度和两个色差分量。
  • 注意到Cr和Cb值通常会加上128,这是为了确保在整数运算中避免负数。
    其实,YCrCb色彩空间的设计原理与YUV色彩空间类似,都是为了将RGB色彩模型中的三个分量分离,但YCrCb色彩空间的亮度分量与色差分量分离得更加彻底。
  • YUV与RGB的转换公式如下:

  1. 量化与压缩

    • 在视频压缩过程中,YCrCb色彩空间的使用有助于减少数据量而不显著降低图像质量。
    • 通常情况下,亮度分量的分辨率会保持较高,而色差分量的分辨率会降低,即所谓的子采样(sub-sampling)。
    • 例如,常见的子采样比例包括4:4:4(无子采样)、4:2:2(水平方向上Cr和Cb各减少一半)和4:2:0(水平和垂直方向上Cr和Cb各减少一半)。
  2. 子采样

    • 子采样比例(Subsampling Ratio)是指在视频或图像处理中,亮度分量(通常表示为Y)与色差分量(如U和V或Cb和Cr)的分辨率之间的关系。子采样是一种减少数据量的方法,通过降低色差分量的分辨率来降低视频或图像的总数据量,同时尽量保持视觉质量。
  1. 4:4:4

    • 这种情况下,亮度分量和色差分量都具有相同的分辨率,即每个像素都有单独的Y、U和V(或Cb和Cr)值。
    • 这种采样模式通常用于高质量的图像或视频处理中,因为它保留了所有的色彩信息。
  2. 4:2:2

    • 在这种模式下,每个像素有一个Y值,但每两个相邻像素共享一个U和V(或Cb和Cr)值。
    • 这意味着色差分量的水平分辨率减半。
    • 4:2:2采样通常用于专业视频制作和传输,因为它在保持较好图像质量的同时减少了数据量。
  3. 4:2:0

    • 这是最常见的子采样比例之一,特别是在视频压缩标准(如MPEG和H.26x系列)中。
    • 在4:2:0模式下,每四个像素共享一个U和V(或Cb和Cr)值。
    • 这意味着色差分量的水平和垂直分辨率都减半。
    • 4:2:0采样大大减少了数据量,同时在大多数情况下仍然能保持可接受的图像质量。
  1. 4:2:0 子采样比例示例

    • 假设我们有一个8×8像素的图像块,采用4:2:0子采样比例,那么亮度分量(Y)和色差分量(U/V或Cb/Cr)的采样过程如下:

    原始图像块

    • 我们有一个8×8像素的图像块,每个像素包含Y、U和V(或Cb和Cr)三个分量。

    亮度分量(Y)

    • 亮度分量Y保持不变,即每个像素都有一个Y值。
    • 因此,我们仍然有8×8 = 64个Y值。

    色差分量(U/V或Cb/Cr)

    • 对于4:2:0子采样,我们将色差分量的水平和垂直分辨率都减半。
    • 在水平方向上,每两个像素共享一个U和V(或Cb和Cr)值。
    • 在垂直方向上,每两个行共享一组U和V(或Cb和Cr)值。
    • 因此,我们只需要4×4 = 16个U和V(或Cb和Cr)值来表示原来8×8像素的图像块。

    实现过程

    1. 亮度分量(Y)

      • 不需要进行任何特殊处理,直接保留每个像素的亮度值。
    2. 色差分量(U/V或Cb/Cr)

      • 水平采样:对每一行的色差分量进行采样,每两个像素共享一个值。
      • 垂直采样:对每一列的色差分量进行采样,每两行共享一组值。

    具体步骤

    1. 水平采样

      • 对于每一行,我们只保留偶数位置的色差值(例如第0、2、4、6列的位置),丢弃奇数位置的值。
      • 对于丢弃的值,可以使用邻近的值进行估计,例如使用线性插值。
    2. 垂直采样

      • 对于每一列,我们只保留偶数行的色差值(例如第0、2、4、6行的位置),丢弃奇数行的值。
      • 对于丢弃的值,同样可以使用邻近的值进行估计。

    示例代码

    以下是一个简单的Python示例,演示如何对一个8×8像素的图像块进行4:2:0子采样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    import numpy as np

    # 假设我们有一个8x8像素的图像块
    image_block = np.random.rand(8, 8, 3) # 生成一个随机的8x8x3数组

    # 分离亮度和色差分量
    Y = image_block[:, :, 0]
    U = image_block[:, :, 1]
    V = image_block[:, :, 2]

    # 4:2:0子采样
    # 水平采样
    U_subsampled = U[::2, ::2] # 选取偶数行和偶数列
    V_subsampled = V[::2, ::2]

    # 输出结果
    print("Original Y shape:", Y.shape)
    print("Subsampled U shape:", U_subsampled.shape)
    print("Subsampled V shape:", V_subsampled.shape)

    在这个示例中,我们首先生成了一个8×8像素的图像块,并将其分成亮度分量(Y)和色差分量(U和V)。然后,我们对U和V进行了4:2:0子采样,只保留了偶数行和偶数列的值。

  1. 影响
    • 数据量减少:通过减少色差分量的分辨率,可以显著降低数据量。
    • 压缩效率提高:子采样有助于提高视频或图像的压缩效率,减少存储空间需求和传输带宽。
    • 视觉质量:适当选择子采样比例可以保持良好的视觉质量,即使在较低的数据率下也是如此。
  1. 应用场景:
  • 视频编码与传输:YCrCb色彩空间广泛应用于视频编码标准中,如MPEG和H.26x系列标准。
  • 图像压缩:JPEG标准使用YCrCb色彩空间来进行图像的有损压缩。
  • 色彩转换:在不同设备间进行色彩转换时,YCrCb色彩空间可以作为中间步骤,帮助实现更高效的色彩转换过程。

1.5 . Lab(Lightness-A-B):亮度、A、B。

  1. LAB色彩空间的组成部分:
  • L (Lightness):表示亮度或明度,即颜色的亮度级别。
  • a (Green-Red Axis):表示从绿色到红色的变化。
  • b (Blue-Yellow Axis):表示从蓝色到黄色的变化。
  1. 特点:

    1. 人眼感知

      • LAB色彩空间的设计尽可能地匹配人眼对颜色的感知方式。
      • 在LAB色彩空间中,两个颜色之间的距离大致反映了人眼感知到的颜色差异。
    2. 亮度与色度分离

      • L分量表示亮度信息,a和b分量表示色度信息。
      • 这种分离有助于在处理颜色时更好地控制亮度和色度。
    3. 颜色转换

      • LAB色彩空间可以方便地与其他色彩空间(如RGB、CMYK等)进行转换。
      • 由于其与人眼感知的接近性,LAB色彩空间在颜色转换过程中能够保持较好的颜色保真度。
    4. 色彩管理

      • LAB色彩空间被广泛用于色彩管理,特别是在印刷和显示设备的颜色校准中。
      • 通过将颜色转换到LAB色彩空间,可以更容易地比较不同设备之间的颜色输出。
    5. 色彩距离

      • 在LAB色彩空间中,两个颜色之间的欧几里得距离(即两点之间的直线距离)可以用来衡量颜色差异。
      • 通常,如果两个颜色之间的距离小于1.0,那么人眼很难分辨它们之间的差异。

3.LAB色彩空间的范围:

  • L 的范围从0到100,其中0表示绝对黑,100表示绝对白。
  • ab 的范围通常是-128到+127,但实际应用中可以根据具体情况有所变化。

4.LAB色彩空间的应用场景:

  • 颜色测量:在工业生产中,用于颜色匹配和质量控制。
  • 颜色转换:在不同的设备和媒介之间进行颜色转换时,LAB色彩空间可以作为中间参考色彩空间。
  • 色彩管理:在印刷和显示设备的颜色校准中,LAB色彩空间可以用来确保颜色的一致性和准确性。

1.6 .灰度图

灰度图是指黑白图像,其颜色空间为单通道灰度。

2 Opencv中如何转换图片格式

Opencv中读取图片的函数是imread(),它可以读取多种格式的图片,包括jpg、png、bmp、tiff等。

imread()函数的第二个参数表示读取图片的颜色空间,默认情况下,它是BGR色彩空间。

下面介绍如何利用Opencv中的imread()函数读取不同格式的图片,并转换为不同的颜色空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <opencv2/opencv.hpp>
#include <C:\Users\.PORJECT\C\CAMERA\test\user.h>



int main() {
std::cout << "Hello, World!" << std::endl;
Mat img = imread("D:/images/example.png");
if (img.empty()) {
std::cout << "Could not open or find the image" << std::endl;
return -1;
}


img = ColourSpace(img,(char*)"YCrCb");


imshow("Example", img);
waitKey(0);

return 0;
}

在上面的代码中,我们首先调用imread()函数读取一个png格式的图片,并将其存储在img变量中。

然后,我们调用ColourSpace()函数,将img变量转换为YCrCb色彩空间。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <C:\Users\.PORJECT\C\CAMERA\test\user.h>
#include <opencv2/opencv.hpp>
#include <cstring> // 用于 strcmp

using namespace cv;


cv::Mat ColourSpace(Mat img, char* target) {

if (strcmp(target, "RGB") == 0) {
cvtColor(img, img, COLOR_BGR2RGB);
return img;
}
else if (strcmp(target, "HSV") == 0) {
cvtColor(img, img, COLOR_BGR2HSV);
return img;
}
else if (strcmp(target, "HSL") == 0) {
cvtColor(img, img, COLOR_BGR2HLS);
return img;
}
else if (strcmp(target, "LAB") == 0) {
cvtColor(img, img, COLOR_BGR2Lab);
return img;
}
else if (strcmp(target, "YCrCb") == 0) {
cvtColor(img, img, COLOR_BGR2YCrCb);
return img;
}
else {
printf("Invalid target colour space\n");
return img; // 返回原始图像或处理错误情况
}

}

在上面的代码中,我们定义了一个ColourSpace()函数,它接收一个Mat类型的图片img和一个字符串类型的目标色彩空间target。

函数首先判断target是否为RGB、HSV、HSL、LAB或YCrCb,并调用cvtColor()函数将img转换为目标色彩空间。

cvtColor()函数是Opencv中用于颜色空间转换的函数,它接收两个参数,第一个参数是输入图片,第二个参数是输出图片。

cvtColor()函数的第二个参数表示输入图片的颜色空间,第三个参数表示输出图片的颜色空间。