数字图像处理在DSP上的实现(旋转)1 绪论1.1设计目的图像旋转是一种应用广泛的数字图像处理技术,随着应用水平的不断提高,对在嵌入式系统中实现高分辨率大图像旋转的需求也越来越高。
如在航空领域的高分辨率数字地图图像的显示处理过程中,由于现有的显示芯片均不能支持图像旋转功能,就需要在资源有限的嵌入式平台上实现大幅面地图图像的实时旋转。
采用DSP平台是一种实现方式,具体实现时需仔细考虑两个方面的问题,一是选用计算量小的旋转算法,二是充分发挥DSP平台强大的并行计算能力。
1.2设计任务1.能从计算机上读取图片。
2.编写图像旋转程序,在TMS320C5509上实现。
2 设计原理及分析2.1设计原理目前,已经有很多有效降低计算量的图像旋转算法,基于图像线性存储结构的旋转方法就是其中之一。
然而,在DSP平台上,有限的高速存储资源限制了这些算法效率的直接发挥,需要针对算法及DSP平台的性能结构特点进行高效的数据调度。
对于图像旋转问题而言,数据调度还需要克服由于存在大量非连续图像像素地址访问而严重影响DSP数据存取及CPU效率发挥的问题。
这是图像旋转本身的特殊性,在其他图像处理技术中是不存在的。
由DSP的结构特点可知,只有在数据和程序均位于片存储器当中的条件下,DSP 的效率才能得到最大化的发挥。
在大图像旋转算法中,由于涉及的图像数据量远大于DSP的片存储器容量,源图像和最终视口图像等数据必须被存放在片外存储器中。
在这种情况下,为了保证DSP CPU高速处理能力的发挥,必须优化数据流,将源图像分块,依次搬移至片处理,并设法保证CPU当前要处理的图像数据块已经事先在片存储器中准备好了。
因此在算法整体优化结构上采用Ping-Pong双缓冲技术,利用EDMA与CPU并行工作来隐藏图像数据块在片和片外之间的传输时间,使CPU能连续不断地处理数据,中间不会出现空闲等待。
传统的图像旋转一般通过矩阵乘法实现:其中,α为旋转角度。
由于图像是线性存储的,各个像素点之间的相对位置关系确定。
如图1(a)所示,图像旋转前,任意像素点P(x,y)和P1(x1,y1)、P2(x2,y2)及A(xA,yA)在几何上是矩形的四顶点关系。
由于旋转变换是线性变换,如图1(b)所示,图像旋转后,各个像素点之间的相对位置关系不发生变化,旋转算法的数据调度目的是使算法能够按照一定的规则,将源图像数据有规律地分块,并按次序分别传输到DSP片存储器中,完成计算后,形成视口图像块,再将视口图像块按同样的顺序进行排列,形成旋转后的视口图像。
整个过程要求调入和调出的图像数据均是规则分块的,并且调入的源图像块中应该包含计算视口图像块的过程中所需要的全部像素数据,尤其需要解决其中的大量非连续图像像素地址访问问题。
视口逆时针旋转的情况与此类似。
区别有以下两点:①源图像块的左边框中点与相应的视口图像块旋转后的左上角顶点对应;②源图像块的顶点局部坐标地址值与视口图像块的顶点局部坐标地址值之间的对应关系式应为:其中height指源图像块的高度。
3 软件程序3.1主程序#include<stdlib.h>#include<stdio.h>#include<graphics.h>#include<alloc.h>#include<ctype.h>int load_cut(char *fname);int load_convolution_matrix(char *fname);int convolve_image(void);int swap_pictures(void);int minx,maxx,miny,maxy;int LOADPAGE=0;int ENHANCEPAGE=1;int *cmat, *pmat, *vmat;int cmx,cmy,cmnum;struct palettetype palette,newpal; int driver,mode;int cleancut=-1;int init_graphics(void){driver=DETECT; mode=0; detectgraph(&driver,&mode);if(driver==VGA) mode=VGAMED; initgraph(&driver,&mode,""); getpalette(&palette); getpalette(&newpal);}int cleanup_image(void){int i,j,num,x,y,k;if(cleancut<0) return; setactivepage(LOADPAGE); setvisualpage(ENHANCEPAGE); for(x=minx;x<maxx;x++) {for(y=miny;y<maxy;y++) {if(getpixel(x,y)!=0) num=-1;else num=0;for(j=-1;j<2;j++) {for(i=-1;i<2;i++) {if(getpixel(x+i,y+j)!=0) num++;}}if(num>cleancut) {k=getpixel(x,y);setactivepage(ENHANCEPAGE);putpixel(x,y,k);setactivepage(LOADPAGE);}}}k=ENHANCEPAGE; ENHANCEPAGE=LOADPAGE; LOADPAGE=k;}void show_test_image(void){int i;minx=cmx; miny=cmy;maxx=100+minx; maxy=100+miny;setcolor(1);moveto(minx,miny);randomize();for(i=0;i<20;i++)lineto(random(100)+minx,random(100)+miny);for(i=0;i<10;i++)fillellipse(random(50)+25+minx,random(50)+25+miny,random(25),random(25));}main(){char fname[50];int flag=0;load_convolution_matrix("matrix.dat");printf(".CUT file (1) or test image (0)?");scanf("%d",&flag);flag= flag? 1:0;if(flag) {fflush(stdin);printf("filename to process:");gets(fname);}printf("Delete pixels with x or fewer neighbors. x="); scanf("%d",&cleancut);if(cleancut>8) cleancut=8;init_graphics();setactivepage(1); cleardevice();setactivepage(0); cleardevice();setactivepage(LOADPAGE); setvisualpage(LOADPAGE); if(flag) load_cut(fname);else show_test_image();cleanup_image();setvisualpage(ENHANCEPAGE);convolve_image();swap_pictures();restorecrtmode();}int toggle_colors(char c){c=tolower(c);c=c-'a';if(c<0 || c>=palette.size) return 0;newpal.colors[c]= palette.colors[c]-newpal.colors[c]; setpalette(c,newpal.colors[c]);return 1;}int swap_pictures(void){int mode=0;char a;setvisualpage(LOADPAGE);for(;;) {a=getch();if(a==27) return;if(toggle_colors(a)) continue;if(mode==0) setvisualpage(ENHANCEPAGE);if(mode==1) setvisualpage(LOADPAGE);mode=1-mode;}}int convolve_image(void){int i,j,k,nval;int *vx, *vy, *c;int colmax,offset,end,midy;char **lines=NULL;char *temp=NULL;offset=-minx+(cmx/2);end=cmy-1; midy=cmy/2;lines=(char **)malloc(cmy*sizeof(char *));for(i=0;i<cmy;i++) lines[i]=(char *)malloc(sizeof(char)*(maxx-minx+cmx+1));setactivepage(LOADPAGE);for(j=-cmy/2;j<cmy/2;j++) {for(i=minx-cmx/2;i<(maxx+cmx/2+1);i++) {lines[j+midy][i+offset]=getpixel(i,j+miny);}}colmax=getmaxcolor();for(j=miny;j<maxy;j++) {setactivepage(LOADPAGE);for(i=j+cmy/2,k=minx-cmx/2,nval=maxx+cmx/2;k<nval;k++) lines[end][k+offset]=getpixel(k,i);for(i=minx;i<maxx;i++) {/* Load & multiply neighbors into matrix */ setactivepage(LOADPAGE);vx=vmat; vy=vmat+1; c=cmat; nval=0;for(k=0;k<cmnum;k++) {if(*c) nval+= lines[(*vy)+midy][i+(*vx)+offset]*(*c);/* if(*c) nval+= getpixel(i+(*vx),j+(*vy)) * (*c); */c++;vx+=2; vy+=2;}/* Cut off values too high or too low */if(nval<0) nval=0;if(nval>colmax) nval=colmax;/* Place new pixel value */setactivepage(ENHANCEPAGE);putpixel(i,j,nval);}if(kbhit()) { getch(); break; }/* rotate line pointers */temp=lines[0];for(i=1;i<cmy;i++) lines[i-1]=lines[i];lines[end]=temp;}for(i=0;i<cmy;i++) {if(lines[i]!=NULL) free(lines[i]);}if(lines!=NULL) {free(lines);}return;}int build_offset_vectors(void){int *t;int il,im,jl,jm,i,j;il=-cmx/2; im=cmx+il;jl=-cmy/2; jm=cmy+jl;t=vmat;for(j=jl;j<jm;j++) {for(i=il;i<im;i++) {*t++=i; *t++=j;}}}int load_convolution_matrix(char *fname) {/* Layout of matrix file:#x #yx0y0 x1y0 ... xny1.... .... ... ....x0ym x1ym ... xnym*/FILE *mf;int *t;int i,j,im,jm;if( (mf=fopen(fname,"rt"))==NULL ) {printf("Cannot load matrix file.\n");abort();}fscanf(mf,"%d%d",&im,&jm);if( (im&1)==0 || (jm&1)==0 ) {printf("Convolution matrix MUST have a center point.\n"); abort();}if( (cmat=(int *)calloc(im*jm,sizeof(int)))==NULL ) {printf("Unable to calloc convolution matrix.\n");abort();}if( (vmat=(int *)calloc(2*im*jm,sizeof(int)))==NULL ) { printf("Unable to calloc offset vector matrix.\n");abort();}cmx=im; cmy=jm; cmnum=im*jm;t=cmat;for(j=0;j<jm;j++) {for(i=0;i<im;i++) {if( fscanf(mf,"%d",t++)!=1 ) {printf("Unable to read matrix.\n");abort();}}}fclose(mf);build_offset_vectors();}int load_cut(char *fname){static unsigned char st[3000];char *sp=st,*spend;int stp=0;int width,height;FILE *fp;int x,y,xl,yl;int i,n,len,d,j;fp=fopen(fname,"rb");width=getw(fp); height=getw(fp);xl=cmx; yl=cmy;minx=xl; miny=yl;maxx=xl+width; maxy=yl+height;if(maxy>(getmaxy()-cmy)) {maxy=getmaxy()-cmy;height=maxy-yl;}getw(fp);y=yl-1;for(sp=st,n=0;n<height;n++) {stp=getw(fp);for(sp=st,spend=st+stp;sp<spend;) *sp++=getc(fp); sp=st; spend=sp+stp; x=xl; y++;while(sp<spend) {if(*((unsigned char *)sp)>0x80) {len=(*sp++) & 0x7f;if(!(*sp)) { x+=len; continue; }setcolor(*sp++);moveto(x,y);linerel(len,0);x+=len;continue;} else {len=*sp++;for(j=0;j<len;j++) putpixel(x++,y,*sp++);continue;}}}fclose(fp);}3.2初始化和读取图像程序#include<stdio.h>#define MODEPHOTO1 1#define MODEPHOTO2 2#define GRAYBARLEVEL 16void ReadImage(unsigned char*pImage,char*cFileName,int nWidth,int nHeight);void InitImage(unsigned int nMode,unsigned char*pImage,int nWidth,int nHeight){swich(nMode){case MODEPHOTO1:Readimage(pImage,"..\\DSP.bmp",nWidth,nHeight);break;case MODEPHOTO2:ReadImage(pImage,"..\\1.bmp",nWidth,nHeight);break;default:break;}}void ReadImage(unsigned char*cFileName,int nWidth,int nHeight) {int j;unsigned char*pWork;FILE*fp;if(fp=fopen(cFileName,"rb")){fseek(fp,1078L,SEEK_SET);pWork=pImage+(nHeight-1)*nWidth;for(j=0;j<nHeight;j++,pWork-=nWidth)fread(pWork,nWidth,1,fp);fclose(fp);}}4 运行结果分析从实验结果可以看出,调整图像旋转,由于存在对称性,一幅图像任意角度的旋转可分解为一次90°或180°或270°的旋转,再加上一次±45°以的旋转。