1.cvtColor的用处和API讲解
1.cvtColor 的作用
cvtColor是OPENCV里面颜色转换的转换函数,它的功能非常强大。能够实现RGB图像转换成灰度图、灰度图转换成RGB图像、RGB转换成HSV等等。下面我们来看看
2.cvtColor 的 API
CV_EXPORTS_W void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );
第一个参数:输入的图像数据
第二个参数:输出的图像数据
第三个参数:颜色转换的标识符,下面是转换的图表。图像转化可以分为11个大类,分别是RGB->BGR 、 RGB->5X5 、 RGB->GRAY 、 RGB->CIEXYZ 、 RGB->YyCrcb(YUV) 、 RGB->HSV 、 RGB->HLS 、 RGB->CIELab 、 RGB->CIELuv 、 RGB->Bayer 、 YUV420->RGB
第四个参数:目标图像通道数,默认为0

2.用代码实现cvtColor的颜色转换功能
这次代码主要是转换几个常见的格式,如RGB->YUV, YUV->RGB。具体的代码思路如下:

这个代码里面我们分别读取两种图片,一种是RGB图片、另外一种是YUV灰度图像、分别用cvtColor把RGB图像转换成YUV图像、把YUV灰度图像转换成RGB图像、最后用imwrite保存两种图片。下面是一些代码的实现截图:
1.调用 imread 读取 RGB 彩色图像

读取RGB彩色通道的图像,这张图片是一张车辆的图片
2.把 RGB 图像转换为 YUV 图像

调用cvtColor把三通道的RGB图像转换为YUV的灰度图像,这里使用的是COLOR_RGB2YUV。
3.调用 imread 读取 YUV 灰度图像

读取YUV的灰度图像,这张图片是一张灰度的汽车图像
4.把 YUV 图像转换为 RGB 图像

调用cvtColor把单通道的图像转换成RGB图像,调用的选项使用的是COLOR_YUV2RGB
5.把处理过后的两种图像保存
使用imwrite保存两种图像
最终的效果:

左边是处理后的YUV图像,右边是RGB图像
cs
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
using namespace cv; //Must Need Write cv
using namespace std;
int main()
{
Mat src_bgr = imread("car.jpg");
Mat img_yuv;
cvtColor(src_bgr,img_yuv,COLOR_BGR2YUV);
imwrite("car_yuv.jpg",img_yuv);
Mat img_gray;
cvtColor(src_bgr,img_gray,COLOR_BGR2GRAY);
imwrite("car_gray.jpg",img_gray);
Mat img_bgr;
cvtColor(img_yuv,img_bgr,COLOR_YUV2BGR);
imwrite("car_bgr.jpg",img_bgr);
return 0;
}
car.jpg car.yuv


car.gray car.bgr


注:
1.灰度图
当你用灰度模式(例如 OpenCV 中的 cv2.IMREAD_GRAYSCALE 或相机 SDK 中的灰度采集)读取或采集图像时,图像数据变成了单通道。
- 彩色图 :每个像素由 3 个值组成(蓝、绿、红),是一个三维矩阵
(Height,Width,3)。 - 灰度图 :每个像素由 1 个值组成(亮度),是一个二维矩阵
(Height,Width)。
在这个过程中,程序将彩色的信息通过加权平均算法(例如 Gray = 0.299R+0.587G+0.114BGray = 0.299R+0.587G+0.114B)合并成了一个亮度值。原本的 R、G、B 三个数值彻底丢失了,只剩下一个亮度值。
然后你对灰度图做了转BGR
gray 是单通道的图像
cvtColor(img_gray,img_bgr ,COLOR_GRAY2BGR)
这行代码做了以下事情:
- 输入:一个单通道的矩阵,数值是亮度 L。
- 输出:一个三通道的矩阵。
- 转换逻辑 :为了让单通道变成三通道,程序将唯一的亮度值 L 复制到了三个通道上。
- 原来的像素值 L
- 转换后的像素值 = (B = L, G = L, R = L)
当三个通道的值相等时,在屏幕上显示出来的就是灰度色(因为没有任何色彩倾向)。所以虽然图像格式变成了 BGR,但视觉上依然是灰色的。
2.YUV
yuv的图像用rgb读取,能转成彩色的。
YUV 和 RGB 一样,都完整保留了彩色信息,只是用不同的数学方式表达而已。
而之前你遇到的灰度转 BGR 之所以不行,是因为灰度图只保留了亮度,丢失了色彩信息。让我们深入看看区别:
YUV 格式本身就包含彩色信息
YUV(以及类似的 YCbCr)并不是黑白格式,而是一种彩色编码格式。它包含三个分量:
- Y(亮度):描述图像的明暗程度(类似于黑白图)
- U(Cb,蓝色色度):描述蓝色分量与亮度的差异
- V(Cr,红色色度):描述红色分量与亮度的差异
关键点:虽然 Y 通道看起来像灰度图,但 UV 通道完整保留了颜色信息!这和灰度图(只有 Y,没有 UV)有本质区别。
CV_BGR2YUV 和 CV_BGR2YUV_I420 的主要区别在于:前者生成的是"平面"但未压缩的格式,后者生成的是"平面且压缩"的格式。

YUV420(家族名称)
├── I420(也叫 IYUV):YYYYYYYY UU VV (平面格式)
├── YV12:YYYYYYYY VV UU (平面格式,UV顺序交换)
├── NV12:YYYYYYYY UVUV (半平面格式)
└── NV21:YYYYYYYY VUVU (半平面格式)
- I420:Y平面 + U平面 + V平面
- NV12:Y平面 + UV交错平面(UV交替存储)
- YV12:Y平面 + V平面 + U平面(顺序不同)
3.cvtColor(img_yuv,img_to_bgr,CV_YUV2BGR);
COLOR_BGR2YUVI420 --> COLOR_YUV2BGR 有问题
当你将BGR转换为YUV_I420格式时,YUV图像的大小计算方式与BGR不同。I420格式要求图像的宽度和高度都是偶数,因为它的UV分量是下采样的(每2x2的Y块对应一组UV)。
COLOR_BGR2YUV --> COLOR_YUV2BGR 没有问题