【Andriod】Andriod-Opencv 實現一些簡單的濾鏡功能
阿新 • • 發佈:2019-02-06
最近比較忙,很久沒有更新部落格了。
這篇文章所說的配置可以直接用android寫opencv,而不需要採用內嵌C++的辦法。(話說我本來想用Dlib來識別人臉的,卻在內嵌c++上吃了不少苦頭。)
下面就簡單介紹下幾種濾鏡的實現以及效果圖:
(1)灰度化:這個比較簡單,主要就一行程式碼搞定。
//灰度化方法 Bitmap RGB2Gray(Bitmap photo) { Mat RGBMat = new Mat(); Bitmap grayBitmap = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.RGB_565); Utils.bitmapToMat(photo, RGBMat);//convert original bitmap to Mat, R G B. Imgproc.cvtColor(RGBMat, RGBMat, Imgproc.COLOR_RGB2GRAY);//rgbMat to gray grayMat Utils.matToBitmap(RGBMat, grayBitmap); return grayBitmap; }
(2)二值化:二值化主要考慮到一個閾值效果,這個我沒有設定,直接就預設中值了,以後也許會加一個控制條啥的。
//二值化濾鏡 Bitmap theshold(Bitmap photo){ Mat mat = new Mat(); Bitmap thes = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.ARGB_8888); Utils.bitmapToMat(photo, mat); Imgproc.cvtColor(mat,mat,Imgproc.COLOR_RGB2GRAY); Core.bitwise_not(mat,mat); Imgproc.threshold(mat,mat,100,255,Imgproc.THRESH_BINARY_INV); Utils.matToBitmap(mat,thes); return thes; }
(3)輪廓:輪廓說到底就是一個邊緣檢測。
//輪廓 Bitmap Lunkuo(Bitmap photo){ Mat mat = new Mat(); Mat Cmat = new Mat(); Mat Bmat = new Mat(); Bitmap cartton = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.ARGB_8888); Utils.bitmapToMat(photo, mat); Imgproc.Canny(mat,Cmat,50,100); Core.bitwise_not(Cmat,Cmat); Utils.matToBitmap(Cmat, cartton); return cartton; }
(4)素描:
//素描濾鏡
Bitmap SuMiao(Bitmap photo){
Mat SM = new Mat();
Mat SM1 = new Mat();
Bitmap sumiaoMap = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.ARGB_8888);
Bitmap SMB = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.ARGB_8888);
Bitmap SMB1 = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.ARGB_8888);
Utils.bitmapToMat(photo, SM);
//灰度化
Imgproc.cvtColor(SM, SM, Imgproc.COLOR_RGB2GRAY);
//顏色取反
Core.bitwise_not(SM,SM1);
//高斯模糊
Imgproc.GaussianBlur(SM1,SM1,new Size(13,13),0,0);
Utils.matToBitmap(SM, SMB);
Utils.matToBitmap(SM1, SMB1);
for(int i = 0;i<SMB.getWidth();i++){
for( int j = 0;j<SMB.getHeight();j++){
int A = SMB.getPixel(i,j);
int B = SMB1.getPixel(i,j);
int CR = colordodge(Color.red(A),Color.red(B));
int CG = colordodge(Color.green(A),Color.red(B));
int CB = colordodge(Color.blue(A),Color.blue(B));
sumiaoMap.setPixel(i,j,Color.rgb(CR,CG,CB));
}
}
return sumiaoMap;
}
(5)接下來是懷舊色。這個要對RGB算式相乘
//懷舊色濾鏡
Bitmap HuaiJiu(Bitmap photo){
Bitmap huaijiu = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.ARGB_8888);
for(int i = 0;i<photo.getWidth();i++){
for( int j = 0;j<photo.getHeight();j++){
int A = photo.getPixel(i,j);
int AR =(int)(0.393*Color.red(A) + 0.769*Color.green(A) + 0.189*Color.blue(A));
int AG =(int)(0.349*Color.red(A) + 0.686*Color.green(A) + 0.168*Color.blue(A));
int AB =(int)(0.272*Color.red(A) + 0.534*Color.green(A) + 0.131*Color.blue(A));
AR = AR > 255 ? 255 : AR;
AG = AG > 255 ? 255 : AG;
AB = AB > 255 ? 255 : AB;
huaijiu.setPixel(i,j,Color.rgb(AR,AG,AB));
}
}
return huaijiu;
}
(6)連環畫:同樣是對RGB色彩操作
Bitmap LianHuanHua(Bitmap photo){
Bitmap lianhuanhua = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.ARGB_8888);
for(int i = 0;i<photo.getWidth();i++){
for( int j = 0;j<photo.getHeight();j++){
int A = photo.getPixel(i,j);
int AR =Math.abs(Color.red(A) - Color.blue(A) + Color.green(A)+ Color.green(A) ) * Color.red(A) / 256;
int AG =Math.abs(Color.red(A) - Color.green(A) + Color.blue(A) + Color.blue(A)) * Color.red(A) / 256;
int AB =Math.abs(Color.red(A) - Color.blue(A) + Color.blue(A) + Color.blue(A)) * Color.green(A) / 256;
AR = AR > 255 ? 255 : AR;
AG = AG > 255 ? 255 : AG;
AB = AB > 255 ? 255 : AB;
lianhuanhua.setPixel(i,j,Color.rgb(AR,AG,AB));
}
}
return lianhuanhua;
}
(7)熔鑄以及冰凍:同上:
//熔鑄濾鏡
Bitmap RongZhu(Bitmap photo){
Bitmap rongzhu = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.ARGB_8888);
for(int i = 0;i<photo.getWidth();i++){
for( int j = 0;j<photo.getHeight();j++){
int A = photo.getPixel(i,j);
int AR =Color.red(A)*128/(Color.blue(A)+Color.green(A)+1);
int AG =Color.green(A)*128/(Color.blue(A)+Color.red(A)+1);
int AB =Color.blue(A)*128/(Color.red(A)+Color.green(A)+1);
AR = AR > 255 ? 255 : AR;
AG = AG > 255 ? 255 : AG;
AB = AB > 255 ? 255 : AB;
rongzhu.setPixel(i,j,Color.rgb(AR,AG,AB));
}
}
return rongzhu;
}
//冰凍濾鏡
Bitmap BingDong(Bitmap photo){
Bitmap bingdong = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.ARGB_8888);
for(int i = 0;i<photo.getWidth();i++){
for( int j = 0;j<photo.getHeight();j++){
int A = photo.getPixel(i,j);
int AR =(Color.red(A)-Color.blue(A)-Color.green(A))*3/2;
int AG =(Color.green(A)-Color.blue(A)-Color.red(A))*3/2;
int AB =(Color.blue(A)-Color.red(A)-Color.green(A))*3/2;
AR = AR > 255 ? 255 : AR;
AG = AG > 255 ? 255 : AG;
AB = AB > 255 ? 255 : AB;
bingdong.setPixel(i,j,Color.rgb(AR,AG,AB));
}
}
return bingdong;
}
(8)浮雕:
//浮雕濾鏡
Bitmap FuDiao(Bitmap photo){
Bitmap bingdong = Bitmap.createBitmap(photo.getWidth(), photo.getHeight(), Bitmap.Config.ARGB_8888);
for(int i = 1;i<photo.getWidth()-1;i++){
for( int j = 1;j<photo.getHeight()-1;j++){
int A = photo.getPixel(i-1,j-1);
int B = photo.getPixel(i+1,j+1);
int AR =Color.red(B)-Color.red(A)+128;
int AG =Color.green(B)-Color.green(A)+128;
int AB =Color.blue(B)-Color.blue(A)+128;
AR = AR > 255 ? 255 : AR;
AG = AG > 255 ? 255 : AG;
AB = AB > 255 ? 255 : AB;
bingdong.setPixel(i,j,Color.rgb(AR,AG,AB));
}
}
return bingdong;
}
(9)此外還做了一個影象人臉識別。
總之效果還可以,但是還有不足的地方,比如RGB顏色的計算和素描色的計算,不像Python有Numpy大法可以直接做矩陣運算。試了很多方法,最終我妥協了,用迴圈計算每一個畫素點,這樣就導致了圖片越大,濾鏡載入的效果就越慢,尤其是素描濾鏡,簡直慢到令人發恥。這與吳恩達教授所說的向量化計算大相徑庭,根本不像一個學機器學習的人做出來的0.0。
不管怎樣完工了,順便搞定了一門課的課程設計,可能以後會對演算法部分進行優化吧,再說。
在這個軟體中,還有一個功能是人臉互換,要用到Dlib,但是在android上配置太麻煩了,我室友就做了一個伺服器端,將圖片上傳到電腦上用Python處理。但是這個功能不是我寫得,所以就不寫在自己的部落格裡了。
就這樣,下次繼續刷leetcode,並將好玩的題目發到部落格上。
完整版的原始碼已經傳到github