opencv没有提供BGR转NV12或者NV21的方法,这里借助中间过程实现一下。

前置阅读:YUV格式

https://blog.csdn.net/qq_40622955/article/details/144427710

效果

  • 原图
    在这里插入图片描述

  • NV12
    在这里插入图片描述

  • NV12转BGR
    在这里插入图片描述

  • NV21
    在这里插入图片描述

  • NV21转BGR
    在这里插入图片描述
    可以看出NV12、NV21和BGR的互转都是OK的。

源码

  • head
#ifndef SRC_CVT_COLOR_HPP_

#define SRC_CVT_COLOR_HPP_

#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"


cv::Mat ConvertBgrToNv21(const cv::Mat &mat);
cv::Mat ConvertBgrToNv12(const cv::Mat &mat);

cv::Mat ConvertNv21ToBgr(const unsigned char *data, int width, int height);
cv::Mat ConvertNv12ToBgr(const unsigned char *data, int width, int height);


#endif // SRC_CVT_COLOR_HPP_
  • cpp
#include "cvt_color.hpp"

#include <iostream>

cv::Mat ConvertBgrToNv21(const cv::Mat &mat)
{

    if(mat.empty())
    {
        std::cout << "Mat is empty" << std::endl;
        return cv::Mat();
    }

    cv::Mat yuvi420;
    cv::cvtColor(mat, yuvi420, cv::COLOR_BGR2YUV_I420);

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

    cv::Mat nv21_mat(height * 3 / 2, width, CV_8UC1);

    int frame_size = width * height;
    int chroma_size = frame_size / 4;

    memcpy((void *)nv21_mat.data, (void *)yuvi420.data, frame_size);

    unsigned char *u_data = yuvi420.data + frame_size;
    unsigned char *v_data = u_data + chroma_size;

    for (int i = 0; i < chroma_size; i ++)
    {
        nv21_mat.data[frame_size + i * 2] = v_data[i];
        nv21_mat.data[frame_size + i * 2 + 1] = u_data[i];
    }

    return nv21_mat;
}

cv::Mat ConvertBgrToNv12(const cv::Mat &mat)
{

    if(mat.empty())
    {
        std::cout << "Mat is empty" << std::endl;
        return cv::Mat();
    }

    cv::Mat yuvi420;
    cv::cvtColor(mat, yuvi420, cv::COLOR_BGR2YUV_I420);

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

    cv::Mat nv12_mat(height * 3 / 2, width, CV_8UC1);

    int frame_size = width * height;
    int chroma_size = frame_size / 4;

    memcpy((void *)nv12_mat.data, (void *)yuvi420.data, frame_size);

    unsigned char *v_data = yuvi420.data + frame_size;
    unsigned char *u_data = v_data + chroma_size;

    for (int i = 0; i < chroma_size; i ++)
    {
        nv12_mat.data[frame_size + i * 2] = v_data[i];
        nv12_mat.data[frame_size + i * 2 + 1] = u_data[i];
    }

    return nv12_mat;
}

cv::Mat ConvertNv21ToBgr(const unsigned char *data, int width, int height)
{
    if(!data)
    {
        std::cout << "Mat is empty" << std::endl;
        return cv::Mat();
    }

    cv::Mat nv21(height * 3 / 2, width, CV_8UC1, (void *)data);

    cv::Mat cv_mat;
    cv::cvtColor(nv21, cv_mat, cv::COLOR_YUV2BGR_NV21);

    return cv_mat;
}

cv::Mat ConvertNv12ToBgr(const unsigned char *data, int width, int height)
{
    if(!data)
    {
        std::cout << "Mat is empty" << std::endl;
        return cv::Mat();
    }

    cv::Mat nv12(height * 3 / 2, width, CV_8UC1, (void *)data);

    cv::Mat cv_mat;
    cv::cvtColor(nv12, cv_mat, cv::COLOR_YUV2BGR_NV12);

    return cv_mat;
}
  • demo

#include "cvt_color.hpp"

#include <iostream>


void Demo()
{
    std::string image_path = "/media/hello/data/image/sample/1.jpeg";
    cv::Mat mat = cv::imread(image_path);
    cv::resize(mat, mat, cv::Size(1920*0.5,1080*0.5));
    if (mat.empty())
    {
        std::cout << "Failed to read image: " << image_path << std::endl;
        return;
    }

    cv::Mat nv21_mat = ConvertBgrToNv21(mat.clone());

    if (nv21_mat.empty())
    {
        std::cout << "Failed to convert BGR to NV21" << std::endl;
        return;
    }

    cv::Mat bgr_mat = ConvertNv21ToBgr(nv21_mat.clone().data, mat.cols, mat.rows);

    if (bgr_mat.empty())
    {
        std::cout << "Failed to convert NV21 to BGR" << std::endl;
        return;
    }

    cv::Mat nv12_mat = ConvertBgrToNv12(mat.clone());
    if( nv12_mat.empty())
    {
        std::cout << "nv12_mat is empty\n"; 
    }
    cv::Mat bgr_mat_nv12 = ConvertNv12ToBgr(nv12_mat.clone().data, mat.cols, mat.rows);
    if(bgr_mat_nv12.empty())
    {
        std::cout << "bgr_mat_nv12 is empty\n";
    }

    cv::imshow("BGR", mat);
    cv::imshow("NV21", nv21_mat);
    cv::imshow("BGR2_NV21R", bgr_mat);
    cv::imshow("NV12", nv12_mat);
    cv::imshow("BGR_NV12R", bgr_mat_nv12);
    cv::waitKey(0);

}




int main()
{
    Demo();
    return 0;
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