利用矩阵来变换图片

 

          在上一个主题中,学习了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,一切都好了,运行程序吧。下面是两张效果图:

                              

      刚开始是左边的图片,然后设定好矩阵的值,点击改变是右边的图片,点击恢复后又变为左边的图片。

      经过上面的实际演练,不知道你有没有掌握矩阵变换的知识呢?你可以试着采用第二种矩阵设置的方式,试一试,这样子能更好的检验你的学习效果。我就不尝试了。在下一篇文章中,将会学习利用画笔风格来实现图片效果。赶快和我一起学习吧!另外,如果继续学习,请妥善保存好本篇代码,因为后面的文章是在这个代码上进行再书写的。

转载于:https://www.cnblogs.com/fuly550871915/p/4886353.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值