在上一个主题中,学习了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,一切都好了,运行程序吧。下面是两张效果图:
刚开始是左边的图片,然后设定好矩阵的值,点击改变是右边的图片,点击恢复后又变为左边的图片。
经过上面的实际演练,不知道你有没有掌握矩阵变换的知识呢?你可以试着采用第二种矩阵设置的方式,试一试,这样子能更好的检验你的学习效果。我就不尝试了。在下一篇文章中,将会学习利用画笔风格来实现图片效果。赶快和我一起学习吧!另外,如果继续学习,请妥善保存好本篇代码,因为后面的文章是在这个代码上进行再书写的。