前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android 图形处理 —— Matrix 原理剖析

Android 图形处理 —— Matrix 原理剖析

作者头像
GeeJoe
发布2021-12-09 12:17:11
1.3K0
发布2021-12-09 12:17:11
举报
文章被收录于专栏:掘金文章

Matrix 简介

Android 图形库中的 android.graphics.Matrix 是一个 3×3 的 float 矩阵,其主要作用是坐标变换

它的结构大概是这样的

其中每个位置的数值作用和其名称所代表的的含义是一一对应的

  • MSCALE_X、MSCALE_Y:控制缩放
  • MTRANS_X、MTRANS_Y:控制平移
  • MSKEW_X、MSKEW_X:控制错切
  • MSCALE_X、MSCALE_Y、MSKEW_X、MSKEW_X:控制旋转
  • MPERSP_0、MPERSP_1、MPERSP_2:控制透视

在 Android 中,我们直接实例化一个 Matrix,内部的矩阵长这样:

是一个左上到右下为 1,其余为 0 的矩阵,也叫单位矩阵,一般数学上表示为 I

Matrix 坐标变换原理

前面说到 Matirx 主要的作用就是处理坐标的变换,而坐标的基本变换有:平移、缩放、旋转和错切

这里所说的基本变换,也称仿射变换 ,透视不属于仿射变化,关于透视相关的内容不在本文的范围内

当矩阵的最后一行是 0,0,1 代表该矩阵是仿射矩阵,下文中所有的矩阵默认都是仿射矩阵

线性代数中的矩阵乘法

在正式介绍 Matrix 是如何控制坐标变换的原理之前,我们先简单复习一下线性代数中的矩阵乘法,详细的讲解可参见维基百科或者翻翻大学的《线性代数》,这里只做最简单的介绍

  • 两个矩阵相乘,前提是第一个矩阵的列数等于第二个矩阵的行数
  • 若 A 为 m × n 的矩阵,B 为 n × p 的矩阵,则他们的乘积 AB 会是一个 m × p 的矩阵,表达可以写为
  • 由定义计算,AB 中任意一点(a,b)的值为 A 中第 a 行的数和 B 中第 b 列的数的乘积的和

了解矩阵乘法的基本方法之后,我们还需要记住几个性质,对后续的分析有用

  • 满足结合律,即 A(BC)=(AB)C
  • 满足分配律,即 A(B + C) = AB + AC (A + B)C = AC + BC
  • 不满足交换律,即 AB != BA
  • 单位矩阵 I 与任意矩阵相乘,等于矩阵本身,即 IA = ABI = B

缩放(Scale)

我们先想想,让我们实现把一个点 (x0, y0) 的 x 轴和 y 轴分别缩放 k1 和 k2 倍,我们会怎么做,很简单

代码语言:javascript
复制
val x = k1 * x0
val y = k2 * y0
复制代码

那如果用矩阵怎么实现呢,前面我们讲到 Matrix 中 MSCALE_XMSCALE_Y 是用来控制缩放的,我们在这里填分别设置为 k1 和 k2,看起来是这样的

而点 (x0, y0) 用矩阵表示是这样的

有些人会疑问,最后一行这里不是还有一个 1 吗,这是使用了齐次坐标系的缘故,在数学中我们的点和向量都是这样表示的 (x, y),两者看起来一样,计算机无法区分,为了让计算机也可以区分它们,增加了一个标志位,即

代码语言:javascript
复制
(x, y, 1) -> 点
(x, y, 0) -> 向量
复制代码

现在 Matrix 和点都可以用矩阵表示了,接下来我们看看怎么通过这两个矩阵得到一个缩放之后的点 (x, y). 前面我们已经介绍过矩阵的乘法,让我们看看把上面两个矩阵相乘会得到什么结果

可以看到,矩阵相乘得到了一个(k1x0, k2y0,1)的矩阵,上面说过,计算机中,这个矩阵就代表点 (k1x0, k2y0), 而这个点刚好就是我们要的缩放之后的点

以上所有过程用代码来实现,看起来就是像下面这样

代码语言:javascript
复制
val xy = FloatArray(x0, y0)
Matrix().apply {
    setScale(k1, k2)   
    mapPoints(xy)
}
复制代码

平移(Translate)

平移和缩放也是类似的,实现平移,我们一般可写为

代码语言:javascript
复制
val x = x0 + deltaX
val y = y0 + deltaY
复制代码

而用矩阵来实现则是

代码语言:javascript
复制
val xy = FloatArray(x0, y0)
Matrix().apply {
    setTranslate(k1, k2)   
    mapPoints(xy)
}
复制代码

换成数学表示

根据矩阵乘法

代码语言:javascript
复制
x = 1 × x0 + 0 × y0 + deltaX × 1 = x0 + deltaX
y = 0 × x0 + 1 × y0 + deltaY × 1 = y0 + deltaY
复制代码

可得和一开始的实现也是效果一致的

错切(Skew)

错切相对于平移和缩放,可能大部分人对这个名词比较陌生,直接看三张图大家可能会比较直观

水平错切

代码语言:javascript
复制
x = x0 + ky0
y = y0
复制代码

矩阵表示

垂直错切

代码语言:javascript
复制
x = x0
y = kx0 + y0
复制代码

矩阵表示

复合错切

代码语言:javascript
复制
x = x0 + k1y0
y = k2x0 + y0
复制代码

矩阵表示

旋转(Rotate)

旋转相对以上三种变化又有一点复杂,这里涉及一些三角函数的计算,忘记的可以去维基百科 先复习下

同样我们先自己实现一下旋转,假设一个点 A(x0, y0), 距离原点的距离为 r,与水平夹角为 α,现绕原点顺时针旋转 θ 度,旋转之后的点为 B(x, y)

用矩阵表示

Matrix 复合操作原理

前面介绍了四种基本变换,如果我们需要同时应用上多种变化,比如先绕原点顺时针旋转 90° 再 x 轴平移 100,y 轴平移 100, 最后 x、y 轴缩放0.5 倍,那么就需要用到复合操作

还是先用自己的实现来实现一下

代码语言:javascript
复制
x = ((x0 · cosθ - y0 · sinθ) + 100) · 0.5
y = ((y0 · cosθ + x0 · sinθ) + 100) · 0.5
复制代码

矩阵表示

按照前面的方式逐个推导,最终也能得到和上述一样的结果

到此,我们可以对 Matrix 做出一个基本的认识:Matrix 基于矩阵计算的原理,解决了计算机中坐标映射和变化的问题

下一篇文章《Matirx 方法详解及应用场景》将介绍 Matrix 中常用的 api 以及实际开发中的应用场景

相关链接

Matrices for developers

Understanding Android Matrix transformations

Android Matrix 最全方法详解与进阶

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021年12月06日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Matrix 简介
  • Matrix 坐标变换原理
    • 线性代数中的矩阵乘法
      • 缩放(Scale)
        • 平移(Translate)
          • 错切(Skew)
            • 旋转(Rotate)
            • Matrix 复合操作原理
            相关产品与服务
            腾讯云 BI
            腾讯云 BI(Business Intelligence,BI)提供从数据源接入、数据建模到数据可视化分析全流程的BI能力,帮助经营者快速获取决策数据依据。系统采用敏捷自助式设计,使用者仅需通过简单拖拽即可完成原本复杂的报表开发过程,并支持报表的分享、推送等企业协作场景。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档