整像素运动估计的C语言代码可用于FPGA验证Word文档下载推荐.docx
《整像素运动估计的C语言代码可用于FPGA验证Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《整像素运动估计的C语言代码可用于FPGA验证Word文档下载推荐.docx(19页珍藏版)》请在冰点文库上搜索。
P_16x16
//最终分割方式
typedefstruct
intframe;
//帧号
uint8_t*plane[3];
//存放一副图像的原始数据
}picture_t;
typedefstruct
FILE*fp;
//图像文件
intpix_width;
//图像宽按像素计
intpix_height;
//图像高按像素计
intmb_width;
//图像宽按宏块计
intmb_height;
//图像高按宏块计
picture_tpic[I_FRAME];
}yuv_t;
intmv[2];
//对应的最佳mv
uint_tsad;
//对应的sad值
}mvs_t;
uint8_tsad[16][16];
mvs_tmvs[9];
//存放种最佳mv
intpartition;
intmv[4];
yuv_t*init_yuv(yuv_t*);
voidinit_sad();
intcreat_yuv(yuv_t*,int);
voidstart_ime(yuv_t*);
voidfull_search(yuv_t*,int,int);
voidcal_sad(uint8_t*,uint8_t*,int);
voidcompare(int,int,int,int);
uint_tsub_block_sad(int[],int[]);
voidfree_yuv(yuv_t*);
voidfinal_opt();
voidadjust_range(int*,int*,int,int);
voidadjust_mv(int,int,int);
intmain(intargc,char*argv[])
yuv_t*h=NULL;
h=init_yuv(h);
//初始化yuv
if(!
h)
return-1;
if(creat_yuv(h,I_FRAME)<
0)//读图像
{
free_yuv(h);
}
start_ime(h);
//开始整像素搜索
free_yuv(h);
//释放内存
return0;
}
//初始化yuv
yuv_t*init_yuv(yuv_t*h)
inti;
h=(yuv_t*)malloc(sizeof(yuv_t));
//分配内存
//初始化像素指针
for(i=0;
i<
I_FRAME;
++i)
h->
pic[i].plane[0]=NULL;
h->
fp=fopen(PIC_P,"
rb"
);
h->
fp)
returnNULL;
pix_width=PIC_W;
//像素宽
pix_height=PIC_H;
//像素高
mb_width=h->
pix_width/16;
//宏块宽
mb_height=h->
pix_height/16;
//宏块高
returnh;
//预测宏块之前,初始化mvs中的sad值
voidinit_sad()
//初始化sad值
9;
++i)
mvs[i].sad=SAD_MAX;
mvs[i].mv[0]=0;
mvs[i].mv[1]=0;
//读取yuv序列
intcreat_yuv(yuv_t*h,inti_frame)
inticnt;
inti,j,sum=0;
//FILE*outf;
for(icnt=0;
icnt<
i_frame;
++icnt)//读取像素
pic[icnt].frame=icnt;
//为存储像素分配存储空间
pic[icnt].plane[0]=(uint8_t*)malloc(h->
pix_width*h->
pix_height*3/2*sizeof(uint8_t));
if(!
pic[icnt].plane[0])//若分配失败,返回-1//Y分量
return-1;
pic[icnt].plane[1]=h->
pic[icnt].plane[0]+h->
pix_height;
//U分量
pic[icnt].plane[2]=h->
pic[icnt].plane[1]+h->
pix_height/4;
//V分量
//找到一帧的开头
if(fseek(h->
fp,(uint64_t)(icnt+BEG)*h->
pix_height*3/2,SEEK_SET))
//分别读取Y、U、V三个分量至内存
if(fread(h->
pic[icnt].plane[0],1,h->
pix_height,h->
fp)<
=0
||fread(h->
pic[icnt].plane[1],1,h->
pix_height/4,h->
pic[icnt].plane[2],1,h->
=0)
//开始整像素运动估计
voidstart_ime(yuv_t*h)
intmb_x,mb_y;
intmbx_max=h->
mb_width-1;
intmby_max=h->
mb_height-1;
for(mb_y=0;
mb_y<
=mby_max;
++mb_y)
for(mb_x=0;
mb_x<
=mbx_max;
++mb_x)
{init_sad();
full_search(h,mb_x,mb_y);
final_opt(mb_x,mb_y);
printf("
\nMB:
x=%d,y=%d"
mb_x,mb_y);
//输出宏块坐标
switch(partition)
{
caseP_8x8:
{
//输出分割方式
printf("
\tPartition:
P_8x8"
//输出最佳sad
\tsad=%d%d%d%d\n"
mvs[0].sad,mvs[1].sad,mvs[2].sad,mvs[3].sad);
//输出参考块坐标
mv[0]=(%d,%d)"
mvs[0].mv[0],mvs[0].mv[1]);
mv[1]=(%d,%d)"
mvs[1].mv[0],mvs[1].mv[1]);
mv[2]=(%d,%d)"
mvs[2].mv[0],mvs[2].mv[1]);
mv[3]=(%d,%d)\n"
mvs[3].mv[0],mvs[3].mv[1]);
break;
}
caseP_8x16:
P_8x16"
\tsad=%d%d\n"
mvs[4].sad,mvs[5].sad);
mvs[4].mv[0],mvs[4].mv[1]);
mv[1]=(%d,%d)\n"
mvs[5].mv[0],mvs[5].mv[1]);
caseP_16x8:
P_16x8"
mvs[6].sad,mvs[7].sad);
mvs[6].mv[0],mvs[6].mv[1]);
mvs[7].mv[0],mvs[7].mv[1]);
caseP_16x16:
P_16x16"
\tsad=%d\n"
mvs[8].sad);
mv=(%d,%d)\n"
mvs[8].mv[0],mvs[8].mv[1]);
}
}
//开始搜索
voidfull_search(yuv_t*h,intmx,intmy)
intsr_x[2];
intsr_y[2];
inti,j=-1,k;
intpix_x,pix_y;
intshift_x,shift_y;
intstride=h->
pix_width;
uint8_t*ref_pix;
uint8_t*ref_mb,*cur_mb;
//找到搜索区域
sr_x[0]=MAX(0,mx-1);
//搜索范围x坐标的最小值按宏块计
sr_x[1]=MIN(h->
mb_width-1,mx+1);
//搜索范围x坐标的最大值按宏块计
sr_y[0]=MAX(0,my-1);
//搜索范围y坐标的最小值按宏块计
sr_y[1]=MIN(h->
mb_height-1,my+1);
//搜索范围y坐标的最大值按宏块计
//搜索范围按像素计
pix_x=(sr_x[1]-sr_x[0])*16;
pix_y=(sr_y[1]-sr_y[0])*16;
adjust_range(&
pix_x,&
pix_y,mx,my);
//搜索区域左上顶点相对于中心点的位移
shift_x=(mx-sr_x[0])*16;
shift_y=(my-sr_y[0])*16;
//找到搜索区域起始像素点
ref_pix=h->
pic[0].plane[0]+mx*16+my*16*stride
-shift_x-shift_y*stride;
//当前待编码宏块的起始像素位置
cur_mb=h->
pic[1].plane[0]+mx*16+my*16*stride;
//按全搜索算法搜索
pix_x;
i+=4)//一次做个点
if(j==-1)//按行正向搜索
{
for(j=0;
j<
pix_y;
++j)
for(k=i;
k<
i+4&
&
++k)
ref_mb=ref_pix+k+j*stride;
cal_sad(cur_mb,ref_mb,stride);
//算出当前个sad值
compare(k,j,mx,my);
//通过比较得出个最佳mv
}
elseif(j==pix_y)//按行逆向搜索
for(j=pix_y-1;
j>
=0;
--j)
//根据宏块位置调整搜索范围
voidadjust_range(int*rx,int*ry,intmx,intmy)
if(mx==MB_W-1&
my>
=0&
my<
MB_H-1)
*rx=*rx+1;
elseif(mx>
mx<
MB_W-1&
my==MB_H-1)
*ry=*ry+1;
elseif(mx==MB_W-1&
*rx=*rx+1;
//计算sad值
voidcal_sad(uint8_t*cur,uint8_t*ref,intstride)
inti,j;
16;
for(j=0;
sad[i][j]=abs(cur[j+i*stride]-ref[j+i*stride]);
//比较sad值,获得个最佳mv
voidcompare(intpx,intpy,intmx,intmy)
introw[2],col[2];
uint_ts[9]={SAD_MAX};
intt;
intmvx,mvy;
for(t=0;
t<
++t)
switch(t)
caseP_8x8_UL:
//左上角x8子块
row[0]=0;
row[1]=8;
col[0]=0;
col[1]=8;
s[P_8x8_UL]=sub_block_sad(row,col);
mvx=px;
mvy=py;
break;
caseP_8x8_UR:
//右上角x8子块
col[0]=8;
col[1]=16;
s[P_8x8_UR]=sub_block_sad(row,col);
mvx=px+8;
if(mx==7&
my==1)
printf("
(%d,%d)sad=%d\n"
mvx,mvy,s[t]);
system("
pause"
caseP_8x8_DL:
//左下角x8子块
row[0]=8;
row[1]=16;
s[P_8x8_DL]=sub_block_sad(row,col);
mvy=py+8;
caseP_8x8_DR:
//右下角x8子块
s[P_8x8_DR]=sub_block_sad(row,col);
caseP_8x16_L:
//左边x16子块
s[P_8x16_L]=s[P_8x8_UL]+s[P_8x8_DL];
caseP_8x16_R:
//右边x16子块
s[P_8x16_R]=s[P_8x8_UR]+s[P_8x8_DR];
caseP_16x8_U:
//上边x8子块
s[P_16x8_U]=s[P_8x8_UR]+s[P_8x8_UL];
caseP_16x8_D:
//下边x8子块
s[P_16x8_D]=s[P_8x8_DL]+s[P_8x8_DR];
caseP_16x16_:
//16x16子块
s[P_16x16_]=s[P_16x8_D]+s[P_16x8_U];
//若当前sad小于以前的sad,则更新sad和mv
if(s[t]<
mvs[t].sad)
mvs[t].sad=s[t];
mvs[t].mv[0]=mvx;
mvs[t].mv[1]=mvy;
adjust_mv(t,mx,my);
//根据宏块位置调整mv的值
voidadjust_mv(intt,intmx,intmy)
if(mx==0&
my==0)
mvs[t].mv[0]=mvs[t].mv[0]+16;
mvs[t].mv[1]=mvs[t].mv[1]+16;
elseif(my==0&
mx>
0&
=MB_W-1)
elseif(mx==0&
=MB_H-1)
mvs[t].mv[0]=mvs[t].mv[0]+16;
else;
//计算某个子块的sad
uint_tsub_block_sad(introw[2],intcol[2])
uint_ts=0;
for(i=row[0];
row[1];
for(j=col[0];
col[1];
s+=sad[i][j];
returns;
//最终分割方式及其最佳mv的判决
voidfinal_opt()
uint_ts=SAD_MAX,s0;
s0=mvs[0].sad+mvs[1].sad+mvs[2].sad+mvs[3].sad;
if(s>
=s0)
s=s0;
partition=P_8x8;
s0=mvs[4].sad+mvs[5].sad;
partition=P_8x16;
s0=mvs[6].sad+mvs[7].sad;
partition=P_16x8;
s0=mvs[8].sad;
partition=P_16x16;
//释放内存
voidfree_yuv(yuv_t*h)
I_FRAM