浅谈android中图片处理之色彩特效处理ColorMatrix(三)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u013064109/article/details/51416389

在android开发中对图片处理很是频繁,其中对图片的颜色处理就是很常见的一种。我们经常看到一些类似美图秀秀,美颜相机的app,为什么那么黑的人拍出来是确实那么地白呢?长的那么那个(丑)的人,用美颜相机拍出来的看起来也有那么回事(拍出来就感觉挺漂亮)。就像网上有个段子,有钱的都去韩国了,没钱都用ps了。韩国的就去整形,中国的就用ps.这些话虽然是调侃,但是从某种程度上来说像类似美图秀秀,美颜相机app确实挺受大家欢迎。但是你是否曾想过它这种效果,它是怎么实现的吗?你是否曾想过它的原理是什么吗?所以我将和大家一同由浅入深结合一些实例从原理上讲解一下如何实现图片的美颜以及各种图片风格实现。

  要想实现对图片的颜色的处理,首先就必须要了解图片的组成原理。图片主要有两种数据结构形式的图片,一种是位图,另一种是矢量图,但是在大部分的时候我们接触到的都是位图。

——的两种分类:

——位图

例子:单色位图

256位图

24位位图

位图图像(bitmap,亦称为点阵图像或绘制图像,是由称作像素(图片元素)的单个点组成的。这些点可以进行不同的排列和染色以构成图样。当放大位图时,可以看见赖以构成整个图像的无数单个方块。扩大位图尺寸的效果是增大单个像素,从而使线条和形状显得参差不齐。然而,如果从稍远的位置观看它,位图图像的颜色和形状又显得是连续的。常用的位图处理软件是Photoshop

位图的常见格式:pngjpgbmp

——矢量图

矢量图,也称为面向对象的图像或绘图图像,在数学上定义为一系列由线连接的点。矢量文件中的图形元素称为对象。每个对象都是一个自成一体的实体,它具有颜色、形状、轮廓、大小和屏幕位置等属性。

矢量图是根据几何特性来绘制图形,矢量可以是一个点或一条线,矢量图只能靠软件生成,文件占用内在空间较小,因为这种类型的图像文件包含独立的分离图像,可以自由无限制的重新组合。它的特点是放大后图像不会失真,和分辨率无关,适用于图形设计、文字设计和一些标志设计、版式设计等。

矢量图的常见格式:svgps

  大家都知道我们经常使用的图片的数据结构是位图---->Bitmap.它包含一张图片的所有的数据信息。整个图片是由点阵和颜色值(ARGB)组成的。因为位图是由像素点组成的,点阵指的是像素点的组成矩阵,而颜色值指的是;ARGB值,(A代表透明度,R代表红色值,G代表绿色值,B则代表蓝色)正好是自然界的三原色和透明度。大家都知道任何一种的颜色都可以使用三原色按照不同比例混合搭配而得到。所以这样就造成了每张图片都是色彩鲜艳,美观好看。一张色彩鲜艳的图片组成是这样的,我们知道图片是位图(这里不考虑矢量图),都是很多个像素点矩阵组成,实际上每个像素点的ARGB都是不一样的,也可以这么说每个像素点的颜色都不一样,然后不同颜色的像素点组成在一起就形成了一张色彩鲜艳图片。

 前面我们多次提到了颜色矩阵,那么我们就推出这次主角ColorMatrix颜色矩阵。

颜色矩阵的分析如下:

  在Android中我们使用ColorMatrix矩阵来处理图片的色彩的效果,Android的为颜色矩阵是一个4X5的数字矩阵,它用来对图片色彩的处理。而对于每个像素点

都会有一个颜色的分量矩阵用来保存的ARGB值。注意:在android中使用的是一维数组来保存这个M矩阵(颜色矩阵)[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t]而C就是颜色分量矩阵

相信学了线性代数的都知道是通过矩阵乘法来对颜色分量矩阵


由以上的公式可以得出每个像素点的颜色分量矩阵,通过矩阵乘法得到:

R1=a*R+b*G+c*B+d*A+e;

G1=f*R+g*G+h*B+i*A+j;

B1=k*R+l*G+m*B+n*A+o;

A1=p*R+q*G+r*B+s*A+t;

通过以上公式的分析可得到,R1,G1,B1,A1分量值取决于他们的系数和最后加部分的偏移量(e,j,o,t).可得出如下结论:

1、第一行的a,b,c,d,e用来决定新的颜色值中的R的值(红色)---a,b,c,d为系数,e则为偏移量(offset),若a=1;b,c,d都为0,e为任意值(0-N),这就可以的得到:R1=R+e(若e=0,则R1=R),那就得出了,影响单个红色变化的有两个因素:一个是系数a,另一个则是偏移量(offset)e.所以当我们想控制单个红色的值话就可以从控制这两个变量值即可。a的系数取值范围为( -1 到 2之间),e为偏移量,当我的a系数定了后,其他的b,c,d参数为0,当修改e的值后就会改变红色这个单个颜色的深浅程度,可以这样理解前面几个系数(a,b,c,d)用来配色的,而e后面偏移量则是用来控制颜色整体的深浅程度的

2、第二行f,g,h,i,j用来决定新的颜色值中的G的值(绿色)---f,g,h,i,j为系数,j则为偏移量(offset),若f=1;g,h,i都为0,j为任意值(0-N),这就可以的得到:G1=G+j(若j=0,则G1=G),那就得出了,影响单个绿色变化的有两个因素:一个是系数f,另一个则是偏移量(offset)j.所以当我们想控制单个绿色的值话就可以从控制这两个变量值即可。f的系数取值范围为( 0到 2之间),j为偏移量,当我的f系数定了后,其他的g,h,i参数为0,当修改j的值后就会改变绿色这个单个颜色的深浅程度,可以这样理解前面几个系数(f,g,h,i)用来配色的,而j后面偏移量则是用来控制颜色整体的深浅程度的

3、第三行的k,l,m,n,o用来决定新的颜色值中的B的值(蓝色)---k,l,m,n为系数o则为偏移量(offset),若k=1;l,m,n都为0,o为任意值(0-N),这就可以的得到:B1=B+o(若o=0,则B1=B),那就得出了,影响单个蓝色变化的有两个因素:一个是系数k,另一个则是偏移量(offset)o.所以当我们想控制单个蓝色的值话就可以从控制这两个变量值即可。k的系数取值范围为( 0到 2之间),o为偏移量,当我的k系数定了后,其他的l,m,n参数为0,当修改o的值后就会改变蓝色这个单个颜色的深浅程度,可以这样理解前面几个系数(k,l,m,n)用来配色的,而o后面偏移量则是用来控制颜色整体的深浅程度的

4、第四行的p,q,r,s,t用来决定新的颜色值中的A的值(透明度)---p,q,r,s为系数,t则为偏移量(offset),若p=1;q,r,s都为0,t为任意值(0-N),这就可以的得到:A1=A+t(若t=0,则A1=A),那就得出了,影响单个透明度变化的有两个因素:一个是系数p,另一个则是偏移量(offset)t.所以当我们想控制单个透明度的值话就可以从控制这两个变量值即可。a的系数取值范围为( 0 到 2之间),t为偏移量.

知道以上的各个参数的意思,那么接下来我们就可以写一个简单的demo来实验一下了。

package com.mikyou.imagecolor;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;


public class MainActivity extends Activity implements OnSeekBarChangeListener{
	private ImageView iv;
	private SeekBar redBar,greenBar,blueBar,alphaBar;
	private Canvas canvas;
	private Bitmap copyBitmap;
	private Bitmap baseBitmap;
	private Paint paint;
	private float redValue,greenValue,blueValue,alphaValue;//这些值都是通过SeekBar移动过程中而得到的变化的值
	//定义一个颜色矩阵,主要通过第一种方式改变颜色系数,来达到修改图片的颜色。
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();

	}

	private void initView() {
		iv=(ImageView) findViewById(R.id.iv);		
		redBar=(SeekBar) findViewById(R.id.red);
		greenBar=(SeekBar) findViewById(R.id.green);
		blueBar=(SeekBar) findViewById(R.id.blue);
		alphaBar=(SeekBar) findViewById(R.id.alpha);
		redBar.setOnSeekBarChangeListener(this);
		greenBar.setOnSeekBarChangeListener(this);
		blueBar.setOnSeekBarChangeListener(this);
		alphaBar.setOnSeekBarChangeListener(this);
	}
	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
		if (fromUser) {
			float count=seekBar.getProgress()/50f;//因为使得拖动条的取值为0f-2f,符合矩阵中每个元素的取值
			switch (seekBar.getId()) {
			case R.id.red:
				this.redValue=count;
				break;
			case R.id.green:
				this.greenValue=count;
				break;
			case R.id.blue:
				this.blueValue=count;
				break;
			case R.id.alpha:
				this.alphaValue=count;
				break;
			default:
				break;
			}
			initBitmap();
		}
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {

	}
	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {

	}

	private void initBitmap() {
		//先加载出一张原图(baseBitmap),然后复制出来新的图片(copyBitmap)来,因为andorid不允许对原图进行修改.
		baseBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.pre);	
		//既然是复制一张与原图一模一样的图片那么这张复制图片的画纸的宽度和高度以及分辨率都要与原图一样,copyBitmap就为一张与原图相同尺寸分辨率的空白画纸
		copyBitmap=Bitmap.createBitmap(baseBitmap.getWidth(), baseBitmap.getHeight(), baseBitmap.getConfig());
		canvas=new Canvas(copyBitmap);//将画纸固定在画布上
		paint=new Paint();//实例画笔对象
		float[] colorArray=new float[]{
				redValue,0,0,0,0,
				0,greenValue,0,0,0,
				0,0,blueValue,0,0,
				0,0,0,alphaValue,0
		};
		ColorMatrix colorMatrix=new ColorMatrix(colorArray);//将保存的颜色矩阵的数组作为参数传入
		ColorMatrixColorFilter colorFilter=new ColorMatrixColorFilter(colorMatrix);//再把该colorMatrix作为参数传入来实例化ColorMatrixColorFilter
		paint.setColorFilter(colorFilter);//并把该过滤器设置给画笔
		canvas.drawBitmap(baseBitmap, new Matrix(), paint);//传如baseBitmap表示按照原图样式开始绘制,将得到是复制后的图片
		iv.setImageBitmap(copyBitmap);
	}
}

