旭日3 -- 颜色空间转换(BGR、NV12)

这篇博客主要介绍了如何使用C++和OpenCV库进行BGR到NV12以及NV12到BGR的颜色空间转换。示例代码包括两种不同的转换方法,涉及从YUV文件读取数据并进行转换,最后将结果显示或保存为图片文件。博客还提到了NV12格式的特点,即图像大小为宽度乘以高度再除以2,包含Y、U、V三个分量。
摘要由CSDN通过智能技术生成

前言:

因为最近在研究地平线旭日xj3AI芯片的使用,其中牵涉到颜色空间转换的问题。因为好时间没有使用过C++,有点生疏,这里做个记录。
旭日xj3中使用的是NV12格式的数据,这里主要基于C++、opencv库完成BGR到NV12的互相转换。

NV12简单介绍:

图像格式为NV12格式,那么图像大小是wxhx3/2,具体就是Y分量大小是wxh,UV分量大小为wxh/2;如果图像是Y格式,那么图像大小是wxh。
在这里插入图片描述

代码实现:

NV12转BGR 方式一:

#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <fstream>

using namespace std;
using namespace cv;

int main()
{
    const int width = 1920;
    const int height = 1080;

    std::ifstream file_in;
    file_in.open("../grp0_chn6_pym_out_basic_layer_DS0_1920_1080.yuv", std::ios::binary);
    std::filebuf *p_filebuf = file_in.rdbuf();
    size_t size = p_filebuf->pubseekoff(0, std::ios::end, std::ios::in);
    p_filebuf->pubseekpos(0, std::ios::in);

    char *buf_src = new char[size];
    p_filebuf->sgetn(buf_src, size);

    cv::Mat mat_src = cv::Mat(height*1.5, width, CV_8UC1, buf_src);
    cv::Mat mat_dst = cv::Mat(height, width, CV_8UC3);

   // cv::cvtColor(mat_src, mat_dst, cv::COLOR_YUV2BGR_NV12);
    cv::cvtColor(mat_src, mat_dst, cv::COLOR_YUV2BGR_NV21);
    cv::imshow("img", mat_dst);
    cv::waitKey(0);
    
    return 0;
}

NV12转BGR 方式二:

#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <fstream>

using namespace std;
using namespace cv;

int main()
{
//    const int width = 1920;
//    const int height = 1080;

    const int width = 720;
    const int height = 452;

//    FILE *fp = fopen("../grp0_chn6_pym_out_basic_layer_DS0_1920_1080.yuv", "rb");
    FILE *fp = fopen("../11.yuv", "rb");
    uchar *yuvdata = new uchar[height * 3 /2 * width * sizeof(uchar)];
    // fread: 从给定流 stream 读取数据到 ptr 所指向的数组中
    fread(yuvdata, height * 3 / 2, width, fp);

    Mat yuvimg(height * 3 / 2, width, CV_8UC1, yuvdata);
    Mat rgbimg(height, width, CV_8UC3);
    cvtColor(yuvimg, rgbimg, COLOR_YUV2BGR_NV12);

    imwrite("11.jpg", rgbimg);
    imshow("img", rgbimg);
    waitKey(0);
    fclose(fp);

    delete[] yuvdata;
    return 0;
}

cvtColor(yuvimg, rgbimg, COLOR_YUV2BGR_NV12)
cv::cvtColor(mat_src, mat_dst, cv::COLOR_YUV2BGR_NV21)
这两个可以直接使用,把BGR转换为NV12和NV21

BGR转NV12

#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>

using namespace std;


int main()
{
    cv::Mat bgr_mat = cv::imread("../1.jpg", cv::IMREAD_COLOR);

    int height = bgr_mat.rows;
    int width = bgr_mat.cols;

    cv::Mat img_nv12;
    cv::Mat yuv_mat;
    cv::cvtColor(bgr_mat, yuv_mat, cv::COLOR_BGR2YUV_I420);


    uint8_t *yuv = yuv_mat.ptr<uint8_t>();
    img_nv12 = cv::Mat(height * 3 / 2, width, CV_8UC1);
    uint8_t *ynv12 = img_nv12.ptr<uint8_t>();

    int32_t uv_height = height / 2;
    int32_t uv_width = width / 2;

    // copy y data
    int32_t y_size = height * width;
    memcpy(ynv12, yuv, y_size);

    // copy uv data
    uint8_t *nv12 = ynv12 + y_size;
    uint8_t *u_data = yuv + y_size;
    uint8_t *v_data = u_data + uv_height * uv_width;

    for (int32_t i = 0; i < uv_width * uv_height; i++) {
        *nv12++ = *u_data++;
        *nv12++ = *v_data++;
    }
    
    int32_t yuv_size = y_size + 2 * uv_height * uv_width;
    FILE *yuvFd = fopen("1.yuv", "w+");
    fwrite(img_nv12.ptr<uint8_t>(), 1, yuv_size, yuvFd);
    fclose(yuvFd);
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值