Android Matrix理論與應用詳解

Matrix學習——基礎知識

以前在線性代數中學習了矩陣,對矩陣的基本運算有一些瞭解,前段時間在使用GDI+的時候再次學習如何使用矩陣來變化圖像,看了之後在這裏總結說明。

首先大家看看下面這個3 x 3的矩陣,這個矩陣被分割成4部分。爲什麼分割成4部分,在後面詳細說明。

clip_image001

首先給大家舉個簡單的例子:現設點P0(x0, y0)進行平移後,移到P(x,y),其中x方向的平移量爲△x,y方向的平移量爲△y,那麼,點P(x,y)的座標爲:

x = x0  + △x
y = y0  + △y

採用矩陣表達上述如下:
clip_image002

上述也類似與圖像的平移,通過上述矩陣我們發現,只需要修改矩陣右上角的2個元素就可以了。

我們回頭看上述矩陣的劃分:
clip_image003

爲了驗證上面的功能劃分,我們舉個具體的例子:現設點P0(x0 ,y0)進行平移後,移到P(x,y),其中x放大a倍,y放大b倍,

矩陣就是:clip_image004,按照類似前面“平移”的方法就驗證。

圖像的旋轉稍微複雜:現設點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θ

於是我們得到矩陣:clip_image005

如果圖像圍繞着某個點(a ,b)旋轉呢?則先要將座標平移到該點,再進行旋轉,然後將旋轉後的圖像平移回到原來的座標原點,在後面的篇幅中我們將詳細介紹。

  Matrix學習——如何使用Matrix

上一篇幅 Matrix學習——基礎知識,從高等數學方面給大家介紹了Matrix,本篇幅我們就結合Android 中的android.graphics.Matrix來具體說明,還記得我們前面說的圖像旋轉的矩陣:

clip_image005[1]

從最簡單的旋轉90度的是:

clip_image006

在android.graphics.Matrix中有對應旋轉的函數:
Matrix matrix = new Matrix();
matrix.setRotate(90);
Test.Log(MAXTRIX_TAG,”setRotate(90):%s” , matrix.toString());

clip_image007

查看運行後的矩陣的值(通過Log輸出):

clip_image008

與上面的公式基本完全一樣(android.graphics.Matrix採用的是浮點數,而我們採用的整數)。

有了上面的例子,相信大家就可以親自嘗試了。通過上面的例子我們也發現,我們也可以直接來初始化矩陣,比如說要旋轉30度:

clip_image010

前面給大家介紹了這麼多,下面我們開始介紹圖像的鏡像,分爲2種:水平鏡像、垂直鏡像。先介紹如何實現垂直鏡像,什麼是垂直鏡像就不詳細說明。圖像的垂直鏡像變化也可以用矩陣變化的表示,設點P0(x0 ,y0 )進行鏡像後的對應點爲P(x ,y ),圖像的高度爲fHeight,寬度爲fWidth,原圖像中的P0(x0 ,y0 )經過垂直鏡像後的座標變爲(x0 ,fHeight- y0);
x = x0
y = fHeight – y0
推導出相應的矩陣是:

clip_image011

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);

按照上述方法運行後的結果:
clip_image012

至於水平鏡像採用類似的方法,大家可以自己去試試吧。

實際上,使用下面的方式也可以實現垂直鏡像:
Matrix matrix = new Matrix();
matrix.setScale (1.0,-1.0);
matrix.postTraslate(0, fHeight);

這就是我們將在後面的篇幅中詳細說明。

  Matrix學習——圖像的複合變化

Matrix學習——基礎知識篇幅中,我們留下一個話題:如果圖像圍繞着某個點P(a,b)旋轉,則先要將座標系平移到該點,再進行旋轉,然後將旋轉後的圖像平移回到原來的座標原點。

我們需要3步:

1. 平移——將座標系平移到點P(a,b);

2. 旋轉——以原點爲中心旋轉圖像;

3. 平移——將旋轉後的圖像平移回到原來的座標原點;

相比較前面說的圖像的幾何變化(基本的圖像幾何變化),這裏需要平移——旋轉——平移,這種需要多種圖像的幾何變化就叫做圖像的複合變化。

設對給定的圖像依次進行了基本變化F1F2F3…..Fn,它們的變化矩陣分別爲T1T2T3…..Tn,圖像複合變化的矩陣T可以表示爲:T = TnTn-1…T1

按照上面的原則,圍繞着某個點(a,b)旋轉θ的變化矩陣序列是:

clip_image013

按照上面的公式,我們列舉一個簡單的例子:圍繞(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);
旋轉後的圖像如下:

clip_image014

Android爲我們提供了更加簡單的方法,如下:
Matrix matrix = new Matrix();
matrix.setRotate(30,100,100);
矩陣運行後的實際結果:
clip_image015
與我們前面通過公式獲取得到的矩陣完全一樣。

在這裏我們提供另外一種方法,也可以達到同樣的效果:
float a = 100.0F,b = 100.0F;
matrix = new Matrix();
matrix.setTranslate(a,b);
matrix.preRotate(30);
matrix.preTranslate(-a,-b);
將在後面的篇幅中爲大家詳細解析

通過類似的方法,我們還可以得到:相對點P(ab)的比例[sx,sy]變化矩陣

