Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上

这篇具有很好参考价值的文章主要介绍了Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 前言

上篇文章 我们已经通过一个简单的例子,在Android Studio中接入了OpenCV
之前我们也 在Visual Studio上,使用OpenCV实现人脸识别 中实现了人脸识别的效果。
接着,我们就可以将OpenCV的人脸识别效果移植到Android中了。

1.1 环境说明

  • 操作系统 : windows 10 64
  • Android Studio版本 : Android Studio Giraffe | 2022.3.1
  • OpenCV版本 : OpenCV-4.8.0 (2023年7月最新版)

1.2 实现效果

先来看下实现效果,识别到的人脸会用红框框出来。

Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上,音视频开发,android,opencv,人工智能,图像识别,人脸识别
接下来我们来一步步实现上述的效果。

2. 前置操作

2.1 添加权限

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
ActivityCompat.requestPermissions(
    this@FaceDetectionActivity,
    arrayOf(
        Manifest.permission.CAMERA,
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.RECORD_AUDIO
    ),
    1
)

2.2 新建FaceDetectionActivity

新建FaceDetectionActivity,并将其设为默认的Activity,然后修改其XML布局

<?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"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:background="@color/black"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <SurfaceView
            android:id="@+id/surfaceView"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintDimensionRatio="w,4:3"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:layout_height="wrap_content">
        <Button

            android:text="切换摄像头"
            android:onClick="switchCamera"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
</RelativeLayout>

2.3 添加JNI方法

然后修改FaceDetectionActivity为如下代码,这里增加了三个JNI方法

  • init : 初始化OpenCV人脸识别
  • setSurface : 设置SurfaceView
  • postData : 发送视频帧数据
class FaceDetectionActivity : AppCompatActivity() {
    private lateinit var binding: ActivityFaceDetectionBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityFaceDetectionBinding.inflate(layoutInflater)
        setContentView(binding.root)
		
		//这里省略了申请权限的代码...
    }

	//初始化OpenCV
    external fun init(path: String?)

	//向OpenCV发送一帧的图像数据
    external fun postData(data: ByteArray?, width: Int, height: Int, cameraId: Int)

	//设置SurfaceView
    external fun setSurface(surface: Surface?)

    companion object {
        init {
            System.loadLibrary("myopencvtest")
        }
    }
}

同时,需要在native-lib.cpp中添加这三个JNI方法,这里的com_heiko_myopencvtest_FaceDetectionActivity需要改为你实际的包名和类名。

extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_init(JNIEnv *env, jobject thiz, jstring path) {

}
extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_postData(JNIEnv *env, jobject thiz,
                                                           jbyteArray data, jint width, jint height,
                                                           jint camera_id) {
}
extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_setSurface(JNIEnv *env, jobject thiz,
                                                             jobject surface) {
}

2.4 实现相机预览功能

这里用到了Camera1 API,直接使用CameraHelper这个工具类接入即可,这部分详见我的另一篇博客 Android 使用Camera1的工具类CameraHelper快速实现相机预览、拍照功能

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityFaceDetectionBinding.inflate(layoutInflater)
	setContentView(binding.root)
	
	//这里省略了申请权限的代码...
	
	val surfaceView = findViewById<SurfaceView>(R.id.surfaceView)
	surfaceView.holder.addCallback(this)
	cameraHelper = CameraHelper(cameraId)
	cameraHelper.setPreviewCallback(this)
}

3. 初始化OpenCV

3.1 配置OpenCV

接着,我们不要忘了配置OpenCV,这部分详见我的另一篇博客 : Android Studio 接入OpenCV最简单的例子 : 实现灰度图效果

3.2 赋值级联分类器文件

配置好OpenCV,我们要将模型,也就是人脸识别的级联分类器文件haarcascade_frontalface_alt.xml复制到asserts文件夹下。

当我们启动App的时候,需要将该文件复制到外置存储中。

 override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
	//省略了其他代码...
	
	//Utils类可以在本文末尾复制
	Utils.copyAssets(this@FaceDetectionActivity, "haarcascade_frontalface_alt.xml")
}

拷贝完成后,调用init()方法,传入路径

override fun onResume() {
        super.onResume()
		//省略了其他代码...

		//Utils类可以在本文末尾复制
        val path = Utils.getModelFile(
            this@FaceDetectionActivity,
            "haarcascade_frontalface_alt.xml"
        ).absolutePath
        
        init(path)
    }

4. 实现CascadeDetectorAdapter

这里我们需要将我的另一篇博客中的 在Visual Studio上,使用OpenCV实现人脸识别 (下面统称为VS实现) 中的代码移植过来。

