2D平面中关于矩阵(Matrix)跟图形变换的讲解

在二维平面上,常用的有以下三种基本的图形变化:

1)Translation

2)Scale

3)Rotation

在Android的开发中,我们也经常会用到这样的一些图形变换,尤其是我们在写自定义View时,更是会经常利用到Matrix来实现一些效果,比如平移,旋转,缩放及切变等,相信很多朋友应该很想知道,矩阵实现这种变换的原理是什么,什么是矩阵的左乘右乘,它们在实现效果上有什么差别吗?今天就让我们一起来看一下吧。

都是由点组成的

平面上的元素,就是点,线,面,而线就是由一个个点组成的,而是由一条条线组成的,所以归根结底,平面上所有的图形都是由点组成的。而在我们坐标系中,一个点就是由一对x,y值组成的,p = {x, y}。而在平面上,过两点间的,我们可以画一条直线,所以我们一般通过 p1, p2可定义一条直线,e = {p1, p2},而图形呢,则是由众多的点和点之间的的线段组成的。所以,其实平面上的图形变换,就是点坐标位置的变换。
在平面上,一个点,可以通过一个向量或者矩阵来表示:

image.png

而下面这条红色的直线则是由一组组的点组成的,起始点是(120,0),终点是(240,120)。

image.png


Translation(平移)

如果我们现在要平移这条直线,向右120(tx),向下120(ty),那么新的点会是怎么样呢?很显然,起始点就会是(240,120),而终点就会是(360,240),效果如下:

image.png


绿色的线就是平移后的线了,可以看出每一个新的点的值是

image.png

这样的一个变换translation也可以用一对值来表示,t = {tx, ty},其中tx是在x坐标上的偏移量,而ty是在y坐标上的偏移量。移动点 p 到 p',我们只要加上这个偏移就行,如果用矩阵或者向量来表示就是:

image.png


(可能会有朋友觉得奇怪,怎么是加呢,Android里面矩阵不都是乘吗?这是什么原因呢?)

Scale(缩放)

那如果我们对这条直线进行放大呢,比如放大2倍呢,一般来讲,我们缩放,是指所有维度的缩放,当然在这里就只有x坐标跟y坐标,当然也可以只针对一个维度,但是就会变形了哦。我们先看一下放大到2倍的效果和只放大列的效果吧。

image.png


很显然,两边都放大的话,起始点由(120,0)变成(240,0),终点由(240,120)变成(480,240)。而如果只放大列的话,起始点的坐标是不变的。而且我们可以看到,放大的时候,线也跟着向右平移了一个单位,为什么会这样呢?这是因为缩放是基于原点(0,0)的,在Android中,也就是屏幕的左上角,但缩放的位数大于1的时候,就会远离原点,而相反,当缩放的位数小于1时,则会趋近原点。
缩放的变换是由下面的矩阵来表示的:

image.png

那么缩放后的直线的点就是:

image.png


各位朋友,可以想一下,这样直接Scale的话,这个图形可是会平移的哦,如果不想要平移,应该怎么办?

Rotation(旋转)

我们再看一下下图,这条直线顺时针旋转了45度,也就是往逆时针方向旋转了 - 45 度,

image.png


那么新的点是怎么算出来的呢?
逆时针(注意这里)旋转的矩阵表示是:

image.png

同样的,旋转后的点就是根据下面的矩阵相乘而得出来的结果:

image.png


我们可以将我们的点代进去求解,可得新的起始点P0'为(84.85,84.85),而新的结束点为:(84.85,254.56),可看出,刚好是上面绿色线所在的地方。

Combine Transformation (组合变换)

对于Scale 和 Rotation 来说,它们都是基于原点(0,0)的变换,那如果我们要让它基于某个点缩放或者旋转,就比如绕着起始点转呢,而这也经常是我们想要的一种效果。这个点就是所谓的旋转,而解决办法其实就是将图形先平移到原点,再进行缩放或者旋转的变化,然后再移回来,就可以了。
假设这三种变换的矩阵表示如下:

image.png

那么它应该实施的变换就如下:先平移 T 到原点,再基于原点进行缩放(或者旋转),然后再平移回去,

image.png

其实这一步,我们可以在Canvas的代码中看到的,如下:

    /**
     * Preconcat the current matrix with the specified scale.
     *
     * @param sx The amount to scale in X
     * @param sy The amount to scale in Y
     * @param px The x-coord for the pivot point (unchanged by the scale)
     * @param py The y-coord for the pivot point (unchanged by the scale)
     */
    public final void scale(float sx, float sy, float px, float py) {
        translate(px, py);
        scale(sx, sy);
        translate(-px, -py);
    }

上面代码中的轴点的实现,其实就是对于平移的来回操作,至于为什么是translate(px,py)在前,而translate(-px,py)在后呢,这涉及到矩阵左乘和右乘的计算,后面我们会谈到的。


Homogeneous Coordinates(齐次坐标)

在上面的矩阵中,我们可以看到平移的矩阵是相加的,而旋转跟缩放的矩阵都是相乘的,这样计算起来多麻烦呀!于是为了方便计算,大家都统一用一种方式来进行计算,聪明的计算机图形科学家,它们就设计出这样一种坐标系,叫homogeneous coordinates,而它的目的只是为了更加方便地去用矩阵来计算图形的变换,没有其他。

那什么是齐次坐标呢?

其实就是在原来2D的维度,再加上一个新的维度,多出来的维度的值永远是1,比如点的矩阵就变成:

image.png

当我们在Canvas上用Scale的时候,其实就是乘上S矩阵,当我们用Rotate的时候,其实就是乘上R矩阵,大家明白没有?
关于矩阵左乘右乘,前乘后乘的关系,如果有困惑的朋友,可以看一下下面这篇文章:



————————————————

版权声明:本文为CSDN博主「linmiansheng」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/linmiansheng/article/details/18801947



本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年3月    »
123
45678910
11121314151617
18192021222324
25262728293031
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864