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转换的方式,代码如下:

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转为RGB24及IplImage格式(I420和YV12)及Java版实现的更多相关文章

  1. 将秒数转为HH:MM:SS格式的时间

    /**  * 将秒数转为HH:MM:SS格式的时间  * @param $seconds  * @return string  */ public static function GetHHMMSSB ...

  2. Java 将Excel转为et和ett格式

    以.et结尾的文件格式是属于金山办公软件WPS Office中的电子表格文件,.ett是一种模板文件格式.除了通过WPS软件可以创建该格式的电子表格外,也可以通过格式转换的方法来获得,如将Micros ...

  3. JSon_零基础_007_将JSon格式的"数组"字符串转换为Java对象"数组"

    将JSon格式的"数组"字符串转换为Java对象"数组". 应用此技术从一个json对象字符串格式中得到一个java对应的对象. JSONObject是一个“n ...

  4. spring mvc3中JACKSON序列化日期格式的问题 - 墙头草的Java - BlogJava

    body { font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI ...

  5. [JsonSchema] 关于接口测试 Json 格式比对核心算法实现 (Java 版)

    引言 为什么要自己重新造轮子,而不是采用第三方的JsonSchema方法进行实现存在以下痛点:1.我之前在网上找了很久,没有找到java版直接进行jsonschema生成的方法或直接比较的方法2.ht ...

  6. fastjson对象转为json字符串日期格式变为时间戳问题

    今天尝试将map集合转为json对象时遇到一个问题.map中的value为日期格式如"2019-03-01",在使用JSONObject.toJSON(map).toString( ...

  7. 用Python递归解决阿拉伯数字转为中文财务数字格式的问题(2)--打开思路的一种方法

    几天前自己写了个将阿拉伯数字转为中文财务数字的程序.用的递归,不幸的是它是树形递归. 虽然实际过程中不太可能出现金额数字大到让Python递归栈溢出,但是始终是一块心病,这玩意终究在理论上是受限制的. ...

  8. 使用FFmpeg解码并用swscale将YUV转为RGB

    #include <stdio.h> #include <libavcodec/avcodec.h> #include <libavformat/avformat.h&g ...

  9. axios的post传参时,将参数转为form表单格式

    import axios from 'axios'; import alert from './alert.js'; import Qs from 'qs' //引入qs 时axios的自带模块 le ...

随机推荐

  1. 可以ping通虚拟机但不能telnet 9000端口

    突然发现eclipse不能连上虚拟机了,报错是本机连接不上9000的端口. 觉得有点奇怪,就在命令行里试图ping通虚拟机,成功:但尝试这telnet 9000端口的时候,却报错连接不上. 上网查了这 ...

  2. 正则表达式匹配a标签或div标签

    这里以a标签为例 a标签的href var a='<P><A href=\'~abc/ccg/ab.jpg\' width="3">文字</A> ...

  3. 优化SQL Server的内存占用之执行缓存

    在论坛上常见有朋友抱怨,说SQL Server太吃内存了.这里笔者根据经验简单介绍一下内存相关的调优知识   首先说明一下SQL Server内存占用由哪几部分组成.SQL Server占用的内存主要 ...

  4. Unity3D实现3D立体游戏原理及过程,需偏振眼镜3D显

    http://tieba.baidu.com/p/3038509618?fr=ala0&pstaala=3

  5. ant design pro 初识

    发送请求 上次讲到在api.js中发送请求,模拟了假数据,这次讲一下调用真实接口进行请求并渲染页面. 先完整的过一遍请求吧 首先view层发送请求例如下面的代码: componentDidMount( ...

  6. jQuery-mobile 学习笔记之三(事件监听)

    续上 触摸事件 - 当用户触摸屏幕时触发(敲击和滑动) 滚动事件 - 当上下滚动时触发 方向事件 - 当设备垂直或水平旋转时触发 页面事件 - 当页面被显示.隐藏.创建.载入以及/或卸载时触发 一.初 ...

  7. Android Training - Volley(Lesson 0 - 序言)

    写在http://hukai.me/blog/android-training-volley-index/

  8. <译>流计算容错

    这篇文档描述了Flink的流式计算的容错机制 Introduction Checkpointing Barriers State Exactly Once vs. At Least Once Reco ...

  9. php抽象类和接口的异同【转】

    1. 相同点: (1)      两者都是抽象类,都不能实例化. (2)      interface 实现类及 abstract class 的子类都必须要实现已经声明的抽象方法. 2. 不同点: ...

  10. IT痴汉的工作现状36-做好准备再上路

    软件开发流程管理是採用瀑布式好还是敏捷好? 如今非常多人会选择敏捷.由于眼下的现状是需求的变化是一天一个样,这是当前(移动)互联网的飞速发展所带来的.当我们仍採用原始的先做全盘的计划.然后在按部就班的 ...