zoukankan      html  css  js  c++  java
  • YUV转为RGB24及IplImage格式(I420和YV12)及Java版实现

    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;
            }
  • 相关阅读:
    Insufficient parameters supplied to the command
    helloworld program of Linden Scripting Language
    使用DEV控件开发的小软件,单词查询及单词浏览
    SqlBulkCopy基本使用
    .NET3.0+中使软件发出声音[整理篇]
    Quick Hack for Setting the Row Height of a ListViewItem
    WCF返回JSON及EXT调用WCF
    拖动PictureBox 代码片断
    WCF配置工具及服务调试工具
    为指定的XML文件生成类并反序列化
  • 原文地址:https://www.cnblogs.com/cuizhf/p/3722471.html
Copyright © 2011-2022 走看看