从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的矩阵运算的例子,无外乎是运用以上三种变换的组合,达到所定义的效果:
- //UIImageOrientation的定义,定义了如下几种变换
- typedef enum
- {
- UIImageOrientationUp, // default orientation
- UIImageOrientationDown, // 180 deg rotation
- UIImageOrientationLeft, // 90 deg CCW
- UIImageOrientationRight, // 90 deg CW
- UIImageOrientationUpMirrored, // as above but image mirrored along other axis. horizontal flip
- UIImageOrientationDownMirrored, // horizontal flip
- UIImageOrientationLeftMirrored, // vertical flip
- UIImageOrientationRightMirrored, // vertical flip
- } UIImageOrientation;
- //按照UIImageOrientation的定义,利用矩阵自定义实现对应的变换;
- -(UIImage *)transformImage:(UIImage *)aImage
- {
- CGImageRef imgRef = aImage.CGImage;
- CGFloat width = CGImageGetWidth(imgRef);
- CGFloat height = CGImageGetHeight(imgRef);
- CGAffineTransform transform = CGAffineTransformIdentity;
- CGRect bounds = CGRectMake(0, 0, width, height);
- CGFloat scaleRatio = 1;
- CGFloat boundHeight;
- UIImageOrientation orient = aImage.imageOrientation;
- switch(UIImageOrientationLeftMirrored)
- {
- case UIImageOrientationUp:
- transform = CGAffineTransformIdentity;
- break;
- case UIImageOrientationUpMirrored:
- transform = CGAffineTransformMakeTranslation(width, 0.0);
- transform = CGAffineTransformScale(transform, -1.0, 1.0);
- break;
- case UIImageOrientationDown:
- transform = CGAffineTransformMakeTranslation(width, height);
- transform = CGAffineTransformRotate(transform, M_PI);
- break;
- case UIImageOrientationDownMirrored:
- transform = CGAffineTransformMakeTranslation(0.0, height);
- transform = CGAffineTransformScale(transform, 1.0, -1.0);
- break;
- case UIImageOrientationLeft:
- boundHeight = bounds.size.height;
- bounds.size.height = bounds.size.width;
- bounds.size.width = boundHeight;
- transform = CGAffineTransformMakeTranslation(0.0, width);
- transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
- break;
- case UIImageOrientationLeftMirrored:
- boundHeight = bounds.size.height;
- bounds.size.height = bounds.size.width;
- bounds.size.width = boundHeight;
- transform = CGAffineTransformMakeTranslation(height, width);
- transform = CGAffineTransformScale(transform, -1.0, 1.0);
- transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
- break;
- case UIImageOrientationRight: //EXIF = 8
- boundHeight = bounds.size.height;
- bounds.size.height = bounds.size.width;
- bounds.size.width = boundHeight;
- transform = CGAffineTransformMakeTranslation(height, 0.0);
- transform = CGAffineTransformRotate(transform, M_PI / 2.0);
- break;
- case UIImageOrientationRightMirrored:
- boundHeight = bounds.size.height;
- bounds.size.height = bounds.size.width;
- bounds.size.width = boundHeight;
- transform = CGAffineTransformMakeScale(-1.0, 1.0);
- transform = CGAffineTransformRotate(transform, M_PI / 2.0);
- break;
- default:
- [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];
- }
- UIGraphicsBeginImageContext(bounds.size);
- CGContextRef context = UIGraphicsGetCurrentContext();
- if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
- CGContextScaleCTM(context, -scaleRatio, scaleRatio);
- CGContextTranslateCTM(context, -height, 0);
- }
- else {
- CGContextScaleCTM(context, scaleRatio, -scaleRatio);
- CGContextTranslateCTM(context, 0, -height);
- }
- CGContextConcatCTM(context, transform);
- CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
- UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return imageCopy;
- }
掌握矩阵运算的原理,对视图的矩阵操作便会得心应手,巧妙利用旋转,平移,缩放,组合起来达到你所想要的变换效果!
从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.矩阵的基本 ...
- 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.矩阵的基 ...
- Struts1——离BeanUtils看struts其原理1
在Struts中非常典型的特点就是使用了ActionForm来搜集表单数据,可是搜集到的表单数据所有都是String类型的.假设我们直接拿来使用我们会面临一个非常麻烦的问题就是频繁的类型装换. Str ...
- 从JDK源码角度看线程池原理
"池"技术对我们来说是非常熟悉的一个概念,它的引入是为了在某些场景下提高系统某些关键节点性能,最典型的例子就是数据库连接池,JDBC是一种服务供应接口(SPI),具体的数据库连接实 ...
- 第6月第17天 CGAffineTransformMake(a,b,c,d,tx,ty) 矩阵运算的原理
1. 为了把二维图形的变化统一在一个坐标系里,引入了齐次坐标的概念,即把一个图形用一个三维矩阵表示,其中第三列总是(0,0,1),用来作为坐标系的标准.所以所有的变化都由前两列完成. 以上参数在矩阵中 ...
- 源代码看CoordinatorLayout.Behavior原理
在上一篇博客CoordinatorLayout高级使用方法-自己定义Behavior中,我们介绍了怎样去自己定义一个CoordinatorLayout的Behavior.通过文章也能够看出Behavi ...
- 从SpringBoot源码看资源映射原理
前言 很多的小伙伴刚刚接触SpringBoot的时候,可能会遇到加载不到静态资源的情况. 比如html没有样式,图片无法加载等等. 今天王子就与大家一起看看SpringBoot中关于资源映射部分的主要 ...
- 从Select语句看Oracle查询原理(了解Oracle的查询机制)
第一步:客户端把语句发给服务器端执行 当我们在客户端执行select语句时,客户端会把这条SQL语句发送给服务器端,让服务器端的进程来处理这语句.也就是说,Oracle客户端是不会做任何的操作,他的主 ...
- 窥看 SpringBoot 的原理与使用
一:SpringBoot的启动 1. 继承spring-boot-starter-parent项目 2. 导入spring-boot-dependencies项目依赖 二:Spring Boot 主类 ...
随机推荐
- Android 给Button加个监听
1.日期设置控件:DatePickerDialog 2.时间设置控件:TimePickerDialog 实例代码 1.页面添加两个Button,单击分别显示日期设置控件和时间设置控件,还是有TextV ...
- Linux学习之六-Yum命令的使用
详细介绍一下yum命令的用法.如果你是一个Linux的初学者,一定会被软件的安装所困扰过,尽管RPM包解决了一定层度的问题,但有些RPM的包的依赖关系让人很是头疼.而YUM.APT等一些RPM包的管理 ...
- 04737_C++程序设计_第2章_从结构到类的演变
例2.1 使用成员函数的实例. #define _SCL_SECURE_NO_WARNINGS #include <iostream> using namespace std; struc ...
- Soft Drinking(水)
A. Soft Drinking time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...
- The Tips of Success(成功的建议)
1.Do one thing at a time,and do well. 2.Never forget to say "thanks". 3,Keep on going.Neve ...
- ruby中输入命令行编译sass(ruby小白)
Ruby(或cmd中)输入命令行编译sass步骤如下: (1)举例而言:首先在F盘下建立一个总文件夹,比如test文件夹:其次在该文件夹下建立html,images,js,sass等文件夹. (2)在 ...
- [RabbitMQ]Error: unable to connect to node rabbit@compute1: nodedown(CentOS7.0)
今天在搭建OpenStack的时候需要安装RabbitMQ,可是使用yum install rabbitmq-server安装之后,按照OpenStack官方提供的文档修改guest用户密码的时候却出 ...
- api(一) 创建窗口 (转)
所有的Windows SDK编程都有一个类似的框架,本文就说说这个框架,Windows程序设计的框架分为“三部曲”: 一.注册窗口类 注册窗口类的API函数是RegisterClass或者Regist ...
- poj3122--二分加贪心
大致题意: 就是公平地分披萨pie 我生日,买了n个pie,找来f个朋友,那么总人数共f+1人 每个pie都是高为1的圆柱体,输入这n个pie的每一个尺寸(半径),如果要公平地把pie分给每一个人(就 ...
- 关于NGINX下开启PHP-FPM 输出PHP错误日志的设置(已解决)
最近在本地搭建的LNMP的开发环境.为了开发的时候不影响前端的正常开发就屏蔽的PHP里面php.ini中的一些错误提示.但是这样一来,就影响到了后端开发的一些问题比如不能及时调试开发中的一些问题. n ...