【Android App】人脸识别中OpenCV根据人脸估算性别和年龄实战(附源码和演示 超详细)

news2024/9/24 9:19:47

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

人脸蕴含的信息量巨大,不管是青春还是年少,还是老年沧桑,都能体现出来,不过从人脸估算年龄估算年龄全凭经验,毕竟计算机无法根据固定框架判断年龄,那么计算机的经验从何而来呢?当然是要人类把经验传授给它,这种经验在机器学习领域称作模型,通过海量的原始样本训出结果模型,然后由计算机依据模型执行辨别操作

一、根据人脸估算性别和年龄

在App工程中使用年龄模型和性别模型需要按照以下步骤处理

(1)导入年龄模型文件,以及性别模型文件。

(2)把assets目录下的模型资源复制到存储卡。

(3)在代码中初始化年龄模型和性别模型。

(4)根据模型网络对人脸矩阵分别猜测年龄和性别。

但是根据这样的方法猜测出来的年龄和性别都带有中文字符,虽然OpenCV的imgproc工具提供了putText方法,但是该方法还不支持往图像上写中文,若调用putText方法写中文的话只会看到一堆乱码,为了在图像上看到年龄和性别,可以采取以下两种方法

1:修改OpenCV的C语言源码,在putText函数旁边增加putTextZH函数,新函数专门用来添加中文字符,同时还要修改sdk的Imgproc.java 补充native类型的putTextZH方法声明

2:第一种方法设计C代码修改与so库编译,操作十分麻烦,为此考虑先将OpenCV的mat结构转换为位图对象,再借助画布往位图上描绘文字

二、效果展示 

先上一张神仙姐姐刘亦菲的照片

可见性别判断的非常准确 但是年龄只能给出一个区间 有待改进

这个就有点抽象了 年轻时候的贝克汉姆竟然识别到51-65这个区间肯定是不合理的  

 

马儿的判断还是比较准确的 

 

梅西判断的也还比较准确 

 

 三、代码

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

package com.example.face;

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

import androidx.appcompat.app.AppCompatActivity;

import com.example.face.util.BitmapUtil;
import com.example.face.util.FaceUtil;
import com.example.face.util.FaceUtil.FaceText;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Core;
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.dnn.Dnn;
import org.opencv.dnn.Net;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

public class GuessAgeActivity extends AppCompatActivity {
    private final static String TAG = "GuessAgeActivity";
    private int CHOOSE_CODE = 3; // 只在相册挑选图片的请求码
    private ImageView iv_face; // 声明一个图像视图对象
    private CascadeClassifier mJavaDetector; // OpenCV的人脸检测器
    private Net mAgeNet, mGenderNet; // 年龄模型,性别模型

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_guess_age);
        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);
                guessAgeAndSex(bitmap); // 根据人脸猜测年龄和性别
            }
        }
    }

    // 根据人脸猜测年龄和性别
    private void guessAgeAndSex(Bitmap orig) {
        Mat rgba = new Mat();
        Utils.bitmapToMat(orig, rgba); // 把位图对象转为Mat结构
        Mat gray = new Mat();
        Imgproc.cvtColor(rgba, gray, Imgproc.COLOR_RGB2GRAY); // 全彩矩阵转灰度矩阵
        Mat three = new Mat();
        Imgproc.cvtColor(rgba, three, Imgproc.COLOR_RGBA2RGB); // 四通道转三通道
        // 下面识别人脸并预测年龄和性别
        MatOfRect faces = new MatOfRect();
        int height = gray.rows();
        int absoluteFaceSize = 0;
        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();
        List<FaceText> textList = new ArrayList<>();
        int lineWidth = Math.max(orig.getWidth()/600 + 1, orig.getHeight()/600 + 1);
        for (Rect rect : faceArray) { // 给找到的人脸标上相框
            String ageText = predictAge(mAgeNet, three.submat(rect)); // 猜测年龄
            String genderText = predictGender(mGenderNet, three.submat(rect)); // 猜测性别
            Scalar scalar = new Scalar(0, 255, 0, 255);
            Imgproc.rectangle(rgba, rect.tl(), rect.br(), scalar, lineWidth);
            PointF pos = new PointF((float) rect.tl().x / rgba.width(), (float) rect.tl().y / rgba.height());
            textList.add(new FaceText(pos, genderText + "," + ageText));
            //OpenCV的putText方法写中文会乱码,目前OpenCV的Java开发包还不支持中文
            //Imgproc.putText(rgba, ageText, rect.tl(), FONT_HERSHEY_PLAIN, 1.2, new Scalar(0, 0, 255), 1);
        }
        Bitmap mark = Bitmap.createBitmap(orig.getWidth(), orig.getHeight(), Bitmap.Config.ARGB_8888);
        Utils.matToBitmap(rgba, mark); // 把Mat结构转为位图对象
        mark = FaceUtil.drawTextList(this, mark, textList); // 往位图添加多个文字
        iv_face.setImageBitmap(mark);
    }

    // 获取年龄列表
    private List<String> ageLabels() {
        List<String> ageList = new ArrayList<>();
        ageList.add("0 - 3");
        ageList.add("4 - 7");
        ageList.add("8 - 14");
        ageList.add("15 - 24");
        ageList.add("25 - 37");
        ageList.add("38 - 50");
        ageList.add("51 - 65");
        ageList.add("66 -");
        return ageList;
    }

    // 根据模型网络分析预测图像矩阵
    private Core.MinMaxLocResult predictResult(Net modelNet, Mat imageMat) {
        // 输入图像矩阵
        Mat blob = Dnn.blobFromImage(imageMat, 1.0, new Size(227, 227));
        modelNet.setInput(blob, "data");
        Mat prob = modelNet.forward("prob"); // 模型网络开始预测
        Mat probMat = prob.reshape(1, 1);
        return Core.minMaxLoc(probMat);
    }

    // 猜测年龄
    private String predictAge(Net modelNet, Mat imageMat) {
        Core.MinMaxLocResult result = predictResult(modelNet, imageMat);
        return ageLabels().get((int) result.maxLoc.x);
    }

    // 猜测性别
    private String predictGender(Net modelNet, Mat imageMat) {
        Core.MinMaxLocResult result = predictResult(modelNet, imageMat);
        //return ((int) result.maxLoc.x)==1 ? "男" : "女";
        return ((int) result.maxLoc.x)==1 ? "女" : "男";
    }

    @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) {
                new Thread(() -> importModel()).start(); // 启动分线程导入年龄模型和性别模型
                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);
            }
        }
    };

    // 导入年龄模型和性别模型
    private void importModel() {
        String prePath = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + "/";
        String age_model = prePath + "age_net.caffemodel";
        String age_text = prePath + "age_deploy.prototxt";
        String gender_model = prePath + "gender_net.caffemodel";
        String gender_text = prePath + "gender_deploy.prototxt";
        mAgeNet = Dnn.readNetFromCaffe(age_text, age_model);
        mGenderNet = Dnn.readNetFromCaffe(gender_text, gender_model);
    }

}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/57023.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ZYNQ之FPGA学习----IIC协议驱动模块仿真实验

