图形矩阵变换(2D篇)

记得看一本书时上面有这样一句话,知识往往不是一个孤岛,而更像漂泊在海上的群岛,当踏上一块岛屿的时候才发现自己需要了解的东西还有太多。然而这些孤岛之间没有任何的桥梁。当我们要远行的时候就要自己造那样一叶孤舟。独自一人在海上漂泊。Opengl中对矩阵的操作已进行了非常棒的封装,但是在高级特性中(比如剔除技术、绘制阴影等等)都发挥了相当大的作用。

       本文有一部分是线性代数的知识,所幸我们涉及到的只是简单的一些线性代数知识,更多的是一些函数和几何的知识。

一、概述。

       若用一个行向量[ x1  x2 …  xn ]表示n维空间中一个点坐标,那么n维空间中m个点坐标就可以表示为一个向量集合:

       如果这些点代表一个空间图形的顶点,也就是说,我们可以用矩阵来描述(表示)空间中的图形。

       上面所诉可能有点抽象,我们来看下面一个例子。左图描述了一个二维坐标系里绘制一个三角形,右图描述了通过矩阵来表示这个三角形。(这回有点感觉了吧)。

       对于二维空间我们可以通过以下的方式来表示一个二维空间的图形。

二、图形变换

       一个图形的变换包括平移、旋转、缩放、投影等。其实质为改变图形的各个顶点的坐标。

       所以我们可以通过对矩阵的运算来实现坐标的变换。下面给出一般形式:

       我们后面的讨论都是基于这样一个模型。下面为更为直观的表示:

       我们假设二维平面的一个点为[x,y],对其矩阵变换:

       因此我们得到了变换的一般形式:

公式1

       这个公式意味着我们可以通过调整转换矩阵里a、b、c、d对每一个坐标点进行平移、旋转、缩放、投影等。

三、比例变换

       有了公式1,我们就可以推算出比例变换、旋转等的计算方法。我们知道比例变换

       我们来看下面一个例子,将p点由(2,1)变换到(4,3),这种变换我们可以通过比例变换或平移变换来实现,这节我们只探讨比例变换,我们知道对于P点x坐标变换的比例因子为2,y坐标变换的比例因子为3。

       由公式1我们可以知道a = 2,c = 0,b = 0, d = 3;所以很容易的我们得到了变换矩阵:

       当然上面讨论的为单个点的状况,而往往我们碰到的是多个点,其实学习更重要的是一些原理性的东西,理解了原理性的东西再实践学习的效果会很快的凸显出来。

       下面为一个缩放的例子:

       △ABC中A(0,0)、B(1,2)、C(2、1)我们将三角形每个坐标放大2倍。

       当然我们要考虑到以下一种情况,变换后图形确实是放大了一倍(当然不是指面积(.^_^.)),但是图形也跟随着偏移了,所以也许我们坐标系建立为可以显示的区域为(-2,2)到(2,-2)但是对图形做了变换后图形却不见了,如果不了解的话又是可能浪费半个小时研究.......

四、对称变换

       对称变换包括3类:

               ·对坐标轴对称变换

               ·对直线对称变换

               ·对坐标原点对称变换

       由前面学到的知识其实不难推测到它的各种变换矩阵,对坐标轴的变换,这里就不再给出详细的解释,只做记录性的工作。

       对x轴变换:

       对y轴变换:

       对直线的变换相对来说往往是多种变换相结合的,这里不再讨论。

       对坐标原点对称变换:

五、错切变换

       错切变换是使图形产生一个扭变。分为x和y方向的错切变换。我们可以通过下面的一幅图片更直观的了解。

       在x方向上的错切变换:

       我们称c为错切系数,cy为延x方向上的偏移量。

       在y方向上的错切变换:

       我们称b为错切系数,bx为延y方向上的偏移量。

六、旋转变换

       二维图形的旋转,一般是指图形绕原点坐标的旋转。

           ·逆时针方向旋转时角度θ取正值;

           ·顺时针方向旋转时角度θ取负值。

       变换矩阵为:

       看起来似乎是云里雾里的,相对于结论来说我还是更喜欢推导一下。如下图

