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分别对图像进行改变,重置以及选择图片。
<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
}
}
然后我们就可以发现图像处理其实就是研究不同的颜色矩阵对图像的处理效果
项目GitHub地址:传送门