1. 程式人生 > >影象處理-矩陣變換

影象處理-矩陣變換

Android中通過矩陣來處理影象問題是非常常見的。

顏色矩陣

影象中的每一個畫素點都是一個顏色矩陣分量,然後我們讓這兩個矩陣相乘就能得到一個新的矩陣(新的顏色矩陣分量),這就是矩陣變換對影象中的每一個點的處理,使得對整個影象進行處理。通常我們會用下面整個矩陣作為初始矩陣,因為這個矩陣乘以任何矩陣都是不會改變顏色矩陣分量的。

初始矩陣

我們對顏色矩陣的分析就可以看出來最後一列不會和原有的RGBA中任何一個有關聯,所以我們可以稱之為顏色偏移量,通過常數來改變顏色。

然後我們怎麼在Android中對影象進行處理的呢,我們就需要新建兩個方法,其中一個是獲得顏色矩陣的值,還有一個是把顏色矩陣對影象進行處理。其實說白了上面那個調節就是自動生成了一個ColorMatrix(可以通過原始碼看出來,我就不詳細說了),然而現在這種是自己輸入ColorMatrix,這就是兩種的區別了。

private void getMatrix(){
    for(int i=0;i<20;i++){
        mColorMatrix[i]=Float.valueOf(mEts[i].getText().toString());
    }
}

private void setImageMatrix(){
    Bitmap bmp=Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(),Bitmap.Config.ARGB_8888);//一定要新建一個Bitmap,因為傳進來的Bitmap是不能修改的,需要重新進行繪製
android.graphics.ColorMatrix colorMatrix = new android.graphics.ColorMatrix(); colorMatrix.set(mColorMatrix);//將顏色矩陣放入ColorMatrix中去 Canvas canvas = new Canvas(bmp); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗鋸齒 paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); canvas.drawBitmap(bitmap,0
,0,paint); mImageView.setImageBitmap(bmp); }

下面來個例子:
先編寫一個color_matrix.xml的佈局檔案,有一個ImageView顯示影象,然後有一個GridLayout對矩陣進行顯示以及修改,然後有三個Button分別對影象進行改變,重置以及選擇圖片。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/imageview"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2" />

    <GridLayout
        android:id="@+id/group"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="3"
        android:columnCount="5"
        android:rowCount="4">

    </GridLayout>

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

        <Button
            android:id="@+id/btnChange"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Change" />

        <Button
            android:id="@+id/btnReset"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Reset" />

        <Button
            android:id="@+id/btnChangeImage"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="ChangeImage" />
    </LinearLayout>

</LinearLayout>

然後新建一個ColorMatrix.java檔案裡面通過我們上述的程式碼構建出一個ColorMatrix,然後通過這個ColorMatrix重新繪製一個Bitmap顯示出來,把上面理解了的話就會好理解好多,Change就是我們根據所調整過後的矩陣對影象進行的處理,Reset就是把矩陣調整成我們上面所說的初始化矩陣,然後在根據這個矩陣對影象進行的處理。其他的就沒有什麼好說的了,感覺都還蠻容易懂的。

package com.xjh.gin.image;

import android.Manifest;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridLayout;
import android.widget.ImageView;

/**
 * Created by Gin on 2017/11/26.
 */

