PaddleDetection学习2——使用Paddle-Lite在 Android 上实现行人检测

使用Paddle-Lite在 Android 上实现行人检测

  • 1. 环境准备
  • 2. 准备模型
    • 2.1 下载模型
    • 2.2 模型优化
  • 3. 部署模型
    • 3.1 目标检测C++代码
      • Pipeline.h
      • Pipeline.cpp
      • preprocess_op.h
      • preprocess_op.cc
    • 3.2 修改配置文件
    • 3.4 部署模型到移动端

1. 环境准备

参考前一篇在 Android 上使用Paddle-Lite实现实时的目标检测功能

2. 准备模型

2.1 下载模型

官网下载行人检测模型,解压下载的mot_ppyoloe_s_36e_pipeline.zip
在这里插入图片描述

2.2 模型优化

使用Paddle-Lite的opt工具可以自动对inference模型进行优化。
安装paddle_lite_opt工具:

pip install paddlelite

在这里插入图片描述

使用paddle_lite_opt工具可以进行inference模型的转换:

paddle_lite_opt --valid_targets=arm \
--model_file=mot_ppyoloe_s_36e_pipeline/model.pdmodel \
--param_file=mot_ppyoloe_s_36e_pipeline/model.pdiparams \
--optimize_out=output_inference/mot_ppyoloe_s_36e_pphuman/model \
#--enable_fp16=true 转化fp16测试报错:paddle-lite提示不支持swish算子

paddle_lite_opt的部分参数如下:
在这里插入图片描述
更详细的paddle_lite_opt工具使用说明请参考使用opt转化模型文档

–model_file表示inference模型的model文件地址,
–param_file表示inference模型的param文件地址;
–optimize_out用于指定输出文件的名称(不需要.nb的后缀)。
直接在命令行中运行paddle_lite_opt,也可以查看所有参数及其说明。

3. 部署模型

3.1 目标检测C++代码

修改yolo_detection_demo中的C++预测代码:

Pipeline.h

class Detector {
public: // NOLINTexplicit Detector(const std::string &modelDir, const std::string &labelPath,const int cpuThreadNum, const std::string &cpuPowerMode,int inputWidth, int inputHeight,const std::vector<float> &inputMean,const std::vector<float> &inputStd, float scoreThreshold);void Predict(const cv::Mat &rgbImage, std::vector<RESULT> *results,double *preprocessTime, double *predictTime,double *postprocessTime);void Predict_for_human(const cv::Mat &rgbImage, std::vector<RESULT> *results,double *preprocessTime, double *predictTime,double *postprocessTime);private: // NOLINTstd::vector<std::string> LoadLabelList(const std::string &path);std::vector<cv::Scalar> GenerateColorMap(int numOfClasses);void Preprocess(const cv::Mat &rgbaImage);void Preprocess_for_human(const cv::Mat &rgbaImage);void Postprocess(std::vector<RESULT> *results);void Postprocess_for_human(std::vector<RESULT> *results,std::vector<int>out_bbox_num);private: // NOLINTint inputWidth_;int inputHeight_;std::vector<float> inputMean_;std::vector<float> inputStd_;float scoreThreshold_;std::vector<std::string> labelList_;std::vector<cv::Scalar> colorMap_;std::shared_ptr<paddle::lite_api::PaddlePredictor> predictor_;//for humanPaddleDetection::Preprocessor preprocessor_;PaddleDetection::ImageBlob inputs_;std::vector<float> output_data_;std::vector<int> out_bbox_num_data_;
};

Pipeline.cpp

