在上一篇文章中,我们学习利用色光三原色调整图片颜色的方法。这一篇文章的代码将在上一篇的基础上继续书写。如果你还没读过,可以点击下面的链接:
http://www.cnblogs.com/fuly550871915/p/4883422.html
在本篇中,我们继续学习图片颜色的变换方法,利用颜色矩阵将更加细致的调整图片颜色。其实颜色矩阵变换是图片颜色变化的基础原理。在下面我们将详细说一说。
一、基础知识
在用色光三原色来变换图片颜色中,涉及到一个类ColorMatrix,也就是颜色矩阵的意思。而android中图像颜色处理的原理就是用一个4*5的数值矩阵来与图片中每一个像素点相乘,即与每一个颜色值相乘从而得到新的颜色的。我们看下面的一张图片
这张图片说的就是颜色处理的原理。其中的矩阵A就是我们的颜色矩阵,是一个数值矩阵,每一个值都在0—255之间。而C是一个5*1的向量,即时图片上的每一个像素点(也就是颜色值)。当A*C时,由线性代数的知识,就得到一个新的4*1的向量。仔细观察右边的计算公式,新的向量的四个元素其实就是新的颜色分量值:红,绿,蓝,透明度。至于原始的向量是5*1,最后一个元素为什么是1,这这只是android设置的一个偏移量而已,不用管它。那么我怎么改变颜色呢?其实我们要做的很简单,就是设定颜色矩阵A的每一个值即可。那么当A的初始化值我多少呢,即A怎么设置,可以将图片还原为以前的颜色呢(或者说是不会改变颜色)。学过线代就会知道,其实很简单,只要能够保证C的值变即可。那么A应该设置为,如下:
好了,基本基础知识你都知道了。也许你还是很困惑,怎么使用颜色矩阵呢?其实思路跟利用色光三元色改变图片效果的方法是一样的。我们通过ColorMatrxi的set方法,将一个长度为20的数值数组传给它,就可以实现颜色矩阵A的设定了。然后同样,利用这个设定好的颜色矩阵来设置画笔,最后用画笔根据我们原来的图片画一张只改变了颜色的图片即可。我们来看具体的一个实现方法吧,代码如下,注释很详细,我就不多解释了。
1 /* 2 * 用来根据颜色矩阵处理图片的颜色 3 */ 4 private void setImage(){ 5 Bitmap bmp = Bitmap.createBitmap(priBmp.getWidth(), priBmp.getHeight(), Bitmap.Config.ARGB_8888); 6 Canvas canvas = new Canvas(bmp); 7 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿设置 8 9 ColorMatrix colorMatrix = new ColorMatrix(); 10 colorMatrix.set(mColorMatrix);//注意这一步是核心,将颜色矩阵设置为我们的颜色矩阵 11 //根据颜色矩阵获得一支这样的画笔 12 paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); 13 //然后利用设置好的颜色画笔将原图画到新的bmp上 14 canvas.drawBitmap(priBmp, 0, 0, paint); 15 16 img.setImageBitmap(bmp);//注意这一步,我们将图片显示在ImageView上了 17 }
需要说明的是,其中img是一个ImageView,priBmp是原来的Bitmap图片,mColorMatrxi是一个长度为20的数值数组。其实上面的代码就是截取我们下面的实战里面的,所以你看不到它们的初始化。那么下面我们快快进入实战吧。
二、实战
我们的实战代码在上一篇用三原色改变颜色效果的基础上继续编写。在上一篇中我们再MainActivity中显示了三个按钮,现在我们就来实现第二个按钮”调整颜色矩阵“。首先编写color2.xml用来显示利用颜色矩阵调整的图片。这里面用到了一个Gridlayout布局,相信大家都不陌生吧,我就不多说了。代码如下:
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical"> 6 <ImageView 7 android:id="@+id/img_color" 8 android:layout_width="match_parent" 9 android:layout_height="0dp" 10 android:layout_weight="2"/> 11 <GridLayout 12 android:id="@+id/glay" 13 android:layout_width="match_parent" 14 android:layout_height="0dp" 15 android:layout_weight="3" 16 android:columnCount="5" 17 android:rowCount="4" ></GridLayout> 18 19 <LinearLayout 20 android:layout_width="match_parent" 21 android:layout_height="wrap_content" 22 android:orientation="horizontal"> 23 <Button 24 android:id="@+id/btn_change" 25 android:layout_width="0dp" 26 android:layout_height="wrap_content" 27 android:layout_weight="1" 28 android:onClick="btnChange" 29 android:text="改变"/> 30 <Button 31 android:id="@+id/btn_ret" 32 android:layout_width="0dp" 33 android:layout_height="wrap_content" 34 android:layout_weight="1" 35 android:onClick="btnRet" 36 android:text="恢复"/> 37 </LinearLayout> 38 39 40 41 42 </LinearLayout>
我们发现在这个布局中,上放置了一个ImageView用来显示图片,下面是一个4*5的GridLayout,其实就是来设置颜色矩阵的,对应于颜色矩阵4*5。最下面是两个按钮,一个”改变“按钮,用来改变颜色,一个”恢复“按钮,用来恢复图片颜色。
然后,再新建”ColorMatrixActivity“,用来显示我们这个布局,处理相应的逻辑。注释很详细了,如下:
1 package com.fuly.image; 2 3 import android.app.Activity; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapFactory; 6 import android.graphics.Canvas; 7 import android.graphics.ColorMatrix; 8 import android.graphics.ColorMatrixColorFilter; 9 import android.graphics.Paint; 10 import android.os.Bundle; 11 import android.view.View; 12 import android.widget.EditText; 13 import android.widget.GridLayout; 14 import android.widget.ImageView; 15 16 public class ColorMatrixActivity extends Activity{ 17 18 private ImageView img; 19 private GridLayout mGrid; 20 private Bitmap priBmp; 21 22 private int mEtWidth;//每一个小编辑框的宽度 23 private int mEtHeight;//每一个小编辑框的高度 24 25 private EditText[] mEts = new EditText[20];//用来存储编辑框 26 private float[] mColorMatrix = new float[20];//用来存储编辑框中的值 27 28 29 30 31 protected void onCreate(Bundle savedInstanceState) { 32 33 super.onCreate(savedInstanceState); 34 setContentView(R.layout.color2); 35 priBmp = BitmapFactory.decodeResource(getResources(), R.drawable.test1); 36 37 img = (ImageView) findViewById(R.id.img_color); 38 mGrid = (GridLayout) findViewById(R.id.glay); 39 img.setImageBitmap(priBmp); 40 41 //当mGrid被画出来之后就会调用这个方法 42 mGrid.post(new Runnable(){ 43 44 public void run() { 45 46 mEtWidth = mGrid.getWidth()/5; 47 mEtHeight = mGrid.getHeight()/4; 48 49 initGrid(); 50 initMatrix(); 51 } 52 53 }); 54 } 55 /* 56 * 初始化mGrid,将小的编辑框添加进去 57 */ 58 private void initGrid(){ 59 60 for(int i=0;i<20;i++){ 61 EditText et = new EditText(this); 62 mGrid.addView(et,mEtWidth,mEtHeight); 63 64 mEts[i] = et; 65 66 } 67 } 68 /* 69 * 初始化矩阵,即mGrid中的那些小编辑框 70 */ 71 private void initMatrix(){ 72 73 for(int i=0;i<20;i++){ 74 if(i%6 == 0){ 75 mEts[i].setText(String.valueOf(1)); 76 }else{ 77 mEts[i].setText(String.valueOf(0)); 78 } 79 } 80 } 81 /* 82 * 用来获取编辑框中的值 83 */ 84 private void getMatrix(){ 85 for(int i=0;i<20;i++){ 86 mColorMatrix[i]=Float.valueOf(mEts[i].getText().toString()); 87 } 88 } 89 /* 90 * 用来根据颜色矩阵处理图片的颜色 91 */ 92 private void setImage(){ 93 Bitmap bmp = Bitmap.createBitmap(priBmp.getWidth(), priBmp.getHeight(), Bitmap.Config.ARGB_8888); 94 Canvas canvas = new Canvas(bmp); 95 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿设置 96 97 ColorMatrix colorMatrix = new ColorMatrix(); 98 colorMatrix.set(mColorMatrix);//注意这一步是核心,将颜色矩阵设置为我们的颜色矩阵 99 //根据颜色矩阵获得一支这样的画笔 100 paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); 101 //然后利用设置好的颜色画笔将原图画到新的bmp上 102 canvas.drawBitmap(priBmp, 0, 0, paint); 103 104 img.setImageBitmap(bmp);//注意这一步,我们将图片显示在ImageView上了 105 } 106 107 /** 108 * 改变按钮的监听事件 109 */ 110 public void btnChange(View view){ 111 112 getMatrix(); 113 setImage(); 114 } 115 /* 116 * 恢复按钮的监听事件 117 */ 118 public void btnRet(View view){ 119 initMatrix(); 120 getMatrix(); 121 setImage(); 122 123 } 124 }
在这里,我们可以看到将颜色矩阵初始化为了只包含1和0的矩阵,就是前面我们所讲的用来恢复图片颜色的矩阵。后面的那个setImage方法就是之前我们所贴出来的改变颜色的那个方法。代码逻辑很简单,不多说了。
最后不要忘记注册这个活动,还要修改MainActivity中的代码如下:
1 package com.fuly.image; 2 3 import android.os.Bundle; 4 import android.view.View; 5 import android.widget.Button; 6 import android.app.Activity; 7 import android.content.Intent; 8 9 public class MainActivity extends Activity { 10 11 private Button btn1; 12 13 14 protected void onCreate(Bundle savedInstanceState) { 15 super.onCreate(savedInstanceState); 16 setContentView(R.layout.activity_main); 17 18 btn1 = (Button) findViewById(R.id.bnt_imgcolor1); 19 20 } 21 22 /* 23 * btn1的点击事件 24 */ 25 public void preferenceClick(View view){ 26 27 Intent intent = new Intent(this,ColorAdjustActivity.class); 28 startActivity(intent); 29 30 31 } 32 /* 33 * btn2的点击事件 34 */ 35 public void matrixClick(View view){ 36 37 Intent intent = new Intent(this,ColorMatrixActivity.class); 38 startActivity(intent); 39 40 } 41 )
好了,我们运行程序,点击第二个按钮,实现的效果如下:
点击按钮,跳转后为第一张效果,然后设置值并点击”改变“是第二张的效果,然后点击恢复是第三张效果。
这样子,是不是很直观啊。不知道用颜色矩阵来处理图片颜色你掌握了没有。下面我们就来实现最后一个按钮”调整色素“,即通过调整色素来实现颜色的改变。在下面的这篇文章中,我们将实现负片效果,浮雕效果,老照片效果,有意思吧,快来学习吧。