最近在系統學習了android的圖像處理(在網上搜集了一些資料並自己編寫了測試程序,做了整理),現在這里做一總結:
一、ColorMatrix類
ColorMatrix是一個5x4階的矩陣 在下面表示為A,第一行表示R紅色分量,第二行表示G綠色分量,第三行表示B藍色分量,第四行表示透明度:

用一維數組的存儲方式如下: [ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ],
顏色矩陣和顏色分量相乘之后得到新的顏色如下:
R‘ = a*R + b*G + c*B + d*A + e; //紅色分量
G' = f*R + g*G + h*B + i*A + j; //綠色分量
B' = k*R + l*G + m*B + n*A + o; //藍色分量
A' = p*R + q*G + r*B + s*A + t; //透明度
/**
* Set the rotation on a color axis by the specified values.
* axis=0 correspond to a rotation around the RED color
* axis=1 correspond to a rotation around the GREEN color
* axis=2 correspond to a rotation around the BLUE color
*/
public void setRotate(int axis, float degrees) {
reset();
float radians = degrees * (float)Math.PI / 180;
float cosine = FloatMath.cos(radians);
float sine = FloatMath.sin(radians);
switch (axis) {
// Rotation around the red color
case 0:
mArray[6] = mArray[12] = cosine;
mArray[7] = sine;
mArray[11] = -sine;
break;
// Rotation around the green color
case 1:
mArray[0] = mArray[12] = cosine;
mArray[2] = -sine;
mArray[10] = sine;
break;
// Rotation around the blue color
case 2:
mArray[0] = mArray[6] = cosine;
mArray[1] = sine;
mArray[5] = -sine;
break;
default:
throw new RuntimeException();
}
}
對應的api為setScale(1,2,1,1);這個函數實際對應設置的是顏色矩陣對角線上的值。
private void useColorMatrix(Canvas canvas,Paint paint) {
// TODO Auto-generated method stub
//清除畫筆的顏色過濾
paint.setColorFilter(null);
cmatrix = new ColorMatrix();
cmatrix.set(carrycolor);
// cmatrix.reset();
// cmatrix.setSaturation(0F);
// cmatrix.setRotate(0, 100);
// cmatrix.setScale(2, 2, 2, 2);
//設置顏色矩陣過濾器
paint.setColorFilter(new ColorMatrixColorFilter(cmatrix));
canvas.drawBitmap(bitmap, 0,0, paint);
}


這個矩陣的作用是對坐標x,y進行變換計算結果如下:
x'=a*x+b*y+c
y'=d*x+e*y+f
x放大a倍,y放大b倍,
x方向的平移量為△x,y方向的平移量為△y,那么,點P(x,y)的坐標為:
x = x0 + △x
y = y0 + △y
先移動再放大用的是矩陣的乘法如A*B。
圖像的旋轉稍微復雜:現設點P0(x0, y0)繞原點旋轉θ角后的對應點為P(x, y)。通過使用向量,我們得到如下,r為旋轉半徑:
x0 = r cosα
y0 = r sinα
x = r cos(α+θ) = x0 cosθ - y0 sinθ (三角函數展開然后變量替換)
y = r sin(α+θ) = x0 sinθ + y0 cosθ
圖像的鏡像,分為2種:水平鏡像、垂直鏡像。先介紹如何實現垂直鏡像,什么是垂直鏡像就不詳細說明。圖像的垂直鏡像變化也可以用矩陣變化的表示,
設點P0(x0 ,y0 )進行鏡像后的對應點為P(x ,y ),圖像的高度為fHeight,寬度為fWidth,原圖像中的P0(x0 ,y0 )經過垂直鏡像后的坐標變為(x0 ,2*fHeight- y0);
x = x0 垂直鏡像后x坐標不變
y = fHeight – y0 垂直鏡像后相當與先將圖像繞x軸旋轉180度,再將圖像向下平移兩個圖像的高度,所以先y=-y0;然后再加2倍高度
推導出相應的矩陣是:
final float f[] = {1.0F,0.0F,0.0F,0.0F,-1.0F,120.0F,0.0F,0.0F,1.0F};
Matrix matrix = new Matrix();
matrix.setValues(f);
代碼如下:
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
Paint paint = mPaint;
// useColorMatrix(canvas,paint);
matrix = new Matrix();
matrix.setValues(carrypos);
paint.setColorFilter(null);
canvas.drawBitmap(bitmap,matrix,paint); // you can setColorFilter(null);
carrypos[5] = 2*bitmap.getHeight(); //設置y坐標移動
carrypos[4] = -1; //設置繞x軸轉180度
matrix.setValues(carrypos);
canvas.drawBitmap(bitmap, matrix, paint);
}
按照上述方法運行后的結果:

實際上,使用下面的方式也可以實現垂直鏡像:
Matrix matrix = new Matrix();
matrix.setScale (1.0,-1.0);
matrix.postTraslate(0,2* fHeight);
Matrix學習——圖像的復合變化
如果圖像圍繞着某個點P(a,b)旋轉,則先要將坐標系平移到該點,再進行旋轉,然后將旋轉后的圖像平移回到原來的坐標原點。
我們需要3步:
1. 平移——將坐標系平移到點P(a,b);
2. 旋轉——以原點為中心旋轉圖像;
3. 平移——將旋轉后的圖像平移回到原來的坐標原點;
相比較前面說的圖像的幾何變化(基本的圖像幾何變化),這里需要平移——旋轉——平移,這種需要多種圖像的幾何變化就叫做圖像的復合變化。
設對給定的圖像依次進行了基本變化F1、F2、F3…..、Fn,它們的變化矩陣分別為T1、T2、T3…..、Tn,圖像復合變化的矩陣T可以表示為:T = TnTn-1…T1。
按照上面的原則,圍繞着某個點(a,b)旋轉θ的變化矩陣序列是:
按照上面的公式,我們列舉一個簡單的例子:圍繞(100,100)旋轉30度(sin 30 = 0.5 ,cos 30 = 0.866)
float f[]= { 0.866F, -0.5F, 63.4F,0.5F, 0.866F,-36.6F,0.0F, 0.0F, 1.0F };
matrix = new Matrix();
matrix.setValues(f);
旋轉后的圖像如下:

