Android圖像處理(二)--Paint,Canvas,ColorMatrix詳細

android開發中可能常常會用到這些東西;html

一.介紹java

Paint:畫筆android

Canvas:畫布算法

Matrix:變換矩陣canvas

  1. Paint數組

    根據咱們要畫的類型,咱們能夠選擇不一樣的筆,好比大氣磅礴的山水畫,咱們能夠選擇大頭的毛筆;細膩入微的肖像畫咱們能夠選擇尖頭的鉛筆。而且根據咱們想要的效果,咱們在繪畫的時候,還會選擇不一樣的顏料或不一樣顏色的筆;app

    那麼在程序中,Paint 就足以知足以上全部的須要,咱們能夠根據咱們本身的須要去自行設置咱們畫筆的屬性,首先來看看都能設置哪些屬性:ide

Public Constructors











Paint()

Create a new paint with default settings.佈局












Paint(int flags)

Create a new paint with the specified flags.好比ANTI_ALIAS_FLAG,抗鋸齒post












Paint(Paint paint)

Create a new paint, initialized with the attributes in the specified paint parameter.











方法經常使用的主要有如下一些:

setARGB (int a, int r, int g, int b):用於設置畫筆顏色,A 表明 alpha(透明度),R 表明Red (紅色),G 表明 Green(綠色),B 表明 Blue(藍色)

色值採用16進制,取值在 0 - 255 之間 ,0(0x00) 即 徹底沒有 ,255(0xff) 表明滿值 ;

setAlpha(int a): 用於設置Paint 的透明度;

setColor(int color):一樣設置顏色,若是是經常使用色,可使用Color 類中定義好的一些色值 ,eg:Color.WHITE

setColorFilter(ColorFilter filter):設置顏色過濾器,能夠經過顏色過濾器過濾掉對應的色值,好比去掉照片顏色,生成老照片效果;

ColorFilter有如下幾個子類可用:

ColorMatrixColorFilter

LightingColorFilter

PorterDuffColorFilter

Known Direct Subclasses

ColorMatrixColorFilter A color filter that transforms colors through a 4x5 color matrix. 
LightingColorFilter A color filter that can be used to simulate simple lighting effects. 
PorterDuffColorFilter A color filter that can be used to tint the source pixels using a single color and a specific Porter-Duff composite mode

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是顏色的偏移量。

  一般,改變顏色份量時能夠經過修改第5列的顏色偏移量來實現,如上面所示的顏色矩陣,經過計算後能夠得知該顏色矩陣的做用是使圖像的紅色份量和綠色份量均增長100,這樣的效果就是圖片泛黃(由於紅色與綠色混合後獲得黃色):


除此以外,也能夠經過直接對顏色值乘以某一系數而達到改變顏色份量的目的。以下圖所示的顏色矩陣,將綠色份量放大了2倍,這樣的效果就是圖片泛綠色:


基於此,咱們利用ColorFilter 和 ColorMatrixColorFilter類 和 Paint 的setColorFilter 就能夠改變圖片的展現效果(顏色,飽和度,對比度等),從而獲得相似市面上圖像軟件中的黑白老照片、泛黃舊照片、羞澀的青春... ...特效;


     

                                  (原圖效果)                         (調節效果)

二.第二部分

接下來,咱們就用colorMatrix

效果圖以下

咱們上面放一張圖片, 下面放20個editText, 表明咱們的ColorMatrix, 咱們就用這個矩陣去處理圖像

首先把第一行最後一個設置100, 就是把紅色的偏移量增長100, 效果以下

而後,再把第二行第二個, 1變成2,也就是把綠色變成原來的兩倍, 效果以下

接下來是咱們的佈局,

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical"
	android:layout_width="match_parent"
	android:layout_height="match_parent">

	<ImageView
	    android:id="@+id/imageview"
	    android:layout_width="match_parent"
	    android:layout_weight="2"
	    android:layout_height="0dp" />
	
	<GridLayout
	    android:id="@+id/group"
	    android:layout_width="match_parent"
	    android:layout_weight="3"
	    android:layout_height="0dp"
	    android:rowCount="4"
	    android:columnCount="5">
	</GridLayout>
	
	<LinearLayout
	    android:layout_width="match_parent"
	    android:layout_height="wrap_content"
	    android:orientation="horizontal">
	
	    <Button
	        android:layout_width="0dp"
	        android:layout_height="wrap_content"
	        android:layout_weight="1"
	        android:text="Change"
	        android:onClick="btnChange" />
	
	    <Button
	        android:layout_width="0dp"
	        android:layout_height="wrap_content"
	        android:layout_weight="1"
	        android:text="Reset"
	        android:onClick="btnReset" />
	</LinearLayout>

