安卓NDK开发——基于JNI与NCNN实现深度神经网络口罩佩带检测模型部署

前言

1.这是一个是检测人员是否佩戴口罩的的安卓NDK项目,只检测人脸上是否有口罩是,是于检测是否佩戴标准,比如是否盖住嘴巴和鼻子,是否标准的医用的口罩的模型还在优化训练中。项目源码地址:https://download.youkuaiyun.com/download/matt45m/85252239
2.开发环境是win10,IDE是Android studio 北极狐,用到的库有NCNN,OpenCV,NCNN库可以用官方编译好的releases库,也可以按官方文档自己编译。OpenCV用的是nihui大佬简化过的opencv-mobile,大小只有10多M,如果不嫌大也可以用OpenCV官方的版本。测试使用的安卓手机是mate 30 pro ,有测试CPU和GPU两个性能。
3.项目的各种依赖版本:
在这里插入图片描述
在这里插入图片描述

一、模型训练

1.使用的数据集是开源的人脸口罩数据集:https://github.com/X-zhangyang/Real-World-Masked-Face-Dataset。数据集基本都是标佩戴。
在这里插入图片描述
2.所用的模型训练框架是 yolov5 lite ,在移动端上在保证精度的同时,如果能用上GPU加速,速度能达到10FPS以上。
3.把训练好的模型先onnx,简化之后再转ncnn的模型,这个可以参考ncnn的官网,如果觉得麻烦,也可以直接转pnnx之后直接转ncnn。

二、项目部署

1.创建一个Native C++项目
在这里插入图片描述
2.把下载好的NCNN和OpenCV so库粘贴到cpp目录下,这里只要arm64-v8a和armeadbi-v7a这两个库,这样的话,项目会小很多,但就是不能在安卓的虚拟机上运行,毕竟ncnn在虚拟机也是跑不动的。
在这里插入图片描述
3.添加推理代码
3.1 faceMask.h

#ifndef _FACE_FACEMASK_H_
#define _FACE_FACEMASK_H_

#include "net.h"
#include <opencv2/opencv.hpp>
#include "cpu.h" //安卓上有cpu推理优化

struct FaceInfo
{
   
	cv::Rect location_;
	float score_;
	bool mask_;
	float mask_prod;
};

class FaceMask
{
   
public:
	FaceMask(AAssetManager *mgr,bool use_gpu); //如果机子有GPU ,这里可以设置成true,就可以使用GPU进行推理
	~FaceMask();
	int loadModel(AAssetManager *mgr,bool use_gpu);
	int detectFace(const cv::Mat& img_src, std::vector<FaceInfo> *faces);

	static FaceMask* face_mask;

private:
	ncnn::Net mask_net;
	std::vector<std::vector<cv::Rect>> anchors_generated;
	bool initialized_;
	const int RPNs_[3] = {
    32, 16, 8 };
	const cv::Size inputSize_ = {
    640, 640 };
	const float iouThreshold_ = 0.4f;
	const float scoreThreshold_ = 0.8f;
    const float maskThreshold_ = 0.2f;

};
#endif 

3.2 faceMask.cpp

#include "faceMaks.h"
#include <iostream>


FaceMask::FaceMask(AAssetManager *mgr,bool use_gpu)
{
   
	loadModel(mgr,use_gpu);
}

FaceMask::~FaceMask() 
{
   
	
}


int RatioAnchors(const cv::Rect& anchor,const std::vector<float>& ratios,std::vector<cv::Rect>* anchors)
{
   
	anchors->clear();
	cv::Point center = cv::Point(anchor.x + (anchor.width - 1) * 0.5f,
		anchor.y + (anchor.height - 1) * 0.5f);
	float anchor_size = anchor.width * anchor.height;
#if defined(_OPENMP)
#pragma omp parallel for num_threads(threads_num)
#endif
	for (int i = 0; i < static_cast<int>(ratios.size()); ++i) {
   
		float ratio = ratios.at(i);
		float anchor_size_ratio = anchor_size / ratio;
		float curr_anchor_width = std::sqrt(anchor_size_ratio);
		float curr_anchor_height = curr_anchor_width * ratio;
		float curr_x = center.x - (curr_anchor_width - 1) * 0.5f;
		float curr_y = center.y - (curr_anchor_height - 1) * 0.5f;

		cv::Rect curr_anchor = cv::Rect(curr_x, curr_y,
			curr_anchor_width - 1, curr_anchor_height - 1);
		anchors->push_back(curr_anchor);
	}
	return 0;
}

int ScaleAnchors(const std::vector<cv::Rect>& ratio_anchors,const std::vector<float>& scales, std::vector<cv::Rect>* anchors) 
{
   
	anchors->clear();
#if defined(_OPENMP)
#pragma omp parallel for num_threads(threads_num)
#endif
	for (int i = 0; i < static_cast<int>(ratio_anchors.size()); ++i)
	{
   
		cv::Rect anchor = ratio_anchors.at(i);
		cv::Point2f center = cv::Point2f(anchor.x + anchor.width * 0.5f,
			anchor.y + anchor.height * 0.5f);
		for (int j = 0; j < static_cast<int>(scales.size()); ++j) 
		{
   
			float scale = scales.at(j);
			float curr_width = scale * (anchor.width + 1);
			float curr_height = scale * (anchor.height + 1);
			float curr_x = center.x - curr_width * 0.5f;
			float curr_y = center.y - curr_height * 0.5f;
			cv::Rect curr_anchor = cv::Rect(curr_x, curr_y,
				curr_width, curr_height);
			anchors->push_back(curr_anchor);
		}
	}

	return 0;
}

int GenerateAnchors(const int& base_size,const std::vector<float>& ratios,const std::vector<float> scales,std::vector<cv::Rect>* anchors)
{
   
	anchors->clear();
	cv::Rect anchor = cv::Rect(0, 0, base_size, base_size);
	std::vector<cv::Rect> ratio_anchors;
	RatioAnchors(anchor, ratios, &ratio_anchors);
	ScaleAnchors(ratio_anchors, scales, anchors);

	return 0;
}

int FaceMask::loadModel(AAssetManager *mgr,bool use_gpu)
{
   
	bool has_gpu = false;

#if NCNN_VULKAN
	ncnn::create_gpu_instance();
	has_gpu = ncnn::get_gpu_count() > 0;
#endif

	bool to_use_gpu = has_gpu && use_gpu;
	mask_net.opt.use_vulkan_compute = to_use_gpu;

	ncnn::set_cpu_powersave(2);
	ncnn::set_omp_num_threads(ncnn::get_big_cpu_count());
	mask_net.opt.num_threads = ncnn::get_big_cpu_count();


	mask_net.opt.use_int8_inference = true;
	int rp = mask_net.load_param(mgr, "mask.param");
	int rm = mask_net.load_model(mgr, "mask.bin");

	// generate anchors
	for (int i = 0; i < 3; ++i)
	{
   
		std::vector<cv::Rect> anchors;
		if (0 == i)
		{
   
			GenerateAnchors(16, {
    1.0f }, {
    32, 16 }, &anchors)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知来者逆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值