【Android】画图之Matrix

来源:互联网 发布:nginx实现session共享 编辑:程序博客网 时间:2024/05/17 08:36

Android画图之Matrix  


Matrix的操作,总共分为translate(平移)rotate(旋转)scale(缩放)skew(倾斜)四种,每一种变换在

         AndroidAPI里都提供了set, postpre三种操作方式,除了translate,其他三种操作都可以指定中心点。
         set是直接设置Matrix的值,每次set一次,整个Matrix的数组都会变掉。

         post是后乘,当前的矩阵乘以参数给出的矩阵。可以连续多次使用post,来完成所需的整个变换。例如,要将一个图片旋

         30度,然后平移到(100,100)的地方,那么可以这样做:

复制到剪贴板  Java代码

1.    Matrix m = new Matrix();   

2.      

3.    m.postRotate(30);   

4.      

5.    m.postTranslate(100, 100);   

6.      

7.    Matrix m = new Matrix();   

8.      

9.    m.postRotate(30);   

10.  

11.m.postTranslate(100, 100);  

 

复制到剪贴板  Java代码

1.    package eoeandroid.demo;   

2.      

3.    import android.content.Context;   

4.    import android.graphics.Bitmap;   

5.    import android.graphics.Canvas;   

6.    import android.graphics.Matrix;   

7.    import android.graphics.Rect;   

8.    import android.graphics.drawable.BitmapDrawable;   

9.    import android.util.DisplayMetrics;   

10.import android.view.MotionEvent;   

11.import android.view.View;   

12.  

13.public class MyView extends View {   

14.  

15.private Bitmap mBitmap;   

16.  

17.private Matrix mMatrix = new Matrix();  

18.  

19.public MyView(Context context) {   

20.  

21.super(context);   

22.  

23.initialize();   

24.  

25.}   

26.  

27.private void initialize() {   

28.  

29.Bitmap bmp = ((BitmapDrawable)getResources().getDrawable(R.drawable.show)).getBitmap();  

30.  

31.mBitmap = bmp;   

32.  

33./*首先,将缩放为100*100。这里scale的参数是比例。有一点要注意,如果直接用100/ 

34.bmp.getWidth()的话,会得到0,因为是整型相除,所以必须其中有一个是float型的,直接用100f就好。*/  

35.  

36.mMatrix.setScale(100f/bmp.getWidth(), 100f/bmp.getHeight());  

37.  

38.//平移到(100,100)处   

39.  

40.mMatrix.postTranslate(100, 100);  

41.  

42.//倾斜x和y轴,以(100,100)为中心。   

43.  

44.mMatrix.postSkew(0.2f, 0.2f, 100, 100);  

45.  

46.}   

47.  

48.@Override    

49.protected void onDraw(Canvas canvas) {  

50.  

51.// super.onDraw(canvas); //如果界面上还有其他元素需要绘制,只需要将这句话写上就行了。   

52.  

53.canvas.drawBitmap(mBitmap, mMatrix, null);   

54.  

55.}   

56.  

57.}  

 

 

以前在线性代数中学习了矩阵,对矩阵的基本运算有一些了解,前段时间在使用GDI+的时候再次学习如何使用矩阵来变化图像,看了之后在这里总结说明。

首先大家看看下面这个3 x 3的矩阵,这个矩阵被分割成4部分。为什么分割成4部分,在后面详细说明。

首先给大家举个简单的例子:现设点P0x0 y0)进行平移后,移到Pxy),其中x方向的平移量为xy方向的平移量为y,那么,点Pxy)的坐标为:

x = x0  + x
y = y0  +
y

采用矩阵表达上述如下:

上述也类似与图像的平移,通过上述矩阵我们发现,只需要修改矩阵右上角的2个元素就可以了。

我们回头看上述矩阵的划分:

为了验证上面的功能划分,我们举个具体的例子:现设点P0x0y0)进行平移后,移到Pxy),其中x放大a倍,y放大b倍,

矩阵就是:,按照类似前面平移的方法就验证。

图像的旋转稍微复杂:现设点P0x0 y0)旋转θ角后的对有点为Px y)。通过使用向量,我们得到如下:

x0 = r  cosα
y0 = r  sinα

x = r cos(α-θ) = x0 cosθ+ y0 sinθ
y = r sia(α-θ) = -x0 sinθ+y0 cosθ

于是我们得到矩阵:

如果图像围绕着某个点(ab)旋转呢?则先要将坐标平移到该点,再进行旋转,然后将旋转后的图像平移回到原来的坐标原点,在后面的篇幅中我们将详细介绍。

 

从高等数学方面给大家介绍了Matrix,本篇幅我们就结合Android中的android.graphics.Matrix来具体说明,还记得我们前面说的图像旋转的矩阵:

从最简单的旋转90度的是:

android.graphics.Matrix中有对应旋转的函数:
Matrix matrix = new Matrix();
matrix.setRotate(90);
Test.Log(MAXTRIX_TAG,”setRotate(90):%s” , matrix.toString());