Android為我們提供了更加簡單的方法,如下:
Matrix matrix = new Matrix();
matrix.setRotate(30,100,100);
矩陣運行后的實際結果: 
與我們前面通過公式獲取得到的矩陣完全一樣。
在這里我們提供另外一種方法,也可以達到同樣的效果:
float a = 100.0F,b = 100.0F;
matrix = new Matrix();
matrix.setTranslate(a,b);
matrix.preRotate(30);
matrix.preTranslate(-a,-b); //等價與matrix=matrix*T(移動相應距離的矩陣) post...(把pre的乘積因子相交換)
Matrix學習——錯切變換
什么是圖像的錯切變換(Shear transformation)?我們還是直接看圖片錯切變換后是的效果:

上圖是設置了x向量的第二個參數為0.5F 即x=x0+0.5y0 所以x隨y的增大而成斜率為0.5的線性變化。
代碼如下:
private float[] carrypos2 ={1,0,100,
0,1,100,
0,0,1}; //z no change
float[] test01 = carrypos2;
test01[1] = 0.5F;
matrix.setValues(test01);
canvas.drawBitmap(bitmap, matrix, paint);
也可以這樣寫:
對圖像的錯切變換做個總結:
x = x0 + b*y0;
y = d*x0 + y0;
這里再次給大家介紹一個需要注意的地方:
通過以上,我們發現Matrix的setXXXX()函數,在調用時調用了一次reset(),這個在復合變換時需要注意。
Matrix學習——對稱變換(反射)
什么是對稱變換?具體的理論就不詳細說明了,圖像的鏡像就是對稱變換中的一種。
利用上面的總結做個具體的例子,產生與直線y= – x對稱的反射圖形,代碼片段如下:
當前矩陣輸出是:
圖像變換的效果如下:
附:三角函數公式
兩角和公式
sin(a+b)=sinacosb+cosasinb
sin(a-b)=sinacosb-sinbcosa
cos(a+b)=cosacosb-sinasinb
cos(a-b)=cosacosb+sinasinb
tan(a+b)=(tana+tanb)/(1-tanatanb)
tan(a-b)=(tana-tanb)/(1+tanatanb)
cot(a+b)=(cotacotb-1)/(cotb+cota)
cot(a-b)=(cotacotb+1)/(cotb-cota)
倍角公式
tan2a=2tana/[1-(tana)^2]
cos2a=(cosa)^2-(sina)^2=2(cosa)^2 -1=1-2(sina)^2
sin2a=2sina*cosa
半角公式
sin(a/2)=√((1-cosa)/2) sin(a/2)=-√((1-cosa)/2)
cos(a/2)=√((1+cosa)/2) cos(a/2)=-√((1+cosa)/2)
tan(a/2)=√((1-cosa)/((1+cosa)) tan(a/2)=-√((1-cosa)/((1+cosa))
cot(a/2)=√((1+cosa)/((1-cosa)) cot(a/2)=-√((1+cosa)/((1-cosa))
tan(a/2)=(1-cosa)/sina=sina/(1+cosa)
和差化積
2sinacosb=sin(a+b)+sin(a-b)
2cosasinb=sin(a+b)-sin(a-b) )
2cosacosb=cos(a+b)-sin(a-b)
-2sinasinb=cos(a+b)-cos(a-b)
sina+sinb=2sin((a+b)/2)cos((a-b)/2
cosa+cosb=2cos((a+b)/2)sin((a-b)/2)
tana+tanb=sin(a+b)/cosacosb
積化和差公式
sin(a)sin(b)=-1/2*[cos(a+b)-cos(a-b)]
cos(a)cos(b)=1/2*[cos(a+b)+cos(a-b)]
sin(a)cos(b)=1/2*[sin(a+b)+sin(a-b)]
誘導公式
sin(-a)=-sin(a)
cos(-a)=cos(a)
sin(pi/2-a)=cos(a)
cos(pi/2-a)=sin(a)
sin(pi/2+a)=cos(a)
cos(pi/2+a)=-sin(a)
sin(pi-a)=sin(a)
cos(pi-a)=-cos(a)
sin(pi+a)=-sin(a)
cos(pi+a)=-cos(a)
tga=tana=sina/cosa
萬能公式
sin(a)= (2tan(a/2))/(1+tan^2(a/2))
cos(a)= (1-tan^2(a/2))/(1+tan^2(a/2))
tan(a)= (2tan(a/2))/(1-tan^2(a/2))
其它公式
a*sin(a)+b*cos(a)=sqrt(a^2+b^2)sin(a+c) [其中,tan(c)=b/a]
a*sin(a)-b*cos(a)=sqrt(a^2+b^2)cos(a-c) [其中,tan(c)=a/b]
1+sin(a)=(sin(a/2)+cos(a/2))^2
1-sin(a)=(sin(a/2)-cos(a/2))^2
其他非重點三角函數
csc(a)=1/sin(a)
sec(a)=1/cos(a)
雙曲函數
sinh(a)=(e^a-e^(-a))/2
cosh(a)=(e^a+e^(-a))/2
tgh(a)=sinh(a)/cosh(a)













