从UIImage的矩阵变换看矩阵运算的原理

1.矩阵的基本知识:

struct CGAffineTransform

{
  CGFloat a, b, c, d;
  CGFloat tx, ty;
};

CGAffineTransform CGAffineTransformMake (CGFloat a,CGFloat b,CGFloat c,CGFloat d,CGFloat tx,CGFloat ty);

为了把二维图形的变化统一在一个坐标系里,引入了齐次坐标的概念,即把一个图形用一个三维矩阵表示,其中第三列总是(0,0,1),用来作为坐标系的标准。所以所有的变化都由前两列完成。

以上参数在矩阵中的表示为:

|a    b    0|

|c    d    0|

|tx   ty   1|

运算原理:原坐标设为(X,Y,1);

|a    b    0|

[X,Y,  1]      |c    d    0|     =     [aX + cY + tx   bX + dY + ty  1] ;

|tx    ty  1|

通过矩阵运算后的坐标[aX + cY + tx   bX + dY + ty  1],我们对比一下可知:

第一种:设a=d=1, b=c=0.  

[aX + cY + tx   bX + dY + ty  1] = [X  + tx  Y + ty  1];

可见,这个时候,坐标是按照向量(tx,ty)进行平移,其实这也就是函数

CGAffineTransform CGAffineMakeTranslation(CGFloat tx,CGFloat ty)的计算原理。

第二种:设b=c=tx=ty=0.  

[aX + cY + tx   bX + dY + ty  1] = [aX    dY   1];

可见,这个时候,坐标X按照a进行缩放,Y按照d进行缩放,a,d就是X,Y的比例系数,其实这也就是函数

CGAffineTransform CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)的计算原理。a对应于sx,d对应于sy。

第三种:设tx=ty=0,a=cos?,b=sin?,c=-sin?,d=cos?。

[aX + cY + tx   bX + dY + ty  1] = [Xcos? - Ysin?    Xsin? + Ycos?  1] ;

可见,这个时候,?就是旋转的角度,逆时针为正,顺时针为负。其实这也就是函数

CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle)的计算原理。angle即?的弧度表示。

2.利用上面的变换写一个UIImage矩阵变换的例子:

下面是一个关于image的矩阵运算的例子,无外乎是运用以上三种变换的组合,达到所定义的效果:

