以前在线性代数中学习了矩阵,对矩阵的基本运算有一些了解,前段时间在使用gdi+的时候再次学习如何使用矩阵来变化图像,看了之后在这里总结说明。
首先大家看看下面这个3 x 3的矩阵,这个矩阵被分割成4部分。为什么分割成4部分,在后面详细说明。
首先给大家举个简单的例子:现设点p0(x0, y0)进行平移后,移到p(x,y),其中x方向的平移量为△x,y方向的平移量为△y,那么,点p(x,y)的坐标为:
x = x0 + △x
y = y0 + △y
采用矩阵表达上述如下:
上述也类似与图像的平移,通过上述矩阵我们发现,只需要修改矩阵右上角的2个元素就可以了。
我们回头看上述矩阵的划分:
为了验证上面的功能划分,我们举个具体的例子:现设点p0(x0 ,y0)进行平移后,移到p(x,y),其中x放大a倍,y放大b倍,
矩阵就是:,按照类似前面“平移”的方法就验证。
图像的旋转稍微复杂:现设点p0(x0, y0)旋转θ角后的对应点为p(x, y)。通过使用向量,我们得到如下:
x0 = r cosα
y0 = r sinα
x = r cos(α+θ) = x0 cosθ - y0 sinθ
y = r sin(α+θ) = x0 sinθ + y0 cosθ
于是我们得到矩阵:
如果图像围绕着某个点(a ,b)旋转呢?则先要将坐标平移到该点,再进行旋转,然后将旋转后的图像平移回到原来的坐标原点,在后面的篇幅中我们将详细介绍。
matrix学习——如何使用matrix本篇幅我们就结合android 中的android.graphics.matrix来具体说明,还记得我们前面说的图像旋转的矩阵:
从最简单的旋转90度的是:
在android.graphics.matrix中有对应旋转的函数:
matrix matrix = new matrix();
matrix.setrotate(90);
test.log(maxtrix_tag,”setrotate(90):%s” , matrix.tostring());
查看运行后的矩阵的值(通过log输出):
与上面的公式基本完全一样(android.graphics.matrix采用的是浮点数,而我们采用的整数)。
有了上面的例子,相信大家就可以亲自尝试了。通过上面的例子我们也发现,我们也可以直接来初始化矩阵,比如说要旋转30度:
前面给大家介绍了这么多,下面我们开始介绍图像的镜像,分为2种:水平镜像、垂直镜像。先介绍如何实现垂直镜像,什么是垂直镜像就不详细说明。图像的垂直镜像变化也可以用矩阵变化的表示,设点p0(x0 ,y0 )进行镜像后的对应点为p(x ,y ),图像的高度为fheight,宽度为fwidth,原图像中的p0(x0 ,y0 )经过垂直镜像后的坐标变为(x0 ,fheight- y0);
x = x0
y = fheight – y0
推导出相应的矩阵是:
final float f[] = {1.0f,0.0f,0.0f,0.0f,-1.0f,120.0f,0.0f,0.0f,1.0f};
matrix matrix = new matrix();
matrix.setvalues(f);
按照上述方法运行后的结果:
至于水平镜像采用类似的方法,大家可以自己去试试吧。
实际上,使用下面的方式也可以实现垂直镜像:
matrix matrix = new matrix();
matrix.setscale (1.0,-1.0);
matrix.posttraslate(0, fheight);
这就是我们将在后面的篇幅中详细说明。
matrix学习——基础知识篇幅中,我们留下一个话题:如果图像围绕着某个点p(a,b)旋转,则先要将坐标系平移到该点,再进行旋转,然后将旋转后的图像平移回到原来的坐标原点。
我们需要3步:
1. 平移——将坐标系平移到点p(a,b);
2. 旋转——以原点为中心旋转图像;
3. 平移——将旋转后的图像平移回到原来的坐标原点;
相比较前面说的图像的几何变化(基本的图像几何变化),这里需要平移——旋转——平移,这种需要多种图像的几何变化就叫做图像的复合变化。
设对给定的图像依次进行了基本变化f1、f2、f3…..、fn,它们的变化矩阵分别为t1、t2、t3…..、tn,图像复合变化的矩阵t可以表示为:t = tntn-1…t1。
按照上面的原则,围绕着某个点(a,b)旋转θ的变化矩阵序列是:
按照上面的公式,我们列举一个简单的例子:围绕(100,100)旋转30度(sin 30 = 0.5 ,cos 30 = 0.866)
float f[]= { 0.866f, -0.5f, 63.4f,0.5f, 0.866f,-36.6f,0.0f, 0.0f, 1.0f };
matrix = new matrix();
matrix.setvalues(f);
旋转后的图像如下:
android为我们提供了更加简单的方法,如下:
matrix matrix = new matrix();
matrix.setrotate(30,100,100);
矩阵运行后的实际结果:
与我们前面通过公式获取得到的矩阵完全一样。
在这里我们提供另外一种方法,也可以达到同样的效果:
float a = 100.0f,b = 100.0f;
matrix = new matrix();
matrix.settranslate(a,b);
matrix.prerotate(30);
matrix.pretranslate(-a,-b);
将在后面的篇幅中为大家详细解析
通过类似的方法,我们还可以得到:相对点p(a,b)的比例[sx,sy]变化矩阵
从最基本的高等数学开始,matrix的基本操作包括:+、*。matrix的乘法不满足交换律,也就是说a*b ≠b*a。还有2种常见的矩阵:
有了上面的基础,下面我们开始进入主题。由于矩阵不满足交换律,所以用矩阵b乘以矩阵a,需要考虑是左乘(b*a),还是右乘(a*b)。在android的android.graphics.matrix中为我们提供了类似的方法,也就是我们本篇幅要说明的preconcats matrix 与 postconcats matrix。下面我们还是通过具体的例子还说明:
通过输出的信息,我们分析其运行过程如下:
看了上面的输出信息。我们得出结论:preconcats matrix相当于右乘矩阵,postconcats matrix相当于左乘矩阵。
matrix学习——错切变换什么是图像的错切变换(shear transformation)?我们还是直接看图片错切变换后是的效果:
对图像的错切变换做个总结:
x = x0 + b*y0;
y = d*x0 + y0;
这里再次给大家介绍一个需要注意的地方:
通过以上,我们发现matrix的setxxxx()函数,在调用时调用了一次reset(),这个在复合变换时需要注意。
matrix学习——对称变换(反射)什么是对称变换?具体的理论就不详细说明了,图像的镜像就是对称变换中的一种。
利用上面的总结做个具体的例子,产生与直线y= – x对称的反射图形,代码片段如下:
当前矩阵输出是:
图像变换的效果如下:
附:三角函数公式
如对本文有疑问, 点击进行留言回复!!
LongClick原理、上下文菜单原理、EditText长按弹窗原理、WebView长按弹窗自定义、修复WebView全选重复bug ———————————————— 版权声明:本文为CSDN博主「
JobScheduler 实现 特定时间,特定条件(系统空闲,电池电量,磁盘空间 ……)下执行任务
网友评论