</LinearLayout>

只是放了一個GridLayout,editText咱們在代碼裏面添加

由於在添加的時候, 要獲取GridLayout的寬和高,才能知道添加editText的時候的大小, 可是咱們在oncreate的時候, 咱們的控件是沒有畫完的, 咱們該如何去獲取GridLayout的寬和高呢, 在API裏面看到這個post,在控件畫完的時候, 就執行post裏的runnable,就能夠去添加editText了

mGroup.post(new Runnable()
		{

			@Override
			public void run()
			{
				// TODO Auto-generated method stub
				mEditWidth = mGroup.getWidth() / 5;
				mEditHeight = mGroup.getHeight() / 4;
				// 添加20個控件
				addEditTexts();
				// 初始化矩陣
				initMatrix();
			}

		});

整個代碼以下

package com.example.imageprocess;

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.Paint;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.EditText;
import android.widget.GridLayout;
import android.widget.ImageView;

public class ColorMatrixActivity extends Activity
{

	private ImageView mImageView;// 圖片
	private GridLayout mGroup;// 存放20個editText
	private Bitmap bitmap;
	private int mEditWidth, mEditHeight;// 每一個editText的寬和高
	private EditText[] mEdits = new EditText[20];
	private float[] mColorMatrix = new float[20];

	protected void onCreate(Bundle savedInstanceState)
	{
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_color_matrix);

		// 先設置imageview 的現實的圖片
		bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test1);

		mImageView = (ImageView) findViewById(R.id.imageview);
		mImageView.setImageBitmap(bitmap);// 設置圖片

		mGroup = (GridLayout) findViewById(R.id.group);

		// 由於在oncreate的時候 控件是沒有畫完的 因此 用post
		// 等加載完了 就調用post方法 加載20個edittext
		mGroup.post(new Runnable()
		{

			@Override
			public void run()
			{
				// TODO Auto-generated method stub
				mEditWidth = mGroup.getWidth() / 5;
				mEditHeight = mGroup.getHeight() / 4;
				// 添加20個控件
				addEditTexts();
				// 初始化矩陣
				initMatrix();
			}

		});

	}

	public void btnChange(View view)
	{
		getMatrix();
		setImageMatrix();

	}

	public void btnReset(View view)
	{
		initMatrix();
		getMatrix();
		setImageMatrix();
	}

	private void setImageMatrix()
	{
		Bitmap bmp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
		ColorMatrix colorMatrix = new ColorMatrix();
		colorMatrix.set(mColorMatrix);

		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);
	}

	/**
	 * 初始化矩陣
	 */
	private void initMatrix()
	{
		// TODO Auto-generated method stub
		for (int i = 0; i < 20; i++)
		{
			if (i % 6 == 0)
			{
				mEdits[i].setText(String.valueOf(1));
			}
			else
			{
				mEdits[i].setText(String.valueOf(0));
			}
		}
	}

	/**
	 * 獲得圖像矩陣 0 0 0 0 0 R // 0 0 0 0 0 G /// 0 0 0 0 0 B // 0 0 0 0 0 A //
	 */
	private void getMatrix()
	{
		for (int i = 0; i < 20; i++)
		{
			mColorMatrix[i] = Float.valueOf(mEdits[i].getText().toString());
		}
	}

	/**
	 * 往GridLayout裏面添加20個edittext
	 */
	private void addEditTexts()
	{
		for (int i = 0; i < 20; i++)
		{
			EditText editText = new EditText(ColorMatrixActivity.this);
			mEdits[i] = editText;
			mGroup.addView(editText, mEditWidth, mEditHeight);
		}
	}

}

其實也只是把上一篇中用到的colorMatrix替換成咱們本身的而已,可見, API給咱們提供的ColorMatrix跟咱們的矩陣是同樣的, 請看下圖

三.第三部分

OK. 接下來咱們真正要用到咱們的矩陣了,用矩陣去處理像素點

如圖, 這要對咱們的蒼老師進行以下三種圖像處理:底片效果,老照片效果, 浮雕效果

先說一下各個效果的算法吧,

1. * @底片效果

* @ABC三個像素點

* @求B點的底片效果的算法那

* @B.r = 255 - B.r

* @B.g = 255 - B.g

* @B.b = 255 - B.b


2. * 老照片效果

* @r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b);

* @g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b);

* @b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b);


3. * 浮雕效果

* @ABC

* @求B點浮雕效果算法

* @B.r = C.r - B.r + 127

