文章目录
- 前置阅读:YUV格式
- 效果
- 源码
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;
}