YUV转为RGB24及IplImage格式(I420和YV12)及Java版实现
2014-05-11 22:45
423 查看
http://blog.csdn.net/xy365/article/details/18735849
———————————————————————————————————————————————————————————
一、YUV简介
一般来说,直接采集到的视频数据是RGB24的格式,RGB24一帧的大小size=width×heigth×3
Byte,RGB32的size=width×heigth×4 Byte,如果是I420(即YUV标准格式4:2:0)的数据量是
size=width×heigth×1.5 Byte。
在采集到RGB24数据后,需要对这个格式的数据进行第一次压缩。即将图像的颜色空间由RGB24转化为IYUV。因为,X264在进行编码的时候需要标
准的YUV(4:2:0)。但是这里需要注意的是,虽然YV12也是(4:2:0),但是YV12和I420的却是不同的,在存储空间上面有些区别。如
下:
YV12 : 亮度(行×列) + V(行×列/4) + U(行×列/4)
I420 : 亮度(行×列) + U(行×列/4) + V(行×列/4)
可以看出,YV12和I420基本上是一样的,就是UV的顺序不同。
YUV420p 和 YUV420的区别在于存储格式上有区别:
YUV420p:yyyyyyyy uuuu vvvvv
YUV420: yuv yuv yuv
关于YUV 更详细资料可参考:http://zh.wikipedia.org/wiki/YUV。
另外,需要注意的是海康设备回调数据类型为YV12格式;而大华设备回调数据类型为YUV420格式。
二、YUV420转IplImage
采用OpenCV转换的方式,代码如下:
采用数学转换的方式,代码如下:
三、YV12转IplImage
————————————————————————————————————————————————————————————————————————
参考以上代码,实现了Java版(注意无符号数及指针的处理)
// YV12格式一个像素占1.5个字节
private byte[] YV12_To_RGB24(byte[] yv12, int width, int height) {
if(yv12 == null) {
return null;
}
int nYLen = (int)width * height;
int halfWidth = width >> 1;
if(nYLen<1 || halfWidth<1) {
return null;
}
// yv12's data structure
// |WIDTH |
// y......y--------
// y......y HEIGHT
// y......y
// y......y--------
// v..v
// v..v
// u..u
// u..u
// Convert YV12 to RGB24
byte[] rgb24 = new byte[width * height * 3];
int[] rgb = new int[3];
int i, j, m, n, x, y;
m = -width;
n = -halfWidth;
for(y=0; y<height; y++) {
m += width;
if(y%2 != 0) {
n += halfWidth;
}
for(x=0; x<width; x++) {
i = m+x;
j = n + (x>>1);
rgb[2] = (int)((int)(yv12[i]&0xFF) + 1.370705 * ((int)(yv12[nYLen+j]&0xFF) - 128)); // r
rgb[1] = (int)((int)(yv12[i]&0xFF) - 0.698001 * ((int)(yv12[nYLen+(nYLen>>2)+j]&0xFF) - 128) - 0.703125 * ((int)(yv12[nYLen+j]&0xFF) - 128)); // g
rgb[0] = (int)((int)(yv12[i]&0xFF) + 1.732446 * ((int)(yv12[nYLen+(nYLen>>2)+j]&0xFF) - 128)); // b
//j = nYLen - iWidth - m + x;
//i = (j<<1) + j; //图像是上下颠倒的
j = m + x;
i = (j<<1) + j;
for(j=0; j<3; j++) {
if(rgb[j]>=0 && rgb[j]<=255) {
rgb24[i+j] = (byte)rgb[j];
} else {
rgb24[i+j] = (byte) ((rgb[j] < 0)? 0 : 255);
}
}
}
}
return rgb24;
}
private IplImage YV12_ToIplImage(byte[] yv12, int width, int height) {
if(yv12 == null) {
return null;
}
byte[] rgb24 = YV12_To_RGB24(yv12, width, height);
if(rgb24 == null) {
return null;
}
IplImage image = cvCreateImage(cvSize(width, height), 8, 3);
image.imageData(new BytePointer(rgb24));
return image;
}
———————————————————————————————————————————————————————————
一、YUV简介
一般来说,直接采集到的视频数据是RGB24的格式,RGB24一帧的大小size=width×heigth×3
Byte,RGB32的size=width×heigth×4 Byte,如果是I420(即YUV标准格式4:2:0)的数据量是
size=width×heigth×1.5 Byte。
在采集到RGB24数据后,需要对这个格式的数据进行第一次压缩。即将图像的颜色空间由RGB24转化为IYUV。因为,X264在进行编码的时候需要标
准的YUV(4:2:0)。但是这里需要注意的是,虽然YV12也是(4:2:0),但是YV12和I420的却是不同的,在存储空间上面有些区别。如
下:
YV12 : 亮度(行×列) + V(行×列/4) + U(行×列/4)
I420 : 亮度(行×列) + U(行×列/4) + V(行×列/4)
可以看出,YV12和I420基本上是一样的,就是UV的顺序不同。
YUV420p 和 YUV420的区别在于存储格式上有区别:
YUV420p:yyyyyyyy uuuu vvvvv
YUV420: yuv yuv yuv
关于YUV 更详细资料可参考:http://zh.wikipedia.org/wiki/YUV。
另外,需要注意的是海康设备回调数据类型为YV12格式;而大华设备回调数据类型为YUV420格式。
二、YUV420转IplImage
采用OpenCV转换的方式,代码如下:
IplImage* YUV420_To_IplImage_Opencv(unsigned char* pYUV420, int width, int height) { if (!pYUV420) { return NULL; } IplImage *yuvimage,*rgbimg,*yimg,*uimg,*vimg,*uuimg,*vvimg; int nWidth = width; int nHeight = height; rgbimg = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,3); yuvimage = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,3); yimg = cvCreateImageHeader(cvSize(nWidth, nHeight),IPL_DEPTH_8U,1); uimg = cvCreateImageHeader(cvSize(nWidth/2, nHeight/2),IPL_DEPTH_8U,1); vimg = cvCreateImageHeader(cvSize(nWidth/2, nHeight/2),IPL_DEPTH_8U,1); uuimg = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,1); vvimg = cvCreateImage(cvSize(nWidth, nHeight),IPL_DEPTH_8U,1); cvSetData(yimg,pYUV420, nWidth); cvSetData(uimg,pYUV420+nWidth*nHeight, nWidth/2); cvSetData(vimg,pYUV420+long(nWidth*nHeight*1.25), nWidth/2); cvResize(uimg,uuimg,CV_INTER_LINEAR); cvResize(vimg,vvimg,CV_INTER_LINEAR); cvMerge(yimg,uuimg,vvimg,NULL,yuvimage); cvCvtColor(yuvimage,rgbimg,CV_YCrCb2RGB); cvReleaseImage(&uuimg); cvReleaseImage(&vvimg); cvReleaseImageHeader(&yimg); cvReleaseImageHeader(&uimg); cvReleaseImageHeader(&vimg); cvReleaseImage(&yuvimage); if (!rgbimg) { return NULL; } return rgbimg; }
采用数学转换的方式,代码如下:
bool YUV420_To_BGR24(unsigned char *puc_y, unsigned char *puc_u, unsigned char *puc_v, unsigned char *puc_rgb, int width_y, int height_y) { if (!puc_y || !puc_u || !puc_v || !puc_rgb) { return false; } //初始化变量 int baseSize = width_y * height_y; int rgbSize = baseSize * 3; BYTE* rgbData = new BYTE[rgbSize]; memset(rgbData, 0, rgbSize); /* 变量声明 */ int temp = 0; BYTE* rData = rgbData; //r分量地址 BYTE* gData = rgbData + baseSize; //g分量地址 BYTE* bData = gData + baseSize; //b分量地址 int uvIndex =0, yIndex =0; //YUV->RGB 的转换矩阵 //double Yuv2Rgb[3][3] = {1, 0, 1.4022, // 1, -0.3456, -0.7145, // 1, 1.771, 0}; for(int y=0; y < height_y; y++) { for(int x=0; x < width_y; x++) { uvIndex = (y>>1) * (width_y>>1) + (x>>1); yIndex = y * width_y + x; /* r分量 */ temp = (int)(puc_y[yIndex] + (puc_v[uvIndex] - 128) * 1.4022); rData[yIndex] = temp<0 ? 0 : (temp > 255 ? 255 : temp); /* g分量 */ temp = (int)(puc_y[yIndex] + (puc_u[uvIndex] - 128) * (-0.3456) + (puc_v[uvIndex] - 128) * (-0.7145)); gData[yIndex] = temp < 0 ? 0 : (temp > 255 ? 255 : temp); /* b分量 */ temp = (int)(puc_y[yIndex] + (puc_u[uvIndex] - 128) * 1.771); bData[yIndex] = temp < 0 ? 0 : (temp > 255 ? 255 : temp); } } //将R,G,B三个分量赋给img_data int widthStep = width_y*3; for (int y = 0; y < height_y; y++) { for (int x = 0; x < width_y; x++) { puc_rgb[y * widthStep + x * 3 + 2] = rData[y * width_y + x]; //R puc_rgb[y * widthStep + x * 3 + 1] = gData[y * width_y + x]; //G puc_rgb[y * widthStep + x * 3 + 0] = bData[y * width_y + x]; //B } } if (!puc_rgb) { return false; } delete [] rgbData; return true; } IplImage* YUV420_To_IplImage(unsigned char* pYUV420, int width, int height) { if (!pYUV420) { return NULL; } //初始化变量 int baseSize = width*height; int imgSize = baseSize*3; BYTE* pRGB24 = new BYTE[imgSize]; memset(pRGB24, 0, imgSize); /* 变量声明 */ int temp = 0; BYTE* yData = pYUV420; //y分量地址 BYTE* uData = pYUV420 + baseSize; //u分量地址 BYTE* vData = uData + (baseSize>>2); //v分量地址 if(YUV420_To_BGR24(yData, uData, vData, pRGB24, width, height) == false || !pRGB24) { return NULL; } IplImage *image = cvCreateImage(cvSize(width, height), 8,3); memcpy(image->imageData, pRGB24, imgSize); if (!image) { return NULL; } delete [] pRGB24; return image; }
三、YV12转IplImage
//YV12转为BGR24数据 bool YV12_To_BGR24(unsigned char* pYV12, unsigned char* pRGB24,int width, int height) { if(!pYV12 || !pRGB24) { return false; } const long nYLen = long(height * width); const int halfWidth = (width>>1); if(nYLen<1 || halfWidth<1) { return false; } // yv12's data structure // |WIDTH | // y......y-------- // y......y HEIGHT // y......y // y......y-------- // v..v // v..v // u..u // u..u unsigned char* yData = pYV12; unsigned char* vData = &yData[nYLen]; unsigned char* uData = &vData[nYLen>>2]; if(!uData || !vData) { return false; } // Convert YV12 to RGB24 int rgb[3]; int i, j, m, n, x, y; m = -width; n = -halfWidth; for(y=0; y<height;y++) { m += width; if(!(y % 2)) n += halfWidth; for(x=0; x<width;x++) { i = m + x; j = n + (x>>1); rgb[2] = int(yData[i] + 1.370705 * (vData[j] - 128)); // r rgb[1] = int(yData[i] - 0.698001 * (uData[j] - 128) - 0.703125 * (vData[j] - 128)); // g rgb[0] = int(yData[i] + 1.732446 * (uData[j] - 128)); // b //j = nYLen - iWidth - m + x; //i = (j<<1) + j; //图像是上下颠倒的 j = m + x; i = (j<<1) + j; for(j=0; j<3; j++) { if(rgb[j]>=0 && rgb[j]<=255) pRGB24[i + j] = rgb[j]; else pRGB24[i + j] = (rgb[j] < 0)? 0 : 255; } } } if (pRGB24 == NULL) { return false; } return true; } IplImage* YV12_To_IplImage(unsigned char* pYV12, int width, int height) { if (!pYV12) { return NULL; } int sizeRGB = width* height *3; unsigned char* pRGB24 = new unsigned char[sizeRGB]; memset(pRGB24, 0, sizeRGB); if(YV12_To_BGR24(pYV12, pRGB24 ,width, height) == false || (!pRGB24)) { return NULL; } IplImage* pImage = cvCreateImage(cvSize(width, height), 8, 3); if(!pImage) { return NULL; } memcpy(pImage->imageData, pRGB24, sizeRGB); if (!(pImage->imageData)) { return NULL; } delete [] pRGB24; return pImage; }
————————————————————————————————————————————————————————————————————————
参考以上代码,实现了Java版(注意无符号数及指针的处理)
// YV12格式一个像素占1.5个字节
private byte[] YV12_To_RGB24(byte[] yv12, int width, int height) {
if(yv12 == null) {
return null;
}
int nYLen = (int)width * height;
int halfWidth = width >> 1;
if(nYLen<1 || halfWidth<1) {
return null;
}
// yv12's data structure
// |WIDTH |
// y......y--------
// y......y HEIGHT
// y......y
// y......y--------
// v..v
// v..v
// u..u
// u..u
// Convert YV12 to RGB24
byte[] rgb24 = new byte[width * height * 3];
int[] rgb = new int[3];
int i, j, m, n, x, y;
m = -width;
n = -halfWidth;
for(y=0; y<height; y++) {
m += width;
if(y%2 != 0) {
n += halfWidth;
}
for(x=0; x<width; x++) {
i = m+x;
j = n + (x>>1);
rgb[2] = (int)((int)(yv12[i]&0xFF) + 1.370705 * ((int)(yv12[nYLen+j]&0xFF) - 128)); // r
rgb[1] = (int)((int)(yv12[i]&0xFF) - 0.698001 * ((int)(yv12[nYLen+(nYLen>>2)+j]&0xFF) - 128) - 0.703125 * ((int)(yv12[nYLen+j]&0xFF) - 128)); // g
rgb[0] = (int)((int)(yv12[i]&0xFF) + 1.732446 * ((int)(yv12[nYLen+(nYLen>>2)+j]&0xFF) - 128)); // b
//j = nYLen - iWidth - m + x;
//i = (j<<1) + j; //图像是上下颠倒的
j = m + x;
i = (j<<1) + j;
for(j=0; j<3; j++) {
if(rgb[j]>=0 && rgb[j]<=255) {
rgb24[i+j] = (byte)rgb[j];
} else {
rgb24[i+j] = (byte) ((rgb[j] < 0)? 0 : 255);
}
}
}
}
return rgb24;
}
private IplImage YV12_ToIplImage(byte[] yv12, int width, int height) {
if(yv12 == null) {
return null;
}
byte[] rgb24 = YV12_To_RGB24(yv12, width, height);
if(rgb24 == null) {
return null;
}
IplImage image = cvCreateImage(cvSize(width, height), 8, 3);
image.imageData(new BytePointer(rgb24));
return image;
}
相关文章推荐
- YUV转为IplImage格式(I420和YV12)
- YUV转为IplImage格式(I420和YV12)
- YUV转为IplImage格式(I420和YV12)(转)
- YUV格式 I420,YV12
- 下列代码可以实现把Java的CST格式的时间字符串转为为Date对象和所需要的日期时间格式!
- Java平台要实现类似豆丁百度文科的文档在线阅读,总体思路是讲doc docx等文件格式利用jcom转换成pdf再用swftools转为swf。再用flexpaper组件显示swf。
- 视频存储格式YUV420 NV12 NV21 i420 YV12
- YUV420数据转为IplImage格式
- Java平台要实现类似豆丁百度文科的文档在线阅读,总体思路是讲doc docx等文件格式利用jcom转换成pdf再用swftools转为swf。再用flexpaper组件显示swf。
- YUV420(YV12,I420)裁剪,画中画算法实现(笔记)
- 【OpenGL】用OpenGL shader实现将YUV(YUV420,YV12)转RGB-(直接调用GPU实现,纯硬件方式,效率高) 这段时间一直在搞视频格式的转换问题,终于最近将一个图片的YUV
- JAVA实现网页快照,存为图片格式
- MySQL通信协议栈Java实现-(2)协议包格式
- YAML的Java实现——JYAML基本原理与示例(2)导入YAML格式文件
- java 将一个字符串解析为日期 将日期转为自己定义的格式以字符串输出
- java 实现将java对象转为yaml文件
- YUV格式学习:YUV420P、YV12、NV12、NV21格式转换成RGB24(转载)
- Java实现将阿拉伯数字转为汉字
- java实现HTTP的post请求 json格式中文乱码问题
- Java实现文件压缩与解压[zip格式,gzip格式]