Android Matrix圖像變換處理

Canvas類中drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)方法中有個參數類型是Matrix。從字面上理解是矩陣的意思,而實際上它也確實是個3x3的矩陣。Matrix在Android中的主要做用是圖像變換,如平移、旋轉、縮放、扭曲等。 關於圖像怎樣經過矩陣進行變化可參考這篇文章圖像處理—關於像素座標矩陣變換(平移,旋轉。縮放。錯切)html

Matrix內部經過維護一個float[9]的數組來構成3x3矩陣的形式,而實際上所有的變換方法說究竟就是經過更改數組中某個或某幾個位置的數值。java

Matrix提供了setValues()和getValues()方法來操做數組。linux

這裏寫圖片描寫敘述

顯然這兩個方法使用起來很是不方便。假設僅僅有這樣,那Matrix預計就不會有人使用了。Google輕易不會辜負咱們的信任。Matrix提供了若干簡單易用的變換方法和映射方法供開發人員使用。android

Matrix變換方法

一、Translate(平移)、Scale(縮放)、Rotate(旋轉)、Skew(扭曲)

Matrix提供了Translate(平移)、Scale(縮放)、Rotate(旋轉)、Skew(扭曲)四中變換操做,這四種操做實質上是調用了setValues()方法來設置矩陣數組來達到變換效果。canvas

除Translate(平移)外。Scale(縮放)、Rotate(旋轉)、Skew(扭曲)都可以環繞一箇中心點來進行,假設不指定。在默認狀況下是環繞(0, 0)來進行對應的變換的。數組

  • Translate操做中markdown

    • 在x軸上使用正數進行平移將向右移動圖像,而使用負數將向左移動圖像。
    • 在y軸上使用正數進行平移將向下移動圖像,而使用負數將向上移動圖像。
  • Scale操做中,ide

    • 在x軸上使用正數進行縮放將在中心點的右邊縮放圖像,而使用負數將在中心點的左邊縮放圖像。
    • 在y軸上使用正數進行縮放將在中心點的下邊縮放圖像,而使用負數將在中心點的上邊縮放圖像。

二、pre、set、post

Matrix提供的四種操做,每一種都有pre、set、post三種形式。緣由是矩陣乘法不知足乘法交換律,所以左乘仍是右乘終於的效果都不同。post

左乘或者右乘是針對變換矩陣的,獲得終於的變換矩陣後,與圖像矩陣想成,圖像矩陣在右邊。spa

pre方法表示矩陣左乘,好比:變換矩陣爲A,原始矩陣爲B。pre方法的含義便是A*B

post方法表示矩陣右乘,好比:變換矩陣爲A,原始矩陣爲B,post方法的含義便是B*A

咱們可以把Matrix變換想象成一個隊列,隊列裏面包括了若干個變換操做,隊列中每個操做依照前後順序操做變換目標完畢變換。pre至關於向隊首添加一個操做,post至關於向隊尾添加一個操做,set至關於清空當前隊列又一次設置。

///這段代碼僅僅有translate(100, 100)生效。因爲第二個set會把以前隊列中的操做清除。

Matrix m = new Matrix(); m.setRotate(100); m.setTranslate(100, 100);
//這段代碼先運行translate(100, 100)。後運行rotate(100)

Matrix m = new Matrix();
m.setTranslate(100, 100);
m.postRotate(100);
///這段代碼先運行rotate(100)。後運行translate(100, 100)
Matrix m = new Matrix();
m.setTranslate(100, 100);
m.preRotate(100);
///這段代碼的運行順序: translate(100f, 100f) -> scale(2f, 2f) -> scale(0.5f, 0.5f) -> translate(50f, 50f)

Matrix m = new Matrix();
m.preScale(2f, 2f);    
m.preTranslate(100f, 100f);   
m.postScale(0.5f, 0.5f);    
m.postTranslate(50f, 50f);
//這段代碼的運行順序:translate(50f, 50f) -> scale(0.8f, 0.8f) -> scale(3f, 3f)
Matrix m = new Matrix();
m.postTranslate(100, 100);   
m.preScale(0.5f, 0.5f);
m.setScale(0.8f, 0.8f);   
m.postScale(3f, 3f);
m.preTranslate(50f, 50f);

