摘要:本案例我們使用FairMOT進行車輛檢測與跟蹤、yolov5進行車牌檢測、crnn進行車牌識別,在停車場入口、出口、停車位對車輛進行跟蹤與車牌識別,無論停車場路線多復雜,小車在你掌控之中!
本文分享自華為云社區《AI尋車》,作者:杜甫蓋房子,
本案例我們使用FairMOT進行車輛檢測與跟蹤、yolov5進行車牌檢測、crnn進行車牌識別,在停車場入口、出口、停車位對車輛進行跟蹤與車牌識別,無論停車場路線多復雜,小車在你掌控之中!最終效果如下:
我們使用ModelBox Windows SDK進行開發,如果還沒有安裝SDK,可以參考ModelBox端云協同AI開發套件(Windows)設備注冊篇、ModelBox端云協同AI開發套件(Windows)SDK安裝篇完成設備注冊與SDK安裝,
技能開發
這個應用對應的ModelBox版本已經做成模板放在華為云OBS中,可以用sdk中的solution.bat工具下載,接下來我們給出該應用在ModelBox中的完整開發程序:
1)下載模板
執行.\solution.bat -l可看到當前公開的技能模板:
PS ███> .\solution.bat -l
...
Solutions name:
mask_det_yolo3
...
vehicle_plate_multi_centernet_yolov5_crnn
結果中的vehicle_plate_multi_centernet_yolov5_crnn即為AI尋車應用模板,可使用如下命令下載模板:
PS ███> .\solution.bat -s vehicle_plate_multi_centernet_yolov5_crnn
...
solution.bat工具的引數中,-l 代表list,即列出當前已有的模板名稱;-s代表solution-name,即下載對應名稱的模板,下載下來的模板資源,將存放在ModelBox核心庫的solution目錄下,
2)創建工程
在ModelBox sdk目錄下使用create.bat創建vehicle_plate工程:
PS ███> .\create.bat -t server -n vehicle_plate -s vehicle_plate_multi_centernet_yolov5_crnn sdk version is modelbox-xxx success: create vehicle_plate in ███\modelbox\workspace
create.bat工具的引數中,-t 表示創建事務的類別,包括工程(server)、Python功能單元(Python)、推理功能單元(infer)等;-n 代表name,即創建事務的名稱;-s 代表solution-name,表示將使用后面引數值代表的模板創建工程,而不是創建空的工程,
workspace目錄下將創建出vehicle_plate工程,工程內容如下所示:
vehicle_plate |--bin │ |--main.bat:應用執行入口 │ |--mock_task.toml:應用在本地執行時的輸入輸出配置,此應用默認使用4路本地視頻檔案為輸入源,最終結果拼接為四宮格輸出到螢屏,可根據需要修改 |--CMake:存放一些自定義CMake函式 |--data:存放應用運行所需要的圖片、視頻、文本、配置等資料 │ |--chuchang_10.mp4:停車場出口測驗視頻 │ |--ruchang_10.mp4:停車場入口測驗視頻 │ |--ruku_10.mp4:停車位1測驗視頻 │ |--kong_10.mp4:停車位2測驗視頻 │ |--plate_keys.txt:車牌字符檔案 │ |--content_file.json:技能引數全域組態檔 |--dependence │ |--modelbox_requirements.txt:應用運行依賴的外部庫在此檔案定義,本應用依賴pillow、scipy等工具包 |--etc │ |--flowunit:應用所需的功能單元存放在此目錄 │ │ |--cpp:存放C++功能單元編譯后的元件,此應用沒有C++功能單元 │ │ |--collapse_ocr:歸攏功能單元,車牌識別后處理 │ │ |--condition:條件功能單元,判斷是否檢測到車輛/車牌 │ │ |--draw_full_screen:多路視頻拼接輸出功能單元 │ │ |--draw_plate:車牌檢測結果繪制 │ │ |--draw_track_bbox:車輛跟蹤結果繪制 │ │ |--expand_image:展開功能單元,展開車輛檢測/車牌檢測結果并行推理 │ │ |--letter_resize:車輛檢測預處理功能單元 │ │ |--object_tracker:跟蹤功能單元 │ │ |--plate_det_post:車牌檢測后處理功能單元 │ │ |--url_cfg:流單元,多路輸入決議 │ │ |--vehicle_det_post:車牌檢測結果繪制 |--flowunit_cpp:存放C++功能單元的源代碼,此應用沒有C++功能單元 |--graph:存放流程圖 │ |--vehicle_plate.toml:默認流程圖,使用本地視頻檔案作為輸入源 │ |--modelbox.conf:modelbox相關配置 |--hilens_data_dir:存放應用輸出的結果檔案、日志、性能統計資訊 |--model:推理功能單元目錄 │ |--vehicle_det:車輛檢測推理功能單元 │ │ |--vehicle_det.toml:車輛檢測推理功能單元的組態檔 │ │ |--vehicle_det_320x576.onnx:車輛檢測onnx模型 │ |--plate_det:車牌檢測推理功能單元 │ │ |--plate_det.toml:車牌檢測推理功能單元的組態檔 │ │ |--plate_det.onnx:車牌檢測onnx模型 │ |--plate_rec:車牌識別推理功能單元 │ │ |--plate_rec.toml:車牌識別推理功能單元的組態檔 │ │ |--plate_rec.onnx:車牌識別onnx模型 |--build_project.sh:應用構建腳本 |--CMakeLists.txt |--rpm:打包rpm時生成的目錄,將存放rpm包所需資料 |--rpm_copyothers.sh:rpm打包時的輔助腳本
3)查看流程圖
vehicle_plate工程graph目錄下存放流程圖,默認的流程圖vehicle_plate.toml與工程同名,其內容為(以Windows版ModelBox為例):
# 功能單元的掃描路徑,包含在[]中,多個路徑使用,分隔 # ${HILENS_APP_ROOT} 表示當前應用的實際路徑 # ${HILENS_MB_SDK_PATH} 表示ModelBox核心庫的實際路徑 [driver] 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資訊的保存位置 [graph] format = "graphviz" # 流程圖的格式,當前僅支持graphviz graphconf = """digraph vehicle_plate{ node [shape=Mrecord] queue_size = 1 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] url_cfg[type=flowunit, flowunit=url_cfg, 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"] letter_resize[type=flowunit, flowunit=letter_resize, device=cpu] 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.003921568627451, 0.003921568627451, 0.003921568627451"] vehicle_det[type=flowunit, flowunit=vehicle_det, device=cpu, deviceid=0, batch_size=1] vehicle_det_post[type=flowunit, flowunit=vehicle_det_post, device=cpu, deviceid=0] object_tracker[type=flowunit, flowunit=object_tracker, device=cpu, deviceid=0] vehicle_condition[type=flowunit, flowunit=condition, device=cpu, deviceid=0] expand_car[type=flowunit, flowunit=expand_image, device=cpu, deviceid=0, img_h=640, img_w=640] plate_color_transpose[type=flowunit flowunit=packed_planar_transpose device=cpu deviceid="0"] plate_normalize[type=flowunit flowunit=normalize device=cpu deviceid=0 standard_deviation_inverse="0.003921568627451,0.003921568627451,0.003921568627451"] plate_det[type=flowunit flowunit=plate_det device=cpu deviceid="0", batch_size=1] plate_det_post[type=flowunit, flowunit=plate_det_post, device=cpu, deviceid=0] plate_condition[type=flowunit, flowunit=condition, device=cpu, deviceid=0, key="plate"] expand_plate[type=flowunit, flowunit=expand_image, device=cpu, deviceid=0, img_h=48, img_w=168, key="plate"] ocr_color_transpose[type=flowunit flowunit=packed_planar_transpose device=cpu deviceid="0"] ocr_mean[type=flowunit flowunit=mean device=cpu deviceid="0" mean="149.94,149.94,149.94"] ocr_normalize[type=flowunit flowunit=normalize device=cpu deviceid=0 standard_deviation_inverse="0.020319,0.020319,0.020319"] plate_rec[type=flowunit flowunit=plate_rec device=cpu deviceid="0", batch_size=1] collapse_ocr[type=flowunit flowunit=collapse_ocr device=cpu deviceid="0"] draw_plate[type=flowunit, flowunit=draw_plate, device=cpu, deviceid=0] draw_track_bbox[type=flowunit, flowunit=draw_track_bbox, device=cpu, deviceid=0] draw_full_screen[type=flowunit, flowunit=draw_full_screen, device=cpu, deviceid=0] video_out[type=flowunit, flowunit=video_out, device=cpu, deviceid=0, full_screen=true] input1:input -> data_source_parser:in_data data_source_parser:out_video_url -> url_cfg:in_1 url_cfg:out_1 -> video_demuxer:in_video_url video_demuxer:out_video_packet -> video_decoder:in_video_packet video_decoder:out_video_frame -> letter_resize:in_image letter_resize:resized_image -> color_transpose:in_image color_transpose:out_image -> normalize:in_data normalize:out_data -> vehicle_det:input vehicle_det:output -> vehicle_det_post:in_feat letter_resize:out_image -> vehicle_det_post:in_image vehicle_det_post:out_feat -> object_tracker:in_feat object_tracker:out_track -> vehicle_condition:in_track video_decoder:out_video_frame -> vehicle_condition:in_image vehicle_condition:out_track -> expand_car:in_image expand_car:out_image -> plate_color_transpose:in_image plate_color_transpose:out_image -> plate_normalize:in_data plate_normalize:out_data -> plate_det:input plate_det:output -> plate_det_post:in_feat expand_car:out_image -> plate_det_post:in_image plate_det_post:out_tracks -> plate_condition: in_track vehicle_condition:out_track -> plate_condition: in_image plate_condition:out_track -> expand_plate:in_image expand_plate:out_image -> ocr_color_transpose:in_image ocr_color_transpose:out_image -> ocr_mean:in_data ocr_mean:out_data -> ocr_normalize:in_data ocr_normalize:out_data -> plate_rec:input plate_rec:output -> collapse_ocr:in_feat expand_plate:out_image -> collapse_ocr:in_image collapse_ocr:out_tracks -> draw_plate:in_feat plate_condition:out_track -> draw_plate:in_image draw_plate:out_image -> draw_track_bbox:in_image plate_condition:out_image -> draw_track_bbox:in_image draw_track_bbox:out_image -> draw_full_screen:in_image vehicle_condition:out_image -> draw_full_screen:in_image draw_full_screen:out_image -> video_out:in_video_frame }""" [flow] desc = "vehicle_plate run in modelbox-win10-x64"
將流程圖可視化:
圖示中,灰色部分為預置功能單元,其余顏色為我們實作的功能單元,其中綠色為一般通用功能單元,紅色為推理功能單元,藍色為條件功能單元,黃色為展開歸攏功能單元,整個應用邏輯相對復雜一些,視頻解碼后做影像預處理,接著是車輛檢測,模型后處理得到車形框與128維車輛reid特征,送入跟蹤演算法進行實時跟蹤,經過條件功能單元判斷,檢測到車輛的圖送入展開功能單元,切圖進行車牌檢測,車牌檢測結果歸攏后同樣要判斷是否檢測到車牌,檢測到車牌的幀再展開并行進行車牌識別,未檢測到的則直接繪制車輛資訊,而未檢測到車輛的幀則直接送入多路拼接功能單元,最終輸出,
4)核心邏輯
本應用核心邏輯中的跟蹤與區域判斷參照客流統計實戰營的應用設計,跟蹤邏輯在object_tracker功能單元中,檢測與跟蹤使用的是FairMOT演算法,演算法介紹可參考論文,
首先查看object_tracker功能單元中回傳的跟蹤物件結構:
def get_tracking_objects(self, online_targets_dict): tracking_objects = {} for cls_id in range(self.num_classes): online_targets = online_targets_dict[cls_id] for t in online_targets: obj = {} tlwh = t.tlwh if tlwh[2] * tlwh[3] < self.min_box_area: continue tid = t.track_id obj["bbox"] = [max(0, tlwh[0]), max(0, tlwh[1]), tlwh[0] + tlwh[2], tlwh[1] + tlwh[3]] obj["licence"] = "" obj["licence_score"] = 0.0 obj["plate"] = np.zeros((4, 2)).tolist() obj["plate_score"] = 0.0 obj["bbox_score"] = t.score tracking_objects[tid] = obj return tracking_objects
可以看到,我們回傳的跟蹤物件包括車型框、車輛檢測得分等已有資訊以及車牌、車牌得分、車牌框、車牌框得分等包含默認資料的占位資訊,方便后續功能單元獲取更新,
從流程圖中可以看到,object_tracker后結果送入車輛檢測條件功能單元,同樣的在流程圖中還包含車牌檢測條件功能單元,我們當然是希望使用同一個功能單元完成兩個判斷,所以在條件功能單元condition中,我們配置了引數key,默認為key = "bbox",即對結構體中的車型框進行判斷,具體實作為:
if track_result and np.any([v.get(self.key) for k, v in track_result.items()]): buffer_img.set("track", track_json) out_track.push_back(buffer_img) else: buffer_img.set("track", track_json) out_image.push_back(buffer_img)
這樣的話如果是對車型框進行判斷,只需要在流程圖中配置key = “plate”即可,
同樣的,圖展開功能單元expand_image也使用了同樣的方法,使車輛檢測與車牌檢測可以共用功能單元:
tracking_objects = json.loads(buffer_img.get("track")) for idx, target in tracking_objects.items(): box = np.array(target.get(self.key)) ...
此外,由于本應用輸入為4路視頻,因此需要在url_cfg單元中進行session級別資訊配置:
url_str = str(self.count) + input_meta.get_private_string("source_url") self.count += 1 data_context.get_session_context().set_private_string("multi_source_url", url_str)
session級別的資訊在功能單元之間是同步的,這樣就可以在后續的功能單元中獲取當前輸入為哪路輸入:
url = data_context.get_session_context().get_private_string("multi_source_url") image_index = int(url[0])
同樣的,對于多路輸入,我們需要在本地mock時在bin/mock_task.toml檔案中進行輸入配置:
[input] type = "url" url = "${HILENS_APP_ROOT}/data/ruchang_10.mp4" [input1] type = "url" url = "${HILENS_APP_ROOT}/data/chuchang_10.mp4" [input2] type = "url" url = "${HILENS_APP_ROOT}/data/ruku_10.mp4" [input3] type = "url" url = "${HILENS_APP_ROOT}/data/kong_10.mp4"
對于多路輸入的感興趣區域劃定,我們使用content_file配置:
[common] content_file = "../data/content_file.json"
組態檔內容為:
[ { "vehicle_area": "190,245,382,656,1265,630,956,249", "plate_area": "190,245,382,656,1265,630,956,249" }, { "vehicle_area": "663,467,228,675,994,682,1167,459", "plate_area": "663,467,228,675,994,682,1167,459" }, { "vehicle_area": "0,0,1280,0,1280,720,0,720", "plate_area": "0,0,1280,0,1280,720,0,720" }, { "vehicle_area": "0,0,1280,0,1280,720,0,720", "plate_area": "0,0,1280,0,1280,720,0,720" } ]
即針對不同輸入配置各自的車型車牌感興趣區域,在后續功能單元中獲取配置的引數資訊進行處理,如plate_det_post功能單元:
self.areas = json.loads(data_context.get_session_config().get_string("iva_task_common")) url = data_context.get_session_context().get_private_string("multi_source_url") image_index = int(url[0]) self.area = self.areas[image_index].get("plate_area") if self.area: self.area = np.array(list(map(int, self.area.split(",")))).reshape(-1, 1, 2).astype(np.int32)
我們目前對于車型和車牌檢測的引數配置是保持一致的,也可以配置為不同引數,
5)三方依賴庫
本應用依賴scipy等工具包,ModelBox應用不需要手動安裝三方依賴庫,只需要配置在dependence\modelbox_requirements.txt,應用在編譯時會自動安裝,
6)用啟動腳本執行應用
在專案目錄下執行.\bin\main.bat運行應用:
PS ███> .\bin\main.bat
...
可以看到螢屏出現技能畫面:
白線即配置的感興趣區域,區域外/未過線車輛根據id賦色,區域內/已過線車輛的使用灰色框,可在輸入輸出配置中修改劃區域任務型別與坐標點,
7)技能除錯
我們1.5.0版本SDK提供了debug工具,在VSCode中打開專案根目錄,在創建專案時已經自動生成了除錯組態檔:
如果有其他安裝包,可以在組態檔中增加PYTHONPATH引數,
在除錯時,可以直接在感興趣的代碼處打斷點除錯即可:
啟動除錯后與其他程式除錯操作一致:
點擊關注,第一時間了解華為云新鮮技術~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/549324.html
標籤:其他
上一篇:大神之路-起始篇 | 第3章.計算機科學導論之【資料存盤】學習筆記
下一篇:ai 寫的故事
