1. 程式人生 > >淺談android中圖片處理之色彩特效處理ColorMatrix(三)

淺談android中圖片處理之色彩特效處理ColorMatrix(三)

在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