基於人形檢測的劃區域客流統計

2023-03-07 21:01:03
摘要:通過本教學,我們學習了一類客流統計應用——區域內客流統計,通常用於室外安防,或室內客流熱力圖,經過簡單改造還可以實現區域入侵檢測、人員在離崗檢測等應用。

本文分享自華為雲社群《客流分析之基於人形檢測的劃區域客流統計》,作者:HiLens_feige 。

在智慧園區、智慧門店等商業場景中,劃區域的客流統計是一類常見的AI應用,本文介紹基於人形檢測的劃區域客流統計:採用人形框檢測行人並進行跟蹤,若人形框中心點位於事先劃定的區域中,增加客流計數;區域內外的人形將使用不同顏色的框表示,畫面中也會實時顯示客流數量。

準備工作

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

  1. 參考 此教學 完成裝置的註冊;
  2. 參考 此教學 完成ModelBox SDK的安裝。

 

技能開發

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

1)下載模板

執行.\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目錄下。

2)建立工程

在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打包時的輔助指令碼

3)檢視流程圖

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
}"""

整個應用邏輯比較簡單,視訊解碼後做影象預處理,接著是人形檢測,模型後處理得到人形框,送入跟蹤演演算法進行實時跟蹤與區域內外判斷,最後將跟蹤資訊畫到影象輸出到視訊中。

4)核心邏輯

本應用的核心邏輯是跟蹤與區域判斷,跟蹤邏輯在 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"]  # 客流統計的劃定區域
...

5)模型訓練

本應用中包含模型推理部分,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按鈕,跟隨教學一步步操作,也可以修改其中的程式碼、更換新的資料集訓練出自己的模型。

6)三方依賴庫

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

7)檢視輸入輸出設定

檢視任務組態檔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中。

8)用啟動指令碼執行應用

啟動應用前執行.\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. 小結

通過本教學,我們學習了一類客流統計應用——區域內客流統計,通常用於室外安防,或室內客流熱力圖,經過簡單改造還可以實現區域入侵檢測、人員在離崗檢測等應用。

 

點選關注,第一時間瞭解華為雲新鮮技術~