一种简单的图形旋转算法
图形旋转好玩又有实用性, 这里介绍一种简单的图形旋转算法.
具体步骤如下:
1. 首先将原图和旋转图的坐标原点都变换到图形的中心位置处.
2. 历遍旋转图形中的每一个pixel, 将pixel的坐标(j,i)反向旋转映射到原图, 得到原图对应的坐标值(Xr,Yr).
3. 考虑到旋转图的尺寸可能大于原图,这时需要检测(Xr,Yr)是否在原图范围内,如果不是,则忽略下面步骤.
4. (Xr,Yr)通常并不是正好对应到原图中一个整点的像素, 而是会夹在四个像素中(如图), 对四个像素的位置进行插值计算(也即所谓的双线性插值), 可以得到对应位置的RGBA值.
5. 由于内存中的图形数据是以左上角为坐标原点逐行记录的, 我们需将(j,i)变换到此坐标系统下(步骤1的反向操作), 得到其对应的内存位置, 然后将RGBA数值存入此处.
6. 通过逐点计算,最终可以得到完整的旋转后的图形.
7. 待改进处: 这里由于对图形边缘点的采样不够密集,因此得到的旋转图形边缘会出现锯齿现象. 可以细化映射颗粒度,如以1/4像素为单位进行映射计算.
更普遍的情况是,我们需要对原图中的指定区域进行旋转操作, 即进行旋转抠图. 下面是这一算法的C语言实现:
/*-----------------------------------------------------------------
@eimg: 输入图像
@oimg: 输出图像(NULL忽略)
@height,width: 输出图像的尺寸
@px,py: 抠图相对原图的位置
@angle: 旋转角度
-------------------------------------------------------------------*/
EGI_IMGBUF* egi_imgbuf_rotBlockCopy2( EGI_IMGBUF *eimg, EGI_IMGBUF *oimg, int height, int width,int px, int py, float angle)
{int i,j;float xr,yr; int index_out;EGI_IMGBUF *outimg=NULL;float sina=sin(MATH_PI*angle/180);float cosa=cos(MATH_PI*angle/180);/* 1. Check input eimg */if(eimg==NULL || eimg->imgbuf==NULL || eimg->height<=0 || eimg->width<=0 ) {egi_dpstd("Input holding eimg is NULL or uninitiliazed!\n");return NULL;}/* 2. Input oimg is NULL *//* 注:这里将输出图像的长宽均设为奇数,这样中心点是个整点位置,便于计算. */if(oimg==NULL) {/* Make H/W an odd value, then it has a symmetrical center point. */height |= 0x1;width |= 0x1;if(height<3)height=3;if(width<3)width=3;/* Create an imgbuf accordingly */outimg=egi_imgbuf_create(height, width, 0, 0); /* H, W, alpah, color */if(outimg==NULL) {egi_dpstd("Fail to create outimg!\n");return NULL;}/* Check ALPHA data */if(eimg->alpha==NULL) {free(outimg->alpha);outimg->alpha=NULL;}}/* Input oimg is NOT NULL */else {height=oimg->height;width=oimg->width;outimg=oimg;}/* 3. Clear outimg first. ALPHA to be 0, OR same as eimg. 如果是RGBA格式,可以在这里设置背景色. */egi_imgbuf_resetColorAlpha(outimg, WEGI_COLOR_GRAY2, outimg->alpha==NULL ? -1:0 ); /* img, color, alpha *//* 4. Map back point coordinates to eimg 以旋转图片中心为原点, 历遍旋转图形中的每一个像素点. 反向映射并插值计算得RGBA. */int m=height>>1;int n=width>>1;for(i=-m; i<=m; i++) {for(j=-n; j<=n; j++) {/* 4.1 Map to original coordiante (xr,yr), Origin at center.* 2D point rotation formula ( a positive: Right_hand Rule. ):* x'=x*cos(a)-y*sin(a)* y'=x*sin(a)+y*cos(a)* Coord axis anti_clockwise, point colokwise rotate.* points coordinates relative to up_right block coord.* 旋转变换公式, 可以查数学手册.*/xr=cosa*j-sina*i;yr=sina*j+cosa*i;/* 4.2 Shift Origin to left_top, as of eimg->imgbuf 变换到原图坐标下 */xr += px;yr += py;/* 4.3 Copy pixel alpha and color. Limit xr,yr, ignore if they are out of original imgbuf area. */if( xr >= 0.0 && xr <= eimg->width-1 && yr >=0.0 && yr <= eimg->height-1) {index_out=width*(i+m)+(j+n);/* 4.3.1 的到相互邻的4个像数 */int indx1 = eimg->width*floorf(yr)+floorf(xr);int indx2 = eimg->width*floorf(yr)+ceilf(xr);int indx3 = eimg->width*ceilf(yr)+floorf(xr);int indx4 = eimg->width*ceilf(yr)+ceilf(xr);EGI_16BIT_COLOR pcolor;EGI_8BIT_ALPHA palpha;float pft;/* 4.3.2 Interpolate within 4 pixles 4点插值得到RGBA */if(eimg->alpha!=NULL && outimg->alpha!=NULL) {egi_16bitColor_interplt4p(eimg->imgbuf[indx1], eimg->imgbuf[indx2], /* color1, color2 */eimg->imgbuf[indx3], eimg->imgbuf[indx4], /* color3, color4 */eimg->alpha[indx1], eimg->alpha[indx2], /* alpha1, alpha2 */eimg->alpha[indx3], eimg->alpha[indx4], /* alpha3, alpah4 */modff(xr,&pft)*(1<<15), modff(yr, &pft)*(1<<15), /* f15_x, f15_y */&pcolor, &palpha );outimg->imgbuf[index_out]=pcolor;outimg->alpha[index_out]=palpha;}else {egi_16bitColor_interplt4p(eimg->imgbuf[indx1], eimg->imgbuf[indx2], /* color1, color2 */eimg->imgbuf[indx3], eimg->imgbuf[indx4], /* color3, color4 */0, 0, 0, 0, /* alpha1, alpha2, alpha3, alpha4 */modff(xr,&pft)*(1<<15), modff(yr, &pft)*(1<<15), /* f15_x, f15_y */&pcolor, NULL );outimg->imgbuf[index_out]=pcolor;}}}}return outimg;
}
(更多代码见 https://github.com/widora/wegi)
效果:
一种简单的图形旋转算法相关推荐
- 选择排序(Selection sort)是一种简单直观的排序算法
选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大 ...
- 一种简单的抗锯齿算法
在LCD等显示器上逐点绘制几何图像的时候, 往往对几何体的边缘采样不足, 这就会导致出现锯齿状不平滑的边缘. 为了尽量减弱这种现象,需要在斜线或物体边缘进行更密集的采样,然后根据一定的权重比例将色彩/ ...
- 一种简单的抽签/抽奖算法逻辑
1.抽签计算方法步骤: 注:A:基数:B:翻转数: X:报名次数:Y:种子号,即起始中签号:Z:阶数: (1)A=(抽签日的上一个工作日的深圳证券交易所深证成指"今收"指数×100 ...
- 一种简单的地图聚合算法
百度地图的聚合算法 这段百度算法的描述来自博客:https://blog.csdn.net/javine/article/details/51195014 总结如下: 百度地图把整个地球是按照一个平面 ...
- 一种简单的图像LDR->HDR算法
算法比较简单,尽量简单说. 文章:Fully-automatic inverse tone mapping algorithm based on dynamic mid-level tone mapp ...
- python素数最优算法_几种简单的求素数算法的复杂度分析
素数的算法有很多种,现在主要讲两种算法及其改进版本的复杂度分析,解释性能提升的幅度.同时应用一个素数定理:素数的平方一定是合数,那么在范围内最大数的开方范围内找不到能整除的数,那么这个数是素数.应用这 ...
- java 路由算法_几种简单的负载均衡算法及其Java代码实现
什么是负载均衡 负载均衡,英文 名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助.通过某种 负载分 ...
- 排序算法(01)— 三种简单排序(冒泡、插入、选择)
一.概述 排序是数据处理中十分常见且核心的操作,虽说实际项目开发中很小几率会需要我们手动实现,毕竟每种语言的类库中都有n多种关于排序算法的实现.但是了解这些精妙的思想对我们还是大有裨益的. 1.1 排 ...
- 快速图像旋转算法的c++实现
0 引言 在数字图像处理技术中,图像旋转算法是最基本的操作之一.本文实现一种快速的图像旋转算法,并和原始方法以及opencv提供的旋转方案进行速度上的比较. 1 基本原理 图像旋转有两种计算坐标的思路 ...
最新文章
- vue.js学习系列-第二篇
- FireDAC 下的 Sqlite [4] - 创建数据库
- 【Paper】2021_Observer-based distributed consensus for multi-agent systems with directed networks and
- boost::lambda模块ll_static_cast,ll_dynamic_cast,ll_const_cast,ll_reinterpret_cast的测试程序
- flask和ajax通信详细步骤与完整代码
- java 固定listview_listview Button始终放在底部示例
- glup node 内存不够_Redis:内存被我用完了!该怎么办?
- CSUOJ修墙壁C语言,棋牌挂怎么编写 -棋牌挂怎么编写V6.1.16
- matlab三角函数降次,三角函数降次公式及推导过程
- 深度学习自学(十九):caffe添加深度可分离卷积
- as3 socket 跨域连接
- gitolite安装及配置
- 简述osi参考模型各层主要功能_简述OSI参考模型及各层的功能
- C语言ascii对照表
- 二分类最优阈值确定_结合mRMR选择和IFCM聚类的遥感影像分类算法
- 带参数的公众号二维码 生成+后台拦截java
- 数据分析入门篇(一)
- 阅读源码-理解torch.utils.data、torch.utils.data.Dataset、torch.utils.data.DataLoader的工作方式
- 计算机网络是计算机科学技术和结合的产物,计算机网络是计算机技术和什么
- 诺基亚如何利用计算机上网,诺基亚S60怎么通过笔记本的WIFI上网?