* @B.g = C.g - B.g + 127

* @B.b = C.b - B.b + 127


用代碼來講說第一個底片效果的思想

/**
	 * @底片效果
	 * @ABC三個像素點
	 * @求B點的底片效果的算法那
	 * @B.r = 255 - B.r
	 * @B.g = 255 - B.g
	 * @B.b = 255 - B.b
	 * @param bm
	 * @return
	 */
	public static Bitmap handleImageNegative(Bitmap bm)
	{
		int width = bm.getWidth();
		int height = bm.getHeight();
		int color;
		int r, g, b, a;

		Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

		int[] oldPx = new int[width * height];
		int[] newPx = new int[width * height];

		bm.getPixels(oldPx, 0, width, 0, 0, width, height);

		for (int i = 0; i < width * height; i++)
		{
			// 取出圖片中各個像素點
			color = oldPx[i];
			// 每一個像素點又是 r g b a合成的
			// 因此下面就是用像素點pixel 去獲得r g b a
			r = Color.red(color);
			g = Color.green(color);
			b = Color.blue(color);
			a = Color.alpha(color);

			// 用算法去實現底片效果
			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;
			}

			// 求得的底片效果的像素點 給新的數組
			newPx[i] = Color.argb(a, r, g, b);
		}
		bmp.setPixels(newPx, 0, width, 0, 0, width, height);

		return bmp;
	}

我以爲代碼說得比我說得清楚多了,我就很少說了.

其餘兩種呢, 這裏也貼出來

老照片效果

public static Bitmap handleImagePixelsOldPhoto(Bitmap bm)
	{
		int width;
		int height;
		int color = 0;
		int a, r, g, b, r1, g1, b1;

		width = bm.getWidth();
		height = bm.getHeight();

		int[] oldPx = new int[width * height];
		int[] newPx = new int[width * height];

		Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

		bm.getPixels(oldPx, 0, width, 0, 0, width, height);

		for (int i = 0; i < width * height; i++)
		{
			color = oldPx[i];
			a = Color.alpha(color);
			r = Color.red(color);
			g = Color.green(color);
			b = Color.green(color);

			r1 = (int) (0.393 * r + 0.769 * g + 0.189 * b);
			g1 = (int) (0.349 * r + 0.686 * g + 0.168 * b);
			b1 = (int) (0.272 * r + 0.534 * g + 0.131 * b);
			if (r1 > 255)
			{
				r1 = 255;
			}
			if (g1 > 255)
			{
				g1 = 255;
			}
			if (b1 > 255)
			{
				b1 = 255;
			}

			newPx[i] = Color.argb(a, r1, g1, b1);

		}

		bitmap.setPixels(newPx, 0, width, 0, 0, width, height);

		return bitmap;
	}
	
	
	
		/**
	 * 浮雕效果
	 * 
	 * @ABC
	 * @求B點浮雕效果算法
	 * @B.r = C.r - B.r + 127
	 * @B.g = C.g - B.g + 127
	 * @B.b = C.b - B.b + 127
	 * @param bm
	 * @return
	 */
	public static Bitmap handleImagePixelsRelief(Bitmap bm)
	{
		int width = bm.getWidth();
		int height = bm.getHeight();

		int[] oldPx = new int[width * height];
		int[] newPx = new int[width * height];

		int color = 0;

		int a, r, g, b;
		int r1, g1, b1;
		int colorAfter;

		Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
		bm.getPixels(oldPx, 0, width, 0, 0, width, height);
		// 下標從1開始
		for (int i = 0; i < width * height - 1; i++)
		{

			color = oldPx[i];
			a = Color.alpha(color);
			r1 = Color.red(color);
			g1 = Color.green(color);
			b1 = Color.blue(color);

			colorAfter = oldPx[i + 1];
			r = Color.red(colorAfter);
			g = Color.green(colorAfter);
			b = Color.blue(colorAfter);

			r1 = r - r1 + 127;
			g1 = g - g1 + 127;
			b1 = b - b1 + 127;

			if (r1 > 255)
			{
				r1 = 255;
			}
			if (g1 > 255)
			{
				g1 = 255;
			}
			if (b1 > 255)
			{
				b1 = 255;
			}
			newPx[i] = Color.argb(a, r1, g1, b1);
		}
		bitmap.setPixels(newPx, 0, width, 0, 0, width, height);
		return bitmap;

	}


!!!!!!不知道爲何, 圖片保存失敗了, 我也不知道源碼如何上傳,  真是失敗,算了 今天就到這裏, 比較累了

相關文章
相關標籤/搜索