1 IIC通信协议简介 IIC通信协议基础知识学习&#xff1a;硬件设计基础----通信协议IIC 2 实验任务 设计IIC驱动模块&#xff0c;并进行仿真验证&#xff0c;观察仿真波形 3 实验设计 3.1 创建工程 新建工程&#xff0c;操作如图所示&#xff1a; 输入工程名和路径&#x…

C++I/O流详解

目录 一&#xff0c;引入 二&#xff0c;C中的输入输出 1&#xff0c;输入输出流分类 2&#xff0c;I/O流类的安全性和可扩展性 (1)I/O流类的安全性 (2)I/O流类的扩展性 三&#xff0c;流类库简介 1&#xff0c;I/O流类库 2&#xff0c;缓冲区类 四&#xff0c;标准输…

python入门基础

1 变量和简单数据类型 变量命名格式&#xff1a;变量名 “赋值” 1.1 变量使用规范 使用变量时&#xff0c;需要遵守一些规则。违反这些规则将引发错误。 ~变量名只能包含数字、字母、下划线。变量名不能以数字开头以及不能包含空格。 ~变量名不能将Python保留字和函数名…

SpringColud——Eureka注册中心

目录 1、SpringColud概述 1.1、什么是微服务 1.2、什么是SpringColud&#xff1f; 1.3、SpringColud的特点 2、SpringColud环境准备 2.1、创建父工程 2.2、修改pom.xml文件 2.3、服务提供者——创建子工程 2.4、编写启动类 2.5、编写User类 2.6、编写UserMapper接口…

永磁同步电机恒压频比(V/F)开环控制系统Matlab/Simulink仿真分析及代码生成到工程实现

文章目录前言一、 恒压频比&#xff08;V/F&#xff09;控制原理二、永磁同步电机恒压频比开环控制系统Matlab/Simulink仿真分析2.1.仿真电路分析2.1.1.恒压频比控制算法2.1.2.输出处理2.1.3.主电路2.2.仿真结果分析2.2.1.设定目标转速为1200r/min2.2.1.设定目标转速为变化值三…

消息中间件ActiveMQ入门概述

目录 举一反三 思考 背景 消息中间件的作用 MQ的定义 MQ的特点 MQ的缺点 消息中间件已经成为互联网企业应用系统内部通信的核心手段&#xff0c;是目前企业内主流标配技术&#xff0c; 它具有解耦、异步、削峰、签收、事务、流量控制、最终一致性等一系列高性能架构所需…

并发编程详解: 十三个工具类, 十大设计模式, 从理论基础到案例实战

前言 对于 Java 程序员而言&#xff0c;熟练掌握并发编程是判断其卓越性的重要标准之一。因为并发编程是 Java 语言中最晦涩的知识点&#xff0c;它涉及操作系统&#xff0c;内存&#xff0c;CPU&#xff0c;编程语言等的基本功&#xff0c;并且还测试了程序员的内功。 那么如…

