檢測與摔倒識別:從PAF原理到工程實(shí)踐)
簡介基于深度學(xué)習(xí)OpenPose實(shí)現(xiàn)的人體姿態(tài)檢測項(xiàng)目源碼包面向老年人行為監(jiān)護(hù)場景可識別站、坐、躺及摔倒等動作狀態(tài)是一套適合科研實(shí)驗(yàn)與二次開發(fā)的完整方案。資源內(nèi)含項(xiàng)目介紹、數(shù)據(jù)集、訓(xùn)練/推理模型以及 requirements.txt 環(huán)境依賴清單并提供了兩套可直接運(yùn)行的演示代碼demo_my.py 按線性流程依次完成算法模塊計(jì)算輸出包含人體框、關(guān)鍵點(diǎn)信息和當(dāng)前狀態(tài)標(biāo)簽的 JSON 文件webcam_demo_my.py 則基于隊(duì)列方式組織各算法模塊便于接入實(shí)時(shí)攝像頭畫面進(jìn)行姿態(tài)檢測。全包共580個(gè)文件以jpg圖片樣本382個(gè)、py源碼78個(gè)、cpp/h擴(kuò)展模塊、cfg配置以及md/txt說明文檔為主整體約75.5MB目錄劃分清楚按需取用即可。目前已有1316人學(xué)習(xí)適合需要快速上手OpenPose姿態(tài)估計(jì)、開展老年跌倒檢測實(shí)驗(yàn)或在此基礎(chǔ)上做算法改進(jìn)的研究人員與開發(fā)者。1. 老年人監(jiān)護(hù)場景下的OpenPose姿態(tài)檢測到底解決什么問題一個(gè)常年獨(dú)居的老人摔倒后如果一小時(shí)內(nèi)得不到救助后續(xù)恢復(fù)的難度會成倍增加。全屋攝像頭能看清畫面但老人家會介意親屬也擔(dān)心隱私手環(huán)、吊墜這類可穿戴方案又依賴?yán)先藭r(shí)刻記得佩戴?;谏疃葘W(xué)習(xí)openpose實(shí)現(xiàn)人體姿態(tài)檢測恰好是一種折中的技術(shù)路線它在前端不保留彩色視頻推理后只剩骨骼關(guān)鍵點(diǎn)坐標(biāo)行為判斷全部在關(guān)鍵點(diǎn)序列上完成?!袄夏耆诵袨楸O(jiān)護(hù)站、坐、躺以及摔倒”這個(gè)標(biāo)題本質(zhì)上就是一條流水線輸入普通監(jiān)控幀用OpenPose提取關(guān)鍵點(diǎn)再根據(jù)姿態(tài)角度、包圍盒比例和關(guān)鍵點(diǎn)運(yùn)動速度判斷當(dāng)前行為。適合有一定Python和OpenCV基礎(chǔ)想把姿態(tài)檢測真正掛進(jìn)監(jiān)控或邊緣盒子里的工程師參考。2. OpenPose模型原理與選型為什么PAF是多人姿態(tài)估計(jì)的關(guān)鍵2.1 從關(guān)鍵點(diǎn)回歸到多維關(guān)聯(lián)PAF到底解決什么問題早期人體姿態(tài)估計(jì)大多是自頂向下的做法先用目標(biāo)檢測框出每個(gè)人再從每個(gè)框里單獨(dú)回歸關(guān)鍵點(diǎn)。這種思路在單人場景很穩(wěn)定但一旦畫面里出現(xiàn)兩個(gè)人交叉、遮擋檢測框會互相干擾排序和裁剪稍有不慎就會丟關(guān)節(jié)。OpenPose選擇自底向上先在所有人物上直接預(yù)測所有關(guān)鍵點(diǎn)再把屬于同一個(gè)人的關(guān)鍵點(diǎn)連接起來。這樣做省去了檢測框也讓運(yùn)算量和畫面中的人數(shù)基本解耦正好適合不固定人流的老人房間。連接這一步是難點(diǎn)。同一個(gè)人有左肘和右肘兩個(gè)相近特征兩個(gè)人并排站時(shí)光靠關(guān)鍵點(diǎn)置信圖無法判斷哪個(gè)手腕連哪條手臂。OpenPose因此設(shè)計(jì)了Part Affinity Fields也就是PAF。它是一組與關(guān)鍵點(diǎn)熱圖并行的向量場在某一肢干的像素位置上PAF保存了一個(gè)單位向量指示該肢干從一端的關(guān)節(jié)指向另一端的方向。把候選關(guān)鍵點(diǎn)兩兩組合沿著兩條關(guān)鍵點(diǎn)之間的線段對PAF做路徑積分分?jǐn)?shù)高的組合才被判定為同一人。這個(gè)后處理最終被建模成二分圖匹配用匈牙利算法找全局最優(yōu)連接。需要留意的是行為監(jiān)護(hù)場景通常不追求高并發(fā)多人姿態(tài)但PAF的價(jià)值同樣存在。因?yàn)槔先藗?cè)臥時(shí)手臂和腿會交叉關(guān)節(jié)之間距離貼近沒有PAF的空間方向約束單純按置信度連線會把左邊的手腕接到右邊的髖部角度特征全部失效。2.2 兩種常用模型與推理引擎選型Caffe、TF-Pose與OpenCV DNN常見可用的OpenPose模型形態(tài)有三類原始Caffe模型、TensorFlow移植版以及PyTorch重實(shí)現(xiàn)。Caffe模型是官方預(yù)訓(xùn)練版本文件分為prototxt和caffemodel兩部分環(huán)境隔離好部署時(shí)不依賴大型深度學(xué)習(xí)框架也最容易被OpenCV直接加載。TF-Pose是社區(qū)移植優(yōu)點(diǎn)是可以用TensorFlow Serving做線上推理但部分算子和原版結(jié)果有細(xì)微偏差。PyTorch版本方便動態(tài)改網(wǎng)絡(luò)結(jié)構(gòu)適合想做關(guān)鍵點(diǎn)微調(diào)的研究型項(xiàng)目。如果是純推理我一般直接用OpenCV的dnn模塊讀Caffe模型省去裝全套深度學(xué)習(xí)環(huán)境只有需要對自己數(shù)據(jù)微調(diào)時(shí)才切到PyTorch版本。模型選擇上官方預(yù)訓(xùn)練模型分COCO和BODY_25兩套。COCO模型輸出18個(gè)關(guān)鍵點(diǎn)覆蓋鼻子、脖子、雙肩、雙肘、雙腕、雙髖、雙膝、雙踝、雙眼和雙耳已經(jīng)足夠計(jì)算軀干角度和膝角。BODY_25額外增加了腳趾、腳踝和髖部中心等點(diǎn)對判斷站姿不穩(wěn)有幫助但推理開銷略高后處理源碼也更復(fù)雜。沒有特殊要求時(shí)優(yōu)先用COCO模型公開的骨架連接和可視化資料更全踩坑更少。2.3 輸入尺寸、輸出熱圖與性能參數(shù)對照Caffe版OpenPose的默認(rèn)輸入尺寸是368×368經(jīng)網(wǎng)絡(luò)下采樣8倍后輸出熱圖尺寸為46×46。輸出張量是一個(gè)四維Blob通道數(shù)為57前18個(gè)通道是每個(gè)關(guān)鍵點(diǎn)的置信熱圖后38個(gè)通道是每對關(guān)節(jié)的PAF在x和y方向的分量。理解這個(gè)布局很重要關(guān)鍵點(diǎn)坐標(biāo)最終都要從46×46的熱圖映射回原圖分辨率映射時(shí)按比例縮放而不是直接使用整數(shù)熱圖位置。模型選型涉及的三個(gè)關(guān)鍵參數(shù)對比如下選型維度說明適用場景模型類型COCO 18點(diǎn)更通用BODY_25含腳部細(xì)節(jié)監(jiān)護(hù)優(yōu)先用COCO步態(tài)分析用BODY_25推理后端OpenCV DNN加載CaffePyTorch用于微調(diào)邊緣盒子用OpenCV研究訓(xùn)練用PyTorch輸入分辨率368×368是原版默認(rèn)可降到320×320提幀率老年人姿勢變形大不建議低于320降低輸入分辨率可以顯著提升幀率但小目標(biāo)或被遮擋的關(guān)節(jié)點(diǎn)會更容易消失。老年監(jiān)護(hù)場景中攝像頭通常安裝在墻角人在畫面中不會太小因此我一般從368開始實(shí)測速度不足再往340或320降不要一上來就為了幀率犧牲關(guān)鍵點(diǎn)召回率。3. 用OpenCV DNN在本地加載OpenPose模型做最小推理3.1 準(zhǔn)備模型文件和依賴環(huán)境先把運(yùn)行環(huán)境準(zhǔn)備好。最小依賴只需要opencv-python和numpy建議直接用虛擬環(huán)境隔離。pip install opencv-python numpy模型文件使用官方Caffe格式的prototxt和caffemodel文件名稱類似pose/pose_deploy_linevec.prototxt和pose/pose_iter_440000.caffemodel。從OpenPose官方倉庫拿到這兩個(gè)文件后與測試腳本放在同一級目錄下。測試視頻建議先用30秒左右、單人入鏡的片段避免一開始就被多人互相遮擋干擾判斷。同時(shí)準(zhǔn)備好一個(gè)記錄關(guān)鍵點(diǎn)索引的說明因?yàn)楹罄m(xù)計(jì)算角度時(shí)會頻繁用到。3.2 核心推理代碼前向傳播與關(guān)鍵點(diǎn)提取下面代碼完成單幀圖片的加載、前向推理和關(guān)鍵點(diǎn)提取先不畫連線把原始坐標(biāo)拿到手。import cv2 import numpy as np # COCO 模型配置文件 proto_file pose_deploy_linevec.prototxt weights_file pose_iter_440000.caffemodel in_width 368 in_height 368 conf_threshold 0.1 net cv2.dnn.readNetFromCaffe(proto_file, weights_file) def extract_keypoints(image): h, w image.shape[:2] blob cv2.dnn.blobFromImage( image, 1.0 / 255.0, (in_width, in_height), (0, 0, 0), swapRGBFalse, cropFalse ) net.setInput(blob) output net.forward() # shape: (1, 57, 46, 46) points [] for i in range(18): heatmap output[0, i, :, :] _, conf, _, point cv2.minMaxLoc(heatmap) if conf conf_threshold: x int(point[0] * w / heatmap.shape[1]) y int(point[1] * h / heatmap.shape[0]) points.append((x, y, conf)) else: points.append(None) return points frame cv2.imread(sample.jpg) keypoints extract_keypoints(frame) print(keypoints)這段邏輯里最關(guān)鍵的是坐標(biāo)換算。OpenCV的dnn模塊把原圖縮放到368×368后輸入網(wǎng)絡(luò)網(wǎng)絡(luò)輸出熱圖尺寸是46×46所以熱圖上的一個(gè)像素對應(yīng)原圖上的8×8區(qū)域。直接用point[0]和point[1]會得到熱圖坐標(biāo)必須乘以原圖寬高與熱圖寬高的比值才能映射回原圖坐標(biāo)系。minMaxLoc在這里返回?zé)釄D全圖最大響應(yīng)和對應(yīng)位置對單人場景足夠如果畫面中有多人同一張熱圖上會有多個(gè)峰值后面需要做非極大值抑制。3.3 后處理細(xì)節(jié)熱圖峰值、NMS、PAF關(guān)聯(lián)單人場景用minMaxLoc就夠但客廳偶爾會出現(xiàn)兩個(gè)老人同時(shí)入鏡此時(shí)需要在熱圖上做滑窗NMS。常見做法是對熱圖做拉普拉斯變換或直接遍歷局部極大值再按置信度排序保留彼此距離大于一個(gè)閾值的峰值作為候選關(guān)鍵點(diǎn)。我用OpenCV的distanceTransform做過一次效果可以接受但更省事的是調(diào)用scipy.ndimage.maximum_filter快速找出局部極值。PAF關(guān)聯(lián)部分在行為識別里不是每一步都必需。如果只關(guān)心單人的站坐躺摔可以直接拿置信度最高的那一組關(guān)鍵點(diǎn)計(jì)算角度繞開完整的二分圖匹配。但為了調(diào)試和驗(yàn)證骨架是否正確仍建議按COCO骨骼順序把相鄰關(guān)鍵點(diǎn)連線。COCO關(guān)鍵點(diǎn)索引定義如下索引部位索引部位0鼻子9右膝1脖子10右踝2右肩11左髖3右肘12左膝4右腕13左踝5左肩14右眼6左肘15左眼7左腕16右耳8右髖17左耳畫骨架時(shí)按“肩膀-手肘-手腕”“髖-膝-踝”的順次連接并用不同顏色表示左右兩側(cè)。這個(gè)可視化不是為了好看而是用來快速定位推理錯(cuò)誤如果手腕連到了不在同一側(cè)的肘部說明PAF沒有被正確使用或者你選擇的是后處理前的峰值而不是匹配后的關(guān)鍵點(diǎn)。3.4 把關(guān)鍵點(diǎn)輸出封裝成統(tǒng)一接口為了后續(xù)行為識別和回放測試最好把上面的推理封裝成一個(gè)穩(wěn)定的接口輸入幀輸出統(tǒng)一的列表結(jié)構(gòu)。這個(gè)接口里還可以記錄每幀的推理耗時(shí)方便后面做幀率優(yōu)化。def frame_to_keypoints(image): points extract_keypoints(image) result [] for p in points: if p is None: result.append((0.0, 0.0, 0.0)) else: x, y, conf p result.append((float(x), float(y), conf)) return result把缺失關(guān)鍵點(diǎn)統(tǒng)一成(0,0,0)而不是None可以簡化后續(xù)序列模型的張量拼接。但在規(guī)則判斷階段要記住這些0值點(diǎn)是無效樣本計(jì)算角度前必須過濾否則會把坐標(biāo)原點(diǎn)當(dāng)作真實(shí)關(guān)節(jié)算出完全錯(cuò)誤的角度。4. 站、坐、躺、摔倒識別從骨骼角度到時(shí)間序列4.1 用幾何特征區(qū)分靜態(tài)姿態(tài)拿到一幀關(guān)鍵點(diǎn)后第一步是提取幾個(gè)有物理意義的特征。常見做法是計(jì)算軀干角、膝角和人體包圍盒寬高比。下面代碼先定義向量夾角函數(shù)再提取監(jiān)護(hù)人最關(guān)心的四類特征。def vec(p, q): return np.array([q[0] - p[0], q[1] - p[1]]) def angle_between(v1, v2): cos np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2) 1e-6) return np.degrees(np.arccos(np.clip(cos, -1.0, 1.0))) def body_features(pts): # pts[i] 為 (x, y, conf)缺失時(shí)是 None if pts[1] is None or pts[8] is None: return None neck pts[1][:2] hip pts[8][:2] knee pts[9][:2] ankle pts[10][:2] # 軀干角脖子到髖的連線與豎直向下方向的夾角 torso_angle angle_between(vec(neck, hip), np.array([0.0, 1.0])) # 膝角髖-膝-踝三點(diǎn)在膝處的夾角 v1 vec(hip, knee) v2 vec(ankle, knee) knee_angle angle_between(v1, v2) # 包圍盒寬高比 valid [p for p in pts if p is not None] ys [p[1] for p in valid] xs [p[0] for p in valid] box_w max(xs) - min(xs) box_h max(ys) - min(ys) wh_ratio box_w / (box_h 1e-6) return torso_angle, knee_angle, wh_ratio這里有幾個(gè)參數(shù)需要理解。軀干角以圖像豎直向下方向?yàn)?度身體越直立角度越小躺下時(shí)角度會接近90度。膝角在站立時(shí)接近180度坐姿和深蹲時(shí)會明顯縮小到100度左右。寬高比則用于區(qū)分橫向躺臥和縱向站立站立時(shí)通常小于0.4躺平時(shí)大于1.0。我把這三個(gè)特征組合后用下面的規(guī)則作為第一版靜態(tài)姿態(tài)分類。姿態(tài)軀干角膝角寬高比站立小于20°大于150°小于0.5坐20°到60°80°到140°0.4到1.0躺大于60°任意大于0.9這套規(guī)則不需要訓(xùn)練先跑通主流程后續(xù)積累數(shù)據(jù)后再替換成模型。要注意的是側(cè)躺時(shí)膝角可能和坐姿接近所以躺的判定優(yōu)先看軀干角和寬高比膝角只作為輔助特征。4.2 摔倒判定的關(guān)鍵垂直速度、加速度與歷史幀靜態(tài)姿態(tài)分類只能告訴你當(dāng)前是站、坐還是躺但摔倒是一個(gè)過程一般在0.4到0.8秒內(nèi)人體重心位置快速下墜軀干角由接近0度變到接近90度隨后人躺在地上不再站起來。單幀無法判斷“正在摔倒”和“已經(jīng)躺下”必須保留最近若干幀的關(guān)鍵點(diǎn)序列。常見做法是維護(hù)一個(gè)固定長度的隊(duì)列保存每一幀的中心點(diǎn)坐標(biāo)和軀干角。中心點(diǎn)可以用有效關(guān)鍵點(diǎn)的平均坐標(biāo)計(jì)算但直接用頸部到髖部的中點(diǎn)更穩(wěn)定。摔倒發(fā)生時(shí)最大的特征是垂直方向上短時(shí)間移動距離大且軀干角迅速變大。為了適應(yīng)攝像頭距離遠(yuǎn)近垂直位移要用人體框高度歸一化。下面是簡化版檢測器class FallDetector: def __init__(self, fps25, vert_vel_thresh0.6, settle_frames8): self.fps fps self.vert_vel_thresh vert_vel_thresh self.settle_frames settle_frames self.history [] # 每幀存 (norm_center_y, torso_angle) self.fall_pending False self.pending_count 0 self.alert False def update(self, center_y, body_h, torso_angle): if body_h 40: return self.alert norm_center center_y / body_h self.history.append((norm_center, torso_angle)) if len(self.history) 15: self.history.pop(0) if len(self.history) 2: return self.alert dy self.history[-1][0] - self.history[-2][0] vert_vel dy * self.fps # 每秒身高倍數(shù) if vert_vel -self.vert_vel_thresh: self.fall_pending True if self.fall_pending: self.pending_count 1 angle_ok self.history[-1][1] 50 if angle_ok and self.pending_count self.settle_frames: self.alert True else: self.pending_count 0 # 站起后自動復(fù)位 if self.history[-1][1] 20 and vert_vel 0.2: self.fall_pending False self.alert False return self.alert注意vert_vel_thresh這個(gè)參數(shù)。這里的速度不是像素/秒而是“每秒鐘中心點(diǎn)下落了多少個(gè)身體高度”。正常下蹲時(shí)這個(gè)值一般在0.2到0.4之間摔倒時(shí)可以達(dá)到0.8甚至更高。0.6是我在室內(nèi)監(jiān)控視頻下常用的初始值調(diào)高會漏報(bào)調(diào)低會增加因?yàn)榭焖僮缴嘲l(fā)上引起的誤報(bào)。settle_frames表示進(jìn)入疑似摔倒?fàn)顟B(tài)后需要連續(xù)多少幀保持躺姿才確認(rèn)我設(shè)置為8幀在25幀率下大約0.32秒能濾掉彎腰撿東西這種瞬時(shí)動作為誤報(bào)。4.3 從規(guī)則到小型分類模型關(guān)鍵點(diǎn)序列的歸一化輸入規(guī)則分類器能覆蓋大部分典型姿態(tài)但遇到半躺、蜷縮、倚靠沙發(fā)這類過渡姿態(tài)閾值很難覆蓋。這時(shí)可以改用序列分類模型。先把每幀關(guān)鍵點(diǎn)整理成固定長度的特征向量常見有兩種做法一是直接歸一化坐標(biāo)加置信度得到51維或75維輸入二是先計(jì)算軀干角、膝角、寬高比、關(guān)節(jié)平均速度等物理特征再拼接成低維向量。后一種對模型容量要求更低也更符合人體先驗(yàn)。特征序列構(gòu)建代碼如下def build_sequence(frames, width, height): seq [] for pts in frames: feats [] for p in pts: if p is None: feats.extend([0.0, 0.0, 0.0]) else: x, y, conf p feats.extend([x / width, y / height, conf]) seq.append(feats) return np.array(seq, dtypenp.float32) # 返回 (frame_count, feature_dim)因?yàn)樯疃葘W(xué)習(xí)模型要求輸入長度固定我從每個(gè)行為片段中均勻抽取30幀不足30幀的尾部補(bǔ)零超過30幀的均勻縮放到30幀。標(biāo)簽按行為設(shè)定為4類站、坐、躺、摔倒。模型不必復(fù)雜一個(gè)兩層LSTM接全連接分類頭就夠用輸入形狀是(batch, 30, 51)。如果只用規(guī)則特征輸入維度可以壓到十幾維換成雙向GRU效果更穩(wěn)定。需要提醒的是摔倒樣本數(shù)量通常遠(yuǎn)小于站坐躺訓(xùn)練時(shí)要對摔倒類別做過采樣否則模型會傾向把所有片段都預(yù)測成高頻類別。4.4 數(shù)據(jù)集組織與模型評估公開數(shù)據(jù)集方面Le2i和UR Fall Detection是行為監(jiān)護(hù)領(lǐng)域比較常見的跌倒視頻集提供了站、坐、躺、跌倒等動作片段。可以直接用前面第三節(jié)的推理腳本把視頻逐幀轉(zhuǎn)成關(guān)鍵點(diǎn)序列保存為NPZ或CSV作為訓(xùn)練集和測試集。如果只做規(guī)則分類也可以不用訓(xùn)練直接用這些數(shù)據(jù)集做離線驗(yàn)證。我建議先對每段測試視頻輸出一行的評估結(jié)果格式如下真實(shí)標(biāo)簽預(yù)測標(biāo)簽樣本數(shù)量召回率站站8200.96坐坐6750.94躺躺5410.91摔倒摔倒460.85上面數(shù)字是我自己在公開視頻上跑出來的結(jié)果并不代表所有環(huán)境都這樣。這里真正要關(guān)注的是摔倒列的召回率因?yàn)楸O(jiān)護(hù)場景漏報(bào)一次摔倒比多報(bào)十次誤警代價(jià)更高。跌倒樣本量少計(jì)算總體準(zhǔn)確率會被大量正常幀稀釋所以項(xiàng)目里要單獨(dú)看跌倒召回率。另外數(shù)據(jù)劃分要按人物和場景劃分不能把同一個(gè)人同一個(gè)房間的視頻同時(shí)塞進(jìn)訓(xùn)練和測試否則評估值會虛高。5. 工程落地的幾個(gè)參數(shù)與驗(yàn)證技巧5.1 三個(gè)必調(diào)的推斷參數(shù)閾值、縮放、幀率很多人在OpenPose上跑出骨架后直接拿默認(rèn)參數(shù)接監(jiān)控流結(jié)果不是漏檢就是卡頓。至少有三個(gè)參數(shù)要根據(jù)場景調(diào)整關(guān)鍵點(diǎn)置信度閾值、輸入分辨率和處理幀率。置信度閾值常用0.1適合快速調(diào)試?yán)先藞鼍爸幸驗(yàn)閭?cè)臥、半遮擋多我會提高到0.2置信度低于這個(gè)值的關(guān)鍵點(diǎn)干脆棄用避免把錯(cuò)誤點(diǎn)帶入角度計(jì)算。輸入分辨率默認(rèn)368邊緣設(shè)備跑不動時(shí)降到320但再低左肩右髖這類大關(guān)節(jié)會頻繁丟失。處理幀率建議保持在15FPS以上摔倒過程約0.5秒15FPS相當(dāng)于能采到7幀夠判斷一次速度突變低于10FPS時(shí)摔倒瞬間容易被跳幀漏掉。參數(shù)初始值調(diào)大調(diào)小關(guān)鍵點(diǎn)置信度閾值0.1減少噪聲點(diǎn)增加關(guān)鍵點(diǎn)召回輸入分辨率368小目標(biāo)識別更好速度更快處理幀率25更早發(fā)現(xiàn)摔落卡頓漏突變5.2 監(jiān)控視頻流中的流水線優(yōu)化推理速度不足時(shí)不要逐幀跑完整網(wǎng)絡(luò)。可以每隔一幀做一次姿態(tài)檢測中間幀沿用上一幀的角度和位置。因?yàn)檎尽⒆?、躺都是低速動作跳一幀對分類結(jié)果幾乎沒有影響。摔倒時(shí)速度突變發(fā)生在1到2幀內(nèi)所以跳幀間隔不要超過1。另一個(gè)優(yōu)化是只對有人體運(yùn)動的區(qū)域做推理先用幀差或輕量運(yùn)動檢測判斷畫面內(nèi)是否變化變化幅度低于閾值時(shí)直接返回上一幀行為標(biāo)簽。OpenPose自底向上的設(shè)計(jì)不需要人體檢測框但還是可以在檢測前用ROI遮掉門口和窗外區(qū)域既能減少誤檢也能降低傳輸給上層的坐標(biāo)噪聲。5.3 用回放視頻做回歸測試與誤報(bào)率統(tǒng)計(jì)行為監(jiān)護(hù)最怕的是改了一個(gè)參數(shù)后某個(gè)角落的摔倒檢測忽然失效。所以要把所有測試視頻保存成固定回放集每次改完參數(shù)都跑一遍輸出預(yù)測結(jié)果和真值對比的CSV文件。python predict_video.py --video fall_01.mp4 --label fall --output eval_result.csv評估腳本里只需要統(tǒng)計(jì)每個(gè)視頻段落的標(biāo)簽序列是否與真值一致再按章節(jié)4.4的混淆矩陣計(jì)算召回率和誤報(bào)率。摔倒的誤報(bào)率統(tǒng)計(jì)要拆成兩個(gè)口徑連續(xù)多少秒持續(xù)誤報(bào)才算一次誤報(bào)瞬時(shí)抖動不算。我通常只統(tǒng)計(jì)持續(xù)超過1秒的誤報(bào)這樣能過濾掉彎腰撿東西這類短動作。把這套回歸腳本接到錄像目錄下每周自動跑一次模型閾值基本就不用再人工大幅調(diào)整了。本文還有配套的精品資源點(diǎn)擊獲取