Android App实战项目之使用OpenCV人脸识别实现找人功能(附源码和演示 超详细)

Posted showswoller

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android App实战项目之使用OpenCV人脸识别实现找人功能(附源码和演示 超详细)相关的知识,希望对你有一定的参考价值。

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

人脸识别自古有之,每当官府要捉拿某人时,便在城墙贴出通缉告示并附上那人的肖像。只是该办法依赖人们的回忆与主观判断,指认结果多有出入,算不上什么先进。 如今利用监控摄像头结合机器学习算法,大大提高了人脸识别的成功率,使得人脸识别真正应用到了日常生活中。 从住宅小区的刷脸开门,到工作单位的刷脸考勤,到超市里便捷的刷脸支付,到各城市地铁的刷脸乘车,再到张学友演唱会上警方连续抓获逃犯,人脸识别被广泛地应用于门禁、购物、交通、公安等诸多领域。

一、需求描述

倘若利用人脸识别技术,寻找失散小孩的操作过程包含下列几个步骤:

(1)由家属提供小孩照片并上传给智慧天眼系统;

(2)智慧天眼迅速从各个监控摄像头实时匹配人脸;

(3)一旦发现高相似度的人脸,马上通知家属甄别画面确认是否找到;

 

 二、功能分析

功能主要通过摄像头实时识别人脸,用户只需录入待寻找人员信息,剩下就交给App自动匹配了,在准备寻人与寻人过程中,主要集成了以下App技术

(1)图像裁剪:待寻人员的头像要从原始图片中抠出来。

(2)数据库框架Room:待寻人员的信息要保存到数据库,更新人脸识别的结果也要修改数据库记录。

(3)计算机视觉库OpenCV:智慧天眼采用OpenCV实时寻人,同时通过OpenCV判定目标人员的相似程度。

(4)定位服务:找到相似人员后,要获取并保存当前所在位置,以便家属前来相认。

(5)网络通信框架:根据经纬度访问WEB服务查询详细地址。

下面介绍代码模块之间的关系

(1)WisdomEyeActivity.java:这是智慧天眼的寻人列表界面。

(2)PersonEditActivity.java:这是人员信息的添加页面,可在此上传待识别的人员头像。

(3)PersonCutActivity.java:这是人员头像的裁剪界面。

(4)PersonDetailActivity.java:这是待寻找人员的详情页面。

(5)PersonVerifyActivity.java:这是实时寻人的扫描界面。

三、效果展示

开始界面添加待寻找的人员信息

 

 

成功找到后效果如下

 

四、代码 

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

package com.example.face;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;

import com.example.face.adapter.PersonListAdapter;
import com.example.face.dao.PersonDao;
import com.example.face.entity.PersonInfo;
import com.example.face.entity.PersonPortrait;

import java.util.ArrayList;
import java.util.List;

public class WisdomEyeActivity extends AppCompatActivity implements
        AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener 
    private final static String TAG = "WisdomEyeActivity";
    private ListView lv_person; // 声明一个列表视图对象
    private PersonDao personDao; // 声明一个人员的持久化对象
    private List<PersonInfo> mPersonList = new ArrayList<>(); // 人员信息列表

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_wisdom_eye);
        findViewById(R.id.iv_back).setOnClickListener(v -> finish());
        TextView tv_title = findViewById(R.id.tv_title);
        tv_title.setText("智慧天眼");
        lv_person = findViewById(R.id.lv_person);
        findViewById(R.id.btn_add).setOnClickListener(v -> 
            Intent intent = new Intent(this, PersonEditActivity.class);
            startActivity(intent);
        );
        // 从App实例中获取唯一的人员持久化对象
        personDao = MainApplication.getInstance().getPersonDB().personDao();
    

    @Override
    protected void onResume() 
        super.onResume();
        new Handler(Looper.myLooper()).post(() -> loadPersonList());
    

    // 加载人员列表
    private void loadPersonList() 
        mPersonList = personDao.queryAllPerson(); // 加载所有人员信息
        for (int i=0; i<mPersonList.size(); i++) 
            PersonInfo person = mPersonList.get(i);
            // 根据人员名称查询该人员的样本头像列表
            List<PersonPortrait> portraitList = personDao.queryPersonPortrait(person.getName(), 0);
            person.setPortraitList(portraitList);
            mPersonList.set(i, person);
        
        PersonListAdapter adapter = new PersonListAdapter(this, mPersonList);
        lv_person.setAdapter(adapter);
        // 注册列表项的点击监听器,点击时打开人员详情页面
        lv_person.setOnItemClickListener(this);
        // 注册列表项的长按监听器,长按时弹出是否删除对话框
        lv_person.setOnItemLongClickListener(this);
    

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) 
        PersonInfo person = mPersonList.get(position);
        Intent intent = new Intent(this, PersonDetailActivity.class);
        intent.putExtra("person_name", person.getName());
        startActivity(intent);
    

    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) 
        PersonInfo person = mPersonList.get(position);
        AlertDialog.Builder builder = new AlertDialog.Builder(this)
                .setTitle("请确认")
                .setMessage("你是否要删除"+person.getName()+"的寻人记录")
                .setPositiveButton("是", (dialog, which) -> 
                    // 确定删除,则删除人员信息及其头像信息
                    personDao.deletePerson(person);
                    personDao.deletePortraitByName(person.getName(), -1);
                    loadPersonList(); // 加载人员列表
                )
                .setNegativeButton("否", null);
        builder.create().show();
        return true;
    

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

