圖片處理——基於openCV實現美顏相機
阿新 • • 發佈:2019-01-29
今天是2017年最後一晚,希望大家元旦前夕玩得開心,準備迎接2018全新的一年,活出程式設計師的態度。
最近發現有些女孩在朋友圈發的自拍照膚白貌美,甚至頭上魔幻般地長出貓耳朵、貓鼻子、貓鬍鬚,各種調皮搞怪。這一切歸功於程式設計師們不懈努力,推動科技發展,最終科技提高生活品質。美顏相機、美妝相機、秒拍、天天P圖們讓自拍更加精彩,帶有濾鏡、美顏、寵萌等各種效果。講真的,一開始我比較好奇的是寵萌效果,認真分析後總結出實現過程經過三個步驟:人臉檢測——>計算放置位置——>繪製寵萌圖示。按照國際慣例,先看下圖片效果:
其實,最關鍵是第一步:人臉檢測。這裡採用openCV開源庫實現(如果不瞭解openCV這個計算機視覺開源庫的,可以去官網學習: https://opencv.org/),先把openCVLibrary整合到專案裡,使用訓練好的haarcascade模型來初始化Detector,在攝像頭每幀預覽資料回撥時,對圖片區域搜尋式掃描進行人臉檢測。需要注意的是,Android使用的是Bitmap,而openCV使用的是Mat,兩者需要進行轉換。關鍵程式碼如下:
public Mat onCameraFrame(CvCameraViewFrame inputFrame) { mRgba = inputFrame.rgba(); mGray = inputFrame.gray(); // 檢測人臉 Rect[] object = mFaceDetector.detectObject(mGray, mObject); if(object != null && object.length > 0){ //檢測到人臉矩形 Rect rect = object[0]; //矩形標識 // Imgproc.rectangle(mRgba, rect.tl(), rect.br(), mFaceDetector.getRectColor(), 3); if(beauty != null){ //新增寵萌妝飾 addBeauty((int)rect.tl().y, (int)(rect.tl().x+rect.br().x-beauty.cols())/2); } } //拍照一幀資料回撥 if(onPhotoTakenListener != null){ onPhotoTakenListener.onPhotoTaken(mRgba); } return mRgba; }
在檢測到人臉後,得到人臉在圖片的矩形位置,然後計算出寵萌特效放置的位置,y軸座標為矩形的top,x軸座標為(矩形left+矩形right-beauty寬度)/2。接著繪製圖標:
/** * 新增寵萌效果 * @param offsetX x座標偏移量 * @param offsetY y座標偏移量 */ private void addBeauty(int offsetX, int offsetY){ offsetX -= 200;//高度校正 if(offsetX < 0){ offsetX = 0; } for (int x=0; x<beauty.rows(); x++){ for (int y=0; y<beauty.cols(); y++){ double[] array = beauty.get(x, y); if(array[0] != 0) {//過濾全黑畫素 mRgba.put(x+offsetX, y+offsetY, array); } } } }
/**
* 獲取寵萌妝飾list集合
*/
private void getBeauty(){
Drawable drawable1 = getResources().getDrawable(R.drawable.cat, null);
Bitmap bitmap1 = ((BitmapDrawable) drawable1).getBitmap();
bitmap1 = Bitmap.createScaledBitmap(bitmap1, 320, 320, true);
Mat beauty1 = new Mat();
Utils.bitmapToMat(bitmap1, beauty1);
beautyList.add(beauty1);
Drawable drawable2 = getResources().getDrawable(R.drawable.rabbit, null);
Bitmap bitmap2 = ((BitmapDrawable) drawable2).getBitmap();
bitmap2 = Bitmap.createScaledBitmap(bitmap2, 320, 320, true);
Mat beauty2 = new Mat();
Utils.bitmapToMat(bitmap2, beauty2);
beautyList.add(beauty2);
}
在拍照時,回撥資料格式是Mat,需要先轉成Bitmap,然後儲存圖片: /**
* 儲存圖片
* @param frameData 幀資料
*/
private void savePicture(Mat frameData){
Bitmap bitmap = Bitmap.createBitmap(frameData.width(), frameData.height(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(frameData, bitmap);
String fileName = PATH + File.separator + dataFormat.format(new Date(System.currentTimeMillis())) + ".jpg";
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(fileName);
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
如果覺得靜態圖片的寵萌效果不夠酷,那麼來看下拍照預覽的動態效果(GIF圖處理比較模糊,大家勿噴):接下來我會繼續研究美顏、濾鏡、摳圖。歡迎熱愛圖片處理與多媒體開發的同行朋友相互交流,互相學習。