旋转原理和旋转公式:

文章出处
https://blog.csdn.net/wonengguwozai/article/details/52049092
推导旋转公式:

旋转示意图
有: tg(b)=y/x ----(1)
tg(a+b)=y’/x’ ----(2)
xx + yy = x’x’ + y’y’ ----(3)
有公式:tg(a+b) = ( tg(a)+tg(b) ) / ( 1-tg(a)tg(b) ) ----(4)
把(1)代入(4)从而消除参数b;
tg(a)+y/x = y’/x’
( 1-tg(a)y/x ) ----(5)
由(5)可以得x’=y’
(x-ytg(a))/( xtg(a)+y ) ----(6)
把(6)代入(3)从而消除参数x’,化简后求得:
y’=xsin(a)+ycos(a); ----(7)
把(7)代入(6),有:
x’=xcos(a)-ysin(a); ----(8)

OK,旋转公式有了,那么来看看在图片旋转中的应用;
假设对图片上任意点(x,y),绕一个坐标点(rx0,ry0)逆时针旋转RotaryAngle角度后的新的坐标设为(x’, y’),有公式:
(x平移rx0,y平移ry0,角度a对应-RotaryAngle , 带入方程(7)、(8)后有: )
x’= (x - rx0)*cos(RotaryAngle) + (y - ry0)*sin(RotaryAngle) + rx0 ;
y’=-(x - rx0)*sin(RotaryAngle) + (y - ry0)*cos(RotaryAngle) + ry0 ;

那么,根据新的坐标点求源坐标点的公式为:
x=(x’- rx0)*cos(RotaryAngle) - (y’- ry0)*sin(RotaryAngle) + rx0 ;
y=(x’- rx0)*sin(RotaryAngle) + (y’- ry0)*cos(RotaryAngle) + ry0 ;

旋转的时候还可以顺便加入x轴和y轴的缩放和平移,而不影响速度,那么完整的公式为:
x=(x’- move_x-rx0)/ZoomXcos(RotaryAngle) - (y’- move_y-ry0)/ZoomYsin(RotaryAngle) + rx0 ;
y=(x’- move_x-rx0)/ZoomXsin(RotaryAngle) + (y’- move_y-ry0)/ZoomYcos(RotaryAngle) + ry0 ;
其中: RotaryAngle为逆时针旋转的角度;
ZoomX,ZoomY为x轴y轴的缩放系数(支持负的系数,相当于图像翻转);
move_x,move_y为x轴y轴的平移量;

一些颜色和图片的数据定义:

#define asm __asmtypedef unsigned  char TUInt8; // [0..255]
struct TARGB32      //32 bit color
{TUInt8  b,g,r,a;          //a is alpha
};struct TPicRegion  //一块颜色数据区的描述,便于参数传递
{TARGB32*    pdata;         //颜色数据首地址long        byte_width;    // 一行数据的物理宽度(字节宽度);//abs(byte_width)有可能大于等于width*sizeof(TARGB32);long        width;         //像素宽度long        height;        //像素高度
};//那么访问一个点的函数可以写为:
inline TARGB32& Pixels(const TPicRegion& pic,const long x,const long  y)
{return ( (TARGB32*)((TUInt8*)pic.pdata+pic.byte_width* y) )[x];
}
//判断一个点是否在图片中
inline bool PixelsIsInPic(const TPicRegion& pic,const long x,const long  y)
{return ( (x>=0)&&(x<pic.width) && (y>=0)&&(y< pic.height) );
}

B:一个简单的浮点实现版本

//函数假设以原图片的中心点坐标为旋转和缩放的中心
void PicRotary0(const TPicRegion& Dst,const TPicRegion& Src,double RotaryAngle,double ZoomX,double ZoomY,double move_x,double  move_y)
{if ( (fabs(ZoomX*Src.width)<1.0e-4) || (fabs(ZoomY*Src.height)<1.0e-4) ) return; //太小的缩放比例认为已经不可见double rx0=Src.width*0.5;  //(rx0,ry0)为旋转中心 double ry0=Src.height*0.5 ; for (long y=0;y<Dst.height;++ y){for (long x=0;x<Dst.width;++ x){long srcx=(long)((x- move_x-rx0)/ZoomX*cos(RotaryAngle) - (y- move_y-ry0)/ZoomY*sin(RotaryAngle) +  rx0) ;long srcy=(long)((x- move_x-rx0)/ZoomX*sin(RotaryAngle) + (y- move_y-ry0)/ZoomY*cos(RotaryAngle) +  ry0) ;if  (PixelsIsInPic(Src,srcx,srcy))Pixels(Dst,x,y)= Pixels(Src,srcx,srcy);}}
}