【Android App】人脸识别中借助摄像头和OpenCV实时检测人脸讲解及实战(附源码和演示 超详细)

需要全部代码请点赞关注收藏后评论区留言私信~~~ 一、借助摄像头实时检测人脸 与Android自带的人脸检测器相比&#xff0c;OpenCV具备更强劲的人脸识别功能&#xff0c;它可以通过摄像头实时检测人脸&#xff0c;实时检测的预览空间是JavaCameraView 常用方法说明如下 setCvC…

舵机应该如果选择?讲讲模拟舵机,数字舵机和总线舵机的区别

推荐视频&#xff1a;模拟舵机&#xff0c;数字舵机和总线舵机科普 &#xff1b;舵机从入门到放弃&#xff1b; 很多时候&#xff0c;我们购买舵机就只知道考虑扭矩以及控制方式。对舵机的分类有所耳闻&#xff0c;但是不清楚其中的区别。接下来我将详细说明模拟舵机&#xff0…

【机器学习】基于机器学习的反弹shell命令识别

引言 本文介绍一个基于机器学习识别反弹shell的项目。 在主机安全检测中&#xff0c;一般是采用基于原理的方式识别反弹shell, 通过判断socket通信相关特征&#xff0c;可以准确地识别到主机中的反弹shell。 但是在容器场景下&#xff0c;检测反弹shell 的能力&#xff0c;可能…

[附源码]计算机毕业设计springboot疫情物资管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

2022年第十一届认证杯数学中国数学建模国际赛小美赛:C 题 对人类活动进行分类 建模方案及代码实现

2022年第十一届认证杯数学中国数学建模国际赛小美赛&#xff1a;C 题 对人类活动进行分类 建模方案及代码实现 1 题目 人类行为理解的一个重要方面是对日常活动的识别和监控。可穿戴活动识别系统可以在许多关键领域提高生活质量&#xff0c;如门诊监测、居家康复、跌倒检测等。…

[附源码]Python计算机毕业设计Django茂名特产销售商城网站

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

[Java安全]—再探Filter内存马

前言 关于tomcat反序列化注入回显内存马问题中&#xff0c;就是通过filter内存马进行反序列化动态注册的&#xff0c;但filter内存马由于当时学的时候就没有学的很明白&#xff0c;所以打算重新回顾一下。 前置知识 Tomcat 与 Servlet 的关系 Tomcat中有四种类型的Servlet容…

[Python私活案例]24行代码,轻松赚取400元,运用Selenium爬取39万条数据

今天分享一单来自金主爸爸的私单&#xff0c;运用简单的爬虫技巧&#xff0c;可以有效的规避反爬机制&#xff0c;正所谓“你有张良计&#xff0c;我有过云梯”。这个案例也很好的体现了python语音的优势&#xff0c;规避了非常复杂的底层逻辑&#xff0c;所见即所得&#xff0…

你真的看懂扩散模型(diffusion model)了吗?(从DALL·E 2讲起,GAN、VAE、MAE都有)

本文全网原创于CSDN&#xff1a;落难Coder &#xff0c;未经允许&#xff0c;不得转载&#xff01; 扩散模型简单介绍 我们来讲一下什么是扩散模型&#xff0c;如果你不了解一些工作&#xff0c;你可能不清楚它究竟是什么。那么我举两个例子说一下&#xff1a;AI作画&#xff…

分布滞后线性和非线性模型(DLNM)分析空气污染(臭氧)、温度对死亡率时间序列数据的影响...

全文下载链接 http://tecdat.cn/?p23947 分布滞后非线性模型&#xff08;DLNM&#xff09;表示一个建模框架&#xff0c;可以灵活地描述在时间序列数据中显示潜在非线性和滞后影响的关联。该方法论基于交叉基的定义&#xff0c;交叉基是由两组基础函数的组合表示的二维函数空间…

为什么要让img浮动:

为什么要浮动&#xff1a; 图片不浮动的话&#xff0c;图片和文字是像下面这样排版的&#xff1a; 代码&#xff1a; <img src"https://static.maizuo.com/pc/v5/usr/movie/1f25dd6943762288dfd84b961c98f478.jpg" /> <div><div>红发歌姬</d…

OpenAI发布ChatGPT:程序员瞬间不淡定了

OpenAI发布ChatGPT&#xff1a;程序员瞬间不淡定了 12月1日&#xff0c;OpenAI发布了针对对话场景优化的语言大模型ChatGPT。ChatGPT是InstructGPT的兄弟模型&#xff0c;可以以对话的形式与用户交互&#xff0c;这使得ChatGPT能够回答问题、承认错误、质疑假设、拒绝不当问题…

时尚品牌Gucci 的Web3元宇宙营销进行时ing

Gucci 宣布在 The Sandbox 中推出 “Gucci Vault Land” 古驰藏宝阁 —— 元宇宙中心 &#xff0c;成为第一个在 The Sandbox 虚拟世界中拥有专门用于 Web3 产品的主流时尚品牌。Gucci 美学概念空间开放日&#xff1a;10月27日-11月 9 日 2022 年 Gucci Vault Land建立虚拟世界…