【Android App】利用自带的人脸检测器和OpenCV检测人脸讲解及实战(附源码和演示 超详细)

需要源码请点赞关注收藏后评论区留言私信~~~~

一、利用人脸检测器识别人脸

对于简单的人脸识别操作,Android已经提供了专门的识别工具,名叫人脸检测器FaceDetector,部分常用方法如下

FaceDetector的findFaces方法可在指定位图中寻找人脸,找到的人脸结果放在该方法的第二个输入参数中,参数类型为人脸数组结构FaceDetector.Face[]。

下面是人脸对象的常用方法说明:

getMidPoint:获取人脸的中心点。

eyesDistance:获取人脸中心点和眼间距离。

confidence:获取人脸结果的信任度,取值区间为0到1,一般信任度达到0.3即可判作人脸。 pose:获取人脸在指定坐标轴的姿势,也就是与指定坐标轴的夹角。

运行测试App效果如下

原图片如下 用最近世界杯上非常火的球星C罗

【Android App】利用自带的人脸检测器和OpenCV检测人脸讲解及实战(附源码和演示 超详细)_第1张图片

 经过系统自带的人脸检测器读取后效果如下 可以精确的圈出人脸位置

 【Android App】利用自带的人脸检测器和OpenCV检测人脸讲解及实战(附源码和演示 超详细)_第2张图片

 代码如下

package com.example.face;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

import com.example.face.util.BitmapUtil;
import com.example.face.widget.FaceView;

public class DetectSystemActivity extends AppCompatActivity {
    private final static String TAG = "DetectSystemActivity";
    private int CHOOSE_CODE = 3; // 只在相册挑选图片的请求码
    private FaceView fv_face; // 声明一个人脸视图对象

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detect_system);
        fv_face = findViewById(R.id.fv_face);
        findViewById(R.id.btn_choose).setOnClickListener(v -> {
            // 创建一个内容获取动作的意图(准备跳到系统相册)
            Intent albumIntent = new Intent(Intent.ACTION_GET_CONTENT);
            albumIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); // 是否允许多选
            albumIntent.setType("image/*"); // 类型为图像
            startActivityForResult(albumIntent, CHOOSE_CODE); // 打开系统相册
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if (resultCode == RESULT_OK && requestCode == CHOOSE_CODE) { // 从相册返回
            if (intent.getData() != null) { // 从相册选择一张照片
                Uri uri = intent.getData(); // 获得已选择照片的路径对象
                // Android自带的人脸检测只支持RGB_565格式
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inPreferredConfig = Bitmap.Config.RGB_565; // 构造位图生成的参数,必须为RGB_565
                // 根据指定图片的uri,获得自动缩小后的位图对象
                Bitmap bitmap = BitmapUtil.getAutoZoomImage(this, uri, options);
                fv_face.setImageBitmap(bitmap); // 设置人脸视图的位图对象
            }
        }
    }

}

二、利用OpenCV检测人脸

计算机视觉是一类智能化的工程领域,它研究怎么样让计算机模拟人类的视觉感知,通过观察采集到的图片或者视频处理画面信息获得三维场景结构,进而识别出有用的物体形态或行为事件

【Android App】利用自带的人脸检测器和OpenCV检测人脸讲解及实战(附源码和演示 超详细)_第3张图片

 OpenCV主要由C/C++编写,同时提供多种程序语言接口,它是一个庞大的开源体系 它的概念结构图如下

【Android App】利用自带的人脸检测器和OpenCV检测人脸讲解及实战(附源码和演示 超详细)_第4张图片

 OpenCV的初始化与加载操作包括:

(1)OpenCV初始化

(2)加载so库

(3)加载级联文件

(4)创建OpenCV的人脸检测器

 Imgproc工具用于加工图像矩阵,例如转换颜色空间、添加各类部件、比较图像矩阵等等。

它的常见方法说明如下:

cvtColor:将图像矩阵从一种颜色空间转换为另一种颜色空间。

circle:在图像矩阵上画圆圈。

polylines:在图像矩阵上画多边形。

putText:在图像矩阵上画文本。

rectangle:在图像矩阵上画矩形。

compareHist:比较两个图像矩阵的直方图,并返回二者的相似程度。

位图中人脸检测步骤如下

(1)先将位图对象转为Mat结构,再将Mat结构转成灰度矩阵;

(2)调用人脸检测器的detectMultiScale方法,检测灰度矩阵得到人脸位置的矩形数组;

(3)依次遍历人脸数组,分别调用Imgproc工具的rectangle方法,往Mat结构上的每张人脸画上相框;

(4)把Mat结构转为位图对象,并显示到界面上; 

