基於頭肩部檢測的過線客流統計

華爲雲開發者聯盟 發佈 2024-04-28T11:38:07.744004+00:00

除了劃區域客流統計之外,另一類常見的客流統計場景是過線客流統計,本文介紹基於頭肩部檢測的過線客流統計技能:採用頭肩部檢測人形並進行跟蹤,當頭肩部中心點跨過事先劃定的線段時,增加客流計數;

本文分享自華為雲社區《客流分析之基於頭肩部檢測的過線客流統計-雲社區-華為雲》,作者:HiLens_feige 。

基於頭肩部檢測的過線客流統計

除了劃區域客流統計之外,另一類常見的客流統計場景是過線客流統計,本文介紹基於頭肩部檢測的過線客流統計技能:採用頭肩部檢測人形並進行跟蹤,當頭肩部中心點跨過事先劃定的線段時,增加客流計數;過線前後的人形將使用不同顏色的框表示,畫面中也會實時顯示客流數量。

準備工作

本文將使用華為雲ModelArts進行人形檢測模型的訓練,並使用ModelBox框架進行應用開發,使用前開發者需要完成如下準備工作:

  1. 參考 此教程→AI Gallery_AI說_文章_詳情_開發者_華為雲 完成設備的註冊;
  2. 參考 此教程→AI Gallery_AI說_文章_詳情_開發者_華為雲 完成ModelBox SDK的安裝。

技能開發

這個應用對應的ModelBox版本已經做成模板放在華為雲OBS中,可以用sdk中的solution.bat工具下載,接下來我們給出該應用在ModelBox中的完整開發過程:

1)下載模板

執行.\solution.bat -l可看到當前公開的技能模板:

PS ███> .\solution.bat -l
...

Solutions name:
mask_det_yolo3
...
passenger_flow_head_det_yolo7

結果中的passenger_flow_head_det_yolo7即為基於頭肩部檢測的過線客流統計應用模板,可使用如下命令下載模板:

PS ███> .\solution.bat -s passenger_flow_head_det_yolo7
...

solution.bat工具的參數中,-l 代表list,即列出當前已有的模板名稱;-s 代表solution-name,即下載對應名稱的模板。下載下來的模板資源,將存放在ModelBox核心庫的solution目錄下。

2)創建工程

ModelBox sdk目錄下使用create.bat創建passenger_flow工程

PS ███> .\create.bat -t server -n passenger_flow -s passenger_flow_head_det_yolo7
sdk version is modelbox-xxx
success: create passenger_flow in ███\modelbox\workspace

create.bat工具的參數中,-t 表示創建事務的類別,包括工程(server)、Python功能單元(Python)、推理功能單元(infer)等;-n 代表name,即創建事務的名稱;-s 代表solution-name,表示將使用後面參數值代表的模板創建工程,而不是創建空的工程。

workspace目錄下將創建出passenger_flow工程,工程內容如下所示:

passenger_flow
|--bin
│  |--main.bat:應用執行入口
│  |--mock_task.toml:應用在本地執行時的輸入輸出配置,此應用默認使用本地視頻文件為輸入源,最終結果輸出到另一本地視頻文件,可根據需要修改
|--CMake:存放一些自定義CMake函數
|--data:存放應用運行所需要的圖片、視頻、文本、配置等數據
│  |--passenger_flow.mp4:客流統計測試用視頻文件
│  |--simsun.ttc:中文字體庫
|--dependence
│  |--modelbox_requirements.txt:應用運行依賴的外部庫在此文件定義,本應用依賴pillow工具包
|--etc
│  |--flowunit:應用所需的功能單元存放在此目錄
│  │  |--cpp:存放C++功能單元編譯後的動態連結庫,此應用沒有C++功能單元
│  │  |--draw_passenger_bbox:客流畫圖功能單元
│  │  |--object_tracker:目標跟蹤功能單元
│  │  |--yolov7_post:頭肩部檢測使用的是YOLO7模型,此處即為後處理功能單元
|--flowunit_cpp:存放C++功能單元的原始碼,此應用沒有C++功能單元
|--graph:存放流程圖
│  |--passenger_flow.toml:默認流程圖,使用本地視頻文件作為輸入源
│  |--modelbox.conf:modelbox相關配置
|--hilens_data_dir:存放應用輸出的結果文件、日誌、性能統計信息
|--model:推理功能單元目錄
│  |--head_detection:頭肩部檢測推理功能單元
│  │  |--head_detection.toml:頭肩部檢測推理功能單元的配置文件
│  │  |--head_det_yolo7_lite_224x352.onnx:頭肩部檢測onnx模型
|--build_project.sh:應用構建腳本
|--CMakeLists.txt
|--rpm:打包rpm時生成的目錄,將存放rpm包所需數據
|--rpm_copyothers.sh:rpm打包時的輔助腳本