public class ColorMatrix extends BaseActivity implements View.OnClickListener {
    private static final int PICK_CODE = 0X110;
    private ImageView mImageView;
    private GridLayout mGroup;
    private String mCurreatPhotoStr;
    private Bitmap bitmap;//就是單獨的bitmap,之後的修改不會覆蓋這個Bitmap
    private Button btn_Change, btn_Reset, btn_ChangeImage;
    private int mEtWidth, mEtHeight;
    private EditText[] mEts = new EditText[20];
    private float[] mColorMatrix = new float[20];

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.color_matrix);
        isPermissionAllGranted(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
        initView();
        initEvent();
    }

    private void initView() {
        mImageView = (ImageView) findViewById(R.id.imageview);
        mGroup = (GridLayout) findViewById(R.id.group);
        btn_Change = (Button) findViewById(R.id.btnChange);
        btn_Reset = (Button) findViewById(R.id.btnReset);
        btn_ChangeImage = (Button) findViewById(R.id.btnChangeImage);
    }

    private void initEvent() {
        btn_Change.setOnClickListener(this);
        btn_Reset.setOnClickListener(this);
        btn_ChangeImage.setOnClickListener(this);
        bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test1);
        mImageView.setImageBitmap(bitmap);
        mGroup.post(new Runnable() {//在onCreate方法中因為控制元件還沒有繪製完畢,所以我們無法獲得控制元件的高和寬,所以當控制元件繪製完畢以後,我們就線上程中獲取,因為這時候控制元件一定繪製完畢了
            @Override
            public void run() {
                mEtWidth = mGroup.getWidth() / 5;
                mEtHeight = mGroup.getHeight() / 4;
                addEts();
                initMatrix();
            }
        });
    }

    private void addEts() {//新增EditText
        for (int i = 0; i < 20; i++) {
            EditText editText = new EditText(ColorMatrix.this);
            mEts[i] = editText;
            mGroup.addView(editText, mEtWidth, mEtHeight);//讓editText動態的載入進mGroup中去
        }
    }

    private void initMatrix() {
        for (int i = 0; i < 20; i++) {
            if (i % 6 == 0) {
                mEts[i].setText(String.valueOf(1));
            } else {
                mEts[i].setText(String.valueOf(0));
            }
        }
    }

    private void getMatrix(){
        for(int i=0;i<20;i++){
            mColorMatrix[i]=Float.valueOf(mEts[i].getText().toString());
        }
    }

    private void setImageMatrix(){
        Bitmap bmp=Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(),Bitmap.Config.ARGB_8888);//一定要新建一個Bitmap,因為傳進來的Bitmap是不能修改的,需要重新進行繪製
        android.graphics.ColorMatrix colorMatrix = new android.graphics.ColorMatrix();
        colorMatrix.set(mColorMatrix);//將顏色矩陣放入ColorMatrix中去
        Canvas canvas = new Canvas(bmp);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗鋸齒
        paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        canvas.drawBitmap(bitmap,0,0,paint);
        mImageView.setImageBitmap(bmp);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnChange:
                getMatrix();
                setImageMatrix();
                break;

            case R.id.btnReset:
                initMatrix();
                getMatrix();
                setImageMatrix();
                break;

            case R.id.btnChangeImage:
                Intent intent = new Intent(Intent.ACTION_PICK);
                intent.setType("image/*");
                startActivityForResult(intent, PICK_CODE);
                break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == PICK_CODE) {
            if (data != null) {
                Uri uri = data.getData();
                Cursor cursor = getContentResolver().query(uri, null, null, null, null);
                cursor.moveToFirst();
                int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                mCurreatPhotoStr = cursor.getString(idx);
                cursor.close();
                resizePhoto();
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    private void resizePhoto() {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;//true為不載入圖片,只有寬高這類的資料
        BitmapFactory.decodeFile(mCurreatPhotoStr, options);

        double ratio = Math.max(options.outWidth * 1.0d / 1024f, options.outHeight * 1.0d / 1024f);//求出壓縮比例
        options.inSampleSize = (int) Math.ceil(ratio);//把壓縮比例傳入options中
        options.inJustDecodeBounds = false;
        bitmap = BitmapFactory.decodeFile(mCurreatPhotoStr, options);
        mImageView.setImageBitmap(bitmap);//壓縮圖片,mPhoto是壓縮過後的Bitmap
    }
}

ColorMatrix

然後我們就可以發現影象處理其實就是研究不同的顏色矩陣對影象的處理效果

專案GitHub地址:傳送門