Android Matrix(变形矩阵)

来源:互联网 发布:云南为什么乱 知乎 编辑:程序博客网 时间:2024/05/16 18:11

概要:

Matrix(矩阵),这是一个数学的概念。通常的nxm(n行,m列)行列数是不受限制的。但这里主要讲的是

3x3矩阵(3行3列)如图:


Matrix对图形的变形通常有如下四种形式:

Translate       平移变换 

Rotate            旋转变换   

Scale              缩放变换

Skew              错切变换

从字面上的意思,MACALE负责缩放,MSKEW负责错切,MARANS负责平移。MPERSP 用于处理透视的

变化(不常用),当然我们不能完全按照上面的意思理解。


针对上面的四种变换,Android进行了封装,提供三种方法setXX(设值),preXX(前乘),postXX(后乘)。


分析:

一,Translate      平移变换

将一个点 ,平移到点的位置,如下图 :


由图可知:


用矩阵来表示的话:

 


二,Rotate    旋转变换

2.1将一个点 ,围绕坐标原点(0,0)顺时针旋转,如图:


其中点到原点的距离为r。到原点连线与X轴正方向的夹角为α。

有图可知:


用矩阵表示为:



2.2 将一个点 ,围绕坐标某个点,顺时针旋转

有上面的推理可知:


矩阵变换:


分析矩阵表达式:

1.   

  是将坐标原点移动到点后, 的新坐标。

2.     


是将上一步变换后的,围绕新的坐标原点顺时针旋转 。

3.     

经过上一步旋转变换后,再将坐标原点移回到原来的坐标原点。

所以,围绕某一点进行旋转变换,可以分成3个步骤,即首先将坐标原点移至该点,然后围绕新

的坐标原点进行旋转变换,再然后将坐标原点移回到原先的坐标原点。


三,Scale    缩放变换

理论上而言,一个点是不存在什么缩放变换的,这里需要说明一下,因为所有图像都是由点组成,所以图像的

变化是由所有的点的变化来完成的(这也是前面分析的都是点的变化的原因)。例如在这里如果图像在x轴和

y轴方向分别放k1k2倍的话,那么图像中的所有点的x坐标y坐标均会分别放大k1k2倍,即


用矩阵表示就是:


缩放变换比较好理解,就不多说了。

四,错切变化:

错切变换就是让所有点的x坐标(或者y坐标)保持不变,而对应的y坐标(或者x坐标)则按比例发生平移,

如图所示:

1,各点的y坐标保持不变,但其x坐标则按比例发生了平移。这种情况将水平错切。


2,各点的x坐标保持不变,但其y坐标则按比例发生了平移。这种情况叫垂直错切。


假定一个点经过错切变换后得到,对于水平错切而言,应该有如下关系:

用矩阵表示为:

 

同理,对于垂直错切,可以有:

在数学上严格的错切变换就是上面这样的。在Android中除了有上面说到的情况外,还可以同时进行水平、

垂直错切,那么形式上就是:

应用:

我们设置九个EditText,自己设置矩阵。然后根据矩阵取变换图像。

