老铁们,大家好,相信还有很多朋友对于高效掌握Matrix应用技巧指南和的相关问题不太懂,没关系,今天就由我来为大家分享分享高效掌握Matrix应用技巧指南以及的问题,文章篇幅可能偏长,希望可以帮助到大家,下面一起来看看吧!
img 曲文涛
android矩阵最全方法详解与进阶(完整文章)
发表于2016/5/18 16:43:27 1385人阅读
类别: 安卓绘图
1 概述
这里我们将详细讲解矩阵的各种方法及其用法。矩阵称为矩阵。在之前讲解ColorFilter的文章中,我们讲解了ColorMatrix,它是一个4*5的矩阵。而这里我们讲解的Matrix并不是用来处理颜色的,而是用来处理图形的。它是一个3*3的矩阵。
2 原则
我们先看一下矩阵的矩阵是什么样的:
在这里写下图片描述
您可以在这里查看Matrix 的代码。那么这些矩阵代表什么?从它们的名字就可以看出,scale的意思是缩放,skew的意思是误切(canvas变换中讨论过),trans的意思是平移,persp的意思是透视(官方文档中没有详细说明)。解释,这里仅简单介绍视角)。这里需要将矩阵根据功能分为4块:
在这里写下图片描述
如上图所示,这四个区域各有各的功能。稍后将详细解释每个功能。我们首先看看这个矩阵如何影响图像。首先看屏幕的坐标系:
在这里写下图片描述
看上图,它显示了屏幕的坐标系。 x轴和y轴大家都熟知,但实际上,一个物体存在于三维空间中,所以一定有一个z轴。我们的屏幕就像一扇窗户。通过它,我们看到了屏幕后面的世界,那里有各种各样的物体。我们看到的是映射在x、y 平面上的投影图像。屏幕就像一个镜头,将里面的物体映射到x、y平面上成为二维图像。那么,如果我们沿z 轴缩小或缩小屏幕镜头,图像会发生什么情况?它肯定会变小或变大。这就像坐在飞机上透过窗户看地面上的汽车一样。尺寸与您在地面上看到的不同。
结论是,屏幕上显示的像素不仅有x、y坐标,还受到z轴的影响。所以这里对应的像素描述就用一个三行一列的矩阵来表示:
在这里写下图片描述
x和y分别表示x轴和y轴上的坐标,1表示屏幕在z轴上的默认坐标。如果将1 调大,屏幕就会缩小,图形也会变小。
现在让我们看看矩阵如何作用于每个像素的值。这里需要用到矩阵乘法。首先需要明确的是,矩阵的前乘和后乘是不一样的,这意味着不满足乘法的交换律。
这里我们通过一个旋转变换来看看原理。其实一张图片是围绕一个点旋转的,即所有的点都围绕一个点旋转,所以只需要关注一个点的情况即可:
假设有一个点,相对于坐标原点顺时针旋转,并假设点P 到坐标原点的距离为r,如下所示:
在这里写下图片描述
然后是:
在这里写下图片描述
改为矩阵运算如下图:
在这里写下图片描述
从这里你可以看到矩阵中的值如何作用于像素的x、y坐标和z轴距离。
同时可以看到,上面矩阵的四个区域的划分也是由矩阵乘法的运算决定的。由于这里的乘法运算中,左上角的四个值可以与x、y值相乘,所以会影响旋转等运算,而右上角的模块只能做加法,所以它只会影响翻译。右下角的模块主要负责z轴,自然可以按比例缩放。左下角的模块一般不用管,否则x、y值会加到z轴上,就会不可控。
3 基本方法分析
解释完矩阵作用于像素的原理后,我们再一一解释它的方法。
(1) 构造函数
公共矩阵()
公共矩阵(矩阵源)
有两个构造函数,第一个是直接创建单位矩阵,第二个是根据提供的矩阵创建一个新矩阵(使用深拷贝)
单位矩阵如下:
在这里写下图片描述
(2) isIdentity 和isAffine
public boolean isIdentity()//判断是否为单位矩阵
public boolean isAffine()//判断是否为仿射矩阵
是否是单位矩阵很简单,这里就不解释了。是否是仿射矩阵可能大家比较难以理解。
首先我们来了解一下什么是仿射变换。仿射变换实际上是二维坐标到二维坐标的线性变换,它保持了二维图形的“平坦性”(即变换后直线仍是直线,没有弯曲,圆弧仍是圆弧)和“平行”(指保持二维图形之间的相对位置关系不变(平行线仍是平行线,直线上点的位置顺序不变),可以通过一系列原子变换的组合来实现,原子变换包括:平移、缩放、翻转、旋转和错切。除透视可以改变z轴外,其他变换基本上都是上述的原子变换。只要最后一行是0,0,1,就是仿射矩阵。
(3) 矩形保持矩形
公共布尔rectStaysRect()
判断矩阵是否仍能将矩形变换为矩形。当矩阵是单位矩阵,或者只有平移、缩放、旋转是90度的倍数时返回true。
(4)复位
公共无效重置()
将矩阵重置为单位矩阵。
(5)设置翻译
公共无效setTranslate(浮点dx,浮点dy)
设置平移效果,参数分别为x、y上的平移量。
效果图如下:
在这里写下图片描述
代码如下:
矩阵矩阵=new Matrix();
canvas.drawBitmap(位图、矩阵、绘画);
矩阵.setTranslate(100, 1000);
canvas.drawBitmap(位图、矩阵、绘画);
1
2
3
4
5
(6)设置比例
公共无效setScale(浮点sx,浮点sy,浮点px,浮点py)
公共无效setScale(浮点sx,浮点sy)
两种方法都将缩放设置为矩阵,sx和sy表示缩放倍数,px和py表示缩放中心。这个和上面的类似,这里就不解释了。
(7)设置旋转
公共无效setRotate(浮点度数,浮点px,浮点py)
公共无效setRotate(浮点数)
与上述类似,不再进一步解释。
(8) 设定正余弦
公共无效setSinCos(浮动sinValue,浮动cosValue,浮动px,浮动py)
公共无效setSinCos(浮动sinValue,浮动cosValue)
这种方法乍一看可能有点令人困惑。其实在前面的原理中,我们解释了一个旋转的例子,它最终的矩阵效果是这样的:
在这里写下图片描述
事实上,旋转就是使用这样的矩阵。显然,这里的参数已经很清楚了。
sinValue:对应图中的sin值
cosValue:对应的cos值
px: 中心x 坐标
py: 中心的y坐标
看一个例子,我们将图像旋转90度,那么90度对应的sin和cos分别为1和0。
在这里写下图片描述
看代码如下:
矩阵矩阵=新矩阵();
Matrix.setSinCos(1, 0, bitmap.getWidth()/2, bitmap.getHeight()/2);
canvas.drawBitmap(位图、矩阵、绘画);
1
2
3
(9) 设置倾斜
公共无效setSkew(浮点kx,浮点ky,浮点px,浮点py)
公共无效setSkew(浮点kx,浮点ky)
误切,这里kx,ky分别表示x和y上的误切因子,px,py表示误切的中心。如果不明白剪错了,可以在前面的画布变换中检查一下。我这里就不解释了。
(10)设置连接
公共布尔setConcat(矩阵a,矩阵b)
将当前矩阵的值更改为a和b的乘积。其意义将在后面的高级方法中讨论。
4 高级方法分析
在上述基本方法中,与变换相关的设置方法可以带来不同的效果,但每设置一次都会清除之前的效果。例如,如果依次调用setSkew和setTranslate,那么最终只有setTranslate起作用。所以呢?采鹤将两种功效结合起来。 Matrix为我们提供了很多方法。但主要有2类:
preXXXX: 以pre 开头,如preTranslate
postXXXX: 以post 开头,例如postScale
它们分别代表前乘和后乘。看一段代码:
矩阵矩阵=new Matrix();
矩阵.setTranslate(100, 1000);
矩阵.preScale(0.5f, 0.5f);
1
2
3
这里,矩阵预乘了一个尺度矩阵,转换成数学公式如下:
在这里写下图片描述
从上面可以看出,最终的矩阵既包含了缩放信息也包含了平移信息。
后乘自然就是矩阵在后面,缩放矩阵在前面。由于前后的矩阵乘法并不等价,所以它们的效果是不同的。我们看一下后乘的结果:
在这里写下图片描述
可以看到,结果和上面不一样,这不是我们想要的结果。这里的缩放没有改变,但是平移减半了。换句话说,平移距离也被缩放。因此,需要注意前后乘法的关系。
我们来看看他们对应的效果图:
前排乘坐:
在这里写下图片描述
之后相乘:
在这里写下图片描述
可以明显看出,后乘的平移距离受到了影响。
理解前向乘法和后向乘法清零的含义。在使用过程中还必须注意多种效果的叠加,否则效果达不到预期。
5 其他分析方法
除了上述方法之外,Matrix还有一些其他的方法,这里依次分析。
(1)设置矩形到矩形
公共布尔setRectToRect(RectF src, RectF dst, ScaleToFit stf)
将矩形转换为矩形。上面的rectStaysRect 已经说了,要保持rect,只能进行缩放和平移以及选择90 度的倍数。所以这里也是如此,只不过这些改变是由stf 参数控制的。
ScaleToFit 有以下四个值:
FILL:可以对矩形的长宽比进行变换,以确保变换与目标矩阵的长宽一致。
START: 保持坐标变换前矩形的长宽比,并最大程度地填充变换后的矩形。至少一侧与目标矩形重叠。左上方对齐。
CENTER: 保持坐标变换前矩形的长宽比,并最大程度地填充变换后的矩形。至少一侧与目标矩形重叠。
END: 保持坐标变换前矩形的长宽比,并最大程度地填充变换后的矩形。至少一侧与目标矩形重叠。右下对齐。
这里我们以Google的api demo的图片为例:
在这里写下图片描述
(2)设置多边形到多边形
公共布尔setPolyToPoly(float[] src, int srcIndex,float[] dst, int dstIndex,int pointCount)
通过指定0-4个点、原始坐标和改变后的坐标,得到一个变换矩阵。如果指定0 点,则没有效果。
下面举例说明1~4点可以达到的效果:
这里写下代码段##### 1分,翻译
仅指定一个点,即可实现平移效果:
在这里写下图片描述
代码如下:
浮点数[] src={0, 0};
整数DX=300;
float[] dst={0 + DX, 0 + DX};
矩阵.setPolyToPoly(src, 0, dst, 0, 1);
canvas.drawBitmap(位图、矩阵、绘画);
1
2
3
4
5
2点,旋转或缩放
两个点可以实现旋转或缩放效果。缩放相对简单。下面我们看一下旋转效果。一点指定中心,一点表示旋转效果。
在这里写下图片描述
代码如下
int bw=bitmap.getWidth();
int bh=bitmap.getHeight();
float[] src={bw/2, bh/2, bw, 0};
float[] dst={bw/2, bh/2, bw/2 + bh/2, bh/2 + bw/2};
矩阵.setPolyToPoly(src, 0, dst, 0, 2);
canvas.drawBitmap(位图、矩阵、绘画);
1
2
3
4
5
6
以图片的中心点作为旋转中心。前后保持不变,只是右上角变成了底部,导致画面旋转了90度。
3分,错误切入
使用3个点,可以产生交错切割效果。指定3 个顶点,其中一个是固定的,另外两个是移动的。
看图片:
在这里写下图片描述
代码如下:
矩阵矩阵=new Matrix();
int bw=bitmap.getWidth();
int bh=bitmap.getHeight();
float[] src={0,0, 0, bh,bw,bh};
float[] dst={0, 0, 200, bh, bw + 200, bh};
矩阵.setPolyToPoly(src, 0, dst, 0, 3);
canvas.drawBitmap(位图、矩阵、绘画);
1
2
3
4
5
6
7
4点、视角
透视是观察角度的变化。导致投影到平面上的二维图像发生变化。
我们看下面的例子,以便于理解:
在这里写下图片描述
图片看起来是倾斜的,实现起来很简单:
矩阵矩阵=new Matrix();
int bw=bitmap.getWidth();
int bh=bitmap.getHeight();
float[] src={0, 0, 0, bh, bw, bh, bw, 0};
整数DX=100;
float[] dst={0 + DX, 0, 0, bh, bw, bh, bw - DX, 0};
矩阵.setPolyToPoly(src, 0, dst, 0, 4);
canvas.drawBitmap(位图、矩阵、绘画);
1
2
3
4
5
6
7
8
正如您所看到的,左右顶点只是向内移动,从而创建了具有3D 效果的透视图。
(3) 反转
公共布尔反转(矩阵逆)
反转当前矩阵。如果可以反转,则返回true,并将反转后的值写入inverse,否则返回false。当前矩阵* 逆=单位矩阵。
反转前后效果如何?让我们看一个例子:
在这里写下图片描述
可见,逆转之后,实际上是效果逆转了。
(4) 地图点
公共无效mapPoints(浮点[] dst,int dstIndex,浮点[] src,int srcIndex,int pointCount)
公共无效mapPoints(浮动[] dst,浮动[] src)
公共无效地图点(浮动[]点)
将点的值映射到指定的数组。该方法可以给出指定点经过矩阵变换后的值。
dst:指定要写入的数组
dstIndex:写入的起始索引。 x 和y 两个坐标算作一对。索引的单位是pair,即两个值后面加1。
src:指定要计算的点
srcIndex:要计算的点的索引
pointCount:要计算的点数。每个点都有两个值:x 和y。
(5) 地图向量
公共无效mapVectors(浮点[] dst,int dstIndex,浮点[] src,int srcIndex,int vectorCount)
公共无效mapVectors(浮点[] dst,浮点[] src)
公共无效mapVectors(浮点[] vecs)
基本上和上面的mapPoionts类似,这里将一个矩阵应用到一个向量上。由于向量的平移前后相等,因此该方法不会对与平移相关的方法做出反应。如果只调用translate相关的方法,那么我们得到的值就和原来的一致了。
(6) 映射矩形
公共布尔映射矩形(矩形dst,矩形src)
公共布尔mapRect(RectF 矩形)
返回值是被调用的rectStaysRect()。这个方法前面已经提到过。这里,将src中指定的矩形的左上角和右下角两点的坐标写入到dst中。
(7) 地图半径
公共浮动mapRadius(浮动半径)
返回圆的平均半径。将矩阵应用于具有指定半径的圆并返回平均半径。
以上基本分析了所有的矩阵方法,以及一些高级用法。本文到此结束。
上一篇下一篇
评论(1)
philipy_meiphilipy_mei1F
博主你好,我现在在做一个功能,就是按比例缩放手机屏幕。我在里面看到了mSurfaceControl.setMatrix。这个矩阵的参数和你提到的不同。如果我想实现规模化,我该怎么做?
mSurfaceControl.setMatrix(
mDsDx * w.mHScale、mDtDx * w.mVScale、
mDsDy * w.mHScale, mDtDy * w.mVScale);
2016-08-23 14:52 回复
发表评论
我的热门文章
android Path 和PathMeasure 高级
Android矩阵详解及进阶(一)
android IntentFilter匹配规则
android矩阵最全方法详解与进阶(完整文章)
Android canvas层(layer)详解与进阶
相关博客文章
我的Android进阶之旅------Android利用Matrix旋转图片模拟光盘加载过程
Android基础入门教程8318 Canvas API详解第3部分Matrix和drawBitmapMash
安卓仿人人客户端完整故事v571最新消息
一篇完整的文章,包含您应该了解的有关Android Activity 的所有内容
Android开发笔记-适配不同机型的完整解决方案
Android抽屉动态布局完整文章
完整的Android环境资源
Android抽屉的完全拖放与动态布局
Android抽屉动态布局完整文章
Coco2dx 20 android开发构建完整文章
未登录
•头版
•移动开发
•Web前端
•建筑设计
•编程语言
•互联网
•数据库
•系统运维
•云计算
•研发管理
【高效掌握Matrix应用技巧指南】相关文章:
用户评论
想学习如何用Matrix来做数据分析,这篇文章很及时!
有13位网友表示赞同!
Matrix在很多领域都有应用,我比较感兴趣它的数值计算能力。
有20位网友表示赞同!
刚开始接触Matrix,这篇文章能帮我入门吗?
有9位网友表示赞同!
MATRIX 的语法复杂吗? 这篇文章有讲解吗?
有7位网友表示赞同!
我以前用过其他的工具来处理数据,想了解Matrix有什么优势。
有8位网友表示赞同!
MATRIX 和其他开源库相比,各有特点吧? 这篇文章有没有比较?
有9位网友表示赞同!
矩阵运算可以解决很多实际问题,期待这篇文章能给我一些启发!
有11位网友表示赞同!
希望能看到更多关于Matrix应用案例的讲解!
有16位网友表示赞同!
MATRIX 的学习资源不多吗? 希望这篇文章能推荐一些好的资料。
有10位网友表示赞同!
MATRIX 能用在机器学习领域吗? 这篇文章有提到吗?
有19位网友表示赞同!
学习Matrix需要编程基础吗? 不懂Python怎么办?
有7位网友表示赞同!
希望能看到更多关于Matrix编程技巧的分享!
有15位网友表示赞同!
MATRIX 的使用场景很多,这篇文章能帮我们理清思路吗?
有12位网友表示赞同!
MATRIX 在科研和工程领域都有应用吗?
有9位网友表示赞同!
对于初学者来说,Matrix是不是比较难上手? 希望这篇文章能讲解得简单易懂!
有7位网友表示赞同!
我想了解如何在实际项目中运用MATRIX。
有8位网友表示赞同!
MATRIX 可以处理大规模数据吗? 这篇文章有答案了吗?
有7位网友表示赞同!
希望能看到更多关于Matrix的使用心得分享!
有19位网友表示赞同!
学习Matrix需要多久的时间才能入门?
有17位网友表示赞同!