运行测试App效果如下 

可以看出照片居中  对于观看者更加友好 这也是OpenCV强大的体现

【Android App】利用自带的人脸检测器和OpenCV检测人脸讲解及实战(附源码和演示 超详细)_第5张图片

 代码如下

package com.example.face;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;

import androidx.appcompat.app.AppCompatActivity;

import com.example.face.util.BitmapUtil;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
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 DetectOpencvActivity extends AppCompatActivity {
    private final static String TAG = "DetectOpencvActivity";
    private int CHOOSE_CODE = 3; // 只在相册挑选图片的请求码
    private ImageView iv_face; // 声明一个图像视图对象
    private CascadeClassifier mJavaDetector; // OpenCV的人脸检测器

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detect_opencv);
        iv_face = findViewById(R.id.iv_face);
        findViewById(R.id.btn_choose).setOnClickListener(v -> {
            // 创建一个内容获取动作的意图(准备跳到系统相册)
            Intent albumIntent = new Intent(Intent.ACTION_GET_CONTENT);
            albumIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); // 是否允许多选
            albumIntent.setType("image/*"); // 类型为图像
            startActivityForResult(albumIntent, CHOOSE_CODE); // 打开系统相册
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if (resultCode == RESULT_OK && requestCode == CHOOSE_CODE) { // 从相册返回
            if (intent.getData() != null) { // 从相册选择一张照片
                Uri uri = intent.getData(); // 获得已选择照片的路径对象
                // 根据指定图片的uri,获得自动缩小后的位图对象
                Bitmap bitmap = BitmapUtil.getAutoZoomImage(this, uri);
                detectFace(bitmap); // 检测位图中的人脸
            }
        }
    }

    // 检测位图中的人脸
    private void detectFace(Bitmap orig) {
        Mat rgba = new Mat();
        Utils.bitmapToMat(orig, rgba); // 把位图对象转为Mat结构
        //Mat rgba = Imgcodecs.imread(mFilePath); // 从文件路径读取Mat结构
        //Imgcodecs.imwrite(tempFile.getAbsolutePath(), rgba); // 把Mate结构保存为文件
        Mat gray = new Mat();
        Imgproc.cvtColor(rgba, gray, Imgproc.COLOR_RGB2GRAY); // 全彩矩阵转灰度矩阵
        // 下面检测并显示人脸
        MatOfRect faces = new MatOfRect();
        int absoluteFaceSize = 0;
        int height = gray.rows();
        if (Math.round(height * 0.2f) > 0) {
            absoluteFaceSize = Math.round(height * 0.2f);
        }
        if (mJavaDetector != null) { // 检测器开始识别人脸
            mJavaDetector.detectMultiScale(gray, faces, 1.1, 2, 2,
                    new Size(absoluteFaceSize, absoluteFaceSize), new Size());
        }
        Rect[] faceArray = faces.toArray();
        for (Rect rect : faceArray) { // 给找到的人脸标上相框
            Imgproc.rectangle(rgba, rect.tl(), rect.br(), new Scalar(0, 255, 0, 255), 3);
            Log.d(TAG, rect.toString());
        }
        Bitmap mark = Bitmap.createBitmap(orig.getWidth(), orig.getHeight(), Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(rgba, mark); // 把Mat结构转为位图对象
        iv_face.setImageBitmap(mark);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (!OpenCVLoader.initDebug()) {
            Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
        } else {
            Log.d(TAG, "OpenCV library found inside package. Using it!");
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }
    }

    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            if (status == LoaderCallbackInterface.SUCCESS) {
                Log.d(TAG, "OpenCV loaded successfully");
                // 在OpenCV初始化完成后加载so库
                System.loadLibrary("detection_based_tracker");
                File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
                File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
                // 从应用程序资源加载级联文件
                try (InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
                     FileOutputStream os = new FileOutputStream(cascadeFile)) {
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = is.read(buffer)) != -1) {
                        os.write(buffer, 0, bytesRead);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                // 根据级联文件创建OpenCV的人脸检测器
                mJavaDetector = new CascadeClassifier(cascadeFile.getAbsolutePath());
                if (mJavaDetector.empty()) {
                    Log.d(TAG, "Failed to load cascade classifier");
                    mJavaDetector = null;
                } else {
                    Log.d(TAG, "Loaded cascade classifier from " + cascadeFile.getAbsolutePath());
                }
                cascadeDir.delete();
            } else {
                super.onManagerConnected(status);
            }
        }
    };

}

创作不易 觉得有帮助请点赞关注收藏~~~

你可能感兴趣的:(Android,App,opencv,人工智能,计算机视觉,android,studio,java)