liuweiele 发表于 2010-2-2 21:20:05

高效率 图像任意角度旋转算法(用整数运算实现)

最近在研究关于图像任意角度旋转算法,由于CPU不带FPU,对于小数运算效率十分低下,所以,有必要对算法进行由小数到整数的改进;
算法改进思路为:小数除法->整数除法->乘法->加法,优化后的代码比原先提高了接近600%的性能,获得了满意的效果.


核心算法源代码ourdev_531929.rar(文件大小:2K) (原文件名:GUI_Image.rar)

liuweiele 发表于 2010-2-2 21:28:58

改进后的测试结果如下:

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)

liuweiele 发表于 2010-2-2 21:32:08

硬件平台: S3C2440 + 4.3寸TFT(480x272)

liuweiele 发表于 2010-2-2 21:33:55

旋转算法:

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);
                                }
                        }
                }
        }
       
        ////
       


}

liuweiele 发表于 2010-2-2 21:34:51

测试程序:

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);
       
}

niba 发表于 2010-2-2 21:36:43

不错呀。。。·GUI方面的专家

eduhf_123 发表于 2010-2-2 21:41:26

MARK 数字图像处理

whlx622 发表于 2010-2-2 21:46:05

标记

thomasdu 发表于 2010-2-2 23:05:01

楼主程序很好,心态更好!

liuweiele 发表于 2010-2-3 09:40:04

回复【5楼】niba
不错呀。。。·GUI方面的专家

-----------------------------------------------------------------------

专家~~~汗~~~雕虫小技

kewen222 发表于 2010-2-3 09:46:01

这个mark下

win2kddk 发表于 2010-2-3 10:04:50

角度也是整数的

liuweiele 发表于 2010-2-3 11:17:22

回复【11楼】win2kddk
角度也是整数的
-----------------------------------------------------------------------

角度最小步进:1度(0-360度)

tomhe666 发表于 2010-2-3 11:21:28

备用

liuweiele 发表于 2010-2-3 11:21:28

回复【11楼】win2kddk
-----------------------------------------------------------------------

在一般情况下,1度的步进也足够了,就算是1600x1200的图片,旋转30度和31度,几乎看不出有明显的区别

wangguanfu 发表于 2010-2-3 11:26:26

超强,膜拜中

xiangyuan_122 发表于 2010-2-3 11:48:17

楼主牛人啊,膜拜,学习。

h2feo4 发表于 2010-2-3 11:51:09

学习了

ct_dev 发表于 2010-2-3 11:55:10

不错!

tuy0326 发表于 2010-2-3 12:16:00

这个要顶一下

AVR_DIY 发表于 2010-2-3 12:18:37

记号一下

moen 发表于 2010-2-3 12:21:41

强得一米
楼主关于2440,44B0的贴都很牛,关注楼主很久了

xiaoche1010 发表于 2010-2-3 12:35:30

很佩服楼主!

liuweiele 发表于 2010-2-3 13:42:12

回复【21楼】moen
强得一米
楼主关于2440,44B0的贴都很牛,关注楼主很久了
-----------------------------------------------------------------------

其时都和具体平台无关

155107149 发表于 2010-2-3 14:47:36

mark起来慢慢看~

falcon8663 发表于 2010-2-3 20:21:38

学习!

ds444 发表于 2010-2-4 00:29:19

能写这程序不是一般的N

lgl_debug 发表于 2010-2-4 03:25:46

常规的旋转就是用浮点数的,一开始就我就猜到楼主用的是整数读写像素.
你把SIN,COS事先做一个5度一项的整数组,小图的话还可以快一个数量级,大图就等于没有了.

liuweiele 发表于 2010-2-4 09:56:02

回复【27楼】lgl_debug
常规的旋转就是用浮点数的,一开始就我就猜到楼主用的是整数读写像素.
你把SIN,COS事先做一个5度一项的整数组,小图的话还可以快一个数量级,大图就等于没有了.
-----------------------------------------------------------------------

SIN和COS只会运算一次,不管如何优化也起不到多少效果