oid Detector::Preprocess_for_human(const cv::Mat &rgbaImage) {// Set the data of input image// Clone the image : keep the original mat for postprocesscv::Mat im = rgbaImage.clone();cv::cvtColor(im, im, cv::COLOR_BGR2RGB);preprocessor_.Run(&im, &inputs_);
}void Detector::Postprocess_for_human(std::vector<RESULT> *results, std::vector<int> bbox_num) {for (int j = 0; j < bbox_num[0/*im_id*/]; j++) {// Class idint class_id = static_cast<int>(round(output_data_[0 + j * 6]));// Confidence scorefloat score = output_data_[1 + j * 6];int xmin = (output_data_[2 + j * 6]);int ymin = (output_data_[3 + j * 6]);int xmax = (output_data_[4 + j * 6]);int ymax = (output_data_[5 + j * 6]);int wd = xmax - xmin;int hd = ymax - ymin;if (score < scoreThreshold_)continue;RESULT object;object.class_name = class_id >= 0 && class_id < labelList_.size()? labelList_[class_id]: "Unknow";object.fill_color = class_id >= 0 && class_id < colorMap_.size()? colorMap_[class_id]: cv::Scalar(0, 0, 0);object.score = score;object.x = xmin*1.0;object.y = ymin*1.0;object.w = wd*1.0;object.h = hd*1.0;results->push_back(object);}
}

preprocess_op.h

#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>namespace PaddleDetection {// Object for storing all preprocessed data
class ImageBlob {public:// image width and heightstd::vector<float> im_shape_;// Buffer for image data after preprocessingstd::vector<float> im_data_;// in net data shape(after pad)std::vector<float> in_net_shape_;// Evaluation image width and height// std::vector<float>  eval_im_size_f_;// Scale factor for image size to origin image sizestd::vector<float> scale_factor_;
};// Abstraction of preprocessing opration class
class PreprocessOp {public:virtual void Init() = 0;virtual void Run(cv::Mat* im, ImageBlob* data) = 0;
};class InitInfo : public PreprocessOp {public:virtual void Init(){};virtual void Run(cv::Mat* im, ImageBlob* data);
};class Permute : public PreprocessOp {public:virtual void Init(){};virtual void Run(cv::Mat* im, ImageBlob* data);
};class Resize : public PreprocessOp {public:virtual void Init() {interp_ = 2;keep_ratio_ = false;target_size_.clear();target_size_.emplace_back(640);target_size_.emplace_back(640);}// Compute best resize scale for x-dimension, y-dimensionstd::pair<float, float> GenerateScale(const cv::Mat& im);virtual void Run(cv::Mat* im, ImageBlob* data);private:int interp_;bool keep_ratio_;std::vector<int> target_size_;std::vector<int> in_net_shape_;
};class Preprocessor {public:void Init() {// initialize image info at firstops_["InitInfo"] = std::make_shared<InitInfo>();
//    ops_["InitInfo"] = CreateOp("InitInfo");ops_["Resize"] = CreateOp("Resize");ops_["Resize"]->Init();ops_["Permute"] = CreateOp("Permute");ops_["Permute"]->Init();}std::shared_ptr<PreprocessOp> CreateOp(const std::string& name) {if (name == "Resize") {return std::make_shared<Resize>();} else if (name == "Permute") {return std::make_shared<Permute>();}std::cerr << "can not find function of OP: " << name<< " and return: nullptr" << std::endl;return nullptr;}void Run(cv::Mat* im, ImageBlob* data);public:static const std::vector<std::string> RUN_ORDER;private:std::unordered_map<std::string, std::shared_ptr<PreprocessOp>> ops_;
};}  // namespace PaddleDetection

preprocess_op.cc

#include <string>
#include <thread>
#include <vector>#include "preprocess_op.h"namespace PaddleDetection {void InitInfo::Run(cv::Mat* im, ImageBlob* data) {data->im_shape_ = {static_cast<float>(im->rows),static_cast<float>(im->cols)};data->scale_factor_ = {1., 1.};data->in_net_shape_ = {static_cast<float>(im->rows),static_cast<float>(im->cols)};
}void Permute::Run(cv::Mat* im, ImageBlob* data) {(*im).convertTo(*im, CV_32FC3);int rh = im->rows;int rw = im->cols;int rc = im->channels();(data->im_data_).resize(rc * rh * rw);float* base = (data->im_data_).data();for (int i = 0; i < rc; ++i) {cv::extractChannel(*im, cv::Mat(rh, rw, CV_32FC1, base + i * rh * rw), i);}
}void Resize::Run(cv::Mat* im, ImageBlob* data) {auto resize_scale = GenerateScale(*im);data->im_shape_ = {static_cast<float>(im->cols * resize_scale.first),static_cast<float>(im->rows * resize_scale.second)};data->in_net_shape_ = {static_cast<float>(im->cols * resize_scale.first),static_cast<float>(im->rows * resize_scale.second)};cv::resize(*im, *im, cv::Size(), resize_scale.first, resize_scale.second, interp_);data->im_shape_ = {static_cast<float>(im->rows), static_cast<float>(im->cols),};data->scale_factor_ = {resize_scale.second, resize_scale.first,};
}std::pair<float, float> Resize::GenerateScale(const cv::Mat& im) {std::pair<float, float> resize_scale;int origin_w = im.cols;int origin_h = im.rows;if (keep_ratio_) {int im_size_max = std::max(origin_w, origin_h);int im_size_min = std::min(origin_w, origin_h);int target_size_max =*std::max_element(target_size_.begin(), target_size_.end());int target_size_min =*std::min_element(target_size_.begin(), target_size_.end());float scale_min =static_cast<float>(target_size_min) / static_cast<float>(im_size_min);float scale_max =static_cast<float>(target_size_max) / static_cast<float>(im_size_max);float scale_ratio = std::min(scale_min, scale_max);resize_scale = {scale_ratio, scale_ratio};} else {resize_scale.first =static_cast<float>(target_size_[1]) / static_cast<float>(origin_w);resize_scale.second =static_cast<float>(target_size_[0]) / static_cast<float>(origin_h);}return resize_scale;
}// Preprocessor op running order
const std::vector<std::string> Preprocessor::RUN_ORDER = {"InitInfo","TopDownEvalAffine","Resize","NormalizeImage","PadStride","Permute"};void Preprocessor::Run(cv::Mat* im, ImageBlob* data) {ops_["InitInfo"]->Run(im, data);ops_["Resize"]->Run(im, data);ops_["Permute"]->Run(im, data);
}void CropImg(cv::Mat& img,cv::Mat& crop_img,std::vector<int>& area,std::vector<float>& center,std::vector<float>& scale,float expandratio) {int crop_x1 = std::max(0, area[0]);int crop_y1 = std::max(0, area[1]);int crop_x2 = std::min(img.cols - 1, area[2]);int crop_y2 = std::min(img.rows - 1, area[3]);int center_x = (crop_x1 + crop_x2) / 2.;int center_y = (crop_y1 + crop_y2) / 2.;int half_h = (crop_y2 - crop_y1) / 2.;int half_w = (crop_x2 - crop_x1) / 2.;if (half_h * 3 > half_w * 4) {half_w = static_cast<int>(half_h * 0.75);} else {half_h = static_cast<int>(half_w * 4 / 3);}crop_x1 =std::max(0, center_x - static_cast<int>(half_w * (1 + expandratio)));crop_y1 =std::max(0, center_y - static_cast<int>(half_h * (1 + expandratio)));crop_x2 = std::min(img.cols - 1,static_cast<int>(center_x + half_w * (1 + expandratio)));crop_y2 = std::min(img.rows - 1,static_cast<int>(center_y + half_h * (1 + expandratio)));crop_img =img(cv::Range(crop_y1, crop_y2 + 1), cv::Range(crop_x1, crop_x2 + 1));center.clear();center.emplace_back((crop_x1 + crop_x2) / 2);center.emplace_back((crop_y1 + crop_y2) / 2);scale.clear();scale.emplace_back((crop_x2 - crop_x1));scale.emplace_back((crop_y2 - crop_y1));
}}  // namespace PaddleDetection

