为方便使用OpenCV进行显示,以BGR交错方式存储,存储方式如下(以4行8列图像为例):
依赖库:OpenCV(任一版本),仅用于显示图像
示例代码只为理解流程,较为冗余,且未加入必要代码优化。
测试图像:https://download.csdn.net/download/u012633319/11341574
<1> 示例代码采用的YUV颜色空间到RGB颜色空间的转换公式为
Y
U
V
→
R
G
B
{
R
=
Y
+
1.403
(
V
−
128
)
G
=
Y
−
0.343
(
U
−
128
)
−
0.714
(
V
−
128
)
B
=
Y
+
1.770
(
U
−
128
)
\footnotesize YUV\rightarrow RGB \begin{cases} R=Y+1.403(V-128) \\ G = Y - 0.343(U-128)-0.714(V-128) \\ B = Y + 1.770(U-128) \end{cases}
YUV→RGB⎩⎨⎧R=Y+1.403(V−128)G=Y−0.343(U−128)−0.714(V−128)B=Y+1.770(U−128)
<2>示例代码中YUV颜色空间到RGB颜色空间的变换函数为
YUV422_YUYV→RGB
void yuv422_yuyv_to_rgb(unsigned char *yuyv, unsigned char *rgb, int width, int height);
YUV420_NV12→RGB
void yuv420_nv12_to_rgb(unsigned char *nv12, unsigned char *rgb, int width, int height);
YUV420_NV21→RGB
void yuv420_nv21_to_rgb(unsigned char *nv21, unsigned char *rgb, int width, int height);
三个函数均以每组UV分量索引为循环变量。
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
void yuv422_yuyv_to_rgb(unsigned char *yuyv, unsigned char *rgb, int width, int height);
void yuv420_nv12_to_rgb(unsigned char *nv12, unsigned char *rgb, int width, int height);
void yuv420_nv21_to_rgb(unsigned char *nv21, unsigned char *rgb, int width, int height);
int main(int argc, char **argv)
{
int width = 800;
int height = 600;
char *yuv422_yuyv_file_path = "../testdata_yuv_convert/yuv422_800x600.YUY2&YUYV";
char *yuv420_nv12_file_path = "../testdata_yuv_convert/yuv420_800x600.NV12";
char *yuv420_nv21_file_path = "../testdata_yuv_convert/yuv420_800x600.NV21";
Mat img(height, width, CV_8UC3);
// 1、yuv422_yuyv(same as yuy2) to rgb
FILE *yuyv_fp = NULL;
uchar *yuyv = (uchar *)calloc(width * height * 2, sizeof(uchar));
fopen_s(&yuyv_fp, yuv422_yuyv_file_path, "rb");
fread_s(yuyv, width * height * 2 * sizeof(uchar), sizeof(uchar), width * height * 2, yuyv_fp);
yuv422_yuyv_to_rgb(yuyv, img.data, width, height);
free(yuyv);
fclose(yuyv_fp);
imshow("yuv422_yuyv(same as yuy2)", img);
waitKey(0);
// 2、yuv420_nv12 to rgb
FILE *nv12_fp = NULL;
uchar *nv12 = (uchar *)calloc(width*height * 3 / 2, sizeof(uchar));
fopen_s(&nv12_fp, yuv420_nv12_file_path, "rb");
fread_s(nv12, width*height * 3 / 2 * sizeof(uchar), sizeof(uchar), width*height * 3 / 2, nv12_fp);
yuv420_nv12_to_rgb(nv12, img.data, width, height);
free(nv12);
fclose(nv12_fp);
imshow("yuv420_nv12", img);
waitKey(0);
// 3、yuv420_nv21 to rgb
FILE *nv21_fp = NULL;
uchar *nv21 = (uchar *)calloc(width*height * 3 / 2, sizeof(uchar));
fopen_s(&nv21_fp, yuv420_nv21_file_path, "rb");
fread_s(nv21, width*height * 3 / 2 * sizeof(uchar), sizeof(uchar), width*height * 3 / 2, nv21_fp);
yuv420_nv21_to_rgb(nv21, img.data, width, height);
free(nv21);
fclose(nv21_fp);
imshow("yuv420_nv21", img);
waitKey(0);
return 0;
}
void yuv422_yuyv_to_rgb(unsigned char *yuyv, unsigned char *rgb, int width, int height)
{
for (int row = 0; row < height; row++)
{
for (int col = 0; col < width / 2; col++)
{
uchar y1 = yuyv[row*width * 2 + col * 4 + 0];
uchar u = yuyv[row*width * 2 + col * 4 + 1];
uchar y2 = yuyv[row*width * 2 + col * 4 + 2];
uchar v = yuyv[row*width * 2 + col * 4 + 3];
uchar r = 1.403*(v - 128);
uchar g = -0.343*(u - 128) - 0.714*(v - 128);
uchar b = 1.770*(u - 128);
rgb[(row*width + col * 2) * 3 + 0] = y1 + b;
rgb[(row*width + col * 2) * 3 + 1] = y1 + g;
rgb[(row*width + col * 2) * 3 + 2] = y1 + r;
rgb[(row*width + col * 2 + 1) * 3 + 0] = y2 + b;
rgb[(row*width + col * 2 + 1) * 3 + 1] = y2 + g;
rgb[(row*width + col * 2 + 1) * 3 + 2] = y2 + r;
}
}
}
void yuv420_nv12_to_rgb(unsigned char *nv12, unsigned char *rgb, int width, int height)
{
for (int row = 0; row < height / 2; row++)
{
for (int col = 0; col < width / 2; col++)
{
uchar y1 = nv12[row * 2 * width + col * 2];
uchar y2 = nv12[row * 2 * width + col * 2 + 1];
uchar y3 = nv12[(row * 2 + 1)*width + col * 2];
uchar y4 = nv12[(row * 2 + 1)*width + col * 2 + 1];
uchar u = nv12[width*height + row*width + col * 2];
uchar v = nv12[width*height + row*width + col * 2 + 1];
uchar r = 1.403*(v - 128);
uchar g = -0.343*(u - 128) - 0.714*(v - 128);
uchar b = 1.770*(u - 128);
rgb[(row * 2 * width + col * 2) * 3 + 0] = y1 + b;
rgb[(row * 2 * width + col * 2) * 3 + 1] = y1 + g;
rgb[(row * 2 * width + col * 2) * 3 + 2] = y1 + r;
rgb[(row * 2 * width + col * 2 + 1) * 3 + 0] = y2 + b;
rgb[(row * 2 * width + col * 2 + 1) * 3 + 1] = y2 + g;
rgb[(row * 2 * width + col * 2 + 1) * 3 + 2] = y2 + r;
rgb[((row * 2 + 1)*width + col * 2) * 3 + 0] = y3 + b;
rgb[((row * 2 + 1)*width + col * 2) * 3 + 1] = y3 + g;
rgb[((row * 2 + 1)*width + col * 2) * 3 + 2] = y3 + r;
rgb[((row * 2 + 1)*width + col * 2 + 1) * 3 + 0] = y4 + b;
rgb[((row * 2 + 1)*width + col * 2 + 1) * 3 + 1] = y4 + g;
rgb[((row * 2 + 1)*width + col * 2 + 1) * 3 + 2] = y4 + r;
}
}
}
void yuv420_nv21_to_rgb(unsigned char *nv21, unsigned char *rgb, int width, int height)
{
for (int row = 0; row < height / 2; row++)
{
for (int col = 0; col < width / 2; col++)
{
uchar y1 = nv21[row * 2 * width + col * 2];
uchar y2 = nv21[row * 2 * width + col * 2 + 1];
uchar y3 = nv21[(row * 2 + 1)*width + col * 2];
uchar y4 = nv21[(row * 2 + 1)*width + col * 2 + 1];
uchar v = nv21[width*height + row*width + col * 2];
uchar u = nv21[width*height + row*width + col * 2 + 1];
uchar r = 1.403*(v - 128);
uchar g = -0.343*(u - 128) - 0.714*(v - 128);
uchar b = 1.770*(u - 128);
rgb[(row * 2 * width + col * 2) * 3 + 0] = y1 + b;
rgb[(row * 2 * width + col * 2) * 3 + 1] = y1 + g;
rgb[(row * 2 * width + col * 2) * 3 + 2] = y1 + r;
rgb[(row * 2 * width + col * 2 + 1) * 3 + 0] = y2 + b;
rgb[(row * 2 * width + col * 2 + 1) * 3 + 1] = y2 + g;
rgb[(row * 2 * width + col * 2 + 1) * 3 + 2] = y2 + r;
rgb[((row * 2 + 1)*width + col * 2) * 3 + 0] = y3 + b;
rgb[((row * 2 + 1)*width + col * 2) * 3 + 1] = y3 + g;
rgb[((row * 2 + 1)*width + col * 2) * 3 + 2] = y3 + r;
rgb[((row * 2 + 1)*width + col * 2 + 1) * 3 + 0] = y4 + b;
rgb[((row * 2 + 1)*width + col * 2 + 1) * 3 + 1] = y4 + g;
rgb[((row * 2 + 1)*width + col * 2 + 1) * 3 + 2] = y4 + r;
}
}
}