查看运行后的矩阵的值(通过Log输出):

与上面的公式基本完全一样(android.graphics.Matrix采用的是浮点数,而我们采用的整数)。

有了上面的例子,相信大家就可以亲自尝试了。通过上面的例子我们也发现,我们也可以直接来初始化矩阵,比如说要旋转30度:

前面给大家介绍了这么多,下面我们开始介绍图像的镜像,分为2种:水平镜像、垂直镜像。先介绍如何实现垂直镜像,什么是垂直镜像就不详细说明。图像的垂直镜像变化也可以用矩阵变化的表示,设点P0x0y0 )进行镜像后的对应点为Pxy ),图像的高度为fHeight,宽度为fWidth,原图像中的P0x0y0 )经过垂直镜像后的坐标变为(x0 fHeight- y0);
x = x0
y = fHeight – y0
推导出相应的矩阵是:

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

按照上述方法运行后的结果:

至于水平镜像采用类似的方法,大家可以自己去试试吧。

实际上,使用下面的方式也可以实现垂直镜像:
Matrix matrix =
new Matrix();
matrix.setScale (1.0
-1.0);
matrix.postTraslate(0, fHeight);

这就是我们将在后面的篇幅中详细说明。

什么是对称变换?具体的理论就不详细说明了,图像的镜像就是对称变换中的一种。

利用上面的总结做个具体的例子,产生与直线y= – x对称的反射图形,代码片段如下:

当前矩阵输出是:

图像变换的效果如下:

 

什么是图像的错切变换Shear transformation)?我们还是直接看图片错切变换后是的效果:

对图像的错切变换做个总结:

x = x0 + b*y0;

y = d*x0 + y0;

这里再次给大家介绍一个需要注意的地方:

通过以上,我们发现MatrixsetXXXX()函数,在调用时调用了一次reset(),这个在复合变换时需要注意。

 

Preconcats matrix or  Postconcats matrix?

从最基本的高等数学开始,Matrix的基本操作包括:+*Matrix的乘法不满足交换律,也就是说A*B ≠B*A

还有2种常见的矩阵:

有了上面的基础,下面我们开始进入主题。由于矩阵不满足交换律,所以用矩阵B乘以矩阵A,需要考虑是左乘(B*A),还是右乘(A*B)。在Androidandroid.graphics.Matrix中为我们提供了类似的方法,也就是我们本篇幅要说明的 Preconcats matrix Postconcats  matrix。下面我们还是通过具体的例子还说明:

通过输出的信息,我们分析其运行过程如下:

看了上面的输出信息。我们得出结论:Preconcats matrix相当于右乘矩阵,Postconcats  matrix相当于左乘矩阵

上一篇副中,我们说到:

其运行过程的详细分析就不在这里多说了。

 

我们留下一个话题:如果图像围绕着某个点P(ab)旋转,则先要将坐标系平移到该点,再进行旋转,然后将旋转后的图像平移回到原来的坐标原点。

我们需要3步:

1.     平移 ——将坐标系平移到点P(ab)

2.     旋转 ——以原点为中心旋转图像;

3.     平移 ——将旋转后的图像平移回到原来的坐标原点;

相比较前面说的图像的几何变化(基本的图像几何变化),这里需要平移——旋转——平移,这种需要多种图像的几何变化就叫做图像的复合变化

设对给定的图像依次进行了基本变化F1F2F3…..Fn,它们的变化矩阵分别为T1T2T3…..Tn,图像复合变化的矩阵T可以表示为:T = TnTn-1…T1

按照上面的原则,围绕着某个点(ab)旋转θ的变化矩阵序列是:

按照上面的公式,我们列举一个简单的例子:围绕(100100)旋转30(sin 30 = 0.5 cos 30 = 0.866)
floatf[]= { 0.866F,  -0.5F,63.4F,0.5F, 0.866F,-36.6F,0.0F,    0.0F,  1.0F };
matrix =
new Matrix ();
matrix.
setValues (f);
旋转后的图像如下:

Android为我们提供了更加简单的方法,如下:
Matrix matrix = newMatrix ();
matrix.
setRotate (30100100);
矩阵运行后的实际结果:

与我们前面通过公式获取得到的矩阵完全一样。

在这里我们提供另外一种方法,也可以达到同样的效果:
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]变化矩阵

 

 

 

 

 

 

 

 

 

 

 

本文将讲述如何如何在Android中使用Matrix实现图片的缩放和旋转,通过本文学习,你将学会如何通过Matrix操作图像。