(调用方法比如:
PicRotary0(ppicDst,ppicSrc,PI/6,0.9,0.9,(dst_wh-ppicSrc.width)*0.5,(dst_wh-ppicSrc.height)*0.5);
//作用:将图片ppicSrc按0.9的缩放比例旋转PI/6幅度后绘制到图片ppicDst的中心
)

//注:测试图片都是800600的图片旋转到10041004的图片中心 测试成绩取各个旋转角度的平均速度值

速度测试:

优化循环内部,化简系数
1.sin和cos函数是很慢的计算函数,可以在循环前预先计算好sin(RotaryAngle)和cos(RotaryAngle)的值:
double sinA=sin(RotaryAngle);
double cosA=cos(RotaryAngle);
2.可以将除以ZoomX、ZoomY改成乘法,预先计算出倒数:
double rZoomX=1.0/ZoomX;
double rZoomY=1.0/ZoomY;
3.优化内部的旋转公式,将能够预先计算的部分提到循环外(即:拆解公式):
原: long srcx=(long)((x- move_x-rx0)/ZoomXcos(RotaryAngle) - (y- move_y-ry0)/ZoomYsin(RotaryAngle) + rx0) ;
long srcy=(long)((x- move_x-rx0)/ZoomXsin(RotaryAngle) + (y- move_y-ry0)/ZoomYcos(RotaryAngle) + ry0) ;
变形为:
long srcx=(long)( Axx + Bxy +Cx ) ;
long srcy=(long)( Ayx + Byy +Cy ) ;
其中: Ax=(rZoomXcosA); Bx=(-rZoomYsinA); Cx=(-(rx0+move_x)rZoomXcosA+(ry0+move_y)rZoomYsinA+rx0);
Ay=(rZoomXsinA); By=(rZoomYcosA); Cy=(-(rx0+move_x)rZoomXsinA-(ry0+move_y)rZoomYcosA+ry0);
(提示: Ax,Bx,Cx,Ay,By,Cy都可以在旋转之前预先计算出来)

改进后的函数为:

void PicRotary1(const TPicRegion& Dst,const TPicRegion& Src,double RotaryAngle,double ZoomX,double ZoomY,double move_x,double  move_y)
{if ( (fabs(ZoomX*Src.width)<1.0e-4) || (fabs(ZoomY*Src.height)<1.0e-4) ) return; //太小的缩放比例认为已经不可见double rZoomX=1.0/ ZoomX;double rZoomY=1.0/ ZoomY;double sinA= sin(RotaryAngle);double cosA= cos(RotaryAngle);double Ax=(rZoomX* cosA); double Ay=(rZoomX* sinA); double Bx=(-rZoomY* sinA); double By=(rZoomY* cosA); double rx0=Src.width*0.5;  //(rx0,ry0)为旋转中心 double ry0=Src.height*0.5 ; double Cx=(-(rx0+move_x)*rZoomX*cosA+(ry0+move_y)*rZoomY*sinA+ rx0);double Cy=(-(rx0+move_x)*rZoomX*sinA-(ry0+move_y)*rZoomY*cosA+ ry0); TARGB32* pDstLine= Dst.pdata;double srcx0_f= (Cx);double srcy0_f= (Cy);for (long y=0;y<Dst.height;++ y){double srcx_f= srcx0_f;double srcy_f= srcy0_f;for (long x=0;x<Dst.width;++ x){long srcx=(long )(srcx_f);long srcy=(long )(srcy_f);if  (PixelsIsInPic(Src,srcx,srcy))pDstLine[x]= Pixels(Src,srcx,srcy);srcx_f+= Ax;srcy_f+= Ay;}srcx0_f+= Bx;srcy0_f+= By;((TUInt8*&)pDstLine)+= Dst.byte_width;}
}

//速度测试:
//==============================================================================
// PicRotary1 62.0 fps