运行结果:


以上方式就是通过第一种改变颜色系数方式来改变颜色,那么接下来通过些简单修改代码,通过他们各个颜色的偏移量来修改颜色。

package com.mikyou.imagecolor;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;


public class MainActivity extends Activity implements OnSeekBarChangeListener{
	private ImageView iv;
	private SeekBar redBar,greenBar,blueBar,alphaBar;
	private Canvas canvas;
	private Bitmap copyBitmap;
	private Bitmap baseBitmap;
	private Paint paint;
	private float redValueOffset,greenValueOffset,blueValueOffset,alphaValueOffset;//这些值都是通过SeekBar移动过程中而得到的变化的值
	//定义一个颜色矩阵,主要通过第一种方式改变颜色系数,来达到修改图片的颜色。
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();

	}

	private void initView() {
		iv=(ImageView) findViewById(R.id.iv);		
		redBar=(SeekBar) findViewById(R.id.red);
		greenBar=(SeekBar) findViewById(R.id.green);
		blueBar=(SeekBar) findViewById(R.id.blue);
		alphaBar=(SeekBar) findViewById(R.id.alpha);
		redBar.setOnSeekBarChangeListener(this);
		greenBar.setOnSeekBarChangeListener(this);
		blueBar.setOnSeekBarChangeListener(this);
		alphaBar.setOnSeekBarChangeListener(this);
	}
	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
		if (fromUser) {
			float count=seekBar.getProgress();//因为使得拖动条的取值为0f-100f,符合矩阵中元素的偏移量取值
			switch (seekBar.getId()) {
			case R.id.red:
				this.redValueOffset=count;
				break;
			case R.id.green:
				this.greenValueOffset=count;
				break;
			case R.id.blue:
				this.blueValueOffset=count;
				break;
			case R.id.alpha:
				this.alphaValueOffset=count;
				break;
			default:
				break;
			}
			initBitmap();
		}
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {

	}
	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {

	}

	private void initBitmap() {
		//先加载出一张原图(baseBitmap),然后复制出来新的图片(copyBitmap)来,因为andorid不允许对原图进行修改.
		baseBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.pre);	
		//既然是复制一张与原图一模一样的图片那么这张复制图片的画纸的宽度和高度以及分辨率都要与原图一样,copyBitmap就为一张与原图相同尺寸分辨率的空白画纸
		copyBitmap=Bitmap.createBitmap(baseBitmap.getWidth(), baseBitmap.getHeight(), baseBitmap.getConfig());
		canvas=new Canvas(copyBitmap);//将画纸固定在画布上
		paint=new Paint();//实例画笔对象
		float[] colorArray=new float[]{
				1,0,0,0,redValueOffset,
				0,1,0,0,greenValueOffset,
				0,0,1,0,blueValueOffset,
				0,0,0,1,alphaValueOffset
		};
		ColorMatrix colorMatrix=new ColorMatrix(colorArray);//将保存的颜色矩阵的数组作为参数传入
		ColorMatrixColorFilter colorFilter=new ColorMatrixColorFilter(colorMatrix);//再把该colorMatrix作为参数传入来实例化ColorMatrixColorFilter
		paint.setColorFilter(colorFilter);//并把该过滤器设置给画笔
		canvas.drawBitmap(baseBitmap, new Matrix(), paint);//传如baseBitmap表示按照原图样式开始绘制,将得到是复制后的图片
		iv.setImageBitmap(copyBitmap);
	}
}

