高效率 图像任意角度旋转算法(用整数运算实现)
最近在研究关于图像任意角度旋转算法,由于CPU不带FPU,对于小数运算效率十分低下,所以,有必要对算法进行由小数到整数的改进;算法改进思路为:小数除法->整数除法->乘法->加法,优化后的代码比原先提高了接近600%的性能,获得了满意的效果.
核心算法源代码ourdev_531929.rar(文件大小:2K) (原文件名:GUI_Image.rar) 改进后的测试结果如下:
http://cache.amobbs.com/bbs_upload782111/files_25/ourdev_531931.jpg
RotateBlt 160x64-> 213帧/秒 (原文件名:照片 1944.jpg)
http://cache.amobbs.com/bbs_upload782111/files_25/ourdev_531932.jpg
340x269 bmp -> 46帧/秒 (原文件名:照片 1958.jpg)
http://cache.amobbs.com/bbs_upload782111/files_25/ourdev_531933.jpg
48x48 bmp -> 2003帧/秒 (原文件名:照片 1959.jpg)
http://cache.amobbs.com/bbs_upload782111/files_25/ourdev_531934.jpg
620x388 bmp -> 28帧/秒 (原文件名:照片 1962.jpg)
http://cache.amobbs.com/bbs_upload782111/files_25/ourdev_531935.jpg
196x380 bmp -> 51帧/秒 (原文件名:照片 1963.jpg)
http://cache.amobbs.com/bbs_upload782111/files_25/ourdev_531936.jpg
272x178 bmp -> 73帧/秒 (原文件名:照片 1964.jpg)
http://cache.amobbs.com/bbs_upload782111/files_25/ourdev_531937.jpg
128x128 bmp -> 177帧/秒 (原文件名:照片 1965.jpg) 硬件平台: S3C2440 + 4.3寸TFT(480x272) 旋转算法:
void RotateImage(HDC hdc,int x,int y,HIMG hImg,int angle)
{
S32 radians;
S32 cos_a,sin_a,cos_ay,sin_ay;
S32 point1x,point1y,point2x,point2y,point3x,point3y;
S32 minx,miny,maxx,maxy;
S32 xx,yy,xx0,yy0,xx1,yy1,cx,cy,src_dx,src_dy,dst_dx,dst_dy;
GUI_COLOR color;
IMAGE *img;
DC *pdc;
///////////
//算法优化思路:小数除法->整数除法->乘法->加法
if(hdc==0) return;
pdc =HDC2DC(hdc);
if(hImg==0) return;
img=(void*)hImg;
src_dx =img->Width;
src_dy =img->Height;
angle %=360;
//计算外接矩形坐标
radians =(2*PI*angle)/360.0;
cos_a =COS(radians)*65536.0;
sin_a =SIN(radians)*65536.0;
point1x =(-src_dy*sin_a)>>16;
point1y =(src_dy*cos_a)>>16;
point2x =(src_dx*cos_a-src_dy*sin_a)>>16;
point2y =(src_dy*cos_a+src_dx*sin_a)>>16;
point3x =(src_dx*cos_a)>>16;
point3y =(src_dx*sin_a)>>16;
minx =MIN(0,MIN(point1x,MIN(point2x,point3x)));
miny =MIN(0,MIN(point1y,MIN(point2y,point3y)));
maxx =MAX(point1x,MAX(point2x,point3x));
maxy =MAX(point1y,MAX(point2y,point3y));
if(angle>90&&angle<180)
{
dst_dx=(int)CEIL(-minx);
}
else
{
dst_dx=(int)CEIL(maxx-minx);
}
if(angle>180&&angle<270)
{
dst_dy=(int)CEIL(-miny);
}
else
{
dst_dy=(int)CEIL(maxy-miny);
}
cx =(dst_dx>>1); //目标位置中心点的x偏移
cy =(dst_dy>>1); //目标位置中心点的y偏移
cos_ay =(miny*cos_a)>>16;
sin_ay =(miny*sin_a)>>16;
////////////
if(((IMAGE*)hImg)->Bpp==32)
{
//ARGB 8888格式(带Alpha通道)
for(yy=0;yy<dst_dy;yy++)
{
cos_ay =((yy+miny)*cos_a)>>16;
sin_ay =((yy+miny)*sin_a)>>16;
////
yy0 =y+yy-cy;
if(yy0<0) continue;
if(yy0>pdc->ymax) return;
for(xx=0;xx<dst_dx;xx++)
{
////
xx1 =((((xx+minx)*cos_a)>>16)+sin_ay); //计算坐标
yy1 =(cos_ay-(((xx+minx)*sin_a)>>16));
////
xx0 =x+xx-cx;
if(xx1>=0&&xx1<src_dx&&yy1>=0&&yy1<src_dy&&xx0>0&&xx0<pdc->xmax)
{
color =img->Data;
pdc->PutPixel(pdc,xx0,yy0,AlphaBlendColor(color,GetPixel(hdc,xx0,yy0),img->AlphaData));
}
}
}
}
else
{
//其它格式(不带Alpha通道)
for(yy=0;yy<dst_dy;yy++)
{
cos_ay =((yy+miny)*cos_a)>>16;
sin_ay =((yy+miny)*sin_a)>>16;
////
yy0 =y+yy-cy;
if(yy0<0) continue;
if(yy0>pdc->ymax) return;
for(xx=0;xx<dst_dx;xx++)
{
////
xx1 =((((xx+minx)*cos_a)>>16)+sin_ay); //计算坐标
yy1 =(cos_ay-(((xx+minx)*sin_a)>>16));
////
xx0 =x+xx-cx;
if(xx1>=0&&xx1<src_dx&&yy1>=0&&yy1<src_dy&&xx0>0&&xx0<pdc->xmax)
{
pdc->PutPixel(pdc,xx0,yy0,img->Data);
}
}
}
}
////
} 测试程序:
void TestRotateImage(void)
{
U32 hfile,himg,angle,frame,width,height;
char key,str_buf;
U8 *buf;
HDC hdc;
COORD x,y;
////
hdc=CreateDC(0,0,ScrWidth(),ScrHeight()-40); //创建设备上下文
angle=0;
while(1)
{
hfile=FILE_INVALID;
while(hfile==FILE_INVALID)
{
DbgUart_Printf("Enter Bmp File Name:\n");
if(DbgUart_Gets(str_buf,64)) //输入目标文件名
{
hfile=FileOpen(str_buf,"rw");
}
else
{
ReleaseDC(hdc);
return;
}
}
////
DbgUart_Printf("File Size =%d Byte\n",GetFileSize(hfile));
buf=MemAlloc(GetFileSize(hfile));
FileRead(buf,GetFileSize(hfile),hfile);
FileClose(hfile);
////
himg=BmpToImage(buf); //Bmp解码
MemFree(buf);
width =((IMAGE*)himg)->Width;
height =((IMAGE*)himg)->Height;
DbgUart_Printf("Image Width=%d,Height=%d\n",width,height);
ThreadLock(); //关线程调度(不关中断)
x=ScrWidth()>>1;
y=ScrHeight()>>1;
while(1)
{
int i;
char str_buf;
////
i =0;
angle =0;
frame =0;
SetSysTime(0); //设置系统时间
while(i<10)
{
RotateImage(hdc,x,y,himg,angle);
angle+=5; //角度每次增加5度
frame++; //帧计数
if(angle>=360)
{
angle=0;
i++;
}
////
key=0;
if(DbgUart_Getch(&key))
{
if(key==0x1b) goto ret;
}
}
////
i=GetSysTime();
StrPrintf(str_buf,"RotateImage 测试(%d*%d):Tick数=%d,时间=%d秒,帧数=%d,平均:%d帧/秒",width,height,i,i/TicksPerSec(),frame,(frame*TicksPerSec())/i);
Label(HDC_SCREEN,0,ScrHeight()-40,ScrWidth(),40,RGB(200,0,0),RGB(200,200,200),RGB(0,0,0),LEFT,str_buf);
}
}
ret:
ThreadUnlock(); //恢复线程调度
ReleaseImage(himg); //释放资源
ReleaseDC(hdc);
} 不错呀。。。·GUI方面的专家 MARK 数字图像处理 标记 楼主程序很好,心态更好! 回复【5楼】niba
不错呀。。。·GUI方面的专家
-----------------------------------------------------------------------
专家~~~汗~~~雕虫小技 这个mark下 角度也是整数的 回复【11楼】win2kddk
角度也是整数的
-----------------------------------------------------------------------
角度最小步进:1度(0-360度) 备用 回复【11楼】win2kddk
-----------------------------------------------------------------------
在一般情况下,1度的步进也足够了,就算是1600x1200的图片,旋转30度和31度,几乎看不出有明显的区别 超强,膜拜中 楼主牛人啊,膜拜,学习。 学习了 不错! 这个要顶一下 记号一下 强得一米
楼主关于2440,44B0的贴都很牛,关注楼主很久了 很佩服楼主! 回复【21楼】moen
强得一米
楼主关于2440,44B0的贴都很牛,关注楼主很久了
-----------------------------------------------------------------------
其时都和具体平台无关 mark起来慢慢看~ 学习! 能写这程序不是一般的N 常规的旋转就是用浮点数的,一开始就我就猜到楼主用的是整数读写像素.
你把SIN,COS事先做一个5度一项的整数组,小图的话还可以快一个数量级,大图就等于没有了. 回复【27楼】lgl_debug
常规的旋转就是用浮点数的,一开始就我就猜到楼主用的是整数读写像素.
你把SIN,COS事先做一个5度一项的整数组,小图的话还可以快一个数量级,大图就等于没有了.
-----------------------------------------------------------------------
SIN和COS只会运算一次,不管如何优化也起不到多少效果 回复【27楼】lgl_debug
常规的旋转就是用浮点数的,一开始就我就猜到楼主用的是整数读写像素.
你把SIN,COS事先做一个5度一项的整数组,小图的话还可以快一个数量级,大图就等于没有了.
-----------------------------------------------------------------------
估计16x16以下的图片,才有效果 高手,请问这个CPU手册你看了多久才看完啊。汗 平时不看手册,开发过程中遇到不太清楚的地方,才会用到数据手册. 这个需要mark下。 你总是给人 惊喜 请问楼主4.3寸TFT(480x272)哪里有卖啊 uCGUI也带图像任意角度旋转函数,不知道楼主有没有对比过 来个视频过下干瘾.. 回复【35楼】yulutong 土土狗
uCGUI也带图像任意角度旋转函数,不知道楼主有没有对比过
-----------------------------------------------------------------------
对ucGUI也大概了解一点点,但没实际用过, 手上也没有可运行的ucGUI代码, 所以没有对比过; 不知ucGUI的速度如何? 旋转48x48的24位色位图,可以达到2003帧/秒么? 回复【36楼】yemingxp
来个视频过下干瘾..
-----------------------------------------------------------------------
演示视频1:
点击此处下载 ourdev_532593.rar(文件大小:24.31M) (原文件名:P2052114.rar) 【37】楼主
对ucGUI也大概了解一点点,但没实际用过, 手上也没有可运行的ucGUI代码, 所以没有对比过; 不知ucGUI的速度如何? 旋转48x48的24位色位图,可以达到2003帧/秒么?
2003帧/秒?有这么快?看你的图片是4.3寸屏,16色的话每帧需要480×272×16/8=261 120 BYTE.
2000帧需要261120×2000=522 240 000Byte.如果SDRAM有CPU50%效率的话,CPU至少需要1GHZ了。楼主你是什么CPU阿?
另外向楼主请教个问题:把你的4.3寸横屏转成竖屏,不知道可用什么方法? 顶一个 这个要顶。 MARK mark 顶一个,谢谢楼主 回复【39楼】yulutong 土土狗
【37】楼主
对ucGUI也大概了解一点点,但没实际用过, 手上也没有可运行的ucGUI代码, 所以没有对比过; 不知ucGUI的速度如何? 旋转48x48的24位色位图,可以达到2003帧/秒么?
2003帧/秒?有这么快?看你的图片是4.3寸屏,16色的话每帧需要480×272×16/8=261 120 BYTE.
2000帧需要261120×2000=522 240 000Byte.如果SDRAM有CPU50%效率的话,CPU至少需要1GHZ了。楼主你是什么CPU阿?
另外向楼主请教个问题:把你的4.3寸横屏转成竖屏,不知道可用什么方法?
-----------------------------------------------------------------------
这个帧速是指:图片1秒钟时间内作旋转运算并显示到屏幕的次数,不是LCD全屏刷新次数。2003帧/秒的含义为:每秒可旋转2003次输出到屏幕。
这个LCD没有硬件翻转功能,横屏转成竖屏,可以用软件算法,旋转90或270度 回复【39楼】yulutong 土土狗
-----------------------------------------------------------------------
38楼,有实际演示视频 好东西,mark 留个记号
这段也在用GUI 回复【48楼】hebj
留个记号
这段也在用GUI
-----------------------------------------------------------------------
你是用的哪个GUI? mark 我很佩服楼主!期待交流合作。。。 mark 回复【51楼】9509238
我很佩服楼主!期待交流合作。。。
-----------------------------------------------------------------------
哪方面的合作? mark一下 有时间再公布一个高速的图像任意尺寸和比例拉伸算法 什么cpu?什么内存?
cpu和内存是关键 回复【56楼】gaiwang42
什么cpu?什么内存?
cpu和内存是关键
-----------------------------------------------------------------------
CPU:S3C2440: 271MHZ - 67MHZ - 33MHZ
内存: 64MB SDRAM ding! 回复【55楼】liuweiele
-----------------------------------------------------------------------
严重期待!!! 回复【59楼】superyongzhe 最后的骑士
回复【55楼】liuweiele
-----------------------------------------------------------------------
严重期待!!!
-----------------------------------------------------------------------
目前比较忙,要过一些时间再公布 关注 拉伸算法在这个帖子公布:
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3909080&bbs_page_no=1&search_mode=4&search_text=liuweiele&bbs_id=9999 好东西 mark mark 顶 mark MARK 图像任意角度旋转算法 感谢楼主分享,MARK…… MARK 图像任意角度旋转 支持楼主,谢谢分享好算法! 记录 mark mark MARK 数字图像处理 mark 嵌入式图像处理。。。不错 mark 不错,顶一下。 mark! mark! 哎。人生最难的莫过于看懂别人写的代码 提高了600%的性能? 回复【83楼】exploer
提高了600%的性能?
-----------------------------------------------------------------------
速度提高了600% mark mark mark mark 学习,LZ在GUI方面很厉害 mark 楼主又出强势代码~~~~ 白沫一下 make! 楼主专家啊 顶贴,好样的 图片很漂亮 厉害啊 牛 很强悍!!! MARK 数字图像处理 太快了,完全可以再以性能换取质量,例如对原图采样时使用双线性插值。 回复【98楼】qwernet 小俊
太快了,完全可以再以性能换取质量,例如对原图采样时使用双线性插值。
-----------------------------------------------------------------------
是的,"插值"也可以用Alpha混合实现
页:
[1]
2