YUV422转YUV420的算法。。。

spring_2011 2011-07-01 03:39:31
VFW采集免驱动USB摄相头的视频,
biCompression = 844715353, 在网上看资料介绍是YUY2格式,也就是YUV422

用下面的代码转换后,发送出去;
传入的参数是VFW采集的原始视频流。

接收端接受到,转成RGB24进行播放,但是视频很模糊。
不清楚什么原因。。。

int YUV422To420(unsigned char *pYUV, unsigned int *yuv, int lWidth, int lHeight)
{
int i,j;
unsigned int *pY = yuv;
unsigned int *pU = yuv + lWidth*lHeight;
unsigned int *pV = pU + (lWidth*lHeight)/4;

unsigned char *pYUVTemp = pYUV;
unsigned char *pYUVTempNext = pYUV+lWidth*2;

for(i=0; i<lHeight; i+=2)
{
for(j=0; j<lWidth; j+=2)
{
pY[j] = *pYUVTemp++;
pY[j+lWidth] = *pYUVTempNext++;

pU[j/2] =(*(pYUVTemp) + *(pYUVTempNext))/2;
pYUVTemp++;
pYUVTempNext++;

pY[j+1] = *pYUVTemp++;
pY[j+1+lWidth] = *pYUVTempNext++;

pV[j/2] =(*(pYUVTemp) + *(pYUVTempNext))/2;
pYUVTemp++;
pYUVTempNext++;
}
pYUVTemp+=lWidth*2;
pYUVTempNext+=lWidth*2;
pY+=lWidth*2;
pU+=lWidth/2;
pV+=lWidth/2;
}

return 1;
}
...全文
2699 22 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
spring_2011 2011-07-07
  • 打赏
  • 举报
回复
最近又碰到一个很奇怪的问题:
用C++封装DLL来采集视频,通过回调函数传给C#,
然后让C#来播放;

RGB格式的播放没有问题,但是YUY2格式的播放的时候,屏幕总是闪烁,
一会清晰,一会绿屏,感觉数据有问题。

不知道是C#不能直接播放YUY2数据,还是因为通过回调函数回发数据的速度太快了。。。。

在C#版块发的一个帖子

C# 是否可以播放YUY2格式的视频?
http://topic.csdn.net/u/20110706/17/6b6fe826-4d28-4d6c-bb0e-0abc8db15c08.html
spring_2011 2011-07-06
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 lifesider 的回复:]
下面均指每通道8bit,即量化除数为256,值为0~255
YUYV/UYVY,每个像素16bit,因为第二个UV丢弃
RGBA,每个像素32bit
RGB/BGR,每个像素24Bit
YUV422/YUV420/YUV411,分片数据,Y一片,U一片,V一片
可查询微软MSDN,或者参考《视频技术手册》
[/Quote]
=======================
YUY2是免驱动USB摄相头,采集的原始视频,
具体是分片,还是打包方式,还不是太清楚.

biCompression = 844715353
biBitCount = 16
看网上介绍说是 YUY2格式, 我也不是很确定.

通过VFW的API来设置biBitCount = 24, 但是设置不成功.
lifesider 2011-07-06
  • 打赏
  • 举报
回复
下面均指每通道8bit,即量化除数为256,值为0~255
YUYV/UYVY,每个像素16bit,因为第二个UV丢弃
RGBA,每个像素32bit
RGB/BGR,每个像素24Bit
YUV422/YUV420/YUV411,分片数据,Y一片,U一片,V一片
可查询微软MSDN,或者参考《视频技术手册》
lifesider 2011-07-06
  • 打赏
  • 举报
回复
YUY2即YUYV,是打包方式
排列即为Y0 U0 Y1 V0 Y2 U2 Y3 V2 Y4 U4 Y5 V4...
注意到,Y是没有丢弃的,但是U和V丢弃了偶数列像素(索引从0开始,即丢弃了U1,V1,U3,V3...)
spring_2011 2011-07-06
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 robertbaker 的回复:]
引用 4 楼 spring_2011 的回复:
biCompression = 844715353
biBitCount = 16
看网上介绍说是 YUY2格式, 我也不是很确定.

biBitCount = 16 ????

"接收端接受到,转成RGB24进行播放,但是视频很模糊。"
RGB24 的 biBitCount = 24 ????

去我的资源看看吧,也许有你需要的……
[/Quote]
===================
好象有驱动的,一般都是24位, RGB24
免驱动的一般都是16位, 大概是 YUY2
LiuYinChina 2011-07-05
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 spring_2011 的回复:]
biCompression = 844715353
biBitCount = 16
看网上介绍说是 YUY2格式, 我也不是很确定.
[/Quote]
biBitCount = 16 ????

"接收端接受到,转成RGB24进行播放,但是视频很模糊。"
RGB24 的 biBitCount = 24 ????