运行效果:



细心的人会发现第二种方式和第一种是不一样的。第二种在原图基础上修改颜色的偏移量。而第一种要达到原图效果都得通过三种颜色搭配出来,所以第一种更加灵活。而第二种就更像我用手机拍了一张图片在基础上修改图片风格。

其实,除了自己去修改那个颜色矩阵外,android官方还给出一些调整图片的色光属性封装的API,主要用于修改色调(setRotate)、饱和度(setSaturation)、亮度(setScale)

1、修改色调的API(setRotate)

colorMatrix.setRotate(axis, degrees);//第一参数可传入:0,1,2(0,1,2分别代表red,green,blue三种颜色的处理),第二个就是需要处理的值

    colorMatrix.setRotate(0, redValueOffset);//0代表红色,redValueOffset表示需要对红色处理的值
colorMatrix.setRotate(1, greenValueOffset);//1代表绿色,greenValueOffset表示需要对绿色处理的值
colorMatrix.setRotate(2, blueValueOffset);//2代表蓝色,blueValueOffset表示需要对蓝色处理的值

2、修改色调API(setSaturation)注意:当饱和度的颜色变为0的时候图片就变为灰色的图片了

3、修改亮度的API(setScale)当三原色如果是以相同的比例混合的话,就会显示出白色。系统也就是根据这些原理来修改一个图像的亮度的。当亮度为0,图像就变黑了。