liuweiele 发表于 2010-2-4 09:58:18

回复【27楼】lgl_debug
常规的旋转就是用浮点数的,一开始就我就猜到楼主用的是整数读写像素.
你把SIN,COS事先做一个5度一项的整数组,小图的话还可以快一个数量级,大图就等于没有了.
-----------------------------------------------------------------------

估计16x16以下的图片,才有效果

ds444 发表于 2010-2-4 22:55:25

高手,请问这个CPU手册你看了多久才看完啊。汗

liuweiele 发表于 2010-2-4 23:04:07

平时不看手册,开发过程中遇到不太清楚的地方,才会用到数据手册.

rodger 发表于 2010-2-5 02:33:04

这个需要mark下。

clever0725 发表于 2010-2-5 08:17:14

你总是给人 惊喜

jiangjx 发表于 2010-2-5 08:22:38

请问楼主4.3寸TFT(480x272)哪里有卖啊

yulutong 发表于 2010-2-5 08:27:50

uCGUI也带图像任意角度旋转函数,不知道楼主有没有对比过

yemingxp 发表于 2010-2-5 09:13:32

来个视频过下干瘾..

liuweiele 发表于 2010-2-5 10:02:58

回复【35楼】yulutong 土土狗
uCGUI也带图像任意角度旋转函数,不知道楼主有没有对比过
-----------------------------------------------------------------------

对ucGUI也大概了解一点点,但没实际用过, 手上也没有可运行的ucGUI代码, 所以没有对比过; 不知ucGUI的速度如何? 旋转48x48的24位色位图,可以达到2003帧/秒么?

liuweiele 发表于 2010-2-5 22:24:49

回复【36楼】yemingxp
来个视频过下干瘾..

-----------------------------------------------------------------------

演示视频1:
点击此处下载 ourdev_532593.rar(文件大小:24.31M) (原文件名:P2052114.rar)

yulutong 发表于 2010-2-6 08:21:02

【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寸横屏转成竖屏,不知道可用什么方法?

cgbabc 发表于 2010-2-6 08:23:26

顶一个

liumaojun_cn 发表于 2010-2-6 08:33:27

这个要顶。

bad_fpga 发表于 2010-2-6 08:50:02

MARK

lwy86 发表于 2010-2-6 08:52:22

mark

Jigsaw 发表于 2010-2-6 10:34:43

顶一个,谢谢楼主

liuweiele 发表于 2010-2-6 13:39:11

回复【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度

liuweiele 发表于 2010-2-6 13:41:37

回复【39楼】yulutong 土土狗
-----------------------------------------------------------------------

38楼,有实际演示视频

bobqq 发表于 2010-2-6 14:26:35

好东西,mark

hebj 发表于 2010-2-6 14:33:23

留个记号
这段也在用GUI

liuweiele 发表于 2010-2-7 22:17:32

回复【48楼】hebj
留个记号
这段也在用GUI
-----------------------------------------------------------------------

你是用的哪个GUI?

yusufu 发表于 2010-2-12 14:26:19

mark

9509238 发表于 2010-3-2 14:32:33

我很佩服楼主!期待交流合作。。。

1181zjf 发表于 2010-3-2 15:17:39

mark

liuweiele 发表于 2010-3-2 19:06:03

回复【51楼】9509238
我很佩服楼主!期待交流合作。。。
-----------------------------------------------------------------------

哪方面的合作?

jeremygg 发表于 2010-3-4 15:32:52

mark一下

liuweiele 发表于 2010-3-6 18:59:55

有时间再公布一个高速的图像任意尺寸和比例拉伸算法

gaiwang42 发表于 2010-3-6 19:33:56

什么cpu?什么内存?
cpu和内存是关键

liuweiele 发表于 2010-3-6 21:01:21

回复【56楼】gaiwang42
什么cpu?什么内存?
cpu和内存是关键
-----------------------------------------------------------------------

CPU:S3C2440: 271MHZ - 67MHZ - 33MHZ
内存: 64MB SDRAM

sunmy 发表于 2010-3-6 22:15:16