去我的资源看看吧,也许有你需要的东西。
spring_2011 2011-07-05
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 lifesider 的回复:]
大意了,每四行计算时,牵引错误,试试下面的代码吧,不过这种代码很有优化的余地
书籍可以参考“视频技术手册”,上面有YUV422到YUV420采样转换的讲解

C/C++ code

int YUV422To420(unsigned char *pYUV, unsigned int *yuv, int lWidth, int lHeight)
{
int i,j;
u……
[/Quote]
======================
谢谢提醒,我再试下看看...
lifesider 2011-07-04
  • 打赏
  • 举报
回复
大意了,每四行计算时,牵引错误,试试下面的代码吧,不过这种代码很有优化的余地
书籍可以参考“视频技术手册”,上面有YUV422到YUV420采样转换的讲解

int YUV422To420(unsigned char *pYUV, unsigned int *yuv, int lWidth, int lHeight)
{
int i,j;
unsigned int *pY = yuv;
unsigned int *pU = yuv + lWidth*lHeight;
unsigned int *pV = pU + (lWidth*lHeight)/4;

unsigned char *pYUVTemp = pYUV;
unsigned char *pYUVTempNext = pYUV+lWidth*2;
unsigned char *pYUV2 = pYUVTempNext + lWidth*2;
unsigned char *pYUV3 = pYUVTempNext + lWidth*4;

for(i=0; i<lHeight; i+=4)
{
for(j=0; j<lWidth; j+=4)
{
// Y0
pY[j] = pYUVTemp[j];
pY[j+lWidth] = pYUVTempNext[j];
pY[j+lWidth*2] = pYUV2[j];
pY[j+lWidth*3] = pYUV3[j];
// U
pU[j/2] = (3*pYUVTemp[j+1] + pYUV2[j+1])/4;
pU[j/2+lWidth/2] = (pYUVTempNext[j+1] + 3*pYUV3[j+1])/4;
// Y1
pY[j+1] = pYUVTemp[j+2];
pY[j+lWidth+1] = pYUVTempNext[j+2];
pY[j+lWidth*2+1] = pYUV2[j+2];
pY[j+lWidth*3+1] = pYUV3[j+2];
// V
pV[j/2] = (3*pYUVTemp[j+3] + pYUV2[j+3])/4;
pV[j/2+lWidth/2] = (pYUVTempNext[j+3] + 3*pYUV3[j+3])/4;

}
// 分别加四行
pYUVTemp+=lWidth*2*4;
pYUVTempNext+=lWidth*2*4;
pYUV2+=lWidth*2*4;
pYUV3+=lWidth*2*4;
// Y加上四行
pY+=lWidth*4;
// UV加两行
pU+=lWidth;
pV+=lWidth;
}

return 1;
}
spring_2011 2011-07-04
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 lifesider 的回复:]
C/C++ code