4、然后还有一个很重要的API,可以使用postConcat()方法将矩阵作用效果混合在一起,从而形成叠加的效果

具体用用法我们也通过一个demo来说明:

package com.mikyou.imagecolor;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;


public class MainActivity extends Activity implements OnSeekBarChangeListener{
	private ImageView iv;
	private SeekBar colorBar,baoheBar,lightBar;
	private Canvas canvas;
	private Bitmap copyBitmap;
	private Bitmap baseBitmap;
	private Paint paint;
	private float colorValue,baoheValue,lightValue;//这些值都是通过SeekBar移动过程中而得到的变化的值
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
	}

	private void initView() {
		iv=(ImageView) findViewById(R.id.iv);		
		colorBar=(SeekBar) findViewById(R.id.color);
		baoheBar=(SeekBar) findViewById(R.id.baohe);
		lightBar=(SeekBar) findViewById(R.id.light);
		colorBar.setOnSeekBarChangeListener(this);
		baoheBar.setOnSeekBarChangeListener(this);
		lightBar.setOnSeekBarChangeListener(this);
	}
	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
		if (fromUser) {
			float count=seekBar.getProgress()/50f;//因为使得拖动条的取值为0f-2f,符合矩阵中元素的偏移量取值
			switch (seekBar.getId()) {
			case R.id.color:
				this.colorValue=count;
				break;
			case R.id.baohe:
				this.baoheValue=count;
				break;
			case R.id.light:
				this.lightValue=count;
				break;
			default:
				break;
			}
			initBitmap();
		}
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {

	}
	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {

	}

	private void initBitmap() {
		//先加载出一张原图(baseBitmap),然后复制出来新的图片(copyBitmap)来,因为andorid不允许对原图进行修改.
		baseBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.pre);	
		//既然是复制一张与原图一模一样的图片那么这张复制图片的画纸的宽度和高度以及分辨率都要与原图一样,copyBitmap就为一张与原图相同尺寸分辨率的空白画纸
		copyBitmap=Bitmap.createBitmap(baseBitmap.getWidth(), baseBitmap.getHeight(), baseBitmap.getConfig());
		canvas=new Canvas(copyBitmap);//将画纸固定在画布上
		paint=new Paint();//实例画笔对象
		ColorMatrix mColorMatrix=new ColorMatrix();
		//设置色调
		mColorMatrix.setRotate(0, colorValue);
		mColorMatrix.setRotate(1, colorValue);
		mColorMatrix.setRotate(2, colorValue);
		//设置饱和度
		ColorMatrix mBaoheMatrix=new ColorMatrix();
		mBaoheMatrix.setSaturation(baoheValue);
		//设置亮度:		colorMatrix.setScale(rScale, gScale, bScale, aScale)//第一个参数表示:红色第二个表示绿色,第三个表示蓝色,第四个表示透明度
		//当三原色如果是以相同的比例混合的话,就会显示出白色。系统也就是根据这些原理来修改一个图像的亮度的。当亮度为0,图像就变黑了。
		//所以他们比例一样
		ColorMatrix mLightMatrix=new ColorMatrix();
		mLightMatrix.setScale(lightValue, lightValue, lightValue, 1);
		//再创建组合的ColorMatrix对象将上面三种ColorMatrix的效果混合在一起
		ColorMatrix mImageViewMatrix=new ColorMatrix();
		mImageViewMatrix.postConcat(mColorMatrix);
		mImageViewMatrix.postConcat(mBaoheMatrix);
		mImageViewMatrix.postConcat(mLightMatrix);
		
		ColorMatrixColorFilter colorFilter=new ColorMatrixColorFilter(mImageViewMatrix);//再把该mImageViewMatrix作为参数传入来实例化ColorMatrixColorFilter
		paint.setColorFilter(colorFilter);//并把该过滤器设置给画笔
		canvas.drawBitmap(baseBitmap, new Matrix(), paint);//传如baseBitmap表示按照原图样式开始绘制,将得到是复制后的图片
		iv.setImageBitmap(copyBitmap);
	}
}