Android App实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)

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

与传统的影视行业相比,诞生于移动互联网时代的短视频是个全新行业,它制作方便又容易传播,一出现就成为大街小巷的时髦潮流。 各行各业的人们均可通过短视频展示自己,短小精悍的视频片段原来能够容纳如此丰富的内蕴。许多人依靠短视频获得大量关注,乃至成为谋生手段,本人甚至成为网红。 这些都离不开短视频分享平台的推波助澜,尤其是一对欢喜冤家——抖音和快手,它们的使用频率甚至超过了老牌App。其中抖音的国际版TikTok更是风靡全球,它鼓励国外年轻人勇敢表现自我,成为中国企业的出海标杆。

一、需求描述

短视频分享平台需要满足两种角色的使用:

(1)一种是作为内容创作者发布自己的视频,

(2)另一种是作为用户欣赏平台上的已有视频。

还有一些点赞关注弹幕功能这里就不再赘述了 相信大家对短视频平台都不陌生

二、功能分析

短视频分享与传统的图文界面大相径庭,因为单个短视频就已经填满了整块屏幕,势必要求采取专门的方式浏览短视频,从用户界面到后台服务,短视频分享主要集成了以下App技术

(1)二代翻页视图:向上滑动浏览界面能够拉出新视频。

(2)下拉刷新控件:下拉手势会触发刷新动作获取最新发布的视频。

(3)新型播放器:ExoPlayer能够快速响应网络视频。

(4)相机视图:录制短视频需要自定义相机视图。

(5)媒体检索工具:从视频中截取某帧作为视频封面。

(6)循环视图:备选的视频各帧画面从左往右依次排开。

(7)网络通信框架:上传视频信息与获取视频列表均需与后端交互。

(8)移动数据格式JSON:通过JSON结构封装http交互数据。

下面介绍代码模块中各部分之间的关系

(1)ShortViewActivity.java:这是短视频分享的浏览首页。

(2)VideoFragment.java:这是每个短视频的碎片页。

(3)ShortTakeActivity.java:这是视频录制页面。

(4)ShortEditActivity.java:这是视频信息的编辑页面。

(5)ShortCoverActivity.java:这是视频封面的挑选页面。

(6)VideoLoadTask.java:这是视频列表的加载任务。

三、效果展示

在初始界面可以点击录制视频 录制完之后进入编辑页面,可以输入视频的名称 摘要 描述 日期等等信息  发布之后可以自己观看(此处要连接后台服务器IDEA)

 

 

 四、代码

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

短视频分享首页代码

package com.example.video;

import android.content.Intent;
import android.os.Bundle;
import android.view.WindowManager;

import androidx.appcompat.app.AppCompatActivity;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.viewpager2.widget.ViewPager2;

import com.example.video.adapter.VideoPagerAdapter;
import com.example.video.bean.VideoInfo;
import com.example.video.task.VideoLoadTask;

import java.util.ArrayList;
import java.util.List;