int YUV422To420(unsigned char *pYUV, unsigned int *yuv, int lWidth, int lHeight)
{
int i,j;
unsigned int *pY = yuv;
unsigned int *pU = yuv + lWidth*lHeight;
unsigned int *pV……
[/Quote]
======================

for(i=0; i<lHeight; i+=4)
{
for(j=0; j<lWidth; j+=4)
{
// Y0
pY[j] = *pYUVTemp++;
pY[j+lWidth] = *pYUVTempNext++;
pY[j+lWidth*2] = *pYUV2++;
pY[j+lWidth*3] = *pYUV3++; //执行到该行代码,出现异常。。。

//获取摄相头原始视频的相关参数
capGetVideoFormat(m_capwnd,&m_bmpinfo,sizeof(m_bmpinfo));

m_bmpinfo.bmiHeader.biSize =40
m_bmpinfo.bmiHeader.biWidth =176
m_bmpinfo.bmiHeader.biHeight =144
m_bmpinfo.bmiHeader.biPlanes =1
m_bmpinfo.bmiHeader.biBitCount =16
m_bmpinfo.bmiHeader.biCompression =844715353
m_bmpinfo.bmiHeader.biSizeImage =50688
spring_2011 2011-07-04
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 willing198703 的回复:]
楼主的这个问题解决了没?我的也是出现了这个问题,我的应该是色彩部队了,只有一个图像的大概!但是在有个同学的机子上可以成功运行,很纳闷啊!
[/Quote]
=============
我从网上拷贝的一段代码,算法没看明白,也没有修改.
spring_2011 2011-07-04
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 lifesider 的回复:]
C/C++ code

int YUV422To420(unsigned char *pYUV, unsigned int *yuv, int lWidth, int lHeight)
{
int i,j;
unsigned int *pY = yuv;
unsigned int *pU = yuv + lWidth*lHeight;
unsigned int *pV……
[/Quote]
=======================
谢谢,我再试下看看.

我现在测试的是从网上拷贝的一段代码,具体算法没看明白也没有修改.
lifesider 2011-07-03
  • 打赏
  • 举报
回复

int YUV422To420(unsigned char *pYUV, unsigned int *yuv, int lWidth, int lHeight)
{
int i,j;
unsigned int *pY = yuv;
unsigned int *pU = yuv + lWidth*lHeight;
unsigned int *pV = pU + (lWidth*lHeight)/4;

unsigned char *pYUVTemp = pYUV;
unsigned char *pYUVTempNext = pYUV+lWidth*2;
unsigned char *pYUV2 = pYUVTempNext + lWidth*2;
unsigned char *pYUV3 = pYUVTempNext + lWidth*4;

for(i=0; i<lHeight; i+=4)
{
for(j=0; j<lWidth; j+=4)
{
// Y0
pY[j] = *pYUVTemp++;
pY[j+lWidth] = *pYUVTempNext++;
pY[j+lWidth*2] = *pYUV2++;
pY[j+lWidth*3] = *pYUV3++;
// U
pU[j/2] = (3*pYUVTemp[j] + pYUV2[j])/4;
pU[j/2+lWidth/2] = (pYUVTempNext[j] + 3*pYUV3[j])/4;
// Y1
pY[j+1] = *pYUVTemp++;
pY[j+lWidth+1] = *pYUVTempNext++;
pY[j+lWidth*2+1] = *pYUV2++;
pY[j+lWidth*3+1] = *pYUV3++;
// V
pV[j/2] = (3*pYUVTemp[j] + pYUV2[j])/4;
pV[j/2+lWidth/2] = (pYUVTempNext[j] + 3*pYUV3[j])/4;

}
pYUVTemp+=lWidth*2*4;
pYUVTempNext+=lWidth*2*4;
pYUV2+=lWidth*2*4;
pYUV3+=lWidth*2*4;
pY+=lWidth*4;
pU+=lWidth;
pV+=lWidth;
}

return 1;
}
lifesider 2011-07-03
  • 打赏
  • 举报
回复
你首先要确定数据是分片数据还是打包数据,常说的YUY2指YUYV,采样信号是Y:U:V=4:2:2,YUV422数据常指分片数据,即和YUV420一样,Y一片,U一片,V一片

看你的代码,实质是打包的YUYV转为分片的YUV420,这种情况下,YUV420的UV的高将变为YUYV中UV高的一半
算法实现上,Y不变化,纯属拷贝
至于UV,算法一样,即YUYV的奇场和偶场分别进行插值按序产生YUV420中UV的一行,而不是你代码中的奇行和偶行进行平均插值
另外,看你UV插值算法中使用的是平均插值,也可以修改,奇场使用3:1插值,偶场使用1:3插值,即对称计算
willing198703 2011-07-03
  • 打赏
  • 举报
回复
楼主的这个问题解决了没?我的也是出现了这个问题,我的应该是色彩部队了,只有一个图像的大概!但是在有个同学的机子上可以成功运行,很纳闷啊!
spring_2011 2011-07-01
  • 打赏
  • 举报
回复
视频的原始数据, 是VFW采集视频时,在回调函数中获取的.
ryfdizuo 2011-07-01
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 spring_2011 的回复:]
void YUV422To420(unsigned char* pYUV,
unsigned char* pY, unsigned char* pU, unsigned char* pV,
int lWidth, int lHeight)

之前看别的程序, 有的多传入三个参数
unsigned char* pY, unsigned char* pU, unsigned char* ……
[/Quote]找个关系不大,你的函数 是结果保存到了yuv一维数组中。
spring_2011 2011-07-01
  • 打赏
  • 举报
回复
void YUV422To420(unsigned char* pYUV,
unsigned char* pY, unsigned char* pU, unsigned char* pV,
int lWidth, int lHeight)

之前看别的程序, 有的多传入三个参数
unsigned char* pY, unsigned char* pU, unsigned char* pV,
不知道这个是否有影响...
spring_2011 2011-07-01
  • 打赏
  • 举报
回复
biCompression = 844715353
biBitCount = 16
看网上介绍说是 YUY2格式, 我也不是很确定.
ryfdizuo 2011-07-01
  • 打赏
  • 举报
回复
花屏应该是你算法的问题。
spring_2011 2011-07-01
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 wutaihua 的回复:]
如果是转换不对的话 应该是视频花屏或者色彩不对。或者视频只有半截。你现在仅仅是视频模糊。可以尝试在转换以后,将码流保存。CSDN下载里面有yuv viewer。直接用那个播放。先不管发送那部分的代码。然后看下问题。
[/Quote]
=================
刚刚是我描述错了, 是视频花屏,等写贴个图片.
加载更多回复(1)

19,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