运行效果:



通过上面一系列的demo相信你应该对ColorMatrix有了一定的认识了吧,其实写到这里我们完全可以做一个类似美颜处理的APP,当然这只是一个整体的思路,中间还有很多的细节需要去完善。我们现在都知道改变颜色矩阵的系数就能达到一种意想不到的图片风格,比如什么温暖色调,复古色调,浪漫色调等等。无非是每种色调的颜色矩阵的系数不一样而已。

下面就给出常见的几种色调的颜色矩阵,并附上相应的Demo图

//几种常见的颜色矩阵:
//1、灰度效果
/* private float[] colorArray=new float[]{
0.33f,0.59f,0.11f,0,0,
0.33f,0.59f,0.11f,0,0,
0.33f,0.59f,0.11f,0,0,
0,0,0,1,0

};*/


//2、图片反转效果
/*private float[] colorArray=new float[]{
-1,0,0,1,1,
0,-1,0,1,1,
0,0,-1,1,1,
0,0,0,1,0

};*/


//3\怀旧效果
/* private float[] colorArray=new float[]{
0.393f,0.769f,0.189f,0,0,
0.349f,0.686f,0.168f,0,0,
0.272f,0.543f,0.131f,0,0,
0,0,0,1,0

};*/


//4\去色效果
/* private float[] colorArray=new float[]{
1.5f,1.5f,1.5f,0,-1,
1.5f,1.5f,1.5f,0,-1,
1.5f,1.5f,1.5f,0,-1,
0,0,0,1,0

};*/


//5\高饱和度效果
private float[] colorArray=new float[]{
1.438f,-0.122f,-0.016f,0,-0.03f,
-0.062f,1.378f,-0.016f,0,0.05f,
-0.062f,-0.122f,1.483f,0,-0.02f,
0,0,0,1,0
};


其实,上面所讲那些方法来修改一张图片的颜色,其实还有一种更为精确的方式,那就是针对每个像素点进行分析,就是通过改变每个像素点的具体ARGB的值来达到整张图片的颜色值修改的目的。但是需要注意我们还是不能在原图上修改,必须通过复制一张原图,然后在复制的图上进行修改即可。

主要是通过原图的bitmap中的一个getPiexs方法获得一张图片的所有像素点,然后将这些像素点保存在一个数组中,然后再去遍历这个数组取出每一个像素点,并按一定算法修改他们的ARGB值,然后通过Color.argb(a, r, g, b);得到新的数组,最后把这个产生的新数组设置到我们的复制的Bitmap中,注意最后绘制的时候,是传入复制的Bitmap对象