ding!

superyongzhe 发表于 2010-3-7 00:43:24

回复【55楼】liuweiele
-----------------------------------------------------------------------

严重期待!!!

liuweiele 发表于 2010-3-7 21:28:54

回复【59楼】superyongzhe 最后的骑士
回复【55楼】liuweiele
-----------------------------------------------------------------------
严重期待!!!
-----------------------------------------------------------------------

目前比较忙,要过一些时间再公布

ep1c3 发表于 2010-3-8 15:05:12

关注

liuweiele 发表于 2010-3-9 14:57:27

拉伸算法在这个帖子公布:
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3909080&bbs_page_no=1&search_mode=4&search_text=liuweiele&bbs_id=9999

youxin2004 发表于 2010-4-15 15:55:20

好东西

yinjinzhong 发表于 2010-4-15 16:05:09

mark

wjhltk 发表于 2010-6-21 16:32:53

mark

wanglituan 发表于 2010-6-21 17:30:41

avrwoo 发表于 2010-6-21 20:26:33

mark

jichong211 发表于 2010-6-21 20:44:18

MARK 图像任意角度旋转算法

tom919 发表于 2010-7-6 16:28:24

感谢楼主分享,MARK……

jichong211 发表于 2010-7-9 21:01:17

MARK 图像任意角度旋转

jiangkehong 发表于 2010-7-9 21:46:02

支持楼主,谢谢分享好算法!

mayou 发表于 2010-7-9 21:53:45

记录

pkk007 发表于 2010-7-9 22:26:03

mark

shaoyidong 发表于 2010-7-10 05:32:22

mark

GuDaoFan 发表于 2010-7-10 10:38:23

MARK 数字图像处理

kuronca 发表于 2010-7-10 22:30:09

mark

NUAA_hp 发表于 2010-7-10 23:34:17

嵌入式图像处理。。。不错

lab1224 发表于 2010-8-20 15:57:23

mark

ctunan 发表于 2010-8-21 02:30:07

不错,顶一下。

zhenke 发表于 2010-8-21 07:46:55

mark!

shanyan 发表于 2010-8-21 08:02:18

mark!

usa9002 发表于 2010-8-22 10:33:38

哎。人生最难的莫过于看懂别人写的代码

exploer 发表于 2010-8-22 12:32:00

提高了600%的性能?

liuweiele 发表于 2010-8-22 18:55:05

回复【83楼】exploer
提高了600%的性能?
-----------------------------------------------------------------------

速度提高了600%

skystalker 发表于 2010-8-22 19:30:44

mark

tomtone 发表于 2010-8-22 23:22:43

mark

marrt.80 发表于 2010-8-24 15:56:27

mark

albert_lu 发表于 2010-11-19 22:53:24

mark

flyunlimit 发表于 2010-11-19 23:41:31

学习,LZ在GUI方面很厉害

fy024 发表于 2010-11-20 00:02:07

mark 楼主又出强势代码~~~~

jrcsh 发表于 2010-11-20 00:41:09

白沫一下

wanxuncpx 发表于 2010-11-20 01:01:52

make! 楼主专家啊

xiaowu191 发表于 2010-11-20 01:20:28

顶贴,好样的

defineme 发表于 2010-11-24 22:03:55

图片很漂亮

psbhero 发表于 2010-11-26 15:13:43

厉害啊 牛

caiyue3577 发表于 2010-11-26 22:19:15

很强悍!!!

lbn2006 发表于 2010-11-26 22:29:59

MARK 数字图像处理

qwernet 发表于 2010-11-26 22:35:12

太快了,完全可以再以性能换取质量,例如对原图采样时使用双线性插值。

liuweiele 发表于 2010-11-27 09:42:09

回复【98楼】qwernet 小俊
太快了,完全可以再以性能换取质量,例如对原图采样时使用双线性插值。

-----------------------------------------------------------------------

是的,"插值"也可以用Alpha混合实现
页: [1] 2
查看完整版本: 高效率 图像任意角度旋转算法(用整数运算实现)