七、平移变换

       我们知道平移的一般公式为x1 = x0 + l;y1 = y0 + m,这里就存在一个问题就是怎样使用        

       我们c=b=0,α=1,a=d=1则有:

       向量[x y ] 改写为[x y 1],就可进行平移变换了。

       在此将 [x  y 1] 称为平面坐标点[x  y]的齐次坐标表示法。一般情况下:用n+1维向量表示n维向量,第n+1个分量取为常数(齐次项)的表示方法为齐次坐标表示法。

       标准化齐次坐标表示法:若齐次项为1,则为标准化齐次坐标表示法。

       但是实际上我们实际上在二维空间中都是用下图所示的转换矩阵来对图片进行操作的。

       关于透视变换这里不讲,以后如果有相关内容的话会补上。

八、例子

       这里我们提供一个Android的小例子,其中主要做的是旋转变换。

       在这里你可以下载到整个项目的源码Demo_Matrix.zip

[java]  view plain copy
  1. package com.example.demo_matrix;  
  2.         
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5.         
  6. import android.content.Context;  
  7. import android.graphics.Bitmap;  
  8. import android.graphics.BitmapFactory;  
  9. import android.graphics.Canvas;  
  10. import android.graphics.Matrix;  
  11. import android.graphics.Paint;  
  12. import android.view.View;  
  13.         
  14. public class MainView extends View  
  15. {  
  16.     // 旋转-45度  
  17.     float angle = -(float) Math.PI / 4;  
  18.     // 变换矩阵  
  19.     float[] matrixPoint =  
  20.         { (float) Math.cos(angle), (float) Math.sin(angle), 0,  
  21.                 -(float) Math.sin(angle), (float) Math.cos(angle), 0001 };  
  22.     Matrix matrix = new Matrix();  
  23.     Matrix saveMatrix = new Matrix();  
  24.     Bitmap toDraw;  
  25.     Paint paint = new Paint();  
  26.         
  27.     public MainView(Context context)  
  28.     {  
  29.         super(context);  
  30.         
  31.         toDraw = getBitmap(R.drawable.ic_launcher);  
  32.         
  33.         paint.setColor(0xFFFF0000);  
  34.         paint.setTextSize(14);  
  35.     }  
  36.         
  37.     @Override  
  38.     protected void onDraw(Canvas canvas)  
  39.     {  
  40.         int dy = 25;  
  41.         // 绘制原始的图片  
  42.         canvas.drawText("原始图片"10, dy, paint);  
  43.         dy += 20;  
  44.         canvas.drawBitmap(toDraw, 10, dy, null);  
  45.         
  46.         dy += 56;  
  47.         // 绘制一个旋转45度的图片,从原点开始旋转的  
  48.         // •逆时针方向旋转时角度θ取正值;  
  49.         // •顺时针方向旋转时角度θ取负值。  
  50.         matrix.setValues(matrixPoint);  
  51.         canvas.save();  
  52.         canvas.translate(dy, dy);  
  53.         canvas.drawBitmap(toDraw, matrix, null);  
  54.         canvas.restore();  
  55.         
  56.         super.onDraw(canvas);  
  57.     }  
  58.         
  59.     Bitmap getBitmap(int id)  
  60.     {  
  61.         InputStream is = this.getResources().openRawResource(id);  
  62.         Bitmap bitmapTmp;  
  63.         try  
  64.             {  
  65.                 bitmapTmp = BitmapFactory.decodeStream(is);  
  66.             }  
  67.         finally  
  68.             {  
  69.                 try  
  70.                     {  
  71.                         is.close();  
  72.                     }  
  73.                 catch (IOException e)  
  74.                     {  
  75.                         e.printStackTrace();  
  76.                     }  
  77.             }  
  78.         return bitmapTmp;  
  79.     }  
  80. }  

你可能感兴趣的:(图形矩阵变换(2D篇))