編輯:關於android開發
這篇主要講解ColorMatrix的相關知識,這裡將涉及到矩陣乘法的相關知識。所以這篇是比較有難度的。
稱為m*n矩陣
矩陣乘法其實並不難,它的意思就是將第一個矩陣A的第一行,與第二個矩陣B的第一列的數字分別相乘,得到的結果相加,最終的值做為結果矩陣的第(1,1)位置的值(即第一行,第一列)。
同樣,A矩陣的第一行與B矩陣的第二列的數字分別相乘然後相加,結果做為結果矩陣第(1,2)位置的值(即第一行第二列)。
再如,A矩陣的第二行與B矩陣的第一列的數字分別相乘,然後相加,結果做為結果矩陣的第(2,1)位置的值(即第二行第一列)
算法其實並不難,這裡要說明一個問題:
注意:對於色彩變換矩陣,這裡的色彩順序是R、G、B、A而不是A、R、G、B!!!
如果想將色彩(0,255,0,255)更改為半透明時,可以使用下面的的矩陣運算來表示:
為什麼使用五階矩陣
上面使用四階矩陣完全可以改變圖片的RGBA值了,但考慮一種情況,如果我們只想在原有的R色上增加一些分量呢?
這時,我們就得再多加一階來表示平移變換。所以,一個既包含線性變換,又包含平移變換的組合變換,稱為仿射變換。使用四階的色彩變換矩陣來修改色彩,只能夠對色彩的每一個分量值進行乘(除)運算,如果要對這些分量值進行加減法的運算(平移變換),只能通過五階矩陣來完成。
考慮下面這個變換:
1、紅色分量值更改為原來的2倍;
2、綠色分量增加100;
則使用4階矩陣的乘法無法實現,所以,應該在四階色彩變換矩陣上增加一個“啞元坐標”,來實現所列的矩陣運算:
這個矩陣中,分量值用的是100
Android中的色彩矩陣是用ColorMatrics類來表示的。使用ColorMatrix的方法如下
// 生成色彩矩陣 ColorMatrix colorMatrix = new ColorMatrix(new float[]{ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0.5, 0, }); mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));有關setColorFilter()函數的其它用法,下篇文章我們將會詳細講述,這篇我們只知道怎麼設置ColorMatrix對象就可以了。
public class MyView extends View { private Paint mPaint = new Paint(); private Bitmap bitmap;// 位圖 public MyView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setAntiAlias(true); mPaint.setARGB(255,200,100,100); // 繪制原始位圖 canvas.drawRect(0,0,500,600,mPaint); canvas.translate(550,0); // 生成色彩矩陣 ColorMatrix colorMatrix = new ColorMatrix(new float[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, }); mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); canvas.drawRect(0,0,500,600,mPaint); } }在上面中,我們先將圖筆顏色值設為(255,200,100,100),然後對其進行ColorMatrix顏色值運算,把紅色和綠色都去掉,僅顯示藍色值;只顯示藍色值的效果在Photoshop中叫做藍色通道。效果圖如下:
這裡只是對一個顏色值,而ColorMatrics的最厲害的地方在於,能夠很批量地改變圖像中的所有顏色值。下面我們就對圖像應用ColorMatrics的例子來看看,如果只顯示圖像中的藍色通道會怎樣
public class MyView extends View { private Paint mPaint = new Paint(); private Bitmap bitmap;// 位圖 public MyView(Context context, AttributeSet attrs) { super(context, attrs); mPaint.setAntiAlias(true); // 獲取位圖 bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.dog); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 繪制原始位圖 canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500 * bitmap.getHeight() / bitmap.getWidth()), mPaint); canvas.translate(510, 0); // 生成色彩矩陣 ColorMatrix colorMatrix = new ColorMatrix(new float[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, }); mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500 * bitmap.getHeight() / bitmap.getWidth()), mPaint); } }這裡分兩次繪制了一個bitmap,第一次繪制了一個原始圖像,然後利用ColorMatrix生成了一個僅包含藍色的圖像,用過PhotoShop的同學應該很清楚這個跟Photoshop中的藍色通道的效果是一致的。效果圖如下:
大家注意哦,不要在onDraw裡new Paint對象,上節中我為了省事就直接在onDraw()函數中直接new 了Paint對象,由於onDraw函數在刷新時會連續調用多次,所以如果在其中不斷的new對象,會造成程序不斷的GC(內存回收),是會嚴重影響性能的!在程序中,我有時會了為了方便理解,就直接在onDraw()中創建對象了,大家在實際應用中一定要杜絕這種應用哦。
比如,同樣是上面的圖片,我們給它應用下面的色彩值:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{ 1, 0, 0, 0, 0, 0, 1, 0, 0, 50, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, });
在綠色值上添加增量50,即增大綠色的飽和度。效果圖如下:
同樣,左側是原圖,右側是增大綠色飽和度後的效果;大家要特別注意的是,由於圖片是由一個個像素組成的,所以用每個像素所對應的色彩數組,來乘轉換矩陣,結果就是轉換後的當前點的顏色值;所以,在應用ColorMatrics後,圖片中每個像素的綠色值都增加了50,從小狗臉上也可以看出來,狗臉也變綠了(它可能看到他女朋友跟人家跑了,哈哈)!
色彩平移除了增加指定顏色飽和度以外,另一個應用就是色彩反轉(PhotoShop中的反相功能)
色彩反轉/反相功能
色彩反轉就是求出每個色彩的補值來做為目標圖像的對應顏色值:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{ -1,0,0,0,255, 0,-1,0,0,255, 0,0,-1,0,255, 0,0,0,1,0 });效果圖如下:
我們可以針對某一個顏色值進行放大縮小運算,但當對R、G、B、A同時進行放大縮小時,就是對亮度進行調節!
看下面的將亮度增大1.2倍的代碼:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{ 1.2f, 0, 0, 0, 0, 0, 1.2f, 0, 0, 50, 0, 0, 1.2f, 0, 0, 0, 0, 0, 1.2f, 0, });效果圖如下:
紅色通道矩陣:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, });綠色通道矩陣:
ColorMatrix colorMatrix2 = new ColorMatrix(new float[]{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, });藍色通道矩陣:
ColorMatrix colorMatrix3 = new ColorMatrix(new float[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, });
所以,我們可以把一個色彩值看成三維空間裡的一個點,色彩值的三個分量可以看成該點的坐標(三維坐標)。我們先不考慮,在三個維度綜合情況下是怎麼旋轉的,我們先看看,在某個軸做為Z軸,在另兩個軸形成的平面上旋轉的情況,下圖分析了,在將藍色軸做為Z軸,僅在紅—綠平面上旋轉a度的情況:
在圖中,我們可以看到,在旋轉後,原R在R軸的分量變為:原R*cosa,但原G分量在旋轉後,在R軸上也有了分量,但分量落在了負軸上,所以我們要減去這部分分量,所以最終的結果是最終的R=原R*cosa-原G*sina;
下面就看下關於幾種旋轉計算及結果矩陣,(注意:這幾個圖只標記了原X軸色彩分量的旋轉,沒有把Y軸色彩分量的旋轉標記出來)
繞藍色軸旋轉a度
對應的色彩變換矩陣是
繞紅色軸旋轉a度
對應的色彩變換矩陣是
繞綠色軸旋轉a度
對應的色彩變換矩陣是
當圍繞紅色軸進行色彩旋轉時,由於當前紅色軸的色彩是不變的,而僅利用三角函數來動態的變更綠色和藍色的顏色值。這種改變就叫做色相調節!當圍繞紅色軸旋轉時,是對圖片就行紅色色相的調節;同理,當圍繞藍色顏色軸旋轉時,就是對圖片就行藍色色相調節;當然,當圍繞綠色軸旋轉時,就是對圖片進行綠色色相的調節.
下面我們做一個動態的調節,針對紅 色色相。
這個效果圖表示的是,在滾輪正中間位置時表示旋轉角度為0度,最右側位置表示向正方向旋轉180,左側到底表示負方向旋轉180.
同理可以得到圍繞綠色軸旋轉的效果圖:
最後是,圍繞藍色軸旋轉的效果圖:
下面我們會再次講到ColorMatrics的色彩旋轉函數,這裡先理解原理和效果,代碼後面會給出。
其中我把紅色運算給單獨拉了出來,紅色標記的那幾個元素a21,a31,a41,在運算中,是利用R、B、A的顏色值的分量來增加紅色值的。
來看具體的運算:
注意:最終結果的140=1*100+0.2*200,可見紅色分量在原有紅色分量的基礎上,增加了綠色分量值的0.2倍;利用其它色彩分量的倍數來更改自己色彩分量的值,這種運算就叫投射運算。
下圖陰影部分;對這些值進行修改時,修改所使用的增加值來自於其它色彩分量的信息。
色彩投射的一個最簡單應用就是變為黑白圖片:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{ 0.213f, 0.715f, 0.072f, 0, 0, 0.213f, 0.715f, 0.072f, 0, 0, 0.213f, 0.715f, 0.072f, 0, 0, 0, 0, 0, 1, 0, });效果圖:
首先了解一下去色原理:只要把RGB三通道的色彩信息設置成一樣;即:R=G=B,那麼圖像就變成了灰色,並且,為了保證圖像亮度不變,同一個通道中的R+G+B=1:如:0.213+0.715+0.072=1;
三個數字的由來:0.213, 0.715, 0.072;
按理說應該把RGB平分,都是0.3333333。三個數字應該是根據色彩光波頻率及色彩心理學計算出來的(本人是這麼認為,當然也查詢了一些資料,目前尚未找到准確答案)。
在作用於人眼的光線中,彩色光要明顯強於無色光。對一個圖像按RGB平分理論給圖像去色的話,人眼就會明顯感覺到圖像變暗了(當然可能有心理上的原因,也有光波的科學依據)另外,在彩色圖像中能識別的一下細節也可能會丟失。
所以google最終給我們的顏色值就是上面的比例:0.213, 0.715, 0.072;
所以,在給圖像去色時我們保留了大量的G通道信息,使得圖像不至於變暗或者綠色信息不至於丟失(我猜想)。
投射運算的另一個應用是:色彩反色
當我們利用色彩矩陣將兩個顏色反轉,這種操作就叫做色彩反色
比如,下面的的將紅色和綠色反色(紅綠反色)
ColorMatrix colorMatrix = new ColorMatrix(new float[]{ 0,1,0,0,0, 1,0,0,0,0, 0,0,1,0,0, 0,0,0,1,0 });效果圖如下:
左側的圖為原圖,右邊為紅綠反色以後的效果圖;
從矩陣中可以看出紅綠反色的關鍵在於,第一行用綠色來代替了紅色,第二行用紅色代替了綠色。
類似可以有紅藍反色,綠藍反色等,對應矩陣難度不大,就不再細講了。
變舊照片
投射運算的另一個應用是照片變舊,對應矩陣如下:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{ 1/2f,1/2f,1/2f,0,0, 1/3f,1/3f,1/3f,0,0, 1/4f,1/4f,1/4f,0,0, 0,0,0,1,0 });
ColorMatrix() ColorMatrix(float[] src) ColorMatrix(ColorMatrix src)這三個構造函數中,上面我們已經使用過第二個構造函數了,第三個構造函數,就是利用另一個ColorMatrix實例來復制一個一樣的ColorMatrix對象。
public void set(ColorMatrix src) public void set(float[] src) public void reset()這裡是設置和重置函數,重置後,對應的數組為:
/** * Set this colormatrix to identity: * [ 1 0 0 0 0 - red vector * 0 1 0 0 0 - green vector * 0 0 1 0 0 - blue vector * 0 0 0 1 0 ] - alpha vector */這些函數難度都不大,就不再講了
//整體增強顏色飽和度,即同時增強R,G,B的色彩飽和度 public void setSaturation(float sat)其中:
滑塊默認在一倍的位置,向左到底是0,向右到底是20(即飽和度放大20倍)
下面來看看代碼:
先來看看布局代碼:(main.xml)
布局很簡單,根據效果圖不難理解出來;
public class MyActivity extends Activity { private SeekBar mSeekBar; private ImageView mImageView; private Bitmap mOriginBmp,mTempBmp; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mImageView = (ImageView) findViewById(R.id.img); mSeekBar = (SeekBar)findViewById(R.id.seekbar); mOriginBmp = BitmapFactory.decodeResource(getResources(), R.drawable.dog); mTempBmp = Bitmap.createBitmap(mOriginBmp.getWidth(), mOriginBmp.getHeight(), Bitmap.Config.ARGB_8888); mSeekBar.setMax(20); mSeekBar.setProgress(1); mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { Bitmap bitmap = handleColorMatrixBmp(progress); mImageView.setImageBitmap(bitmap); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); } private Bitmap handleColorMatrixBmp(int progress){ // 創建一個相同尺寸的可變的位圖區,用於繪制調色後的圖片 Canvas canvas = new Canvas(mTempBmp); // 得到畫筆對象 Paint paint = new Paint(); // 新建paint paint.setAntiAlias(true); // 設置抗鋸齒,也即是邊緣做平滑處理 ColorMatrix mSaturationMatrix = new ColorMatrix(); mSaturationMatrix.setSaturation(progress); paint.setColorFilter(new ColorMatrixColorFilter(mSaturationMatrix));// 設置顏色變換效果 canvas.drawBitmap(mOriginBmp, 0, 0, paint); // 將顏色變化後的圖片輸出到新創建的位圖區 // 返回新的位圖,也即調色處理後的圖片 return mTempBmp; } }最關鍵的位置在於,在調整progress時,生成對應圖像的過程:
private Bitmap handleColorMatrixBmp(int progress){ // 創建一個相同尺寸的可變的位圖區,用於繪制調色後的圖片 Canvas canvas = new Canvas(mTempBmp); // 得到畫筆對象 Paint paint = new Paint(); // 新建paint paint.setAntiAlias(true); // 設置抗鋸齒,也即是邊緣做平滑處理 ColorMatrix mSaturationMatrix = new ColorMatrix(); mSaturationMatrix.setSaturation(progress); paint.setColorFilter(new ColorMatrixColorFilter(mSaturationMatrix));// 設置顏色變換效果 canvas.drawBitmap(mOriginBmp, 0, 0, paint); // 將顏色變化後的圖片輸出到新創建的位圖區 // 返回新的位圖,也即調色處理後的圖片 return mTempBmp; }mTempBmp是生成的一個跟原始的bitmap同樣大小的空白圖片,然後在設置的Paint的ColorMatrics之後,利用canvas.drawBitmap(mOriginBmp, 0, 0, paint);在原始圖片的基礎上應用Paint把生成的圖像畫在canvas上。drawBitmap()的第一個參數表示的是源圖像;
public void setScale(float rScale, float gScale, float bScale,float aScale)總共有四個參數,分別對應R,G,B,A顏色值的縮放倍數。
canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500 * bitmap.getHeight() / bitmap.getWidth()), mPaint); canvas.save(); canvas.translate(510, 0); // 生成色彩矩陣 ColorMatrix colorMatrix = new ColorMatrix(); colorMatrix.setScale(1,1.3f,1,1); mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); canvas.drawBitmap(bitmap, null, new Rect(0, 0, 500, 500 * bitmap.getHeight() / bitmap.getWidth()), mPaint);效果圖如下:
在僅將綠色放大1.3倍後,整個圖片看起來更鮮艷了有沒有。
/** * 將旋轉圍繞某一個顏色軸旋轉 * axis=0 圍繞紅色軸旋轉 * axis=1 圍繞綠色軸旋轉 * axis=2 圍繞藍色軸旋轉 */ public void setRotate(int axis, float degrees);這裡有兩個參數:
處理代碼如下:
public class SecondActivity extends Activity { private SeekBar mSeekBar; private ImageView mImageView; private Bitmap mOriginBmp,mTempBmp; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mImageView = (ImageView) findViewById(R.id.img); mSeekBar = (SeekBar)findViewById(R.id.seekbar); mOriginBmp = BitmapFactory.decodeResource(getResources(), R.drawable.dog); mTempBmp = Bitmap.createBitmap(mOriginBmp.getWidth(), mOriginBmp.getHeight(), Bitmap.Config.ARGB_8888); mSeekBar.setMax(360); mSeekBar.setProgress(180); mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { Bitmap bitmap = handleColorRotateBmp(progress); mImageView.setImageBitmap(bitmap); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); } private Bitmap handleColorRotateBmp(int progress){ // 創建一個相同尺寸的可變的位圖區,用於繪制調色後的圖片 Canvas canvas = new Canvas(mTempBmp); // 得到畫筆對象 Paint paint = new Paint(); // 新建paint paint.setAntiAlias(true); // 設置抗鋸齒,也即是邊緣做平滑處理 ColorMatrix colorMatrix = new ColorMatrix(); colorMatrix.setRotate(0,progress-180); paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));// 設置顏色變換效果 canvas.drawBitmap(mOriginBmp, 0, 0, paint); // 將顏色變化後的圖片輸出到新創建的位圖區 // 返回新的位圖,也即調色處理後的圖片 return mTempBmp; } }這裡的代碼與調節飽和度的代碼都是一樣的,只是有兩點不同:
mSeekBar.setMax(360); mSeekBar.setProgress(180);第二:處理當前progress
ColorMatrix colorMatrix = new ColorMatrix(); colorMatrix.setRotate(0,progress-180); paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));將當前progress位置減去180,即中間位置的數字。所以在中間位置的色彩旋轉度數為0,整個旋轉度數的范圍是-180到180;360度正好是正余弦函數的一個最小正周期
public void setConcat(ColorMatrix matA, ColorMatrix matB)這個函數接收兩個ColorMatrix矩陣matA和matB,乘法規則為matA*matB,然後將結果做為當前ColorMatrix的值。(為什麼要強調乘法規則為matA*matB?我們前面講過矩陣A*矩陣B和矩陣B*矩陣A的結果是不一樣的!)
public void preConcat(ColorMatrix prematrix)假如當前矩陣的A,而preConcat的意思就是將當前的矩陣A乘以prematrix
public void postConcat(ColorMatrix postmatrix)上面prematrix是當前矩陣A*prematrix;而postConcat函數的意義就是postmatrix*當前矩陣A;這就是一個前乘,一個是後乘的區別!我們上面已經很清楚的講了,前乘和後乘結果是不一樣的!
public void setConcat(ColorMatrix matA, ColorMatrix matB)我們提了setConcat會將matA乘以matB,將結果做為當前ColorMatrics實例的顏色矩陣。所以會把當前ColorMatrics實例以前的顏色矩陣給覆蓋掉!這是我們首先需要提示的。
估計有些同學看到這些數字的時候,心頭會有一萬頭草泥馬奔過……數學算起來確實是有些難度……慢慢看吧……
我們前面講過,只有當第一個矩陣的列數等於第二個矩陣的行數的時候,才能相乘!這泥媽不對啊……明明第一個矩陣有五列,而第二個矩陣只有四行……第一個矩陣的最後一列這泥馬要打光棍的節奏啊……
這不光是光棍的問題,這兩個矩陣是根本沒辦法相乘的,因為第一個矩陣的列數和第二個矩陣的行數不相等!
那為了解決這個問題,Android提供了一個方案,讓這兩個矩陣相乘,就是把第一個矩陣的最後一列單獨拿出來,另外加到結果上,即:
為了驗證上面的運算法則,我們使用setConcat函數來做一下實驗:
public class MyActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ColorMatrix colorMatrix1 = new ColorMatrix(new float[]{ 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, }); ColorMatrix colorMatrix2 = new ColorMatrix(new float[]{ 0.11f, 0, 0, 0, 0, 0, 0.22f, 0, 0, 0, 0, 0, 0.33f, 0, 0, 0, 0, 0, 0.44f, 0, }); ColorMatrix resultMatrix = new ColorMatrix(new float[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }); resultMatrix.setConcat(colorMatrix1,colorMatrix2); Log.d("qijian",printArray(colorMatrix1.getArray())); Log.d("qijian",printArray(colorMatrix2.getArray())); Log.d("qijian",printArray(resultMatrix.getArray())); } private String printArray(float[] array){ StringBuilder builder = new StringBuilder("array dump:\n"); for (int i=0;i這段代碼很好理解,生成三個ColorMatrics對象colorMatrix1、colorMatrix2和resultMatrix,然後利用resultMatrix.setConcat函數將colorMatrix1與colorMatrix2相乘,結果會覆蓋resultMatrix的原有矩陣,最後利用日志把colorMatrix1、colorMatrix2和resultMatrix的最終值打印出來:
大家可以拿筆來算算,結果是與上面的算法一致的。 preConcat(ColorMatrix prematrix) 然後我們來看看postConcat的運算原理:
public void preConcat(ColorMatrix prematrix)假如當前ColorMatrix中所對應的矩陣是A,而preConcat的意思就是將當前的矩陣A乘以prematrix
示例代碼如下:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ColorMatrix colorMatrix1 = new ColorMatrix(new float[]{ 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, }); ColorMatrix colorMatrix2 = new ColorMatrix(new float[]{ 0.11f, 0, 0, 0, 0, 0, 0.22f, 0, 0, 0, 0, 0, 0.33f, 0, 0, 0, 0, 0, 0.44f, 0, }); //打印出原始的colorMatrix1的矩陣 Log.d("qijian",printArray(colorMatrix1.getArray())); colorMatrix1.preConcat(colorMatrix2); Log.d("qijian",printArray(colorMatrix2.getArray())); //打印出乘後的colorMatrix1的矩陣 Log.d("qijian",printArray(colorMatrix1.getArray())); }結果如下:
從結果也可以看出,preConcat的意義就是將當前矩陣乘以prematrix矩陣
postConcat(ColorMatrix postmatrix)
下面我們再看看 postConcat(ColorMatrix postmatrix)
public void postConcat(ColorMatrix postmatrix)我們上面講了,上面prematrix是當前矩陣A*prematrix;而postConcat函數的意義就是postConcat*當前矩陣A;剛好與preConcat反過來。所以如果我們在實例中,利用colorMatrix2.postConcat(colorMatrix1);它得到結果應該是與colorMatrix1.preConcat(colorMatrix2);得到結果是一樣的,我們來實驗一下:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ColorMatrix colorMatrix1 = new ColorMatrix(new float[]{ 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, }); ColorMatrix colorMatrix2 = new ColorMatrix(new float[]{ 0.11f, 0, 0, 0, 0, 0, 0.22f, 0, 0, 0, 0, 0, 0.33f, 0, 0, 0, 0, 0, 0.44f, 0, }); Log.d("qijian",printArray(colorMatrix1.getArray())); Log.d("qijian",printArray(colorMatrix2.getArray())); colorMatrix2.postConcat(colorMatrix1); Log.d("qijian",printArray(colorMatrix2.getArray())); }結果如下:
可以看到結果與上面的一模一樣哦。這同時也驗證了postConcat函數與preConcat函數正好反過來,一個前乘一個後乘
7、getArray()獲取當前矩陣數組
前面我們已經用到過getArray函數了,getArray函數的意義就是返回當前ColorMatrics對象中的所保存的矩陣
public float[] getArray()返回值是float[]數組,它的索引順序為:
好啦,本篇到這裡就結束了,有關矩陣的知識是比較有難度的,但是這篇對於圖像處理是至關重要的,因為在有些相機軟件中會有各種濾鏡效果,這些濾鏡效果大部分就是通過更改ColorMatrics矩陣來完成的!當然要完全會構造ColorMatrics矩陣是需要色彩設計相關的知識的;相信通過本篇知識,你也能寫出些濾鏡效果了,做出來一個簡單的圖片處理APP也不是問題了哦。下篇將繼續給大家說圖像處理
源碼在文章底部給出
這篇文章真泥馬難謄寫,從makedown抄到網上寫成Html真是想死的節奏啊……光抄過來用了三個小時……MyGOD,關鍵是CSDN的markdown的界面真是太丑了,不方便大家閱讀
源碼內容:
1、BlogColorMatrix:圖片處理及最後的SetConcat、PreConcat和PostConcat計算都在這裡
2、BlogProgressMetrics:通過滾動軸動態改變圖像的飽和度和色相的源碼在這裡哦
Android ExpandableListView相關介紹 一、ExpandableListView介紹 一個垂直滾動的顯示兩個級別(Child,Group)列
Android視圖控件架構分析之View、ViewGroup,androidviewgroup 在Android中,視圖控件大致被分為兩類,即ViewGroup和Vie
Android 貝塞爾曲線的淺析,android貝塞爾淺析博客也開了挺長時間了,一直都沒有來寫博客,主要原因是自己懶~~~此篇博客算是給2017年一個好的開始,同時也給2
Android 自定義控件之第三講:obtainStyledAttributes 系列函數詳解 在項目中開發自定義控件時,或多或少都會用到 obtainStyledAtt