3.2 修改配置文件

app/src/main/res/values/strings.xml中的模型路径、模型输入宽高设置为对应值。
在这里插入图片描述

3.4 部署模型到移动端

手机连接电脑,打开 USB 调试和文件传输模式,并在 Android Studio 上连接自己的手机设备(手机需要开启允许从 USB 安装软件权限)
在这里插入图片描述点击 Run 按钮,自动编译 APP 并安装到手机。图一:APP 安装到手机 图二: APP 打开后的效果,会自动识别图片中的物体并标记。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity之射线检测

不知道大家有没有玩过红色警戒 —— 一款即时战略游戏&#xff0c;和罪恶都市一样小编小学的时候就开始玩了&#xff0c;这款游戏控制单位角色移动是通过鼠标的点击来实现。 同样的操作方法还有英雄联盟等很多游戏&#xff0c;那本篇文章小编就通过简单小实例来讲解这种操作在U…

DolphinDB学习(1):数据库的增删查与常用操作

下载并配置好DolphinDB&#xff0c;同时添加vscode的插件&#xff0c;我们就在vscode上进行操作 创建xxx.dos文件后&#xff0c;就会被识别为DolphinDB的运行文件&#xff0c;非常方便 文章目录 登录数据库的操作创建数据库查找与删除数据库 示例 登录 如果是vscode&#xff…