这里创建了CascadeDetectorAdapter,实现了DetectionBasedTracker::IDetector接口,和VS实现上代码是一样的。

class CascadeDetectorAdapter : public DetectionBasedTracker::IDetector
{
public:
    CascadeDetectorAdapter(cv::Ptr<cv::CascadeClassifier> detector) :
            IDetector(),
            Detector(detector)
    {
        CV_Assert(detector);
    }

    void detect(const cv::Mat& Image, std::vector<cv::Rect>& objects)
    {
        Detector->detectMultiScale(Image, objects, scaleFactor, minNeighbours, 0, minObjSize, maxObjSize);
    }

    virtual ~CascadeDetectorAdapter()
    {
    }

private:
    CascadeDetectorAdapter();
    cv::Ptr<cv::CascadeClassifier> Detector;
};

cv::Ptr<DetectionBasedTracker> tracker;

5. 实现init方法

init方法也是一样的,声明tracker对象,并调用run()方法,会启动一个异步线程,后面的人脸检测会在这个异步线程进行检测了。(这个是保障实时人脸检测不卡的前提)

//cv::Ptr<DetectionBasedTracker> tracker;
DetectionBasedTracker *tracker = 0;

extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_init(JNIEnv *env, jobject thiz, jstring path) {
    string stdFileName = env->GetStringUTFChars(path, 0);
    //创建一个主检测适配器
    cv::Ptr<CascadeDetectorAdapter> mainDetector = makePtr<CascadeDetectorAdapter>(
            makePtr<CascadeClassifier>(stdFileName));
    //创建一个跟踪检测适配器
    cv::Ptr<CascadeDetectorAdapter> trackingDetector = makePtr<CascadeDetectorAdapter>(
            makePtr<CascadeClassifier>(stdFileName));
    //创建跟踪器
    DetectionBasedTracker::Parameters DetectorParams;
    //tracker = makePtr<DetectionBasedTracker>(mainDetector, trackingDetector, DetectorParams);
    tracker= new DetectionBasedTracker(mainDetector, trackingDetector, DetectorParams);
    tracker->run();
}

5. 设置Surface

Android NDK 中,ANativeWindow 是一个C/C++接口,它提供了一种在 CC++ 代码中访问 Android Surface 的方式。通过使用ANativeWindow接口,开发者可以在NDK中直接访问和操作Android窗口系统,实现图形处理和渲染操作。
这里我们将SurfaceView传到JNI中,方便C/C++代码后边将图像实时渲染到Android SurfaceView上。

#include <android/native_window_jni.h>

ANativeWindow *window = 0;

extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_setSurface(JNIEnv *env, jobject thiz,
                                                             jobject surface) {
    if (window) {
        ANativeWindow_release(window);
        window = 0;
    }
    window = ANativeWindow_fromSurface(env, surface);
}

6. 处理数据并实现人脸识别

处理图像数据的部分我们在postData中实现,这部分会先对图像进行处理,然后进行人脸识别,并渲染到SurfaceView上。

extern "C"
JNIEXPORT void JNICALL
Java_com_heiko_myopencvtest_FaceDetectionActivity_postData(JNIEnv *env, jobject instance, jbyteArray data_,
                                                                                                    jint w, jint h, jint cameraId) {
    //待实现的代码
}

6.1 将图片转化为Mat

参数中的jbyteArray data_,是从Android Java层中获取到的。
然后转化为jbyte *data这个字节数组,接着将其转为一个Mat矩阵。
Mat是是OpenCV最基本的数据结构。它用于存储图像数据。
需要注意的是,由于传入的数据是YUV420,每个像素占1.5byte
所以这个图像的宽度需要传入实际宽度*1.5,宽度不变。
这里的CV_8UC1是单通道的意思,就是说无论是Y分量还是UV分量,都存储在同一个通道里。

jbyte *data = env->GetByteArrayElements(data_, NULL);
Mat src(h + h / 2, w, CV_8UC1, data);

要获取Mat对象中每个通道的数据,可以使用OpenCV提供的函数和方法。
对于一个BGR图像(即具有三个通道的图像),每个通道的数据可以分别获取并进行处理。
以下是一些示例代码,演示如何获取每个通道的数据:

// 假设img是包含BGR图像的Mat对象    
// 获取B通道数据   
Mat bChannel = img.channel(0);   
// 获取G通道数据   
Mat gChannel = img.channel(1);   
//获取R通道数据   
Mat rChannel = img.channel(2); 

6.2 将YUV转为RGBA

接着,需要将YUV格式转化为RGBA格式,方便后续的操作。
这里的COLOR_YUV2RGBA_NV21表示原始是NV21YUV格式,将其转为RGBA格式。

