【YUV】【3】YUV格式图像转换为RGB格式图像示例代码—YUV420_NV12、YUV420_NV21、YUV422_YUYV / YUV422_YUY2

为方便使用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} YUVRGBR=Y+1.403(V128)G=Y0.343(U128)0.714(V128)B=Y+1.770(U128)
<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;

        }
    }
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值