public class ShortViewActivity extends AppCompatActivity 
    private SwipeRefreshLayout srl_dynamic; // 声明一个下拉刷新布局对象
    private List<VideoInfo> mVideoList = new ArrayList<>(); // 声明一个地址列表
    private VideoPagerAdapter mAdapter; // 声明一个视频翻页适配器对象

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_short_view);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // 保持屏幕常亮
        initView(); // 初始化视图
        startLoad(); // 开始加载短视频
    

    // 初始化视图
    private void initView() 
        srl_dynamic = findViewById(R.id.srl_dynamic);
        ViewPager2 vp2_content = findViewById(R.id.vp2_content);
        srl_dynamic.setOnRefreshListener(() -> startLoad()); // 设置下拉布局的下拉刷新监听器
        // 构建一个视频地址的翻页适配器
        mAdapter = new VideoPagerAdapter(this, mVideoList);
        vp2_content.setAdapter(mAdapter); // 设置二代翻页视图的适配器
        findViewById(R.id.iv_add).setOnClickListener(v ->
                startActivity(new Intent(this, ShortTakeActivity.class)));
    

    // 开始加载最新的短视频
    private void startLoad() 
        // 创建一个视频列表加载任务
        VideoLoadTask task = new VideoLoadTask(this, videoList -> 
            srl_dynamic.setRefreshing(false); // 结束下拉刷新布局的刷新动作
            mVideoList.clear();
            mVideoList.addAll(videoList);
            mAdapter.notifyDataSetChanged(); // 通知适配器数据发生变化
        );
        task.start(); // 启动短视频列表加载任务
    

短视频任务类代码

package com.example.video;

import android.content.Intent;
import android.hardware.camera2.CameraCharacteristics;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.VideoView;

import androidx.appcompat.app.AppCompatActivity;

import com.example.video.util.MediaUtil;
import com.example.video.util.Utils;
import com.example.video.widget.ArcView;
import com.example.video.widget.Camera2View;

