OpencvSharp 算子学习教案之 - Cv2.CvtColorTwoPlane
OpencvSharp 算子学习教案之 - Cv2.CvtColorTwoPlane
大家好,Opencv在很多工程项目中都会用到,而OpencvSharp则是以C#开发与实现的Opencv操作库,对.NET开发人员友好,但很多API的中文资料、应用场景及常见坑点等缺乏系统性归纳,因此这系列博客将给大家带来Cv2及Mat对象全系列算子学习教案,供大家参考学习。
Cv2.CvtColorTwoPlane
- 教案版本:V1.0
- 面向对象:OpenCvSharp 初学者
- 所属模块:imgproc
- 源码位置:OpenCvSharp/Cv2/Cv2_imgproc.cs:2483
摘要:Cv2.CvtColorTwoPlane专门处理 YUV420 双平面到 RGB/BGR 的转换。它最容易讲清楚“第一个平面是亮度 Y,第二个平面是交错的 UV 或 VU”这一点,也非常适合用来入门 NV12 和 NV21。
1. 函数名称(带参数签名)
publicstaticvoidCvtColorTwoPlane(InputArraysrc1,InputArraysrc2,OutputArraydst,ColorConversionCodescode)2. 函数用途
Cv2.CvtColorTwoPlane用来把双平面 YUV420 图像转换成 RGB/BGR 图像。
它最常见的用途有:
- 处理来自视频流、硬件解码器或摄像头的 NV12 / NV21 数据。
- 把 Y 平面和 UV 平面合并还原成可显示的彩色图像。
- 在不额外手工拼接大矩阵的情况下,直接完成双平面颜色转换。
- 作为讲解 YUV420 采样格式的教学入口。
3. 函数公式
这个函数的核心不是一个固定公式,而是一个“双平面输入 + 指定转换码”的映射关系:
d s t = T c o d e ( Y , U V ) dst = T_{code}(Y, UV)dst=Tcode(Y,UV)
其中:
Y表示亮度平面。UV表示交错的色度平面。code决定你要按 NV12 还是 NV21 来解释第二个平面。
从尺寸上看,典型的 YUV420 双平面可以理解为:
Y ∈ C V 8 U C 1 H × W , U V ∈ C V 8 U C 2 H 2 × W 2 Y \in CV_{8UC1}^{H\times W}, \qquad UV \in CV_{8UC2}^{\frac{H}{2}\times\frac{W}{2}}Y∈CV8UC1H×W,UV∈CV8UC22H×2W
也就是说:
src1是完整的 Y 平面。src2是按 2x2 下采样后的色度平面。- 输出图像的尺寸和 Y 平面相同。
4. 函数原理说明
YUV420 的含义可以拆成两部分理解:
Y负责亮度,所以它通常是单通道,并且和最终图像大小相同。UV负责色彩,但它的分辨率更低,因为人眼对色度的敏感度低于亮度。
NV12 和 NV21 的差别只在于第二个平面的顺序:
- NV12:
U, V, U, V, ... - NV21:
V, U, V, U, ...
对初学者来说,最容易犯的错就是把 NV12 和 NV21 混用。它们的输入数据看起来非常像,但色彩解释顺序不同,最终输出会明显偏色。
5. 参数含义解析
| 参数名 | 类型 | 必填 | 含义 |
|---|---|---|---|
| src1 | InputArray | 是 | Y 平面,8 位单通道图像 |
| src2 | InputArray | 是 | 交错的 UV 或 VU 平面 |
| dst | OutputArray | 是 | 输出图像 |
| code | ColorConversionCodes | 是 | 只支持 NV12 / NV21 系列转换码 |
补充说明:
src1是亮度平面。src2是交错的色度平面。dst通常是 3 通道 BGR/RGB 或 4 通道 BGRA/RGBA。- 绑定层目前只支持 YUV420 到 RGB/BGR 的双平面转换。
6. 应用场景列表
| 场景名 | 场景说明 | 典型用途 |
|---|---|---|
| 场景A:NV12 解码 | 把Y + UV组合还原成 BGR 图 | 视频帧显示、解码后预览 |
| 场景B:NV21 解码 | 把Y + VU组合还原成 BGR 图 | 安卓相机数据处理 |
| 场景C:Y 平面分析 | 单独观察亮度层 | 亮度检测、曝光分析 |
| 场景D:UV 平面分析 | 单独观察色度层 | 色偏排查、格式调试 |
7. 函数使用示例(与 WPF 场景一一对应)
说明:下面代码对应 WPF 页面里的
CvtColorTwoPlane场景。为了让初学者更容易理解,这里直接手工构造 Y 平面和 UV 平面,再分别按 NV12 和 NV21 解释它们。
usingSystem;usingOpenCvSharp;internalstaticclassProgram{privatestaticvoidMain(){// 先构造一个很小的 Y 平面,便于理解双平面数据的结构。usingvaryPlane=newMat(8,8,MatType.CV_8UC1);for(varrow=0;row<yPlane.Rows;row++){for(varcol=0;col<yPlane.Cols;col++){// 亮度从左到右缓慢变化,这样输出图像能看出明暗梯度。vary=50+col*20;yPlane.At<byte>(row,col)=(byte)Math.Clamp(y,0,255);}}// UV 平面是 4x4,每个元素是一个 U/V 对,对应 2x2 的 Y 像素块。usingvaruvPlane=newMat(4,4,MatType.CV_8UC2);FillUvBlock(uvPlane,0,0,2,2,84,240);FillUvBlock(uvPlane,0,2,2,2,54,60);FillUvBlock(uvPlane,2,0,2,2,220,108);FillUvBlock(uvPlane,2,2,2,2,128,128);// 同一张双平面数据,按照 NV12 和 NV21 两种方式解释,会得到不同的颜色结果。usingvarnv12=newMat();usingvarnv21=newMat();Cv2.CvtColorTwoPlane(yPlane,uvPlane,nv12,ColorConversionCodes.YUV2BGR_NV12);Cv2.CvtColorTwoPlane(yPlane,uvPlane,nv21,ColorConversionCodes.YUV2BGR_NV21);// 把结果保存出来,初学者可以直接对比 NV12 和 NV21 的色彩差异。Cv2.ImWrite("cvtcolortwoplane_y.png",yPlane);Cv2.ImWrite("cvtcolortwoplane_uv.png",CreateUvPreview(uvPlane));Cv2.ImWrite("cvtcolortwoplane_nv12.png",nv12);Cv2.ImWrite("cvtcolortwoplane_nv21.png",nv21);Console.WriteLine("CvtColorTwoPlane 演示已完成。");}privatestaticvoidFillUvBlock(MatuvPlane,intstartRow,intstartCol,introws,intcols,byteu,bytev){// 把一块区域的 UV 值填成相同的颜色,方便观察不同色度组合的效果。for(varrow=startRow;row<startRow+rows;row++){for(varcol=startCol;col<startCol+cols;col++){uvPlane.Set(row,col,newVec2b(u,v));}}}privatestaticMatCreateUvPreview(MatuvPlane){// UV 是双通道矩阵,不适合直接按 BGR 显示,所以这里拆开后做热力图。varchannels=Cv2.Split(uvPlane);try{usingvaruHeat=CreateHeatmap(channels[0]);usingvarvHeat=CreateHeatmap(channels[1]);returnCv2.HConcat(uHeat,vHeat);}finally{foreach(varchannelinchannels){channel.Dispose();}}}privatestaticMatCreateHeatmap(Matsource){usingvarnormalized=newMat();source.ConvertTo(normalized,MatType.CV_8UC1);varpreview=newMat();Cv2.ApplyColorMap(normalized,preview,ColormapTypes.Turbo);returnpreview;}}8. 常见错误与避坑
- 把 NV12 和 NV21 的第二平面顺序搞反。
- 把
src2当成普通 3 通道彩色图,而不是交错的 UV 平面。 - 让
src1和src2的尺寸不符合 YUV420 结构。 - 传入了不在支持列表里的转换码。
- 误以为这个函数可以处理任意 YUV 格式,其实它只处理当前绑定层支持的 YUV420 双平面格式。
9. 进阶扩展
- 可以把视频解码器输出的 NV12 帧直接接进这个函数,减少中间拷贝。
- 可以先观察 Y 平面,再单独分析 UV 平面的色偏。
- 可以把 NV12 和 NV21 的解码结果并排显示,用来排查摄像头格式错误。
- 可以把这个函数和
CvtColor结合起来,做从 YUV 到 Lab/HSV 的进一步分析。
10. 小结
Cv2.CvtColorTwoPlane的关键不是“转色”本身,而是“正确理解双平面布局”。只要记住下面三点,就不容易写错:
src1是 Y 平面。src2是交错的 UV 或 VU 平面。code决定你到底按 NV12 还是 NV21 来解释数据。
11. 相关链接
- WPF 教学控件:Cv2CvtColorTwoPlaneControl.xaml.cs
- 样例实现:CvtColorTwoPlaneSample.cs
- 官方文档源码位置:OpenCvSharp/Cv2/Cv2_imgproc.cs:2483
