OpenCV图像色彩空间转换
在计算机视觉与图像处理任务中,色彩空间转换 是一个非常常见的操作。
例如,在做人脸检测时,我们往往会先把彩色图像转换为灰度图;在做颜色追踪时,我们会用 HSV 空间代替 RGB 空间;而在图像压缩、医学图像、计算机图形学等场景中,其他色彩空间也大有用武之地。
OpenCV 提供了一个功能强大且使用简单的接口 —— cv::cvtColor()
,用于在不同色彩空间之间转换。
cv::cvtColor
基本用法
#include <opencv2/opencv.hpp>
using namespace cv;int main() {Mat src = imread("image.jpg");Mat dst;// BGR 转灰度cvtColor(src, dst, COLOR_BGR2GRAY);imshow("Gray Image", dst);waitKey(0);return 0;
}
void cv::cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0);
- src:输入图像(可为多通道)
- dst:输出图像
- code:颜色转换代码(例如
COLOR_BGR2GRAY
) - dstCn:输出通道数(默认为 0,即由转换规则自动决定)
常见色彩空间与使用场景
下面我们重点介绍几种常见的色彩空间及其应用场景。
RGB / BGR
- 描述:最常见的颜色表示方式,三通道分别表示红、绿、蓝分量。
- 在 OpenCV 中:默认读取的图像是 BGR 排列,而不是 RGB。
- 应用场景:图像显示、基本图像处理,与计算机图形学、GUI 等直接交互的场景
- 转换码:COLOR_BGR2RGB
Grayscale(灰度)
- 描述:单通道图像,仅包含亮度信息,没有色彩信息。
- 应用场景:图像分割,边缘检测,特征提取等
- 转换码:COLOR_BGR2GRAY
HSV(Hue, Saturation, Value)
- 描述:用色相(Hue)、饱和度(Saturation)、亮度(Value)来表示颜色,更接近人眼感知方式。
- 应用场景:颜色跟踪,光照不均匀时颜色分割
- 示例(红色检测):以下代码将图像变换到HSV空间,然后定义一个区间以实现红色检测,最终被判断为红色区域使用mask进行标记。
// 创建一个Mat对象来存储HSV色彩空间的图像
Mat hsv;// 将源图像 'src' 从BGR色彩空间转换为HSV色彩空间,并将结果存储在 'hsv' 中。
// HSV色彩空间更适合进行颜色分割,因为它将色调(Hue)、饱和度(Saturation)和亮度(Value)分离开来。
cvtColor(src, hsv, COLOR_BGR2HSV);// 定义一个Scalar对象来表示红色在HSV色彩空间中的下限。
// 这里的参数依次是:Hue(色调)、Saturation(饱和度)、Value(亮度)。
// 红色在色调环中通常位于0-10和170-180之间。这里我们选取了0-10这个范围。
// 饱和度和亮度范围设置为相对较宽,以便捕捉各种亮度和饱和度的红色。
Scalar lower_red(0, 120, 70);// 定义一个Scalar对象来表示红色在HSV色彩空间中的上限。
Scalar upper_red(10, 255, 255);// 创建一个Mat对象来存储掩码(mask),它是一个二值图像。
Mat mask;// 使用inRange函数根据HSV范围创建掩码。
// inRange函数会遍历 'hsv' 图像中的每个像素,检查其值是否在 'lower_red' 和 'upper_red' 之间。
// 如果像素值在这个范围内,'mask' 中对应位置的像素值将被设置为255(白色),表示匹配。
// 如果不在范围内,则设置为0(黑色),表示不匹配。
// 最终得到的 'mask' 图像可以用来提取原图中所有红色的区域。
inRange(hsv, lower_red, upper_red, mask);
Lab(CIE Lab*)
- 描述:接近人类视觉的感知均匀色彩空间,
L
表亮度,a
与b
表颜色分量。 - 示例:在亮度分量上进行直方图均衡化增强
// 创建一个Mat对象来存储Lab色彩空间的图像
Mat lab;// 将源图像 'src' 从BGR色彩空间转换为Lab色彩空间,并将结果存储在 'lab' 中。
// Lab色彩空间特别适合图像增强,因为它将亮度(L)通道与颜色(a和b)通道完全分离。
cvtColor(src, lab, COLOR_BGR2Lab);// 创建一个向量(vector)来存储Lab图像的三个通道。
vector<Mat> lab_planes;// 使用split函数将Lab图像分解成三个独立的通道,并存储在 'lab_planes' 向量中。
// lab_planes[0] 对应L(亮度)通道。
// lab_planes[1] 对应a(绿-红)通道。
// lab_planes[2] 对应b(蓝-黄)通道。
split(lab, lab_planes);// 对L(亮度)通道(lab_planes[0])应用直方图均衡化。
// 直方图均衡化只作用于亮度信息,而不会改变颜色信息,这能有效地提升图像对比度,同时保持色彩的自然。
equalizeHist(lab_planes[0], lab_planes[0]);// 使用merge函数将经过均衡化的L通道与原始的a和b通道重新合并为一个Lab图像。
merge(lab_planes, lab);// 将Lab图像 'lab' 转换回BGR色彩空间,并将结果存储在目标图像 'dst' 中。
// 这是为了显示或保存图像,因为大多数显示设备和图像文件格式都使用BGR或RGB色彩空间。
cvtColor(lab, dst, COLOR_Lab2BGR);
YCrCb
- 描述:亮度与色度分离的色彩空间,
Y
表亮度,Cr
与Cb
表色度。 - 示例(肤色检测):
// 创建一个Mat对象来存储YCrCb色彩空间的图像
Mat ycrcb;// 将源图像 'src' 从BGR色彩空间转换为YCrCb色彩空间,并将结果存储在 'ycrcb' 中。
// YCrCb色彩空间常用于肤色检测,因为它能有效地将亮度(Y)和颜色(CrCb)分离开来。
cvtColor(src, ycrcb, COLOR_BGR2YCrCb);// 定义一个Scalar对象来表示肤色在YCrCb色彩空间中的下限。
// YCrCb的分量依次是:Y(亮度)、Cr(红色分量)、Cb(蓝色分量)。
// 这里设定的范围是根据经验得出的,用于匹配大多数人的肤色。
Scalar lower_skin(0, 133, 77);// 定义一个Scalar对象来表示肤色在YCrCb色彩空间中的上限。
Scalar upper_skin(255, 173, 127);// 创建一个Mat对象来存储掩码(mask),它是一个二值图像。
Mat mask;// 使用inRange函数根据YCrCb范围创建掩码。
// inRange函数会遍历 'ycrcb' 图像中的每个像素,检查其值是否在 'lower_skin' 和 'upper_skin' 之间。
// 如果像素值在这个范围内,'mask' 中对应位置的像素值将被设置为255(白色),表示匹配。
// 如果不在范围内,则设置为0(黑色),表示不匹配。
// 最终得到的 'mask' 图像可以用来提取原图中所有肤色的区域。
inRange(ycrcb, lower_skin, upper_skin, mask);