本文共 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.