cvtColor(src, src, COLOR_YUV2RGBA_NV21);

6.3 对图像做翻转和镜像

由于手机摄像头硬件安装在手机里时,和屏幕的方向并不是一致的,所以需要将摄像头拍摄的画面进行旋转。

  • 如果是前置摄像头 : 需要将画面逆时针旋转90度,并做左右镜像操作
  • 如果是后置摄像头 : 需要将画面顺时针旋转90度
if (cameraId == 1) {
    //前置摄像头
    rotate(src, src, ROTATE_90_COUNTERCLOCKWISE);
    //1:左右镜像
    //0:上下镜像
    flip(src, src, 1);
}    else {
    //顺时针旋转90度
    rotate(src, src, ROTATE_90_CLOCKWISE);
}

6.4 转为灰度图并进行直方图均衡化处理

接着需要对图像进行灰度和直方图均衡化处理,以便提高人脸识别的准确性和可靠性,这部分和VS实现上是一样。

Mat gray;
//转为灰度图
cvtColor(src, gray, COLOR_RGBA2GRAY);
//直方图均衡化
equalizeHist(gray, gray);

6.5 进行人脸检测

接着就可以调用tracker->process来建人脸检测了。
检测完成后,接着调用tracker->getObjects将检测的人脸位置赋值给faces

std::vector<Rect> faces;
tracker->process(gray);
tracker->getObjects(faces);

6.6 将人脸用红框框出来

接着,将识别到的人脸,用红色的矩形框绘制出来,rectangle方法就是用来绘制一个矩形框的方法。

for (Rect face : faces) {
    rectangle(src, face, Scalar(255, 0, 0));
}

6.7 将图像渲染到SurfaceView上

6.7.1 设置窗口缓冲区

ANativeWindow_setBuffersGeometry是设置Android Native窗口的缓冲区的大小和像素格式。

if (window) {
    ANativeWindow_setBuffersGeometry(window, src.cols, src.rows, WINDOW_FORMAT_RGBA_8888);
	
	//后续代码在这里编写...
}
6.7.2 将图像数据填充到窗口的缓冲区

这里是个while循环,会不断地将图像数据(RGBA),填充到窗口的缓冲区,最后调用ANativeWindow_unlockAndPost提交刷新,图像就渲染到SurfaceView上了。

ANativeWindow_Buffer window_buffer;
do {
    //如果 lock 失败,直接 break
    if (ANativeWindow_lock(window, &window_buffer, 0)) {
        ANativeWindow_release(window);
        window = 0;
        break;
    }
    //将window_buffer.bits转化为 uint8_t *
    uint8_t *dst_data = static_cast<uint8_t *>(window_buffer.bits);
    //stride : 一行多少个数据 (RGBA) * 4
    int dst_linesize = window_buffer.stride * 4;

    //一行一行拷贝
    for (int i = 0; i < window_buffer.height; ++i) {
        memcpy(dst_data + i * dst_linesize, src.data + i * src.cols * 4, dst_linesize);
    }
    //提交刷新
    ANativeWindow_unlockAndPost(window);
} while (0);

6.8 回收资源

最后,别忘了回收资源

src.release();
gray.release();
env->ReleaseByteArrayElements(data_, data, 0);

7. 运行项目

我们可以看到效果如下,至此我们就完成在Android上,使用OpenCV实现实时的人脸识别了。

Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上,音视频开发,android,opencv,人工智能,图像识别,人脸识别

8. 本文源码下载

Android和Windows下,使用OpenCV实现人脸识别 示例 Demo

9. OpenCV系列文章

Visual Studio 2022 cmake配置opencv开发环境_opencv visualstudio配置_氦客的博客-CSDN博客
在Visual Studio上,使用OpenCV实现人脸识别_氦客的博客-CSDN博客
Android Studio 接入OpenCV,并实现灰度图效果_氦客的博客-CSDN博客
Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上_氦客的博客-CSDN博客

❤️ 如果觉得这篇博文写的不错,对你有所帮助,帮忙点个赞👍
⭐ 这是对我持续输出高质量博文的最好鼓励。😄文章来源地址https://www.toymoban.com/news/detail-692211.html

