yuv420 还原为RGB图像

来源:互联网 发布:js二维数组 用处 编辑:程序博客网 时间:2024/05/10 09:52

终于搞定了

YUV420 Planar存储方式,先存储所有的Y,再存储所有的U,再存储所有的V,所以读取出来的数据分为三个平式数组

tYData,tUData,tVData

对于每一个像素点转换为RGB,需要从tYData中提取Y值,从tUData中提取U值,从tVData中提取V值,要注意U、V可是4个Y使用同一对。

为了方便还原,我们将整个图像分为奇数行和偶数行,

先进行奇数行的扫描,再进行偶数行的扫描。不过这种使用setPixel一个像素一个像素的描点,效率太低了,暂时没有找到好的办法。因为YUV需要一个点一个点的转换为RGB。

提取Y值是比较简单的,一次一个,但是提取U、V值是要注意的,因为每一个2x2的Y值使用同一个U和同一个V,这就需要计算好偏移量(或叫坐标吧,反正俺老张喜欢这么叫的)。最初是试过不行的,从网上搜索了大量的YUV420数据格式看后,再加上俺用Libreoffice spreadsheet做了一张8x8像素的表格,推出公式来才解决的。

因为俺一直使用OpenSuse,所以很方便的使用Libreoffice的。有些时候还得用笨办法才能解决。

奶奶的,为了还原这个YUV,搞了2天时间。不容易呀。记录一下,下次就不会再不理解了。

话说YUV420这种使用2x2矩阵方式的采样数据,真是...............................

(看吧。漂亮的OpenSuse,使用5年了。。。。。。。。。)



void MainWindow::paintEvent(QPaintEvent *e)
{
    QPainter tPainter(this);
    tPainter.drawText(10,50,"hello");
    QString tYUVFile("/home/shell.albert/project/H.264/football/fb001.yuv");
    QFile tFile(tYUVFile);
    if(!tFile.open(QIODevice::ReadOnly))
    {
            qDebug()<<"open file failed!";
            return;
    }
    QByteArray tYData=tFile.read(84480);
    QByteArray tUData=tFile.read(21120);
    QByteArray tVData=tFile.read(21120);
    QByteArray tRestData=tFile.readAll();
    qDebug()<<"Y:"<<tYData.size();
    qDebug()<<"U:"<<tUData.size();
    qDebug()<<"V:"<<tVData.size();
    qDebug()<<"Rest:"<<tRestData.size();

#if 0
    //write Y to file.
    QFile tYFile("/home/shell.albert/y.yuv");
    if(tYFile.open(QIODevice::WriteOnly))
    {
        tYFile.write(tYData);
        tYFile.close();
    }
#endif

#if 0
    QImage tImage(352,240, QImage::Format_Indexed8);
    QVector<QRgb> table(256);
    for(int i=0;i<256;i++)
    {
        table[i]=qRgb(i,i,i);
    }
    tImage.setColorTable(table);
    qint32 tYIndex=0;
    for(qint32 i=0;i<tImage.height();i++)
    {
        for(qint32 j=0;j<tImage.width();j++)
        {
                quint8 tTableIndex=tYData.at(tYIndex);
                tImage.setPixel(j,i,tTableIndex);
                tYIndex++;
        }
    }
    qDebug()<<"after Y:"<<tYIndex;
#endif


    QImage tImage(352,240,QImage::Format_RGB32);
    qint32 tYUVWidth=tImage.width();
#if 1
    //1,3,5,7..................
    for(qint32 i=1;i<tImage.height();i+=2)
    {
        for(qint32 j=0;j<tImage.width();j++)
        {
            qint32 x=i;
            qint32 y=j;
            qint32 tYOffset=x*tYUVWidth+y;
            qint32 tUOffset=(x/2)*(tYUVWidth/2)+y/2;
            qint32 tVOffset=(x/2)*(tYUVWidth/2)+y/2;
            qDebug("1,3,5,7:(%d,%d):%d,%d,%d",i,j,tYOffset,tUOffset,tVOffset);
            quint8 tYValue=tYData.at(tYOffset);
            quint8 tUValue=tUData.at(tUOffset);
            quint8 tVValue=tVData.at(tVOffset);
            qint32 tRed=1.164*(tYValue-16)+1.596*(tVValue-128);
            qint32 tGreen=1.164*(tYValue-16)-0.813*(tVValue-128)-0.391*(tUValue-128);
            qint32 tBlue=1.164*(tYValue-16)+2.018*(tUValue-128);
            tRed=tRed>255?255:tRed<0?0:tRed;
            tGreen=tGreen>255?255:tGreen<0?0:tGreen;
            tBlue=tBlue>255?255:tBlue<0?0:tBlue;
            tImage.setPixel(j,i,qRgb(tRed,tGreen,tBlue));
        }
    }
#endif
#if 1
    //0,2,4,6,8...............
    for(qint32 i=0;i<tImage.height();i+=2)
    {
        for(qint32 j=0;j<tImage.width();j++)
        {
            qint32 x=i;
            qint32 y=j;
            qint32 tYOffset=x*tYUVWidth+y;
            qint32 tUOffset=(x/2)*(tYUVWidth/2)+y/2;
            qint32 tVOffset=(x/2)*(tYUVWidth/2)+y/2;
            qDebug("0,2,4,6:(%d,%d):%d,%d,%d",i,j,tYOffset,tUOffset,tVOffset);
            quint8 tYValue=tYData.at(tYOffset);
            quint8 tUValue=tUData.at(tUOffset);
            quint8 tVValue=tVData.at(tVOffset);
            qint32 tRed=1.164*(tYValue-16)+1.596*(tVValue-128);
            qint32 tGreen=1.164*(tYValue-16)-0.813*(tVValue-128)-0.391*(tUValue-128);
            qint32 tBlue=1.164*(tYValue-16)+2.018*(tUValue-128);
            tRed=tRed>255?255:tRed<0?0:tRed;
            tGreen=tGreen>255?255:tGreen<0?0:tGreen;
            tBlue=tBlue>255?255:tBlue<0?0:tBlue;
            tImage.setPixel(j,i,qRgb(tRed,tGreen,tBlue));
        }
    }
#endif
    tPainter.drawImage(0,0,tImage);
    tYData.resize(0);
    tUData.resize(0);
    tVData.resize(0);
}



By zhangshaoyan at April 29,2015.

0 0
原创粉丝点击