( 在AMD64x2 4200+和VC2005编译下PicRotary1(51.8fps)比PicRotary0(27.1fps)快90%;
在AMD64x2 4200+和VC6编译下PicRotary1(20.3fps)比PicRotary0(16.1fps)快26%;
以前在赛扬2G和VC6编译下PicRotary1(8.4fps)反而比PicRotary0(12.7fps)慢50%!

c/c++实现图像旋转任意角度相关推荐

  1. c++实现图像旋转任意角度

    图形图像处理-之-任意角度的高质量的快速的图像旋转 上篇 纯软件的任意角度的快速旋转                                 HouSisong@GMail.com   200 ...

  2. OPENCV入门教程九:图像旋转任意角度

    一.目标 学习如何旋转图片. 二.函数说明 在OpenCV中,没有现成的函数直接用来实现图像旋转,它是用仿射变换函数warpAffine来实现的,此函数目前支持4种插值算法,最近邻.双线性.双三次.兰 ...

  3. opencv图片旋转关于中心旋转任意角度与坐标转换

    如下例子,实现图片关于中心旋转任意角度,及坐标变换 import os import os.path import cv2 import numpy as np from math import co ...

  4. matlab控制三角形绕原点旋转任意角度

    项目中遇到一个问题,需要把正三角形绕原点旋转任意角度,平时操作图片的时候,顺便旋转,感觉好像很简单,但是自己去做的时候还是有些困难. 我觉得旋转的难点在于由原始点计算新的目标点上,因为你需要考虑点位于 ...

  5. JQuery插件让图片旋转任意角度且代码极其简单 - 摘自网友

    JQuery插件让图片旋转任意角度且代码极其简单 2012-04-01 09:57:03     我来说两句       收藏    我要投稿 引入下方的jquery.rotate.js文件,然后通过 ...

  6. PDF任意页旋转任意角度

    使用软件:Adobe Acrobat Pro DC.Enfocus PitStop Pro插件 1.打开PDF文件 2.在左侧选中右键可以旋转固定角度 3.如果要旋转任意角度,Alt+Ctrl+G  ...

  7. JQuery插件让图片旋转任意角度且代码极其简单

    引入下方的jquery.rotate.js文件,然后通过$("选择器").rotate(角度);可以旋转任意角度, 例如$("#rotate-image").r ...

  8. 利用Matlab将任意曲线旋转任意角度

    利用Matlab将任意曲线旋转任意角度 公式计算 数据 matlab代码 结果 公式计算 对于如上图所示的任意曲线,需要绕固定点O旋转某一角度,取曲线上任意一点A计算旋转后的坐标值. 设OA的长度为L ...

  9. html图片旋转任意角度,将图像快速旋转任意角度 - jixu2008的日志 - VB爱好者乐园(VBGood) - Powered by Discuz!...

    ' '下面是窗体代码,在 VB6 调试通过 '需在窗体放置以下 6 个控件,所有控件不必设置任何属性(包括位置和大小),全部采用默认设置: '   Command1.Command2.Label1.P ...

最新文章

  1. PHP学习笔记-流程控制语句
  2. Charles 从入门到精通
  3. Linux 内存管理篇(2)内核初始化与内存管理启用
  4. Insert Interval
  5. 【疑问】SD更新凭证流
  6. 数组——两个有序数组的合并
  7. oracle exp consistent,exp CONSISTENT=Y 原理:export前发出SET TRANSACTION READ ONLY命令
  8. flask-uploads扩展的使用笔记
  9. java--方法重写与重载
  10. CCF NOI1001 温度转换
  11. arduino 步进电机驱动库_Arduino基础入门篇27—步进电机驱动库的使用
  12. matlab中函数在哪儿,matlab怎么调用函数
  13. win7系统怎么查看电脑配置,win7电脑系统配置查看
  14. 20多岁的生活方式决定了你30岁的打开方式_演讲稿
  15. 物联网全景动态图谱2.0|PaaS物联网平台汇总(上篇)
  16. C语言读取指定文件夹下面的所有文件
  17. python科赫曲线画树叶_Python——科赫曲线绘制
  18. ubuntu20.02安装显卡驱动常见问题总结
  19. 爬取糗事百科段子 + 数据可视化
  20. Working Practice-破窗理论与写代码

热门文章

  1. 医疗物联网投资趋势报告:当务之急是抓住机遇
  2. w32.downadup.b蠕虫病毒详解及清除攻略(转)
  3. matlab图形标注名称_MATLAB图形的标注与修饰
  4. Android电话录音
  5. 必要回报率(Required Rate Of Return)
  6. 大数据技术原理与应用笔记
  7. 卷积神经网络识别图像,卷积神经网络图像处理
  8. 【王喆-推荐系统】模型篇-(task7)DeepFM处理交叉特征
  9. NOIP2018普及组复赛——T3摆渡车
  10. 计算机中office是应用软件吗,如何从Win10计算机中卸载单个Office 365应用程序