public class ShortTakeActivity extends AppCompatActivity 
    private final static String TAG = "ShortTakeActivity";
    private RelativeLayout rl_preview; // 声明一个相对布局对象
    private VideoView vv_content; // 声明一个视频视图对象
    private RelativeLayout rl_record; // 声明一个相对布局对象
    private Camera2View c2v_preview; // 声明一个二代相机视图对象
    private TextView tv_cost; // 声明一个文本视图对象
    private ImageView iv_record; // 声明一个图像视图对象
    private ArcView av_progress; // 声明一个圆弧视图对象
    private LinearLayout ll_next; // 声明一个线性布局对象
    private int mCameraType = CameraCharacteristics.LENS_FACING_BACK; // 默认使用后置摄像头拍照
    private boolean isRecording = false; // 是否正在录像
    private int MAX_RECORD_TIME = 15; // 最大录制时长,默认15秒
    private String mVideoPath; // 待上传的视频文件路径
    private int CHOOSE_CODE = 3; // 只在视频库挑选视频的请求码

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_short_take);
        initView(); // 初始化视图
        initCamera(); // 初始化相机
    

    // 初始化视图
    private void initView() 
        findViewById(R.id.iv_back).setOnClickListener(v -> finish());
        rl_preview = findViewById(R.id.rl_preview);
        c2v_preview = findViewById(R.id.c2v_preview);
        vv_content = findViewById(R.id.vv_content);
        rl_record = findViewById(R.id.rl_record);
        tv_cost = findViewById(R.id.tv_cost);
        iv_record = findViewById(R.id.iv_record);
        av_progress = findViewById(R.id.av_progress);
        iv_record.setOnClickListener((v) -> dealRecord()); // 处理录像动作
        findViewById(R.id.btn_album).setOnClickListener(v -> 
            // 创建一个内容获取动作的意图(准备跳到系统视频库)
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); // 是否允许多选
            intent.setType("video/*"); // 类型为视频
            startActivityForResult(intent, CHOOSE_CODE); // 打开系统视频库
        );
        findViewById(R.id.iv_switch).setOnClickListener((v) -> 
            mCameraType = (mCameraType == CameraCharacteristics.LENS_FACING_BACK) ?
                    CameraCharacteristics.LENS_FACING_FRONT : CameraCharacteristics.LENS_FACING_BACK;
            c2v_preview.switchCamera(mCameraType); // 切换摄像头
        );
        ll_next = findViewById(R.id.ll_next);
        findViewById(R.id.btn_cancel).setOnClickListener(v -> finish());
        findViewById(R.id.btn_next).setOnClickListener((v) -> 
            // 下面跳到视频编辑界面
            Intent intent = new Intent(this, ShortEditActivity.class);
            intent.putExtra("video_path", mVideoPath);
            startActivity(intent);
        );
    

    // 处理录像动作
    private void dealRecord() 
        if (!isRecording) 
            iv_record.setImageResource(R.drawable.short_stop);
            c2v_preview.startRecord(MAX_RECORD_TIME, false); // 开始录像
            startRecordAnim(); // 播放录像动画
            isRecording = !isRecording;
         else 
            rl_record.setVisibility(View.GONE);
            c2v_preview.stopRecord(); // 停止录像
        
    

    // 初始化相机
    private void initCamera() 
        // 初始化二代相机,并指定准备就绪监听器和停止录像监听器
        c2v_preview.initCamera(mCameraType, (size) -> 
            int adjustHeight = Utils.getScreenWidth(this) * size.getWidth() / size.getHeight();
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) c2v_preview.getLayoutParams();
            params.height = adjustHeight; // 根据预览尺寸调整预览窗口的高度
            c2v_preview.setLayoutParams(params); // 设置预览视图的布局参数
        , (result) -> 
            runOnUiThread(() -> 
                isRecording = false;
                Toast.makeText(this, result, Toast.LENGTH_SHORT).show();
                mVideoPath = c2v_preview.getVideoPath();
                playVideo(); // 播放视频
            );
        );
    

    // 播放视频
    private void playVideo() 
        c2v_preview.closeCamera(); // 关闭相机
        rl_preview.setVisibility(View.GONE);
        rl_record.setVisibility(View.GONE);
        vv_content.setVisibility(View.VISIBLE);
        vv_content.setVideoURI(Uri.parse(mVideoPath)); // 设置视频视图的视频路径
        // 设置视频视图的就绪监听器,在播放源准备完成后,命令媒体播放器循环播放视频
        vv_content.setOnPreparedListener(mp -> mp.setLooping(true));
        vv_content.start(); // 视频视图开始播放
        ll_next.setVisibility(View.VISIBLE);
    

    // 播放录像动画
    private void startRecordAnim() 
        tv_cost.setVisibility(View.VISIBLE);
        av_progress.setVisibility(View.VISIBLE);
        // 定义一个圆弧渐进动画
        Animation animation = new Animation() 
            private String costDesc=""; // 耗时描述
            @Override
            protected void applyTransformation(float interpolatedTime, Transformation t) 
                String cost = String.format("%.1f秒", MAX_RECORD_TIME*interpolatedTime);
                if (!costDesc.equals(cost))  // 秒数发生变化
                    costDesc = cost;
                    tv_cost.setText(costDesc);
                    av_progress.setAngle((int) (360*interpolatedTime)); // 设置圆弧的角度
                
            
        ;
        animation.setDuration(MAX_RECORD_TIME*1000); // 设置动画的持续时间
        tv_cost.startAnimation(animation); // 开始播放动画
    

    @Override
    protected void onDestroy() 
        super.onDestroy();
        c2v_preview.closeCamera(); // 关闭相机
    

    @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的视频复制一份到内部存储空间,并返回存储路径
                mVideoPath = MediaUtil.copyVideoFromUri(this, uri);
                playVideo(); // 播放视频
            
        
    

    private int mCurrentPosition = 0; // 当前的播放位置
    @Override
    protected void onResume() 
        super.onResume();
        // 恢复页面时立即从上次断点开始播放视频
        if (!TextUtils.isEmpty(mVideoPath) && mCurrentPosition>0 && !vv_content.isPlaying()) 
            vv_content.seekTo(mCurrentPosition); // 找到指定位置
            vv_content.start(); // 视频视图开始播放
        
    

    @Override
    protected void onPause() 
        super.onPause();
        // 暂停页面时保存当前的播放进度
        if (!TextUtils.isEmpty(mVideoPath) && vv_content.isPlaying())  // 视频视图正在播放
            // 获得视频视图当前的播放位置
            mCurrentPosition = vv_content.getCurrentPosition();
            vv_content.pause(); // 视频视图暂停播放
        
    

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

以上是关于Android App实战项目之使用OpenCV人脸识别实现找人功能(附源码和演示 超详细)的主要内容,如果未能解决你的问题,请参考以下文章

Android App实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)

Android App实战项目之仿微信的视频通话(附源码和演示 超详细必看)

Android App人脸识别中使用Opencv比较两张人脸相似程度实战(附源码和演示 超详细)

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

Android App实战项目之实现你问我答的智能语音机器人(超详细 附源码和演示视频)

Android App实战项目之虚拟现实(VR)的全景相册(附源码和演示视频 可用于学习和大作业)