终于搞定了
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:"<
#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
for(int i=0;i<256;i++)
{
table[i]=qRgb(i,i,i);
}
tImage.setColorTable(table);
qint32 tYIndex=0;
for(qint32 i=0;i
for(qint32 j=0;j
quint8 tTableIndex=tYData.at(tYIndex);
tImage.setPixel(j,i,tTableIndex);
tYIndex++;
}
}
qDebug()<<"after Y:"<
QImage tImage(352,240,QImage::Format_RGB32);
qint32 tYUVWidth=tImage.width();
#if 1
//1,3,5,7..................
for(qint32 i=1;i
for(qint32 j=0;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
for(qint32 j=0;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.