1. 程式人生 > >OpenCV在Android上實現人臉背景虛化

OpenCV在Android上實現人臉背景虛化

1. 背景

在手機拍照技術日新月異的今天,很多手機廠商都陸續上了雙攝,並衍生出人像模式(背景虛化)。雖然博主不是很懂雙攝虛化的原理,但是看到一些樣張之後,還是被深深吸引,覺得很漂亮,很有虛幻的感覺。
小米6的人像模式&背景虛化

自己也想動手做一個“影象虛化”的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. 測試結果

原始圖片:
這裡寫圖片描述

手機上的實測虛化效果:
這裡寫圖片描述

看起來還是不錯的哦!

5. 程式碼下載