博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
yuv420 还原为RGB图像
阅读量:4058 次
发布时间:2019-05-25

本文共 3464 字,大约阅读时间需要 11 分钟。

终于搞定了

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.

你可能感兴趣的文章
Sudoku Solver
查看>>
Bitwise AND of Numbers Range
查看>>
Happy Number
查看>>
Count Primes
查看>>
Isomorphic Strings
查看>>
Reverse Linked List
查看>>
Android面试题整理【转载】
查看>>
【opencv学习笔记】010之图像非线性滤波原理与操作(中值滤波、双边滤波)
查看>>
【opencv学习笔记】011之基本形态学操作(膨胀与腐蚀)
查看>>
【CryptoZombies - 1 Solidity 教程】010 msg.sender
查看>>
【opencv学习笔记】012之形态学操作(开闭操作,形态学梯度,顶帽与黑帽)
查看>>
【CryptoZombies - 1 Solidity 教程】011 Require
查看>>
【CryptoZombies - 1 Solidity 教程】012 继承(Inheritance)和 引用 (import)
查看>>
【CryptoZombies - 1 Solidity 教程】013 永久存储变量(storage)和 临时存储变量(memory)
查看>>
【opencv学习笔记】013之形态学操作应用(trackbar应用)
查看>>
【CryptoZombies - 1 Solidity 教程】014 函数可见性
查看>>
【CryptoZombies - 1 Solidity 教程】015 接口interface
查看>>
【opencv学习笔记】014之上采样与降采样
查看>>
【opencv学习笔记】015之基本阈值操作
查看>>
【CryptoZombies - 1 Solidity 教程】016 函数多返回值&奖励实战
查看>>