public class MatrixActivity extends Activity {    private EditText[] edits;    private Button btn_change, btn_reset;    private ImageView imageView;    private static final String tag = "tag_matrix";    Matrix matrix = new Matrix();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_matrix);        initViews();        btn_change.setOnClickListener(onClickListener);        btn_reset.setOnClickListener(onClickListener);    }    private void initViews() {        imageView = (ImageView) findViewById(R.id.iv_show);        edits = new EditText[9];        for (int i = 0; i < 9; i++) {            edits[i] = (EditText) findViewById(R.id.et_0 + i);        }        btn_change = (Button) findViewById(R.id.btn_change);        btn_reset = (Button) findViewById(R.id.btn_reset);    }    View.OnClickListener onClickListener = new View.OnClickListener() {        @Override        public void onClick(View v) {            switch (v.getId()) {                case R.id.btn_change:                    changeImage();                    break;                case R.id.btn_reset:                    resetImage();                    break;            }        }    };    private void changeImage() {        LogUtil.i(tag, "changeImage");        float[] data = new float[9];        for (int i = 0; i < edits.length; i++) {            String txt = edits[i].getText().toString();            try {                if ("".equals(txt)) {                    data[i] = 0;                } else {                    data[i] = Float.parseFloat(txt);                }            } catch (Exception e) {                data[i] = 0;            }            LogUtil.i(tag, "" + data[i]);        }        matrix.setValues(data);        BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.aa2);        Bitmap tempBitmap = bitmapDrawable.getBitmap();        Bitmap bitmap = Bitmap.createBitmap(tempBitmap, 0, 0, tempBitmap.getWidth(), tempBitmap.getHeight(), matrix, true);        imageView.setImageBitmap(bitmap);    }    private void resetImage() {        LogUtil.i(tag, "resetImage");        matrix.reset();        imageView.setImageResource(R.drawable.aa2);    }}
布局文件:res/layout/activity_matrix

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <LinearLayout        android:id="@+id/ll_title"        android:layout_width="match_parent"        android:layout_height="wrap_content">        <TextView            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:gravity="center"            android:text="原图"/>        <TextView            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_weight="1"            android:gravity="center"            android:text="变换图"/>    </LinearLayout>    <ImageView        android:id="@+id/iv_init"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentLeft="true"        android:src="@drawable/aa2"        android:layout_margin="10dp"        android:layout_below="@+id/ll_title"/>    <RelativeLayout        android:layout_below="@+id/ll_title"        android:layout_toRightOf="@+id/iv_init"        android:layout_above="@+id/rl_input"        android:layout_width="match_parent"        android:layout_height="match_parent">        <ImageView            android:id="@+id/iv_show"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:scaleType="center"            android:src="@drawable/aa2"/>    </RelativeLayout>    <RelativeLayout        android:id="@+id/rl_input"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_above="@+id/ll_button">        <EditText            android:id="@+id/et_0"            android:layout_width="50dp"            android:layout_marginLeft="20dp"            android:layout_height="wrap_content" />        <EditText            android:id="@+id/et_1"            android:layout_width="50dp"            android:layout_centerHorizontal="true"            android:layout_height="wrap_content" />        <EditText            android:id="@+id/et_2"            android:layout_width="50dp"            android:layout_height="wrap_content"            android:layout_marginRight="20dp"            android:layout_alignParentRight="true"/>        <EditText            android:id="@+id/et_3"            android:layout_width="50dp"            android:layout_margin="20dp"            android:layout_below="@+id/et_0"            android:layout_height="wrap_content" />        <EditText            android:id="@+id/et_4"            android:layout_width="50dp"            android:layout_margin="20dp"            android:layout_below="@+id/et_0"            android:layout_centerHorizontal="true"            android:layout_height="wrap_content" />        <EditText            android:id="@+id/et_5"            android:layout_width="50dp"            android:layout_margin="20dp"            android:layout_below="@+id/et_0"            android:layout_alignParentRight="true"            android:layout_height="wrap_content" />        <EditText            android:id="@+id/et_6"            android:layout_width="50dp"            android:layout_marginLeft="20dp"            android:layout_marginBottom="20dp"            android:layout_below="@+id/et_3"            android:layout_height="wrap_content" />        <EditText            android:id="@+id/et_7"            android:layout_width="50dp"            android:layout_below="@+id/et_3"            android:layout_centerHorizontal="true"            android:layout_height="wrap_content" />        <EditText            android:id="@+id/et_8"            android:layout_width="50dp"            android:layout_marginRight="20dp"            android:layout_marginBottom="20dp"            android:layout_below="@+id/et_3"            android:layout_alignParentRight="true"            android:layout_height="wrap_content" />    </RelativeLayout>    <LinearLayout        android:id="@+id/ll_button"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:orientation="horizontal">        <Button            android:id="@+id/btn_change"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:text="change"/>        <Button            android:id="@+id/btn_reset"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_weight="1"            android:text="reset"/>    </LinearLayout>    </RelativeLayout>

3.1缩放变换(宽高同时放大到2倍):


3.2错切变换(垂直错切)


3.3 绕原点旋转变换(旋转30度)。


4,平移变换,使用这种方式(

Bitmap.createBitmap(tempBitmap, 0, 0, tempBitmap.getWidth(), tempBitmap.getHeight(), matrix, true)
)不起作用(平移并不会改变图像本身)。

可改用Canvas。drawBitmap(Bitmap, Matrix, Paint);

我们修改一下代码:

        BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.aa2);        Bitmap tempBitmap = bitmapDrawable.getBitmap();        Bitmap bitmap = Bitmap.createBitmap(tempBitmap.getWidth(), tempBitmap.getHeight(), Bitmap.Config.ARGB_8888);        Canvas canvas = new Canvas(bitmap);        MatrixDrawable matrixDrawable = new MatrixDrawable(tempBitmap, matrix);        matrixDrawable.draw(canvas);

其中MatrixDrawable的代码:

public class MatrixDrawable extends Drawable {    private final static String tag = "MatrixDrawable";    //画笔    Paint mPaint;    //绘图矩阵    Matrix mMatrix;    //原始图    Bitmap mBitmap;    //矩阵元素存储的数组    float[] params;    Bitmap temp;    MatrixDrawable(Bitmap bitmap, Matrix matrix) {        this.mBitmap = bitmap;        this.mMatrix = matrix;        mPaint = new Paint();        mPaint.setAntiAlias(true);    }        @Override    public void draw(Canvas canvas) {        canvas.drawBitmap(mBitmap, mMatrix, mPaint);    }    @Override    public int getIntrinsicWidth() {        if (mBitmap != null) {            return mBitmap.getWidth();        }        return super.getIntrinsicWidth();    }    @Override    public int getIntrinsicHeight() {        if (mBitmap != null) {            return mBitmap.getHeight();        }        return super.getIntrinsicHeight();    }    @Override    public void setAlpha(int alpha) {        mPaint.setAlpha(alpha);    }    @Override    public void setColorFilter(ColorFilter colorFilter) {        mPaint.setColorFilter(colorFilter);    }    @Override    public int getOpacity() {        return PixelFormat.TRANSLUCENT;    }    public Matrix getmMatrix(){        return mMatrix;    }}
效果如图:







0 0