3)查看流程圖

passenger_flow工程graph目錄下存放流程圖,默認的流程圖passenger_flow.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 head-shoulder detection with yolov7 for local video or rtsp video Stream" # 應用的簡單描述

[graph]
format = "graphviz" # 流程圖的格式,當前僅支持graphviz
graphconf = """digraph passenger_flow {
    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=352, image_height=224]
    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.0039215686,0.0039215686,0.0039215686"]
    head_detection[type=flowunit flowunit=head_detection 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 -> head_detection:input
    head_detection: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
}"""

整個應用邏輯比較簡單,視頻解碼後做圖像預處理,接著是頭肩部檢測,模型後處理得到頭肩框,送入跟蹤算法進行實時跟蹤與過線判斷,最後將跟蹤信息畫到圖像輸出到視頻中。

4)核心邏輯

本應用的核心邏輯是跟蹤與過線判斷,體現在 object_tracker 功能單元中,它是一個Stream功能單元,Stream功能單元的概念和案例可以參考 ModelBox AI應用開發——Stream功能單元 。

object_tracker 功能單元的實現代碼在object_tracker.pyeasy_tracker.py文件中,目標跟蹤算法 EasyTracker 根據IoU使用貪心法進行匹配,過線判斷邏輯在object_tracker.pyget_tracking_objects 函數中:

    def get_tracking_objects(self, line_y):
        '''從跟蹤器中獲取跟蹤目標,保存到結構化數據中'''
        def _is_pass_line(bbox, line_y):
            '''根據檢測框的中心點與線段的水平位置關係判斷是否過線'''
            center_y = (bbox[1] + bbox[3]) / 2
            return center_y > line_y

        tracking_objects = []  # 所有跟蹤目標
        for track in self.tracker.tracks:
            # 只記錄CONFIRMED狀態的跟蹤目標
            if track.state != EasyTracker.TrackingState.CONFIRMED:
                continue
            tracking_obj = {}  # 使用字典保存跟蹤目標
            tracking_obj["id"] = track.track_id  # 跟蹤id
            tracking_obj["bbox"] = track.det  # 跟蹤框
            if not track.passline and _is_pass_line(track.det, line_y):  # 剛好過線
                track.passline = True
                self.flow_count += 1
            tracking_obj["passline"] = track.passline  # 記錄過線信息
            tracking_objects.append(tracking_obj)
        return tracking_objects

可以看到,應用做了簡化處理,假設過線統計的線段為水平線段,使用檢測框的中心點y坐標與線段的y坐標比較判斷是否過線。此處開發者可以進行修改擴展,使得應用可以支持非水平線段的過線判斷。

5)三方依賴庫

本應用中的畫圖功能單元以來 pillow 工具包以實現中文輸出,ModelBox應用不需要手動安裝三方依賴庫,只需要配置在 dependence\modelbox_requirements.txt ,應用在編譯時會自動安裝。另外,中文輸出還需要對應的字體庫,存放在 data 目錄下,畫圖功能單元初始化時將從此目錄加載資源。

6)查看輸入輸出配置

查看任務配置文件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中。

7)用啟動腳本執行應用

啟動應用前執行.\build_project.sh進行工程構建,該腳本將編譯自定義的C++功能單元(本應用不涉及)、將應用運行時會用到的配置文件轉碼為Unix格式(防止執行過程中的格式錯誤)、安裝第三方依賴庫:

PS ███> .\build_project.sh
...
PS ███>

然後執行.\bin\main.bat運行應用:

PS ███> .\bin\main.bat
...

運行結束後在hilens_data_dir目錄下生成了passenger_flow_result.mp4文件,可以打開查看:

可以看到,黃色線段即為過線統計的水平線段,未過線的人使用灰色框標記其頭肩部,已過線的使用藍色框,畫面左上角實時顯示總的過線客流數量。

3. 小結

通過本教程,我們學習了另一類客流統計應用——過線客流統計,通常用於室內出入口,攝像頭會架設在高處俯拍,使用頭肩部檢測可以減少人與人之間的遮擋。

點擊下方,第一時間了解華為雲新鮮技術~

華為雲博客_大數據博客_AI博客_雲計算博客_開發者中心-華為雲

關鍵字: