重點是人臉檢測,檢測吼野,檢測校哎。
就是把人臉檢測出來,不是識別瞳步,不是識別闷哆,不是識別。識別的意思单起,就是檢測到人臉抱怔,并且通過數(shù)據(jù)比對,算法分析后得出人臉相識度的過程嘀倒。而檢測屈留,僅僅是檢測出來。
針對全網(wǎng)關(guān)于安卓OpenCV識別XXX之類的標(biāo)題括儒,而實際只做了檢測的相關(guān)文章绕沈,在此表示呵呵
回到正題
如何預(yù)覽視頻并進行人臉檢測锐想?
(一)預(yù)覽視頻
可直接使用OpenCV庫中的JavaCameraView控件帮寻,進行視頻的預(yù)覽。
1赠摇、布局中聲明該對象:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.opencv.android.JavaCameraView
android:id="@+id/activity_main_camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
2固逗、在布局中,直接調(diào)用該對象的enableView()方法藕帜,即可預(yù)覽烫罩。
備注:權(quán)限申請之類的老生常談,這里不再啰嗦洽故。
(二)構(gòu)建檢測分類器
OpenCV中贝攒,CascadeClassifier是用于分類器進行數(shù)據(jù)處理的。首先时甚,構(gòu)建一個分類器隘弊,需要數(shù)據(jù)源,而人臉檢測的分類器數(shù)據(jù)源荒适,OpenCV官方已經(jīng)有一個可以直接用了梨熙,這里可以直接拿過來用。而文件的路徑刀诬,就在下載的資源文件中的OpenCV-android-sdk\sdk\etc\lbpcascades目錄下咽扇,關(guān)于構(gòu)建項目的流程,不懂可看我上一篇文章
OpenCV導(dǎo)入
把分類器數(shù)據(jù)復(fù)制到主項目的res-raw目錄下,沒有該目錄就新建质欲,復(fù)制后如下圖:
然后树埠,在應(yīng)用檢測前,進行分類器數(shù)據(jù)復(fù)制到本地把敞,并初始化分類器弥奸,代碼如下:
try {
InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
File mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
FileOutputStream os = new FileOutputStream(mCascadeFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
is.close();
os.close();
cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
} catch (Exception e) {
Log.e("OpenCVActivity", "Error loading cascade", e);
}
這樣就完成了分類器的構(gòu)建了。
(三)監(jiān)聽視頻數(shù)據(jù)
對JavaCameraView設(shè)置CameraBridgeViewBase.CvCameraViewListener即可對視頻數(shù)據(jù)進行監(jiān)聽
(四)人臉檢測奋早,基于第三部盛霎,在監(jiān)聽回調(diào)方法onCameraFragment()中,對回調(diào)的視頻數(shù)據(jù)進行監(jiān)聽耽装,實現(xiàn)代碼如下:
@Override
public Mat onCameraFrame(Mat aInputFrame) {
Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);
MatOfRect faces = new MatOfRect();
if (cascadeClassifier != null) {
cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 3, 2,
new Size(absoluteFaceSize, absoluteFaceSize), new Size());
}
Rect[] facesArray = faces.toArray();
for (int i = 0; i <facesArray.length; i++){
Imgproc.rectangle(aInputFrame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3);
}
return aInputFrame;
}
首先愤炸,這里對傳入的圖片幀,進行了一個色值轉(zhuǎn)換的才做掉奄,然后再通過分類器的detectMultiScale方法规个,進行人臉檢測,最后通過Imgproc.rectangle()方法姓建,進行繪制人臉诞仓。
對于detectMultiScale方法的傳入?yún)?shù),析意如下:
1.image表示的是要檢測的輸入圖像
2.objects表示檢測到的人臉目標(biāo)序列
3.scaleFactor表示每次圖像尺寸減小的比例
4.minNeighbors表示每一個目標(biāo)至少要被檢測到3次才算是真的目標(biāo)(因為周圍的像素和不同的窗口大小都可以檢測到人臉)
5.minSize為目標(biāo)的最小尺寸
6.minSize為目標(biāo)的最大尺寸
最后附上完整代碼:
package com.north.light.libopencv;
import android.Manifest;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import androidx.appcompat.app.AppCompatActivity;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.JavaCameraView;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
public class MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener{
private CameraBridgeViewBase openCvCameraView;
private CascadeClassifier cascadeClassifier;
private Mat grayscaleImage;
private int absoluteFaceSize;
private void initializeOpenCVDependencies() {
try {
InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
File mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
FileOutputStream os = new FileOutputStream(mCascadeFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
is.close();
os.close();
cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
} catch (Exception e) {
Log.e("OpenCVActivity", "Error loading cascade", e);
}
openCvCameraView.enableView();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main); // 為該活動設(shè)置布局
openCvCameraView = findViewById(R.id.activity_main_camera_view);
openCvCameraView.setCvCameraViewListener(this);
}
@Override
public void onCameraViewStarted(int width, int height) {
grayscaleImage = new Mat(height, width, CvType.CV_8UC4);
absoluteFaceSize = (int) (height * 0.2);
}
@Override
public void onCameraViewStopped() {
}
@Override
public Mat onCameraFrame(Mat aInputFrame) {
Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);
MatOfRect faces = new MatOfRect();
if (cascadeClassifier != null) {
cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 3, 2,
new Size(absoluteFaceSize, absoluteFaceSize), new Size());
}
Rect[] facesArray = faces.toArray();
for (int i = 0; i <facesArray.length; i++){
Imgproc.rectangle(aInputFrame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3);
}
return aInputFrame;
}
@Override
public void onResume() {
super.onResume();
if (!OpenCVLoader.initDebug()) {
}
initializeOpenCVDependencies();
final String[] permissions = {
Manifest.permission.CAMERA
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permissions,0);
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
Log.d("返回鍵","back back back");
}
}
至此速兔,人臉檢測已經(jīng)完成墅拭,不過目前檢測人臉的預(yù)覽顯示,還是橫屏了涣狗,官方的demo也是橫屏顯示的谍婉,而對于豎屏顯示,請看我下一篇文章镀钓。
that's all---------------------------------------------------------------------------------