到了这里,关于Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java使用opencv实现人脸识别、人脸比对

    1. opencv概述 OpenCV是一个开源的计算机视觉库,它提供了一系列丰富的图像处理和计算机视觉算法,包括图像读取、显示、滤波、特征检测、目标跟踪等功能。 opencv官网:https://opencv.org/ opencv官网文档:https://docs.opencv.org/4.7.0/index.html 参考教程1:https://www.w3cschool.cn/opencv/ 参考教

    2024年02月08日
    浏览(19)
  • 使用Python和OpenCV实现实时人脸检测并保存截图

    在本篇博客中,我们将使用Python和OpenCV库实现一个实时人脸检测的小项目。我们将利用OpenCV中的Haar级联分类器来检测摄像头捕获的图像中的人脸。 通过摄像头实时捕获视频流。 使用Haar级联分类器检测视频帧中的人脸。 在检测到的人脸周围绘制矩形框。 实时显示检测结果。

    2024年02月11日
    浏览(15)
  • Android:绘制自定义View人脸识别框

    项目开发需要自定义View实现一个人脸框,代码实现很平常,一些细节记录一下,方便以后查阅。 代码实现: FaceView.java 注意: 这里我把FaceView的layout_width、layout_height都设置成了\\\"match_parent\\\" 这里面有个 坑 容易踩到 本次开发时,xml中FaceView控件往上一直到第一层父布局宽、高

    2024年02月09日
    浏览(34)
  • 使用opencv实现简单的人脸识别

    opencv-python是一个python绑定库,旨在解决计算机视觉问题。使用opencv模块,可以实现一些对图片和视频的操作。 安装opencv之前需要先安装numpy, matplotlib。然后使用pip安装opencv库即可。 使用import cv2进行导入即可,需要注意的是cv2读取图片的颜色通道是BGR(蓝绿红)。 使用cv2.

    2023年04月19日
    浏览(18)
  • Qt开发_调用OpenCV(4.x)完成人脸检测并绘制马赛克(摄像头实时数据)

    这个基于Qt和OpenCV的人脸检测和人脸打码项目是通过实时视频流中的人脸识别来保护隐私。 该项目目的是保护隐私并确保人脸数据安全。在某些情况下,使用实时视频流进行人脸检测和识别可能涉及对个人隐私的侵犯。通过在图像中打码人脸区域,可以避免未经许可的人脸出

    2024年02月06日
    浏览(19)
  • 在Visual Studio上,使用OpenCV实现人脸识别

    本文介绍了如何在 Visual Studio 上,使用 OpenCV 来实现人脸识别的功能 环境说明 : 操作系统 : windows 10 64位 Visual Studio 版本 : Visual Studio Community 2022 (社区版) OpenCV 版本 : OpenCV-4.8.0 (2023年7月最新版) 实现效果如图所示,识别到的人脸会用红框框出来 : 这部分详见我的另一篇博客 :

    2024年02月12日
    浏览(20)
  • 使用OpenCV工具包成功实现人脸检测与人脸识别,包括传统视觉和深度学习方法(附完整代码,模型下载......)

    要实现人脸识别功能,首先要进行人脸检测,判断出图片中人脸的位置,才能进行下一步的操作。 参考链接: 1、OpenCV人脸检测 2、【OpenCV-Python】32.OpenCV的人脸检测和识别——人脸检测 3、【youcans 的图像处理学习课】23. 人脸检测:Haar 级联检测器 4、OpenCV实战5:LBP级联分类器

    2024年02月08日
    浏览(16)
  • 使用OpenCV工具包成功实现人脸检测与人脸识别,包括传统视觉和深度学习方法(附完整代码,吐血整理......)

    要实现人脸识别功能,首先要进行人脸检测,判断出图片中人脸的位置,才能进行下一步的操作。 参考链接: 1、OpenCV人脸检测 2、【OpenCV-Python】32.OpenCV的人脸检测和识别——人脸检测 3、【youcans 的图像处理学习课】23. 人脸检测:Haar 级联检测器 4、OpenCV实战5:LBP级联分类器

    2024年02月12日
    浏览(11)
  • 基于OpenCV提供的人脸识别算法LBPH实现人脸识别

    本文通过学习LBPH人脸识别算法,简要了解人脸识别技术的原理,实现人脸采集、训练人脸模型实现人脸识别。 OpenCV库自带的人脸级联分级器具有很好的人脸检测和人脸追踪效果,它是一个基于Haar特征的Adaboost级联分类器。特别注意,OpenCV库虽然自带人脸级联分级器,但是识

    2024年02月03日
    浏览(17)
  • 【图像处理】使用Python进行实时人脸检测和识别

            你有没有想过用Python构建一个面部识别系统?不要再看了!在本教程中,我们将使用 face_recognition 库来检测和识别视频流、图像甚至使用网络摄像头实时检测和识别人脸。         人脸识别和人脸检测是计算机视觉领域的两个独立任务。         人脸检测

    2024年02月13日
    浏览(13)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包