从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的矩阵运算的例子,无外乎是运用以上三种变换的组合,达到所定义的效果:

 

  1. //UIImageOrientation的定义,定义了如下几种变换  
  2. typedef enum   
  3. {  
  4.     UIImageOrientationUp,            // default orientation  
  5.   
  6.     UIImageOrientationDown,          // 180 deg rotation  
  7.   
  8.     UIImageOrientationLeft,          // 90 deg CCW  
  9.       
  10.     UIImageOrientationRight,         // 90 deg CW  
  11.       
  12.     UIImageOrientationUpMirrored,    // as above but image mirrored along other axis. horizontal flip  
  13.       
  14.     UIImageOrientationDownMirrored,  // horizontal flip  
  15.       
  16.     UIImageOrientationLeftMirrored,  // vertical flip  
  17.       
  18.     UIImageOrientationRightMirrored, // vertical flip  
  19.   
  20. } UIImageOrientation;  
  21.   
  22. //按照UIImageOrientation的定义,利用矩阵自定义实现对应的变换;  
  23.   
  24. -(UIImage *)transformImage:(UIImage *)aImage    
  25.   
  26. {    
  27.   
  28.     CGImageRef imgRef = aImage.CGImage;    
  29.       
  30.     CGFloat width = CGImageGetWidth(imgRef);    
  31.       
  32.     CGFloat height = CGImageGetHeight(imgRef);    
  33.        
  34.     CGAffineTransform transform = CGAffineTransformIdentity;    
  35.       
  36.     CGRect bounds = CGRectMake(0, 0, width, height);    
  37.          
  38.     CGFloat scaleRatio = 1;    
  39.          
  40.     CGFloat boundHeight;    
  41.       
  42.     UIImageOrientation orient = aImage.imageOrientation;    
  43.       
  44.     switch(UIImageOrientationLeftMirrored)    
  45.       
  46.     {    
  47.               
  48.         case UIImageOrientationUp:    
  49.               
  50.             transform = CGAffineTransformIdentity;  
  51.   
  52.             break;    
  53.                          
  54.         case UIImageOrientationUpMirrored:   
  55.               
  56.             transform = CGAffineTransformMakeTranslation(width, 0.0);    
  57.               
  58.             transform = CGAffineTransformScale(transform, -1.0, 1.0);    
  59.               
  60.             break;    
  61.                          
  62.         case UIImageOrientationDown:              
  63.             transform = CGAffineTransformMakeTranslation(width, height);    
  64.               
  65.             transform = CGAffineTransformRotate(transform, M_PI);    
  66.               
  67.             break;    
  68.                          
  69.         case UIImageOrientationDownMirrored:   
  70.               
  71.             transform = CGAffineTransformMakeTranslation(0.0, height);    
  72.               
  73.             transform = CGAffineTransformScale(transform, 1.0, -1.0);    
  74.               
  75.             break;    
  76.                         
  77.         case UIImageOrientationLeft:     
  78.               
  79.             boundHeight = bounds.size.height;    
  80.               
  81.             bounds.size.height = bounds.size.width;    
  82.               
  83.             bounds.size.width = boundHeight;    
  84.               
  85.             transform = CGAffineTransformMakeTranslation(0.0, width);    
  86.               
  87.             transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);    
  88.               
  89.             break;  
  90.                          
  91.         case UIImageOrientationLeftMirrored:     
  92.               
  93.             boundHeight = bounds.size.height;    
  94.               
  95.             bounds.size.height = bounds.size.width;    
  96.               
  97.             bounds.size.width = boundHeight;    
  98.               
  99.             transform = CGAffineTransformMakeTranslation(height, width);    
  100.               
  101.             transform = CGAffineTransformScale(transform, -1.0, 1.0);    
  102.               
  103.             transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);    
  104.               
  105.             break;    
  106.               
  107.         case UIImageOrientationRight: //EXIF = 8    
  108.               
  109.             boundHeight = bounds.size.height;    
  110.               
  111.             bounds.size.height = bounds.size.width;    
  112.               
  113.             bounds.size.width = boundHeight;    
  114.               
  115.             transform = CGAffineTransformMakeTranslation(height, 0.0);    
  116.               
  117.             transform = CGAffineTransformRotate(transform, M_PI / 2.0);    
  118.               
  119.             break;  
  120.                          
  121.         case UIImageOrientationRightMirrored:   
  122.               
  123.             boundHeight = bounds.size.height;    
  124.               
  125.             bounds.size.height = bounds.size.width;    
  126.               
  127.             bounds.size.width = boundHeight;    
  128.               
  129.             transform = CGAffineTransformMakeScale(-1.0, 1.0);    
  130.               
  131.             transform = CGAffineTransformRotate(transform, M_PI / 2.0);    
  132.               
  133.             break;    
  134.                                                                      
  135.         default:    
  136.               
  137.             [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];    
  138.               
  139.     }    
  140.        
  141.     UIGraphicsBeginImageContext(bounds.size);    
  142.              
  143.     CGContextRef context = UIGraphicsGetCurrentContext();    
  144.             
  145.     if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {    
  146.           
  147.         CGContextScaleCTM(context, -scaleRatio, scaleRatio);    
  148.           
  149.         CGContextTranslateCTM(context, -height, 0);    
  150.           
  151.     }    
  152.       
  153.     else {    
  154.           
  155.         CGContextScaleCTM(context, scaleRatio, -scaleRatio);    
  156.           
  157.         CGContextTranslateCTM(context, 0, -height);    
  158.           
  159.     }    
  160.          
  161.     CGContextConcatCTM(context, transform);    
  162.          
  163.     CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);    
  164.       
  165.     UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();  
  166.          
  167.     UIGraphicsEndImageContext();    
  168.          
  169.     return imageCopy;    
  170.       
  171. }   

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

posted @ 2016-01-16 12:53  北狐  阅读(184)  评论(0编辑  收藏  举报