网站建设加盟创业,wordpress模板层级,大企业门户网站建设,百度搜索收录提交入口图像处理 文章目录 图像处理前言一、RGB格式二、YUV格式三、RGB与YUV转换四、NV21转换为YUV420p五、YUV旋转 前言
在图像的世界里#xff0c;一般使用RGB作为存储格式。而在视频的世界里#xff0c;一般使用YUV作为压缩存储格式。有时候面试官会问#xff1a;为什么视频使用…图像处理 文章目录 图像处理前言一、RGB格式二、YUV格式三、RGB与YUV转换四、NV21转换为YUV420p五、YUV旋转 前言
在图像的世界里一般使用RGB作为存储格式。而在视频的世界里一般使用YUV作为压缩存储格式。有时候面试官会问为什么视频使用YUV来压缩存储而不用RGBYUV与RGB有什么区别两者如何转换的常见的RGB格式有哪些常见的YUV格式又有哪些手机摄像头的预览格式是什么如何转换为YUV420P的我们带着这些问题来揭开RGB与YUV格式的面纱。
一、RGB格式
RGB是一种图像存储格式也是三原色取值范围[0, 255]。R代表Red红色G代表Green绿色B代表Blue蓝色。在openCV中一般使用BGR格式。在图像中一般使用32位色的ARGB(或RGBA)代表一个像素其中A代表Alpha透明度。常见的RGB格式有RGB888、RGBA8888、RGB565等。
1、RGBA8888 关于RGBA8888格式每个通道占8位即一个字节。四个通道构成一个像素总共占32位。排列顺序如下图所示 2、RGB565 关于RGB565格式其中R占5位G占6位B占5位。三个通道构成一个像素总共占16位。排列顺序如下图所示 3、图像的像素阵列 一张图像由宽x高的像素阵列构成为了内存对齐会使用stride来填充。如下图所示由4x3构成的像素阵列其中P代表pixel
二、YUV格式
YUV是一种视频压缩存储格式。其中Y代表Luma亮度U代表Chroma色度V代表Contrast对比度。常见的YUV采样比例如下
4:4:4 表示完全采样 4:2:2 表示水平2:1采样垂直完全采样 4:2:0 表示水平2:1采样垂直2:1采样 4:1:1 表示水平4:1采样垂直完全采样
常见的YUV格式有YUV420p、YUV420sp、NV21等。由于U和V分量都是Y分量的1/4而RGB888的所有分量占比都是1。进一步可得YUV整体占比是3/2RGB整体占比是6/2YUV所占存储空间比RGB少了3/2。因此默认采用YUV作为视频压缩存储格式。 1、YUV420p YUV420p属于平面存储YUV分量占比为4:1:1即每4个Y共享一组UV。先是Y分量然后是U分量最后是V分量。排列如下图所示 2、YUV420sp YUV420sp属于交错存储YUV分量占比为4:1:1即每4个Y共享一组UV。先是Y分量然后是UV分量交错存储。排列如下图所示 3、NV21 NV21属于交错存储YUV分量占比为4:1:1即每4个Y共享一组UV。Android手机摄像头预览数据默认是NV21格式。和YUV420sp的区别是NV21是VUVU这样排列如下图所示
三、RGB与YUV转换
关于YUV与RGB的转换公式可 参考ITU标准https://www.itu.int/rec/R-REC-BT.601。 也可以 参考维基百科https://zh.wikipedia.org/wiki/YUV。 咱们来看下转换公式 以rgb转yuv为例示例代码如下
void rgb_to_yuv(int8_t *yuv, int *rgb, int width, int height) {int rgbIndex 0;int yIndex 0;int uIndex width * height;int vIndex width * height * 5 / 4;int R, G, B;float Y, U, V;// 遍历图像获取所有像素点 for (int i 0; i height; i) {for (int j 0; j width; j) {// 从像素点获取R、G、B分量R (rgb[rgbIndex] 0xFF0000) 16;G (rgb[rgbIndex] 0xFF00) 8;B (rgb[rgbIndex] 0xFF);// 使用公式把RGB转成YUVY 0.299 * R 0.587 * G 0.114 * B;U -0.147 * R - 0.289 * G 0.436 * B;V 0.615 * R - 0.515 * G - 0.100 * B;// YUV分量赋值给yuv数组yuv[yIndex] (int8_t)Y;if (i % 2 0 j % 2 0) {yuv[uIndex] (int8_t) U;yuv[vIndex] (int8_t) V;}rgbIndex;}}
}四、NV21转换为YUV420p
由于NV21是交错存储4个Y共享一组UV而且是VUVU这样排列。所以我们需要把偶数的V分量、奇数的U分量读出来然后赋值给YUV420p。代码如下
static void nv21_to_yuv420p(int8_t *dst, int8_t *src, int len) {memcpy(dst, src, len); // yfor (int i 0; i len / 4; i) {*(dst len i) *(src len i * 2 1); // u*(dst len * 5 / 4 i) *(src len i * 2); // v}
}五、YUV旋转
YUV的存储是有旋转角度的存在。在手机拍摄时按照逆时针来看横屏向左是0度竖屏向下是90度横屏向右是180度竖屏向上是270度。既然有旋转角度我们就需要对YUV进行旋转处理代码如下
static void yuv420p_rotate90(int8_t *dst, const int8_t *src, int width, int height) {int n 0;int wh width * height;int half_width width / 2;int half_height height / 2;// yfor (int j 0; j width; j) {for (int i height - 1; i 0; i--) {dst[n] src[width * i j];}}// ufor (int i 0; i half_width; i) {for (int j 1; j half_height; j) {dst[n] src[wh ((half_height - j) * half_width i)];}}// vfor (int i 0; i half_width; i) {for (int j 1; j half_height; j) {dst[n] src[wh wh / 4 ((half_height - j) * half_width i)];}}
}static void yuv420p_rotate180(int8_t *dst, const int8_t *src, int width, int height) {int n 0;int half_width width / 2;int half_height height / 2;// yfor (int j height - 1; j 0; j--) {for (int i width; i 0; i--) {dst[n] src[width * j i - 1];}}// uint offset width * height;for (int j half_height - 1; j 0; j--) {for (int i half_width; i 0; i--) {dst[n] src[offset half_width * j i - 1];}}// voffset half_width * half_height;for (int j half_height - 1; j 0; j--) {for (int i half_width; i 0; i--) {dst[n] src[offset half_width * j i - 1];}}
}static void yuv420p_rotate270(int8_t *dst, const int8_t *src, int width, int height) {for (int j 0; j width; j) {for (int i 1; i height; i) {*dst *(src i * width - j);}}auto *src_u const_castint8_t *(src width * height);for (int j 0; j width / 2; j) {for (int i 1; i height / 2; i) {*dst *(src_u i * width / 2 - j);}}auto *src_v const_castint8_t *(src width * height * 5 / 4);for (int j 0; j width / 2; j) {for (int i 1; i height / 2; i) {*dst *(src_v i * width / 2 - j);}}
}static void yuv420p_rotate(int8_t *dst, int8_t *src, int width, int height, int degree) {switch(degree) {case 0:memcpy(dst, src, width * height * 3 / 2);break;case 90:yuv420p_rotate90(dst, src, width, height);break;case 180:yuv420p_rotate180(dst, src, width, height);break;case 270:yuv420p_rotate270(dst, src, width, height);break;default:break;}
}