【机组】算术逻辑单元带进位运算实验的解密与实战

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《机组 | 模块单元实验》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 ​ 目录 &#x1f33a;一、 实验目…

[C#]winform部署openvino官方提供的人脸检测模型

【官方框架地址】 https://github.com/sdcb/OpenVINO.NET 【框架介绍】 OpenVINO&#xff08;Open Visual Inference & Neural Network Optimization&#xff09;是一个由Intel推出的&#xff0c;针对计算机视觉和机器学习任务的开源工具套件。通过优化神经网络&#xff…

AP5193 补光灯阅读灯 DC-DC宽电压5-100V 2.5A LED降压恒流带调光驱动器

产品描述 AP5193是一款PWM工作模式,高效率、外围简单、内置功率MOS管&#xff0c;适用于4.5-100V输入的高精度降压LED恒流驱动芯片。最大电流2.5A。AP5193可实现线性调光和PWM调光&#xff0c;线性调光脚有效电压范围0.55-2.6V.AP5193 工作频率可以通过RT 外部电阻编程来设定&a…

Windows如何部署TortoiseSVN客户端

文章目录 前言1. TortoiseSVN 客户端下载安装2. 创建检出文件夹3. 创建与提交文件4. 公网访问测试 前言 TortoiseSVN是一个开源的版本控制系统&#xff0c;它与Apache Subversion&#xff08;SVN&#xff09;集成在一起&#xff0c;提供了一个用户友好的界面&#xff0c;方便用…

Leetcoder Day9|栈与队列part01

语言&#xff1a;Java/C 目录 理论基础 C 栈 队列 Java 栈 队列 ​编辑 232.用栈实现队列 225. 用队列实现栈 Queue Deque 今日心得 理论基础 又是考研时数据结构里接触到的老朋友&#xff0c;栈是先进后出&#xff0c;队列是先进先出。 C 现在刷题除了思路还…

【记账本实战】07 记账本实战之登录注册页面(2)

记账本实战之登录注册页面(2) 目录 记账本实战之登录注册页面(2)前言登录注册页面表单组件的完善图形验证码组件制作修改之前的错误的代码axios 容错处理总结 前言 在本篇教程中&#xff0c;我们将会来完善登录和注册页面&#xff0c;并通过 canvas 手写一个验证码组件&#x…

推荐几个Github高星GoLang管理系统

在Web开发领域&#xff0c;Go语言&#xff08;Golang&#xff09;以其高效、简洁、高并发等特性逐渐成为许多开发者的首选语言。有许多优秀的Go语言Web后台管理系统&#xff0c;这些项目星星众多&#xff0c;提供了丰富的功能和良好的代码质量。本文将介绍一些GitHub高星的GoLa…

Linux第33步_TF-A移植的第1步_创建新的设备树

TF-A移植第1步就是创建新的设备树&#xff0c;并命名为“stm32mp157d-atk”。 和“TF-A移植”有关的知识点&#xff1a; 1)设备树英文名字叫做Device tree&#xff0c;用来描述板子硬件信息的&#xff0c;比如开发板上的 CPU有几个核 、每个CPU核主频是多少&#xff0c;IIC、…

JVM:垃圾收集器(7种)

垃圾收集器关系图&#xff1a; 如果两个收集器之间存在连线&#xff0c;就说明它们可以搭配使用。它们说在的区域则表示这个收集器属于新生代收集器还是老年代收集器。其中Serial&#xff08;串行&#xff09;、Parallel&#xff08;并行&#xff09; 1、Serial收集器 Serial收…

【力扣·每日一题】2182.构造限制重复的字符串(模拟 贪心 优先队列 C++ Go)

题目链接 题意 给你一个字符串 s 和一个整数 repeatLimit &#xff0c;用 s 中的字符构造一个新字符串 repeatLimitedString &#xff0c;使任何字母 连续 出现的次数都不超过 repeatLimit 次。你不必使用 s 中的全部字符。 返回 字典序最大的 repeatLimitedString 。 如果…