NV12 、NV21 和 BGR转换
可以看出NV12、NV21和BGR的互转都是OK的。
·
文章目录
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;
}
更多推荐

所有评论(0)