[cpp] view plaincopyprint?

  1. //UIImageOrientation的定义,定义了如下几种变换
  2. typedef enum
  3. {
  4. UIImageOrientationUp,            // default orientation
  5. UIImageOrientationDown,          // 180 deg rotation
  6. UIImageOrientationLeft,          // 90 deg CCW
  7. UIImageOrientationRight,         // 90 deg CW
  8. UIImageOrientationUpMirrored,    // as above but image mirrored along other axis. horizontal flip
  9. UIImageOrientationDownMirrored,  // horizontal flip
  10. UIImageOrientationLeftMirrored,  // vertical flip
  11. UIImageOrientationRightMirrored, // vertical flip
  12. } UIImageOrientation;
  13. //按照UIImageOrientation的定义,利用矩阵自定义实现对应的变换;
  14. -(UIImage *)transformImage:(UIImage *)aImage
  15. {
  16. CGImageRef imgRef = aImage.CGImage;
  17. CGFloat width = CGImageGetWidth(imgRef);
  18. CGFloat height = CGImageGetHeight(imgRef);
  19. CGAffineTransform transform = CGAffineTransformIdentity;
  20. CGRect bounds = CGRectMake(0, 0, width, height);
  21. CGFloat scaleRatio = 1;
  22. CGFloat boundHeight;
  23. UIImageOrientation orient = aImage.imageOrientation;
  24. switch(UIImageOrientationLeftMirrored)
  25. {
  26. case UIImageOrientationUp:
  27. transform = CGAffineTransformIdentity;
  28. break;
  29. case UIImageOrientationUpMirrored:
  30. transform = CGAffineTransformMakeTranslation(width, 0.0);
  31. transform = CGAffineTransformScale(transform, -1.0, 1.0);
  32. break;
  33. case UIImageOrientationDown:
  34. transform = CGAffineTransformMakeTranslation(width, height);
  35. transform = CGAffineTransformRotate(transform, M_PI);
  36. break;
  37. case UIImageOrientationDownMirrored:
  38. transform = CGAffineTransformMakeTranslation(0.0, height);
  39. transform = CGAffineTransformScale(transform, 1.0, -1.0);
  40. break;
  41. case UIImageOrientationLeft:
  42. boundHeight = bounds.size.height;
  43. bounds.size.height = bounds.size.width;
  44. bounds.size.width = boundHeight;
  45. transform = CGAffineTransformMakeTranslation(0.0, width);
  46. transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
  47. break;
  48. case UIImageOrientationLeftMirrored:
  49. boundHeight = bounds.size.height;
  50. bounds.size.height = bounds.size.width;
  51. bounds.size.width = boundHeight;
  52. transform = CGAffineTransformMakeTranslation(height, width);
  53. transform = CGAffineTransformScale(transform, -1.0, 1.0);
  54. transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
  55. break;
  56. case UIImageOrientationRight: //EXIF = 8
  57. boundHeight = bounds.size.height;
  58. bounds.size.height = bounds.size.width;
  59. bounds.size.width = boundHeight;
  60. transform = CGAffineTransformMakeTranslation(height, 0.0);
  61. transform = CGAffineTransformRotate(transform, M_PI / 2.0);
  62. break;
  63. case UIImageOrientationRightMirrored:
  64. boundHeight = bounds.size.height;
  65. bounds.size.height = bounds.size.width;
  66. bounds.size.width = boundHeight;
  67. transform = CGAffineTransformMakeScale(-1.0, 1.0);
  68. transform = CGAffineTransformRotate(transform, M_PI / 2.0);
  69. break;
  70. default:
  71. [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];
  72. }
  73. UIGraphicsBeginImageContext(bounds.size);
  74. CGContextRef context = UIGraphicsGetCurrentContext();
  75. if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
  76. CGContextScaleCTM(context, -scaleRatio, scaleRatio);
  77. CGContextTranslateCTM(context, -height, 0);
  78. }
  79. else {
  80. CGContextScaleCTM(context, scaleRatio, -scaleRatio);
  81. CGContextTranslateCTM(context, 0, -height);
  82. }
  83. CGContextConcatCTM(context, transform);
  84. CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
  85. UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
  86. UIGraphicsEndImageContext();
  87. return imageCopy;
  88. }

掌握矩阵运算的原理,对视图的矩阵操作便会得心应手,巧妙利用旋转,平移,缩放,组合起来达到你所想要的变换效果!

时间: 2024-10-11 05:53:22

从UIImage的矩阵变换看矩阵运算的原理的相关文章

CGAffineTransformMake(a,b,c,d,tx,ty) 矩阵运算的原理