代码示例:
直接上代码了,我在代码中附带了详细的解释,代码如下:

  1. package com.eoeandroid.demo.testcode;
  2.  
  3. import android.app.Activity;
  4. import android.graphics.Bitmap;
  5. import android.graphics.BitmapFactory;
  6. import android.graphics.Matrix;
  7. import android.graphics.drawable.BitmapDrawable;
  8. import android.os.Bundle;
  9. import android.view.ViewGroup.LayoutParams;
  10. import android.widget.ImageView;
  11. import android.widget.LinearLayout;
  12. import android.widget.ImageView.ScaleType;
  13.  
  14. public class bitmaptest extends Activity {
  15. public void onCreate(Bundle icicle) {
  16.         super.onCreate(icicle);
  17.         setTitle("eoeAndroid教程: 缩放和旋转图片 -by:IceskYsl");
  18.         LinearLayout linLayout = new LinearLayout(this);
  19.  
  20.         // 加载需要操作的图片,这里是eoeAndroid的logo图片
  21.         Bitmap bitmapOrg = BitmapFactory.decodeResource(getResources(),
  22.                R.drawable.eoe_android);
  23.  
  24.         //获取这个图片的宽和高
  25.         int width = bitmapOrg.getWidth();
  26.         int height = bitmapOrg.getHeight();
  27.  
  28.         //定义预转换成的图片的宽度和高度
  29.         int newWidth = 200;
  30.         int newHeight = 200;
  31.  
  32.         //计算缩放率,新尺寸除原始尺寸
  33.         float scaleWidth = ((float) newWidth) / width;
  34.         float scaleHeight = ((float) newHeight) / height;
  35.  
  36.         // 创建操作图片用的matrix对象
  37.         Matrix matrix = new Matrix();
  38.  
  39.         // 缩放图片动作
  40.         matrix.postScale(scaleWidth, scaleHeight);
  41.  
  42.         //旋转图片 动作
  43.         matrix.postRotate(45);
  44.  
  45.         // 创建新的图片
  46.         Bitmap resizedBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0,
  47.                           width, height, matrix, true);
  48.  
  49.         //将上面创建的Bitmap转换成Drawable对象,使得其可以使用在ImageView, ImageButton中
  50.         BitmapDrawable bmd = new BitmapDrawable(resizedBitmap);
  51.  
  52.         //创建一个ImageView
  53.         ImageView imageView = new ImageView(this);
  54.  
  55.         // 设置ImageView的图片为上面转换的图片
  56.         imageView.setImageDrawable(bmd);
  57.  
  58.         //将图片居中显示
  59.         imageView.setScaleType(ScaleType.CENTER);
  60.  
  61.         //将ImageView添加到布局模板中
  62.         linLayout.addView(imageView,
  63.           new LinearLayout.LayoutParams(
  64.                       LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT
  65.                 )
  66.         );
  67.  
  68.         // 设置为本activity的模板
  69.         setContentView(linLayout);
  70.     }
  71. }

这里没用定义XML布局模板,而是直接在代码中生成了需要的模板和视图组件,你可以可以定义XML模板,其他原理是一样的。


在游戏开发中,自定义View是一个相当重要的功能,下面先讲一讲在View上绘制所需的四个基本主键:
Bitmap:
用于容纳像素点(android.graphics.Bitmap)
Canvas
:负责调用绘制方法,是整个过程的入口
要绘制的对象:比如绘制一个Bitmap,矩形或者圆
Paint:
设置绘制图形的颜色和样式

Matrix
:它包含一个3x3的矩阵,用于做变换匹配(图像处理中有讲),Matrix没有一个结构体,它必须被初始化,通过实现reset()方法或者set..()方法来实现。
下面来看代码:
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.View;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
//import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Canvas;
import android.graphics.Paint;
//import android.graphics.Rect;

public class TestMartix extends Activity {
//
新建Bitmap,CanvasPaint
private Bitmap img,r_img;
private Canvas canvas;
private Paint paint;
//
由于是自定义view,所以不需要调用Layout文件
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//
调用自定义View
setContentView(new MyView(this));

}

public class MyView extends View{
//View
的初始化
public MyView(Context context) {
super(context);

//BitmapFactory
:从源创建一个Bitmap对象,这些源包括:文件,流或者数组
img = BitmapFactory.decodeResource(getResources(),R.drawable.img);
//
新建一个Matrix对象
Matrix matrix = new Matrix();
//
让矩阵实现翻转,参数为FLOAT
matrix.postRotate(90);
//matrix.postRotate(0);
//
获取Bitmap的高与宽
int width = img.getWidth();
int height = img.getHeight();
//
Bitmap通过一个Matrix变化后,返回一个不可变的Bitmap
b_img = Bitmap.createBitmap(img, 0, 0, width, height, matrix, true);
paint = new Paint();

}
//
在自定义VIEW时,必须实现此方法
public void onDraw(Canvas canvas){
//
在重写父类的方法时,必须先调用父类的方法
super.onDraw(canvas);
//
利用CanvasView上绘制一个Bitmap,并设置它的样式和颜色
canvas.drawBitmap(b_img, 10, 10, paint);

//
该方法是用来更新View的方法,多与线程结合使用。
//this.invalidate ()
//
下面三段代码用于在View上绘制一个实心矩形,设置颜色为绿色,
//paint.setColor(Color.GREEN);
//paint.setAntiAlias(true);
//canvas.drawRect(new Rect(30,30,100,100), paint);

}
}

}

                                                                                           

原创粉丝点击