1.ColorMatrixColorFilter:通过颜色矩阵(ColorMatrix)对图像中的色值进行改变

在Android中,图片是以一个个 RGBA 的像素点的形式加载到内存中的,所以如果需要改变图片的颜色,就需要针对这一个个像素点的RGBA的值进行修改,其实主要是RGB,A是透明度;

修改图片 RGBA 的值需要ColorMatrix类的支持,它定义了一个 4*5 的float[]类型的矩阵,矩阵中每一行表示 RGBA 中的一个参数。

颜色矩阵M是以一维数组m=[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t]的方式进行存储的;

颜色矩阵

 

而对于一张图像来说,展示的颜色效果取决于图像的RGBA(红色、绿色、蓝色、透明度)值。而图像的 RGBA 值则存储在一个5*1的颜色分量矩阵C中,由颜色分量矩阵C可以控制图像的颜色效果。颜色分量矩阵如图所示: 

更形象的说, 比如一张图片, width = 320, height = 640; 那么这张图片就有width * height个像素点, 每一个像素点又包含了a,r,g,b这四个分量, 我们可以从代码去求出这4个分量,如果在增加一行, 就像上面的矩阵C一样, 就变成了上面的矩阵, 这就是它的由来吧.

所以为了改变图像的显示效果,只需要改变 4*5 的颜色矩阵ColorMatrix,然后通过

,再把新的矩阵,R1,G1,B1,A1整合在一起,变成一个像素点, 最终把所有的像素点都经过这样的变换,也就达到了图像处理的效果了.

即可得到新的图像显示矩阵;

 

由此可见,通过颜色矩阵 ColorMatrix 修改了原图像的 RGBA 值,从而达到了改变图片颜色效果的目的。并且,通过如上图所示的运算可知,颜色矩阵 ColorMatrix 的第一行参数abcde决定了图像的红色成分,第二行参数fghij决定了图像的绿色成分,第三行参数klmno决定了图像的蓝色成分,第四行参数pqrst决定了图像的透明度,第五列参数ejot是颜色的偏移量。

矩阵,通过计算后可以得知该颜色矩阵的作用是使图像的红色分量和绿色分量均增加100,这样的效果就是图片泛黄(因为红色与绿色混合后得到黄色):

除此之外,也可以通过直接对颜色值乘以某一系数而达到改变颜色分量的目的。如下图所示的颜色矩阵,将绿色分量放大了2倍,这样的效果就是图片泛绿色:

基于此,我们利用ColorFilter 和 ColorMatrixColorFilter类 和 Paint 的setColorFilter 就可以改变图片的展示效果(颜色,饱和度,对比度等),从而得到类似市面上图像软件中的黑白老照片、泛黄旧照片、羞涩的青春… …特效;

 

     

 

Bitmap bitmap= BitmapFactory.decodeResource(getResources(), R.drawable.ic_file_download_black_24dp);
 //注释:颜色矩阵,采用齐次坐标矩阵左乘颜色RGBA分量
 /**
 *
 * 0,0,0,0,0, R 0
 0,0,0,0,255, G 255
 0,0,0,0,0, * B = 0 即保留原来的透明度不变,同时R分量为0,G分量为25,B分量为0,得到颜色就是透明度不变的绿色 若想得到红色 只需要把255移动到上面去 矩阵相乘
 0,0,0,1,0 A A
 * 1
 *
 *
 *
 *
 *
 *
 *
 */
 ColorMatrix colorMatrix=new ColorMatrix(new float[]{0,0,0,0,0,
 0,0,0,0,255,
 0,0,0,0,0,
 0,0,0,1,0});
 ColorMatrixColorFilter colorMatrixColorFilter=new ColorMatrixColorFilter(colorMatrix);
 Bitmap newBitmap=Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888);
 Canvas canvas=new Canvas(newBitmap);
 Paint paint=new Paint();
 paint.setColorFilter(colorMatrixColorFilter);
 canvas.drawBitmap(bitmap,0,0,paint);
 imageView.setImageBitmap(newBitmap); 
 
 
 
 
 
//给出一个改变bitmap的颜色的方法
/**
 * 利用ColorMatrix颜色矩阵更改bitmap的每个像素点的颜色
 * 比如将图片的颜色全改为红色
 */ public Bitmap produceSpecifyColorBitmap(Bitmap oldBitmap,int specifyColor){
 Bitmap newBitmap=Bitmap.createBitmap(oldBitmap.getWidth(),oldBitmap.getHeight(), Bitmap.Config.ARGB_8888);
 Canvas canvas=new Canvas(newBitmap);
 /**
 *
 * 一个新的齐次颜色矩阵左乘上一个原来的颜色向量矩阵即得到一个新的颜色向量矩阵
 * a1,b1,c1,d1,e1 R R1 R1=a1*R+b1*G+c1*B+d1*A+e1
 * a2,b2,c2,d2,e2 G G1 G1=a2*R+b2*G+c2*B+d2*A+e2
 * a3,b3,c3,d3,e3 * B = B1 -> B1=a3*R+b3*G+c3*B+d3*A+e3
 * a4,b4,c4,d4,e4 A A1 A1=a4*R+b4*G+c4*B+d4*A+e4
 * 1
 *
 * 如果现在我想的到透明度不变的红色图片 那么R1=255,G1=0,B1=0,A1=A
 * 那么颜色矩阵就应该是
 * 0,0,0,0,255
 * 0,0,0,0,0
 * 0,0,0,0,0
 * 0,0,0,1,0
 */
 ColorMatrix colorMatrix=new ColorMatrix(new float[]{0,0,0,0,Color.red(specifyColor),
 0,0,0,0,Color.green(specifyColor),
 0,0,0,0,Color.blue(specifyColor),
 0,0,0,1,0});
 ColorMatrixColorFilter colorMatrixColorFilter=new ColorMatrixColorFilter(colorMatrix);
 Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
 paint.setColorFilter(colorMatrixColorFilter);
 canvas.drawBitmap(oldBitmap,0,0,paint); return newBitmap;
 }