简记: CGAffineTransformMake(a,b,c,d,tx,ty) ad缩放bc旋转tx,ty位移,基础的2D矩阵 公式 x=ax+cy+tx    y=bx+dy+ty 1.矩阵的基本知识: struct CGAffineTransform {  CGFloat a, b, c, d;  CGFloat tx, ty;}; CGAffineTransform CGAffineTransformMake (CGFloat a,CGFloat b,CGFloat c,CGFloat

第6月第17天 CGAffineTransformMake(a,b,c,d,tx,ty) 矩阵运算的原理

1. 为了把二维图形的变化统一在一个坐标系里,引入了齐次坐标的概念,即把一个图形用一个三维矩阵表示,其中第三列总是(0,0,1),用来作为坐标系的标准.所以所有的变化都由前两列完成. 以上参数在矩阵中的表示为: |a    b    0| |c    d    0| |tx   ty   1| 运算原理:原坐标设为(X,Y,1); |a    b    0| [X,Y,  1]      |c    d    0|     =     [aX + cY + tx   bX + dY + ty 

从Linux协议栈代码和RFC看西厢计划原理

终于搞定了西厢计划的方案,由于一直无法下载那个内核模块,于是也就只能自己写了,在理解了西厢计划的原理之后,写这个模块并不很费事(其实为了简单不是写模块,而是直接修改内核协议栈代码),下面先说一下原理,然后再说一下关于内核修改的建议. 序.西厢计划 所谓西厢计划是一个借用历史小说而命名的欺骗GfW的方案,有很多的实现.说实话我真的不知道<西厢记>中的那家伙FQ到底有何与众不同,有时间一定看一下.而西厢计划无非就是利用了防火墙的一些弱点而瞒天过海的一个方案.本质上作者是利用对TCP协议规范以及防火

从Select语句看Oracle查询原理(了解Oracle的查询机制)

第一步:客户端把语句发给服务器端执行 当我们在客户端执行select语句时,客户端会把这条SQL语句发送给服务器端,让服务器端的进程来处理这语句.也就是说,Oracle客户端是不会做任何的操作,他的主要任务就是把客户端产生的一些SQL语句发送给服务器端.虽然在客户端也有一个数据库进程,但是,这个进程的作用跟服务器上的进程作用是不相同的.服务器上的数据库进程才会对SQL语句进行相关的处理.不过,有个问题需要说明,就是客户端的进程跟服务器的进程是一一对应的.也就是说,在客户端连接上服务器后,在客户端

TRIZ系列-创新原理-20-有效作用的连续性原理

有效作用的连续性原理表述如下:1)连续实施动作不要中断,物体的所有部分应该一直处于满负荷工作状态:2)去除所有空闲的,中间的动作:3)用循环的动作代替"来来回回"的动作: 这个原理可以看着是原理19的一个反面,我们可以通过检查系统的间歇时刻,这种间歇可能会造成系统的能量损失(浪费),而任何"从零开始"的或使工作流中断的"过渡过程",都有可能损害到系统的效率,因此必须消除这些不利的因素.对于1)和2)很好理解,就是要消除系统的无用功时刻和中间过渡动

关于计算机编译原理

从我个人理解,计算机编译原理,顾名思义,就是关于计算机编程翻译的相关原理,即对计算机编程的,更为深入.更为详细的去解读计算机语言.上网看了许多个人解读编译原理,发现最令我信服的,就是把编译原理类比成人体解剖:只有认真解剖.研究人体各部位,才能在手术中.医治中做到更好的处理.因此,唯有理解编译原理,才能更好地进行计算机的编程等一系列的操作. 博客上有人说到,学习编译原理能够更加容易理解算法之间的关系.能培育自己的观点.提高学习语言的效率.但在我个人看来,学好编译原理,能让我们有一个更强的临时变换的

0909对编译原理的初了解

1.编译原理学什么? "编译原理":研究设计和构造编译程序原理和方法以及主要实现技术.其中蕴含着计算机科学中解决问题的思路.形式化问题和解决问题的方法.通过本课程的学习,使学生掌握编译理论和方法方面的基本知识,同时也获得设计.实现.分析和移植编译程序方面的初步能力. 编译原理(第3版)共10章,内容包括语言及文法的基本知识.词法分析.语法分析.语义分析及中间代码生成.符号表组织.运行时的存储组织与分配.代码优化及目标代码生成等.此外编译原理是一门实践性较强的课程,要联系实际,多看实验参

Http原理及PHP中cURL的使用

为了给接下来的教程做好铺垫,本文将讲述如何用PHP发出Http请求进行模拟登录,顺带会讲一些Http请求原理.模拟登录…就是模拟浏览器登录嘛,所谓请求,只不过是你向网站发一些字,网站又给你回复一些字,这一般都是基于Http或Https协议的.平时是浏览器帮我们做好了这些工作,封装数据发送到指定网站,然后接收,最后编译成网页显示出来.在模拟登录中,呵呵,这些都要我们自己做,只是最后不用编译…只要提取到需要的数据就行了. PHP中模拟登录有三种方式.第一是直接用file_get_contens(网站

九爷 带你了解 Memcache工作原理总结

Memcache工作原理总结 一 <!--[if !supportLists]-->1.  <!--[endif]-->分片原理 咱们废话话不多说了,直接看Memcache的原理. 首先memcache解决的最大的一个问题:<就是内存多次读取的内存碎片问题>.内存碎片分为内存内部碎片和内存外部碎片.一般是指在外部碎片中出现了不连续的细小内存片段,不能够被进程利用.因为不连续,不能组合成大而的连续空间,导致这部分空间很可惜的浪费了.内存碎片是因为在分配一个内存块后,使之空