OpenCV在Android上實現人臉背景虛化
1. 背景
在手機拍照技術日新月異的今天,很多手機廠商都陸續上了雙攝,並衍生出人像模式(背景虛化)。雖然博主不是很懂雙攝虛化的原理,但是看到一些樣張之後,還是被深深吸引,覺得很漂亮,很有虛幻的感覺。
自己也想動手做一個“影象虛化”的Demo來玩玩,當然並不是用的手機的雙攝原理,而是用一些影象處理的演算法。比如說高斯模糊,博主阮一峰的這篇部落格對“高斯模糊在影象處理中的應用”講得非常詳細,大家可以移步去看看,我這裡就不再贅述。
簡而言之,高斯模糊就是對每一個畫素點的值,以二維高斯分佈的概率作為權重,對周圍”kernal”範圍的畫素點的值做畫素加權得到新的畫素值。
2. 虛化背景提取
我們要做背景虛化,首先需要先把拍照的目標或者重心提取出來,其餘的稱為背景。在上一篇《OpenCV實戰:Android Studio配置並執行OpenCV4Android的face-detection》的部落格裡,我們基於OpenCV4Android的sample完成了人臉檢測功能。
那麼基於此,我們可以按照下列的步驟做虛化背景提取:
- 利用人臉檢測的矩形框得到一系列輪廓點MatOfPoint;
- 建立一個灰度值為0的單通道Mat影象hole,並在hole上面畫出上一步得到的輪廓;
- 對原始的檢測到人臉的影象mRgba進行高斯模糊處理,得到frameBlur;
- 將原始影象mRgba中的輪廓內部分利用mask的方式拷貝進frameBlur
最終得到的影象frameBlur就是對人臉背景虛化處理的影象。
主要的演算法程式碼如下:
Mat hole = new Mat(rows, cols, CvType.CV_8UC1, new Scalar(0));
Imgproc.drawContours(hole, last_contour, last_contour.size()-1, new Scalar(255),-1);
Mat frameBlur = new Mat(rows, cols, mRgba.type());
Imgproc.GaussianBlur(mRgba, frameBlur, new Size(61 , 61), 0);
mRgba.copyTo(frameBlur, hole);//將原影象拷貝進遮罩圖層
mImageView.setImageBitmap(matToBitmap(frameBlur));
3. 其餘的關鍵程式碼
3.1 Layout
整個Android工程的layout配置如下,可以看到除了用來顯示camera預覽影象的activity_main之外,還加入了cameraImageView,它是用來顯示虛化後的靜態影象,即我們這個工程的虛化處理不是實時的。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<org.opencv.android.JavaCameraView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/activity_main" />
<ImageView android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/cameraImageView"/>
</RelativeLayout>
3.2 OnTouchListener
對於主程式class MainActivity,添加了對OnTouchListener的實現來支援觸控事件,當用戶觸控式螢幕幕的任何一點時,完成拍照功能,並對當前影象進行虛化處理。關鍵程式碼在於需要重新實現OnTouchListener的函式onTouch來處理監聽事件。
public boolean onTouch(View v, MotionEvent event) {
cameraView_OnTouch(v, event);
isImageViewShown = true;
return false;
}
private void cameraView_OnTouch(View view, MotionEvent event) {
//
//虛化背景提取
//
mImageView.setImageBitmap(matToBitmap(frameBlur));
// show imageView and hide cameraView
mOpenCvCameraView.setVisibility(View.INVISIBLE);
mImageView.setVisibility(View.VISIBLE);
}
當onTouch觸發時,mOpenCvCameraView會被隱藏,同時mImageView被顯示,完成camera預覽視訊與靜態圖片的切換。
4. 測試結果
原始圖片:
手機上的實測虛化效果:
看起來還是不錯的哦!