我们先来看看NV21 以及其他相似的存储格式吧~
NV21(YUV420)介绍
NV12和NV21属于YUV420格式(每2x2四个Y,共用一组uv),是一种two-plane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。先存储所有的Y,然后UV交错存储:NV12先U后V,NV21先V后U。
YUV420sp示例格式如下:
NV21:
NV12:
可以看到NV21 和NV12 的储存形式是Y分量和U、V分量进行分离的,而不像RBG的存储格式那样是进行对储存的。
我实现的功能是将RGB格式的图片存储为NV21的二进制格式,然后用专门用来打开YUV的软件—7YUV,来打开文件。
先来康康效果吧~
RGB.jpg(原图)
用opencv打开NV21储存的图片:
下面的灰色空白就是U、V分量在opencv下的表现形式
在利用7YUV软件打开后的效果图:
具体的代码实现如下:
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <vector>
#include <fstream>
#include <string>
void RGB2NV21()
const char *filename = "yuv.yuv";
cv::Mat Img = cv::imread("RGB.jpg");
FILE *fp = fopen(filename,"wb");
if (Img.empty())
std::cout << "empty!check your image";
return;
int cols = Img.cols;
int rows = Img.rows;
int Yindex = 0;
int UVindex = rows * cols;
unsigned char* yuvbuff = new unsigned char[1.5 * rows * cols];
cv::Mat NV21(rows+rows/2, cols, CV_8UC1);
cv::Mat OpencvYUV;
cv::Mat OpencvImg;
cv::cvtColor(Img, OpencvYUV, CV_BGR2YUV_YV12);
int UVRow{ 0 };
for (int i=0;i<rows;i++)
for (int j=0;j<cols;j++)
uchar* YPointer = NV21.ptr<uchar>(i);
int B = Img.at<cv::Vec3b>(i, j)[0];
int G = Img.at<cv::Vec3b>(i, j)[1];
int R = Img.at<cv::Vec3b>(i, j)[2];
//计算Y的值
int Y = (77 * R + 150 * G + 29 * B) >> 8;
YPointer[j] = Y;
yuvbuff[Yindex++] = (Y < 0) ? 0 : ((Y > 255) ? 255 : Y);
uchar* UVPointer = NV21.ptr<uchar>(rows+i/2);
//计算U、V的值,进行2x2的采样
if (i%2==0&&(j)%2==0)
int U = ((-44 * R - 87 * G + 131 * B) >> 8) + 128;
int V = ((131 * R - 110 * G - 21 * B) >> 8) + 128;
UVPointer[j] = V;
UVPointer[j+1] = U;
yuvbuff[UVindex++] = (V < 0) ? 0 : ((V > 255) ? 255 : V);
yuvbuff[UVindex++] = (U < 0) ? 0 : ((U > 255) ? 255 : U);
for (int i=0;i< 1.5 * rows * cols;i++)
fwrite(&yuvbuff[i], 1, 1, fp);
fclose(fp);
std::cout << "write to file ok!" << std::endl;
std::cout << "srcImg: " << "rows:" << Img.rows << "cols:" << Img.cols << std::endl;
std::cout << "NV21: " << "rows:" << NV21.rows << "cols:" << NV21.cols << std::endl;
std::cout << "opencv_YUV: " << "rows:" << OpencvYUV.rows << "cols:" << OpencvYUV.cols << std::endl;
cv::imshow("src", Img);//原图
cv::imshow("YUV", NV21);//转换后的图片
cv::imshow("opencv_YUV", OpencvYUV); //opencv转换后的图片
cv::imwrite("NV21.jpg", NV21);
cv::waitKey(30000);
int main()
RGB2NV21();
return 0;
以上就是RBG转NV21的全部内容啦
本程序实现了简单的YUV数据之间的转换和YUV与RGB的转换。
注:1、本程序只是简单YUV之间的颜色空间转换和YUV与RGB的转换。
2、本程序使用的vs2019创建的,需使用2019打开工程。
3、包含功能:
1)YV12_2_I420;
2)I420_2_YV12;
3)NV12_2_I420;
4)I420_2_NV12;
5)NV21_2_YV12;
6)YV12_2_NV21;
7)I420_2_rgb32;
8)rgb32_2_I420;
9)I420_2_rgb24;
10)rgb24_2_I420。
RGB转NV21格式读取本地图片生成BitmapRGB转NV21保存NV21格式的byte[]为图片参考
NV21 格式属于 YUV420SP 类型,是安卓中有的模式,它的存储顺序是先存 Y 分量,再 VU 交替存储。存储大小=height * width * 3 / 2。
注意,对于图片宽、高为奇数时,需要进行处理,否则会在byte[] yuv时发生越界。如果将byte[] yuv的初始化采用b...