利用矩陣來變換圖片


 

          在上一個主題中,學習了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,一切都好了,運行程序吧。下面是兩張效果圖:

                              

      剛開始是左邊的圖片,然后設定好矩陣的值,點擊改變是右邊的圖片,點擊恢復后又變為左邊的圖片。

      經過上面的實際演練,不知道你有沒有掌握矩陣變換的知識呢?你可以試着采用第二種矩陣設置的方式,試一試,這樣子能更好的檢驗你的學習效果。我就不嘗試了。在下一篇文章中,將會學習利用畫筆風格來實現圖片效果。趕快和我一起學習吧!另外,如果繼續學習,請妥善保存好本篇代碼,因為后面的文章是在這個代碼上進行再書寫的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM