在上一個主題中,學習了android圖像的顏色處理。沒讀過的朋友可以點擊一下鏈接學習:
http://i.cnblogs.com/EditPosts.aspx?catid=744685
那么在從這一篇文章開始,繼續學習android的圖像處理知識之圖像的變換。比如說圖像的縮放,拉伸,平移,旋轉,以及高級點的圖像的漸變和最有用的像素點變換方法。在這里進行一一的學習。這些知識也是我在學習后,總結在這里的,畢竟知識是積累起來的,每天積累一點學習一點,就會進步的很快。
好了,廢話不多說。在這篇文章中,將學習最基本的圖像變換知識,即圖像的縮放,拉伸等。而其中的原理就是利用矩陣來實現這些效果。我們還是按照老規矩,先學習一下基礎的知識,然后再進行實戰的代碼編寫。
一、必須要知道的基礎知識
下面有一張圖片,完美的解釋了矩陣變換的知識點。如下:
如上圖所示,矩陣A就是我們需要設置的矩陣,而C代表着圖像上每一個像素點的位置(X為橫坐標,Y為縱坐標),R就是A*C得來的新的坐標位置。這樣子通過這樣子的矩陣運算,我們就把一張圖片的每一個像素點的坐標都做了改變,因此就會呈現出不同的效果。而這就是矩陣變換實現縮放,拉伸等效果的基本原理。我們還需要知道的是,矩陣A的某些元素是會控制一些特殊的效果的,下圖就是一個很好的總結:
那么怎么根據矩陣畫出效果呢?對應於android中的API,其實就是利用了Canvas的一個方法,如下:
//畫出根據矩陣的變換后的圖像 canvas.drawBitmap(bmp, matrix, null);
其中bmp對應於一個Bitmap圖片,而matrix是一個Matrix對象。那么下面的問題就是我們要怎么來設置這個矩陣了,也就是A。設定A有兩種方式。
第一種,直接賦值
很容易知道矩陣A其實是3*3的矩陣,有9個數值。因此,我們只需要給Matrix的setValues方法傳入一個長度為9的數值數組即可。
第二種,利用縮放,旋轉等封裝好的api
如果你覺得第一種方式太麻煩,不利於控制,沒關系。對於常見的縮放,旋轉等效果,android已經給你封裝好了API,只要你調用相關方法,就可以自動設置好矩陣A。方法很多,舉出一些如下:
Matrix matrix=new Matrix(); matrix.setTranslate(100, 50);//水平方向平移量為100,垂直方向平移量為50 matrix.setRotate(30, 20, 30);//旋轉30度,其中旋轉圍繞點(20,30)進行,默認為(0,0) matrix.setScale(1, 2);//縮放,水平方向放大1倍,垂直方向放大2倍 matrix.setScale(1, 2,20,30);//依然是縮放,但是以點(20,30)為基准進行縮放 matrix.setSkew(5,10);//將圖片水平方向傾斜3,垂直方向傾斜10 matrix.setSkew(5,10,24,24);//同樣的道理,為傾斜找個基准點(24,24) canvas.drawBitmap(bitmap,matrix, paint);
好了,基礎的知識你差不多都知道了。下面我們趕緊編寫一些實際的代碼來試試吧。
二、實戰
首先新建android項目“圖形變換”。編寫activity_main.xml代碼,如下:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 android:gravity="center"> 7 8 <TextView 9 android:layout_width="match_parent" 10 android:layout_height="wrap_content" 11 android:textSize="25sp" 12 android:gravity="center" 13 android:background="#cc00ff" 14 android:text="圖像圖形變換" /> 15 <Button 16 android:id="@+id/btn1" 17 android:layout_width="match_parent" 18 android:layout_height="wrap_content" 19 android:onClick="btnMatrix" 20 android:textSize="25sp" 21 android:text="矩陣變換"/> 22 <Button 23 android:id="@+id/btn2" 24 android:layout_width="match_parent" 25 android:layout_height="wrap_content" 26 android:onClick="btnXFermode" 27 android:textSize="25sp" 28 android:text="畫筆風格"/> 29 <Button 30 android:id="@+id/btn3" 31 android:layout_width="match_parent" 32 android:layout_height="wrap_content" 33 android:onClick="btnShader" 34 android:textSize="25sp" 35 android:text="圖片渲染實驗"/> 36 <Button 37 android:id="@+id/btn4" 38 android:layout_width="match_parent" 39 android:layout_height="wrap_content" 40 android:onClick="btnLShader" 41 android:textSize="25sp" 42 android:text="線性渲染實驗"/> 43 <Button 44 android:id="@+id/btn5" 45 android:layout_width="match_parent" 46 android:layout_height="wrap_content" 47 android:onClick="btnMesh" 48 android:textSize="25sp" 49 android:text="像素塊實驗"/> 50 51 52 </LinearLayout>
怎么那么多按鈕啊。嘿嘿,這說明我們還有好多知識要學習要實驗呢,下面的一系列文章會一一實現這些按鈕功能的。不用着急,我們這篇文章先來實現第一個按鈕“矩陣變換”的效果,就是我們幾天所學的內容。
然后需要一個自定義的view來畫出原來的圖片和經過矩陣變換后的圖片,這樣有比較才有感覺。新建類MyMatrixView繼承自View,代碼如下:
1 package com.fuly.image; 2 3 import android.content.Context; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.graphics.Canvas; 7 import android.graphics.Matrix; 8 import android.util.AttributeSet; 9 import android.view.View; 10 11 public class MyMatrixView extends View{ 12 13 private Bitmap bmp; 14 private Matrix matrix;//顏色矩陣 15 16 public MyMatrixView(Context context) { 17 super(context); 18 initView(); 19 } 20 public MyMatrixView(Context context, AttributeSet attrs) { 21 super(context, attrs); 22 initView(); 23 } 24 public MyMatrixView(Context context, AttributeSet attrs, int defStyleAttr) { 25 super(context, attrs, defStyleAttr); 26 initView(); 27 } 28 29 private void initView(){//初始化方法 30 bmp = BitmapFactory.decodeResource(getResources(), R.drawable.hudie2); 31 setMatrix(new Matrix());//剛開始給個空矩陣即可 32 } 33 34 /** 35 * 該方法用來設置顏色矩陣 36 * @param matrix 顏色矩陣 37 */ 38 public void setMatrix(Matrix matrix){ 39 this.matrix = matrix; 40 } 41 42 43 protected void onDraw(Canvas canvas) { 44 super.onDraw(canvas); 45 //畫出原來的圖像 46 canvas.drawBitmap(bmp, 0, 0, null); 47 //畫出根據矩陣的變換后的圖像 48 canvas.drawBitmap(bmp, matrix, null); 49 } 50 51 }
在代碼中,我們首先將兩張相同的圖片畫在了同一個地方。這樣子,當其中的一張圖片旋轉或者拉伸,就很好的得到對比效果了。所用的圖片資源,讀者可自行替換為自己的一張小圖片。下面就是新建imagematrix.xml文件,將這個自定義的view放進去。代碼如下:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" 6 android:gravity="center"> 7 8 <LinearLayout 9 android:layout_width="match_parent" 10 android:layout_height="0dp" 11 android:layout_weight="2"> 12 <com.fuly.image.MyMatrixView 13 android:id="@+id/myview" 14 android:layout_width="wrap_content" 15 android:layout_height="wrap_content"/> 16 </LinearLayout> 17 <LinearLayout 18 android:layout_width="match_parent" 19 android:layout_height="0dp" 20 android:layout_weight="3"> 21 <GridLayout 22 android:id="@+id/mGrid" 23 android:layout_width="match_parent" 24 android:layout_height="match_parent" 25 android:columnCount="3" 26 android:rowCount="3"></GridLayout> 27 </LinearLayout> 28 <LinearLayout 29 android:layout_width="match_parent" 30 android:layout_height="wrap_content" 31 > 32 <Button 33 android:id="@+id/btnChange" 34 android:layout_width="0dp" 35 android:layout_weight="1" 36 android:layout_height="wrap_content" 37 android:onClick="btnChange" 38 android:text="改變"/> 39 <Button 40 android:id="@+id/btnReset" 41 android:layout_width="0dp" 42 android:layout_weight="1" 43 android:onClick="btnReset" 44 android:layout_height="wrap_content" 45 android:text="恢復"/> 46 </LinearLayout> 47 48 </LinearLayout>
在這里,我們仍舊准備了兩個按鈕,用來改變和還原,而GridLayout就是用來設置矩陣A的。好了,下面就開始新建MatrixActivity,用於將這個布局顯示出來。注意不要忘記給這個活動注冊哈。代碼很簡單,不用多解釋的,注釋也很詳細。如下:
1 package com.fuly.image; 2 3 import android.app.Activity; 4 import android.graphics.Matrix; 5 import android.os.Bundle; 6 import android.view.View; 7 import android.widget.EditText; 8 import android.widget.GridLayout; 9 10 public class MatrixActivity extends Activity{ 11 12 private MyMatrixView mv; 13 private GridLayout mGrid; 14 private int mEtWidth; 15 private int mEtHeight; 16 private Matrix matrix = new Matrix(); 17 private float[] mMtatrix = new float[9]; 18 19 private EditText[] Ets = new EditText[9]; 20 21 protected void onCreate(Bundle savedInstanceState) { 22 super.onCreate(savedInstanceState); 23 setContentView(R.layout.imagematrix); 24 25 mGrid = (GridLayout) findViewById(R.id.mGrid); 26 mv = (MyMatrixView) findViewById(R.id.myview); 27 //這個方法在mGrid被畫出來后調用 28 mGrid.post(new Runnable(){ 29 30 public void run() { 31 mEtWidth = mGrid.getWidth()/3; 32 mEtHeight = mGrid.getHeight()/3; 33 initGrid(); 34 initMatrix(); 35 } 36 37 }); 38 39 } 40 /* 41 * 初始化GridLayout 42 */ 43 private void initGrid(){ 44 for(int i=0;i<9;i++){ 45 EditText et = new EditText(this); 46 Ets[i] = et; 47 mGrid.addView(et,mEtWidth,mEtHeight); 48 } 49 } 50 /* 51 * 該法初始化矩陣 52 */ 53 private void initMatrix(){ 54 for(int i=0;i<9;i++){ 55 if(i%4 == 0){ 56 Ets[i].setText(String.valueOf(1)); 57 }else{ 58 Ets[i].setText(String.valueOf(0)); 59 } 60 } 61 } 62 /* 63 * 該方法獲取矩陣 64 */ 65 private void getMatrix(){ 66 for(int i=0;i<9;i++){ 67 mMtatrix[i]= Float.valueOf(Ets[i].getText().toString()); 68 } 69 matrix.setValues(mMtatrix); 70 } 71 //下面是兩個按鈕事件 72 public void btnChange(View v){ 73 getMatrix(); 74 mv.setMatrix(matrix); 75 mv.invalidate(); 76 } 77 78 public void btnReset(View v){ 79 initMatrix(); 80 getMatrix(); 81 mv.setMatrix(matrix); 82 mv.invalidate(); 83 } 84 }
東西都准備齊全了,下面就在MainActivity里面添加按鈕事件,跳轉到我們這個活動中來吧。如下:
1 package com.fuly.image; 2 3 import android.os.Bundle; 4 import android.view.View; 5 import android.app.Activity; 6 import android.content.Intent; 7 8 9 public class MainActivity extends Activity { 10 11 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.activity_main); 15 } 16 17 //下面是按鈕事件 18 public void btnMatrix(View v){ 19 Intent intent = new Intent(this,MatrixActivity.class); 20 startActivity(intent); 21 } 22 23 }
OK,一切都好了,運行程序吧。下面是兩張效果圖:
剛開始是左邊的圖片,然后設定好矩陣的值,點擊改變是右邊的圖片,點擊恢復后又變為左邊的圖片。
經過上面的實際演練,不知道你有沒有掌握矩陣變換的知識呢?你可以試着采用第二種矩陣設置的方式,試一試,這樣子能更好的檢驗你的學習效果。我就不嘗試了。在下一篇文章中,將會學習利用畫筆風格來實現圖片效果。趕快和我一起學習吧!另外,如果繼續學習,請妥善保存好本篇代碼,因為后面的文章是在這個代碼上進行再書寫的。