三、Matrix 映射方法

Matrix提供了mapPoints(),mapRects(),mapVectors()等映射方法。用來獲取經Matrix映射後的值

//這段代碼的做用是獲取通過平移後該bitmap四個點的座標
Matrix m = new Matrix();
m.postTranslate(100f, 100f);

float[] src = {
    0, 0, 
    0, bitmap.getHeight(), 
    bitmap.getWidth(), 0, 
    bitmap.getWidth(), bitmap.getHeight()
};
float[] dst = new float[8];

m.mapPoints(dst, src);

常常使用的矩陣變化方法

如下是常常使用變換的樣例,除了變換參數。其它代碼也有一些差別,可以多認識幾種實現方法

平移Translate

/** * 圖片移動 */
    protected void bitmapTranslate(float dx, float dy) {
        // 需要依據移動的距離來建立圖片的拷貝圖大小
        Bitmap afterBitmap = Bitmap.createBitmap(
                (int) (baseBitmap.getWidth() + dx),
                (int) (baseBitmap.getHeight() + dy), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(afterBitmap);
        Matrix matrix = new Matrix();
        // 設置移動的距離
        matrix.setTranslate(dx, dy);
        canvas.drawBitmap(baseBitmap, matrix, paint);
        iv_after.setImageBitmap(afterBitmap);
    }

縮放Scale

/** * 縮放圖片 */
    protected void bitmapScale(float x, float y) {
        // 因爲要將圖片放大,因此要依據放大的尺寸又一次建立Bitmap
        Bitmap afterBitmap = Bitmap.createBitmap(
                (int) (baseBitmap.getWidth() * x),
                (int) (baseBitmap.getHeight() * y), baseBitmap.getConfig());
        Canvas canvas = new Canvas(afterBitmap);
        // 初始化Matrix對象
        Matrix matrix = new Matrix();
        // 依據傳入的參數設置縮放比例
        matrix.setScale(x, y);
        // 依據縮放比例,把圖片draw到Canvas上
        canvas.drawBitmap(baseBitmap, matrix, paint);
        iv_after.setImageBitmap(afterBitmap);
    }

注意觀察如下兩個鏡像的實現方法。

X軸鏡像

/** * x軸鏡像 */
    protected void bitmapXMirror() {
        // 因爲要將圖片放大,因此要依據放大的尺寸又一次建立Bitmap
        Bitmap afterBitmap = Bitmap.createBitmap(
                baseBitmap.getWidth() ,
                baseBitmap.getHeight() , baseBitmap.getConfig());
        Canvas canvas = new Canvas(afterBitmap);
        // 初始化Matrix對象
        Matrix matrix = new Matrix();
        // 依據傳入的參數設置縮放比例
        matrix.postScale(-1, 1);
        matrix.postTranslate(baseBitmap.getWidth(), 0);
        // 依據縮放比例,把圖片draw到Canvas上
        canvas.drawBitmap(baseBitmap, matrix, paint);
        iv_after.setImageBitmap(afterBitmap);
    }

Y軸鏡像

/** * y軸鏡像 */
    protected void bitmapYMirror() {

        // 初始化Matrix對象
        Matrix matrix = new Matrix();
        // 依據傳入的參數設置縮放比例
        matrix.postScale(1, -1);
        //依據變換矩陣,繪製新的圖片
        Bitmap afterBitmap = Bitmap.createBitmap(baseBitmap, 0, 0,baseBitmap.getWidth(),baseBitmap.getHeight(), matrix, true);
        iv_after.setImageBitmap(afterBitmap);
    }

旋轉Rotate

/** * 圖片旋轉 */
    protected void bitmapRotate(float degrees) {
        // 建立一個和原圖同樣大小的圖片
        Bitmap afterBitmap = Bitmap.createBitmap(baseBitmap.getWidth(),
                baseBitmap.getHeight(), baseBitmap.getConfig());
        Canvas canvas = new Canvas(afterBitmap);
        Matrix matrix = new Matrix();
        // 依據原圖的中心位置旋轉
        matrix.setRotate(degrees, baseBitmap.getWidth() / 2,
                baseBitmap.getHeight() / 2);
        canvas.drawBitmap(baseBitmap, matrix, paint);
        iv_after.setImageBitmap(afterBitmap);
    }

扭曲Skew

/** * 傾斜圖片 */
    protected void bitmapSkew(float dx, float dy) {
        // 依據圖片的傾斜比例。計算變換後圖片的大小,
        Matrix matrix = new Matrix();
        // 設置圖片傾斜的比例
        matrix.setSkew(dx, dy);
        //依據變換矩陣,繪製新的圖片
        Bitmap afterBitmap = Bitmap.createBitmap(baseBitmap, 0, 0,baseBitmap.getWidth(),baseBitmap.getHeight(), matrix, true);
        iv_after.setImageBitmap(afterBitmap);
    }

源代碼

完整的Demo

MainActivity.java

public class MainActivity extends AppCompatActivity {
 private Button btn_scale, btn_rotate, btn_translate, btn_skew,btn_XMirror,btn_YMirror;
    private ImageView iv_base, iv_after;
    private Bitmap baseBitmap;
    private Paint paint;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btn_scale = (Button) findViewById(R.id.btn_scale);
        btn_rotate = (Button) findViewById(R.id.btn_rotate);
        btn_translate = (Button) findViewById(R.id.btn_translate);
        btn_skew = (Button) findViewById(R.id.btn_skew);
        btn_XMirror = (Button) findViewById(R.id.btn_x_mirror);
        btn_YMirror = (Button) findViewById(R.id.btn_y_mirror);

        btn_scale.setOnClickListener(click);
        btn_rotate.setOnClickListener(click);
        btn_translate.setOnClickListener(click);
        btn_skew.setOnClickListener(click);
        btn_XMirror.setOnClickListener(click);
        btn_YMirror.setOnClickListener(click);

        iv_base = (ImageView) findViewById(R.id.iv_base);
        iv_after = (ImageView) findViewById(R.id.iv_after);

        baseBitmap = BitmapFactory.decodeResource(getResources(),
                R.mipmap.ic_launcher);
        iv_base.setImageBitmap(baseBitmap);

        // 設置畫筆,消除鋸齒
        paint = new Paint();
        paint.setAntiAlias(true);
    }

    private View.OnClickListener click = new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            switch (v.getId()) {
                case R.id.btn_scale:
                    bitmapScale(2.0f, 4.0f);
                    break;
                case R.id.btn_rotate:
                    bitmapRotate(180);
                    break;
                case R.id.btn_translate:
                    bitmapTranslate(20f, 20f);
                    break;
                case R.id.btn_skew:
                    bitmapSkew(0.2f, 0.4f);
                    break;
                case R.id.btn_x_mirror:
                    bitmapXMirror();
                    break;
                case R.id.btn_y_mirror:
                    bitmapYMirror();
                    break;
                default:
                    break;
            }

        }
    };

    /** * 縮放圖片 */
    protected void bitmapScale(float x, float y) {
        // 因爲要將圖片放大。因此要依據放大的尺寸又一次建立Bitmap
        Bitmap afterBitmap = Bitmap.createBitmap(
                (int) (baseBitmap.getWidth() * x),
                (int) (baseBitmap.getHeight() * y), baseBitmap.getConfig());
        Canvas canvas = new Canvas(afterBitmap);
        // 初始化Matrix對象
        Matrix matrix = new Matrix();
        // 依據傳入的參數設置縮放比例
        matrix.setScale(x, y);
        // 依據縮放比例。把圖片draw到Canvas上
        canvas.drawBitmap(baseBitmap, matrix, paint);
        iv_after.setImageBitmap(afterBitmap);
    }


    /** * x軸鏡像 */
    protected void bitmapXMirror() {
        // 因爲要將圖片放大,因此要依據放大的尺寸又一次建立Bitmap
        Bitmap afterBitmap = Bitmap.createBitmap(
                baseBitmap.getWidth() ,
                baseBitmap.getHeight() , baseBitmap.getConfig());
        Canvas canvas = new Canvas(afterBitmap);
        // 初始化Matrix對象
        Matrix matrix = new Matrix();
        // 依據傳入的參數設置縮放比例
        matrix.postScale(-1, 1);
        matrix.postTranslate(baseBitmap.getWidth(), 0);
        // 依據縮放比例,把圖片draw到Canvas上
        canvas.drawBitmap(baseBitmap, matrix, paint);
        iv_after.setImageBitmap(afterBitmap);
    }


    /** * y軸鏡像 */
    protected void bitmapYMirror() {

        // 初始化Matrix對象
        Matrix matrix = new Matrix();
        // 依據傳入的參數設置縮放比例
        matrix.postScale(1, -1);
        //依據變換矩陣。繪製新的圖片
        Bitmap afterBitmap = Bitmap.createBitmap(baseBitmap, 0, 0,baseBitmap.getWidth(),baseBitmap.getHeight(), matrix, true);
        iv_after.setImageBitmap(afterBitmap);
    }




    /** * 傾斜圖片 */
    protected void bitmapSkew(float dx, float dy) {
        // 依據圖片的傾斜比例。計算變換後圖片的大小,
        Matrix matrix = new Matrix();
        // 設置圖片傾斜的比例
        matrix.setSkew(dx, dy);
        //依據變換矩陣,繪製新的圖片
        Bitmap afterBitmap = Bitmap.createBitmap(baseBitmap, 0, 0,baseBitmap.getWidth(),baseBitmap.getHeight(), matrix, true);
        iv_after.setImageBitmap(afterBitmap);
    }

    /** * 圖片移動 */
    protected void bitmapTranslate(float dx, float dy) {
        // 需要依據移動的距離來建立圖片的拷貝圖大小
        Bitmap afterBitmap = Bitmap.createBitmap(
                (int) (baseBitmap.getWidth() + dx),
                (int) (baseBitmap.getHeight() + dy), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(afterBitmap);
        Matrix matrix = new Matrix();
        // 設置移動的距離
        matrix.setTranslate(dx, dy);
        canvas.drawBitmap(baseBitmap, matrix, paint);
        iv_after.setImageBitmap(afterBitmap);
    }

    /** * 圖片旋轉 */
    protected void bitmapRotate(float degrees) {
        // 建立一個和原圖同樣大小的圖片
        Bitmap afterBitmap = Bitmap.createBitmap(baseBitmap.getWidth(),
                baseBitmap.getHeight(), baseBitmap.getConfig());
        Canvas canvas = new Canvas(afterBitmap);
        Matrix matrix = new Matrix();
        // 依據原圖的中心位置旋轉
        matrix.setRotate(degrees, baseBitmap.getWidth() / 2,
                baseBitmap.getHeight() / 2);
        canvas.drawBitmap(baseBitmap, matrix, paint);
        iv_after.setImageBitmap(afterBitmap);
    }
}

xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" >

    <LinearLayout  android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" >

        <Button  android:id="@+id/btn_scale" android:layout_height="wrap_content" android:layout_width="0dp" android:layout_weight="1" android:text="縮放" />

        <Button  android:id="@+id/btn_rotate" android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="旋轉" />

        <Button  android:id="@+id/btn_translate" android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content" android:text="平移" />

        <Button  android:id="@+id/btn_skew" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:text="傾斜" />

        <Button  android:id="@+id/btn_x_mirror" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:text="X軸鏡像" />

        <Button  android:id="@+id/btn_y_mirror" android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" android:text="Y軸鏡像" />

    </LinearLayout>
    <!-- 原始圖片 -->
    <ImageView  android:id="@+id/iv_base" android:layout_width="wrap_content" android:layout_height="wrap_content" />
    <!-- 處理以後的圖片 -->
    <ImageView  android:id="@+id/iv_after" android:layout_width="wrap_content" android:layout_height="wrap_content" />

</LinearLayout>

參考:
Android Matrix
Android—Matrix類的使用
Android中Matrix的pre post set方法理解
Android–Matrix圖片變換處理
android bitmap翻轉180,鏡像的簡單實現方法
圖像處理—關於像素座標矩陣變換(平移,旋轉。縮放。錯切)

相關文章
相關標籤/搜索