clip_image016

Matrix學習——Preconcats or Postconcats?

從最基本的高等數學開始,Matrix的基本操作包括:+、*。Matrix的乘法不滿足交換律,也就是說A*B ≠B*A。

還有2種常見的矩陣:

clip_image017

有了上面的基礎,下面我們開始進入主題。由於矩陣不滿足交換律,所以用矩陣B乘以矩陣A,需要考慮是左乘(B*A),還是右乘(A*B)。在Android的android.graphics.Matrix中爲我們提供了類似的方法,也就是我們本篇幅要說明的Preconcats matrix 與 Postconcats  matrix。下面我們還是通過具體的例子還說明:

clip_image018

通過輸出的信息,我們分析其運行過程如下:

clip_image019

看了上面的輸出信息。我們得出結論:Preconcats matrix相當於右乘矩陣,Postconcats  matrix相當於左乘矩陣

上一篇幅中,我們說到:

clip_image020

其暈死過程的詳細分析就不在這裏多說了。

  Matrix學習——錯切變換

什麼是圖像的錯切變換(Shear transformation)?我們還是直接看圖片錯切變換後是的效果:

clip_image021

clip_image022

對圖像的錯切變換做個總結:

clip_image023

x = x0 + b*y0;

y = d*x0 + y0;

clip_image024

這裏再次給大家介紹一個需要注意的地方:

clip_image025

通過以上,我們發現MatrixsetXXXX()函數,在調用時調用了一次reset(),這個在複合變換時需要注意。

  Matrix學習——對稱變換(反射)

什麼是對稱變換?具體的理論就不詳細說明了,圖像的鏡像就是對稱變換中的一種。

clip_image026

利用上面的總結做個具體的例子,產生與直線y= – x對稱的反射圖形,代碼片段如下:

clip_image027

當前矩陣輸出是:

clip_image028

圖像變換的效果如下:

clip_image029


  附:三角函數公式

兩角和公式

sin(a+b)=sinacosb+cosasinb

sin(a-b)=sinacosb-sinbcosa 

cos(a+b)=cosacosb-sinasinb

cos(a-b)=cosacosb+sinasinb

tan(a+b)=(tana+tanb)/(1-tanatanb)

tan(a-b)=(tana-tanb)/(1+tanatanb)

cot(a+b)=(cotacotb-1)/(cotb+cota) 

cot(a-b)=(cotacotb+1)/(cotb-cota)

倍角公式

tan2a=2tana/[1-(tana)^2]

cos2a=(cosa)^2-(sina)^2=2(cosa)^2 -1=1-2(sina)^2

sin2a=2sina*cosa

半角公式

sin(a/2)=√((1-cosa)/2) sin(a/2)=-√((1-cosa)/2)

cos(a/2)=√((1+cosa)/2) cos(a/2)=-√((1+cosa)/2)

tan(a/2)=√((1-cosa)/((1+cosa)) tan(a/2)=-√((1-cosa)/((1+cosa))

cot(a/2)=√((1+cosa)/((1-cosa)) cot(a/2)=-√((1+cosa)/((1-cosa)) 

tan(a/2)=(1-cosa)/sina=sina/(1+cosa)

和差化積

2sinacosb=sin(a+b)+sin(a-b)

2cosasinb=sin(a+b)-sin(a-b) )

2cosacosb=cos(a+b)-sin(a-b)

-2sinasinb=cos(a+b)-cos(a-b)

sina+sinb=2sin((a+b)/2)cos((a-b)/2

cosa+cosb=2cos((a+b)/2)sin((a-b)/2)

tana+tanb=sin(a+b)/cosacosb

積化和差公式

sin(a)sin(b)=-1/2*[cos(a+b)-cos(a-b)]

cos(a)cos(b)=1/2*[cos(a+b)+cos(a-b)]

sin(a)cos(b)=1/2*[sin(a+b)+sin(a-b)]

誘導公式

sin(-a)=-sin(a)

cos(-a)=cos(a)

sin(pi/2-a)=cos(a)

cos(pi/2-a)=sin(a)

sin(pi/2+a)=cos(a)

cos(pi/2+a)=-sin(a)

sin(pi-a)=sin(a)

cos(pi-a)=-cos(a)

sin(pi+a)=-sin(a)

cos(pi+a)=-cos(a)

tga=tana=sina/cosa

萬能公式

sin(a)= (2tan(a/2))/(1+tan^2(a/2))

cos(a)= (1-tan^2(a/2))/(1+tan^2(a/2))

tan(a)= (2tan(a/2))/(1-tan^2(a/2))

其它公式

a*sin(a)+b*cos(a)=sqrt(a^2+b^2)sin(a+c) [其中,tan(c)=b/a]

a*sin(a)-b*cos(a)=sqrt(a^2+b^2)cos(a-c) [其中,tan(c)=a/b]

1+sin(a)=(sin(a/2)+cos(a/2))^2

1-sin(a)=(sin(a/2)-cos(a/2))^2

其他非重點三角函數

csc(a)=1/sin(a)

sec(a)=1/cos(a)

雙曲函數

sinh(a)=(e^a-e^(-a))/2

cosh(a)=(e^a+e^(-a))/2

tgh(a)=sinh(a)/cosh(a)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章