- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
摘要: 通过本教程,我们学习了一类客流统计应用——区域内客流统计,通常用于室外安防,或室内客流热力图,经过简单改造还可以实现区域入侵检测、人员在离岗检测等应用。
本文分享自华为云社区《 客流分析之基于人形检测的划区域客流统计 》,作者:HiLens_feige .
在智慧园区、智慧门店等商业场景中,划区域的客流统计是一类常见的AI应用,本文介绍基于人形检测的划区域客流统计:采用人形框检测行人并进行跟踪,若人形框中心点位于事先划定的区域中,增加客流计数;区域内外的人形将使用不同颜色的框表示,画面中也会实时显示客流数量.
本文将使用华为云ModelArts进行人形检测模型的训练,并使用ModelBox框架进行应用开发,使用前开发者需要完成如下准备工作:
ModelBox
SDK的安装。 。
这个应用对应的ModelBox版本已经做成模板放在华为云OBS中,可以用sdk中的solution.bat工具下载,接下来我们给出该应用在ModelBox中的完整开发过程:
执行.\solution.bat -l可看到当前公开的技能模板:
PS ███> .\solution.bat -
l
...
Solutions name:
mask_det_yolo3
...
passenger_flow_person_det_yolo7
结果中的 passenger_flow_person_det_yolo7 即为基于人形检测的划区域客流统计应用模板,可使用如下命令下载模板:
PS ███> .\solution.bat -
s passenger_flow_person_det_yolo7
...
solution.bat工具的参数中,-l 代表list,即列出当前已有的模板名称;-s 代表solution-name,即下载对应名称的模板。下载下来的模板资源,将存放在ModelBox核心库的solution目录下.
在ModelBox sdk目录下使用create.bat创建passenger_flow_count工程 。
PS ███> .\create.bat -t server -n passenger_flow_count - s passenger_flow_person_det_yolo7 sdk version is modelbox- xxx success: create passenger_flow_count in ███\modelbox\workspace
create.bat工具的参数中,-t 表示创建事务的类别,包括工程(server)、Python功能单元(Python)、推理功能单元(infer)等;-n 代表name,即创建事务的名称;-s 代表solution-name,表示将使用后面参数值代表的模板创建工程,而不是创建空的工程.
workspace目录下将创建出passenger_flow_count工程,工程内容如下所示:
passenger_flow_count |-- bin │ |-- main.bat:应用执行入口 │ |-- mock_task.toml:应用在本地执行时的输入输出配置,此应用默认使用本地视频文件为输入源,最终结果输出到另一本地视频文件,可根据需要修改 |-- CMake:存放一些自定义CMake函数 |-- data:存放应用运行所需要的图片、视频、文本、配置等数据 │ |-- passenger_flow.mp4:客流统计测试用视频文件 │ |-- simsun.ttc:中文字体库 |-- dependence │ |-- modelbox_requirements.txt:应用运行依赖的外部库在此文件定义,本应用依赖pillow、lap、scipy等工具包 |-- etc │ |-- flowunit:应用所需的功能单元存放在此目录 │ │ |--cpp:存放C++功能单元编译后的动态链接库,此应用没有C++ 功能单元 │ │ |-- draw_passenger_bbox:客流画图功能单元 │ │ |-- object_tracker:目标跟踪功能单元 │ │ |-- yolov7_post:人形检测使用的是YOLO7模型,此处即为后处理功能单元 |--flowunit_cpp:存放C++功能单元的源代码,此应用没有C++ 功能单元 |-- graph:存放流程图 │ |-- passenger_flow_count.toml:默认流程图,使用本地视频文件作为输入源 │ |-- modelbox.conf:modelbox相关配置 |-- hilens_data_dir:存放应用输出的结果文件、日志、性能统计信息 |-- model:推理功能单元目录 │ |-- person_det:人形检测推理功能单元 │ │ |-- person_det.toml:人形检测推理功能单元的配置文件 │ │ |-- person_det.onnx:人形检测onnx模型 |-- build_project.sh:应用构建脚本 |-- CMakeLists.txt |-- rpm:打包rpm时生成的目录,将存放rpm包所需数据 |--rpm_copyothers.sh:rpm打包时的辅助脚本
passenger_flow_count工程graph目录下存放流程图,默认的流程图passenger_flow_count.toml与工程同名,其内容为(以Windows版ModelBox为例):
[driver] # 功能单元的扫描路径,包含在[]中,多个路径使用,分隔 # ${HILENS_APP_ROOT} 表示当前应用的实际路径 # ${HILENS_MB_SDK_PATH} 表示ModelBox核心库的实际路径 dir = [ " ${HILENS_APP_ROOT}/etc/flowunit " , " ${HILENS_APP_ROOT}/etc/flowunit/cpp " , " ${HILENS_APP_ROOT}/model " , " ${HILENS_MB_SDK_PATH}/flowunit " , ] skip - default = true [profile] # 通过配置profile和trace开关启用应用的性能统计 profile = false # 是否记录profile信息,每隔60s记录一次统计信息 trace = false # 是否记录trace信息,在任务执行过程中和结束时,输出统计信息 dir = " ${HILENS_DATA_DIR}/mb_profile " # profile/ trace信息的保存位置 [flow] desc = " passenger detection using person detection with yolov7 for local video or rtsp video stream " # 应用的简单描述 [graph] format = " graphviz " # 流程图的格式,当前仅支持graphviz graphconf = """ digraph passenger_flow_count { node [shape= Mrecord] queue_size = 4 batch_size = 1 # 定义节点,即功能单元及其属性 input1[type =input,flowunit=input,device=cpu,deviceid= 0 ] data_source_parser[type =flowunit, flowunit=data_source_parser, device=cpu, deviceid= 0 ] video_demuxer[type =flowunit, flowunit=video_demuxer, device=cpu, deviceid= 0 ] video_decoder[type =flowunit, flowunit=video_decoder, device=cpu, deviceid= 0 , pix_fmt= " rgb " ] resize[type =flowunit flowunit=resize device=cpu deviceid= " 0 " image_width= 416 , image_height= 320 ] color_transpose[type =flowunit flowunit=packed_planar_transpose device=cpu deviceid= " 0 " ] normalize[type =flowunit flowunit=normalize device=cpu deviceid= 0 standard_deviation_inverse= " 0.003921568, 0.003921568, 0.003921568 " ] person_det[type =flowunit flowunit=person_det device=cpu deviceid= " 0 " ] yolov7_post[type =flowunit flowunit=yolov7_post device=cpu deviceid= " 0 " ] object_tracker[type =flowunit, flowunit=object_tracker, device=cpu, deviceid= 0 ] draw_passenger_bbox[type =flowunit, flowunit=draw_passenger_bbox, device=cpu, deviceid= 0 ] video_out[type =flowunit flowunit=video_out device=cpu deviceid= " 0 " ] # 定义边,即功能间的数据传递关系 input1:input -> data_source_parser:in_data data_source_parser:out_video_url -> video_demuxer:in_video_url video_demuxer:out_video_packet -> video_decoder:in_video_packet video_decoder:out_video_frame -> resize:in_image resize:out_image -> color_transpose:in_image color_transpose:out_image -> normalize:in_data normalize:out_data -> person_det:input person_det:output -> yolov7_post:in_feat yolov7_post:out_data -> object_tracker:in_bbox object_tracker:out_track -> draw_passenger_bbox:in_track video_decoder:out_video_frame -> draw_passenger_bbox:in_image draw_passenger_bbox:out_image -> video_out:in_video_frame } """
整个应用逻辑比较简单,视频解码后做图像预处理,接着是人形检测,模型后处理得到人形框,送入跟踪算法进行实时跟踪与区域内外判断,最后将跟踪信息画到图像输出到视频中.
本应用的核心逻辑是跟踪与区域判断,跟踪逻辑在 object_tracker 功能单元中,使用的是 JDE(Towards Real-Time Multi-Object Tracking)算法,算法介绍可参考论文,本应用使用的是简化版本,未使用人形reid特征值做匹配.
区域判断在 draw_passenger_bbox 功能单元draw_passenger_bbox.py的 draw_tracking_object 函数中:
def draw_tracking_object(self, img_data, tracking_objects): ''' 在图中画出跟踪对象的检测框和过线的行人数据 ''' thickness = 2 GRAY = ( 117 , 117 , 117 ) GREEN = ( 0 , 255 , 0 ) YELLO = ( 255 , 255 , 0 ) # 画出区域边界线 cv2.polylines(img_data, [self.area], True, YELLO, 3 ) flow_count = 0 for track in tracking_objects: # 人形框的中心点 c_x = int ((track[ " bbox " ][ 0 ] + track[ " bbox " ][ 2 ]) / 2 ) c_y = int ((track[ " bbox " ][ 1 ] + track[ " bbox " ][ 3 ]) / 2 ) # 判断人形框的中心点是否在区域内 flag = cv2.pointPolygonTest(self.area, (c_x, c_y), False) if flag > 0 : # 区域内人形框用绿色,同时客流计数增加 flow_count += 1 cv2.rectangle(img_data, (track[ " bbox " ][ 0 ], track[ " bbox " ][ 1 ]), (track[ " bbox " ][ 2 ], track[ " bbox " ][ 3 ]), GREEN, 2 ) else : # 区域内人形框用灰色 cv2.rectangle(img_data, (track[ " bbox " ][ 0 ], track[ " bbox " ][ 1 ]), (track[ " bbox " ][ 2 ], track[ " bbox " ][ 3 ]), GRAY, thickness) # 左上角显示实时的客流数量 img_data = self.put_chi_text( img_data, ' 客流计数:%d ' % flow_count, ( 50 , 20 ), YELLO, 50 ) return img_data
可以看到,我们使用了OpenCV的 pointPolygonTest 函数判断点与区域的位置关系。其中区域参数配置在draw_passenger_bbox.toml文件中,配置的是划定区域的4个顶点坐标,围成一个封闭的四边形:
... # 自定义的配置项 [config] area = [ " 0 " , " 325 " , " 1280 " , " 25 " , " 1280 " , " 360 " , " 0 " , " 720 " ] # 客流统计的划定区域 ...
本应用中包含模型推理部分,ModelBox内置了主流的推理引擎,如TensorFlow,TensorRT,LibTorch,Ascend ACL,MindSpore,以及Windows版本中所用的ONNXRuntime。在开发推理功能单元时,只需要准备模型文件,并配置对应的toml文件,即可完成推理功能单元的开发,无需掌握推理引擎的开发接口.
passenger_flow_person_det_yolo7 模板中内置了人形检测模型,这个模型基于yolov7与yolov5-lite,训练数据集用的是开源的CUHK-SYSU,在ModelArts的Notebook环境中训练后,再转换成对应平台的模型格式:onnx格式可以用在Windows设备上,RK系列设备上需要转换为 rknn格式.
模型的训练与转换教程已经开放在AI Gallery中,其中包含训练数据、训练代码、模型转换脚本,以及详细的指导文档。开发者如果希望尝试自己训练模型,或者对模板中提供的模型效果不满意,可以进入 【ModelBox】行人检测模型训练 页面,点击右上角的 Run in ModelArts 按钮,跟随教程一步步操作,也可以修改其中的代码、更换新的数据集训练出自己的模型.
本应用中的画图功能单元依赖 pillow 工具包以实现中文输出,ModelBox应用不需要手动安装三方依赖库,只需要配置在 dependence\modelbox_requirements.txt ,应用在编译时会自动安装。另外,中文输出还需要对应的字体库,存放在 data 目录下,画图功能单元初始化时将从此目录加载资源.
查看任务配置文件bin/mock_task.toml,可以看到其中的任务输入和任务输出配置为如下内容::
[input] type = " url " url = " ${HILENS_APP_ROOT}/data/passenger_flow.mp4 " # 表示输入源为本地视频文件 [output] type = " local " url = " ${HILENS_APP_ROOT}/hilens_data_dir/passenger_flow_result.mp4 " # 表示输出为本地视频文件
即,使用本地视频文件data/passenger_flow.mp4作为输入,统计过线客流后,画图输出到本地视频文件data/passenger_flow_result.mp4中.
启动应用前执行.\build_project.sh进行工程构建,该脚本将编译自定义的C++功能单元(本应用不涉及)、将应用运行时会用到的配置文件转码为Unix格式(防止执行过程中的格式错误)、安装第三方依赖库:
PS ███>
.\build_project.sh
...
PS ███
>
然后执行.\bin\main.bat运行应用:
PS ███>
.\bin\main.bat
...
运行结束后在hilens_data_dir目录下生成了passenger_flow_result.mp4文件,可以打开查看:
可以看到,黄色线段包围的即客流统计的区域,区域外人使用灰色框标记,区域内的使用绿色框,画面左上角实时显示总的过线客流数量.
通过本教程,我们学习了一类客流统计应用——区域内客流统计,通常用于室外安防,或室内客流热力图,经过简单改造还可以实现区域入侵检测、人员在离岗检测等应用.
。
点击关注,第一时间了解华为云新鲜技术~ 。
最后此篇关于基于人形检测的划区域客流统计的文章就讲到这里了,如果你想了解更多关于基于人形检测的划区域客流统计的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
这是一个与 Get OS-Version in WinRT Metro App C# 相关的问题但不是它的重复项。 是否有任何选项可以从 Metro 应用程序检测系统上是否有可用的桌面功能?据我所知,
我想在闹钟响起时做点什么。例如, toast 或设置新闹钟。我正在寻找可以检测闹钟何时响起的东西。首先,我在寻找广播 Action ,但找不到。也许是我的错? 当闹钟响起时,还有其他方法可以做些什么吗
如果某个 JS 添加了一个突变观察者,其他 JS 是否有可能检测、删除、替换或更改该观察者?我担心的是,如果某些 JS 旨在破坏某些 DOM 元素而不被发现,那么 JS 可能想要摆脱任何观察该 DOM
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想要改善这个问题吗?更新问题,以便将其作为on-topi
有没有办法在您的 Activity/应用程序中(以编程方式)知道用户已通过 USB 将您的手机连接到 PC? 最佳答案 有人建议使用 UMS_CONNECTED自最新版本的 Android 起已弃用
我正在想办法测量速度滚动事件,这将产生某种代表速度的数字(相对于所花费的时间,从滚动点 A 到点 B 的距离)。 我欢迎任何以伪代码形式提出的建议...... 我试图在网上找到有关此问题的信息,但找不
某些 JavaScript 是否可以检测 Skype 是否安装? 我问的原因是我想基于此更改链接的 href:如果未安装 Skype,则显示一个弹出窗口,解释 Skype 是什么以及如何安装它,如果已
我们正在为 OS X 制作一个使用 Quartz Events 移动光标的用户空间设备驱动程序,当游戏(尤其是在窗口模式下运行的游戏)无法正确捕获鼠标指针时,我们遇到了问题(= 将其包含/保留在其窗口
我可以在 Controller 中看到事件 $routeChangeStart,但我不知道如何告诉 Angular 留下来。我需要弹出类似“您要保存、删除还是取消吗?”的信息。如果用户选择取消,则停留
我正在解决一个问题,并且已经花了一些时间。问题陈述:给你一个正整数和负整数的数组。如果索引处的数字 n 为正,则向前移动 n 步。相反,如果为负数(-n),则向后移动 n 步。假设数组的第一个元素向前
我试图建立一个条件,其中 [i] 是 data.length 的值,问题是当有超过 1 个值时一切正常,但当只有 1 个值时,脚本不起作用。 out.href = data[i].hr
这是我的问题,我需要检测图像中的 bolt 和四分之一,我一直在搜索并找到 OpenCV,但据我所知它还没有在 Java 中。你们打算如何解决这个问题? 最佳答案 实际上有一个 OpenCV 的 Ja
是否可以检测 ping? IE。设备 1 ping 设备 2,我想要可以在设备 2 上运行的代码,该代码可以在设备 1 ping 设备时进行检测。 最佳答案 ping 实用程序使用的字面消息(“ICM
我每天多次运行构建脚本。我的感觉是我和我的同事花费了大量时间等待这个脚本执行。现在想知道:我们每天花多少时间等待脚本执行? .我可以对总体平均值感到满意,即使我真的很想拥有每天的数据(例如“上周一我们
我已经完成了对项目的编码,但是当我在客户端中提交了源代码时,就对它进行了测试,然后检测到内存泄漏。我已经在Instruments using Leaks中进行了测试。 我遇到的问题是AVPlayer和
我想我可以用 std.traits.functionAttributes 来做到这一点,但它不支持 static。对于任何类型的可调用对象(包含 opCall 的结构),我如何判断该可调用对象是否使用
我正在使用多核 R 包中的并行和收集函数来并行化简单的矩阵乘法代码。答案是正确的,但并行版本似乎与串行版本花费的时间相同。 我怀疑它仅在一个内核上运行(而不是在我的机器上可用的 8 个内核!)。有没有
我正在尝试在读取 csv 文件时编写一个这样的 if 语句: if row = [] or EOF: do stuff 我在网上搜索过,但找不到任何方法可以做到这一点。帮忙? 最佳答案 wit
我想捕捉一个 onFontSizeChange 事件然后做一些事情(比如重新渲染,因为浏览器已经改变了我的字体大小)。不幸的是,不存在这样的事件,所以我必须找到一种方法来做到这一点。 我见过有人在不可
我有一个使用 Windows 服务的 C# 应用程序,该服务并非始终打开,我希望能够在该服务启动和关闭时发送电子邮件通知。我已经编写了电子邮件脚本,但我似乎无法弄清楚如何检测服务状态更改。 我一直在阅
我是一名优秀的程序员,十分优秀!