因为很容易理解,因为我把原图的像素点的修改后ARGB值都设置给复制的Bitmap,这张图其实也就确定了,只是还没画出来而已。

代码如下:

package com.mikyou.imagecolor;

import android.R.integer;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;


public class MainActivity extends Activity{
	private ImageView iv;
	private Canvas canvas;
	private Bitmap copyBitmap;
	private Bitmap baseBitmap;
	private Paint paint;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
		initBitmap();
	}
	private void initView() {
		iv=(ImageView) findViewById(R.id.iv);		
	}
	private void initBitmap() {
		//先加载出一张原图(baseBitmap),然后复制出来新的图片(copyBitmap)来,因为andorid不允许对原图进行修改.
		baseBitmap=BitmapFactory.decodeResource(getResources(), R.drawable.pre);
		copyBitmap=handleImageByPiex(baseBitmap);
		canvas=new Canvas(copyBitmap);//将画纸固定在画布上
		paint=new Paint();//实例画笔对象
		canvas.drawBitmap(copyBitmap, new Matrix(), paint);//传如copyBitmap因为我已经取到了原图的所有像素点,并把他们设置到copyBitmap中
		//所以现在只需要将他画出即可
		iv.setImageBitmap(copyBitmap);
	}
	
	//通过针对控制每个像素点ARGB方式来实现颜色控制
	//主要是通过getPixels方法得到所有的像素点,
	//第一个参数是用于接收像素点的数组
	//第二个参数是写入到数组中的第一个像素的下标
	//第三个参数是数组的中行间距
	//第四,五个表示读取第一个像素的坐标(x,y)
	//第六、width表示从每一行中读取中读取的像素宽度
	//第七、height表示读取的行数
	private Bitmap  handleImageByPiex(Bitmap baseBitmap2) {
		int width=baseBitmap2.getWidth();
		int height=baseBitmap2.getHeight();
		int color,r,g,b,a;
		int [] oldPixels=new int[width*height];
		int [] newPixels=new int[width*height];
		Bitmap myCopyBitmap=Bitmap.createBitmap(baseBitmap2.getWidth(), baseBitmap2.getHeight(), baseBitmap2.getConfig());
		baseBitmap2.getPixels(oldPixels, 0, width, 0, 0, width, height);
		//然后就去遍历这个数组oldPixels,并取出每个像素,然后再取出每个像素的ARGB属性,然后通过想修改ARGB属性,得到新的像素点
		//并把新的像素点保存新的数组newPixels中
		for (int i = 0; i < width*height; i++) {
			color=oldPixels[i];//取出每一个像素点
			r=Color.red(color);//取出当前像素点的R值
			g=Color.green(color);//取出当前像素点的G值
			b=Color.blue(color);////取出当前像素点的B值
			a=Color.alpha(color);////取出当前像素点的A值
			//然后通过相应的算法,重新修改这些值,并把最后的每个像素点保存到新的数组中
			//不同的效果对应着不同的算法:
/*			//1、底片效果
			B.r=255-B.r;
			 * B.g=255-B.g;
			 * B.b=255-B.b;
			 * 
			r=255-r;
			g=255-g;
			b=255-b;
			if (r>255) {
				r=255;
			}else if (r<0) {
				r=0;
			}
			if (g>255) {
				g=255;
			}else if (g<0) {
				g=0;
			}
			if (b>255) {
				b=255;
			}else if (b<0) {
				b=0;
			}*/
			/*老照片效果*/
			r=(int)(0.393*r+0.769*g+0.189*b);
			g=(int)(0.349*r+0.686*g+0.168*b);
			b=(int)(0.272*r+0.534*g+0.131*b);
			newPixels[i]=Color.argb(a, r, g, b);
		}
		myCopyBitmap.setPixels(newPixels, 0, width, 0, 0, width, height);
		return myCopyBitmap;
	}
}

运行结果:

底片效果:


老照片效果:


最后有关图片的色彩的处理就到了,其实学到这里真的可以根据自己思维去写一个有关美颜图片的app

所有Demo的下载链接

阅读更多

扫码向博主提问

mikyou

博客专家

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • Kotlin
  • Android
  • Java
去开通我的Chat快问

没有更多推荐了,返回首页