據(jù)標(biāo)注全流程解析:關(guān)鍵幀插值與半自動標(biāo)注實踐)
簡介這份PPT圍繞視頻數(shù)據(jù)標(biāo)注中的目標(biāo)跟蹤任務(wù)展開以百度EasyDL平臺為操作主線面向剛接觸計算機視覺數(shù)據(jù)標(biāo)注的算法工程師、標(biāo)注團隊或相關(guān)專業(yè)學(xué)生。內(nèi)容從創(chuàng)建模型、創(chuàng)建數(shù)據(jù)集、上傳數(shù)據(jù)開始到在線標(biāo)注、添加標(biāo)簽、標(biāo)注關(guān)鍵幀與目標(biāo)消失幀逐步演示了目標(biāo)跟蹤標(biāo)注的完整流程能夠幫助初學(xué)者理解從原始視頻到可訓(xùn)練數(shù)據(jù)集的關(guān)鍵步驟與常見操作細(xì)節(jié)。PPT共1個演示文稿文件壓縮包大小3.13MB單文件便于按頁碼翻看步驟截圖與界面說明。目前已有1109人學(xué)習(xí)瀏覽適合需要快速上手視頻目標(biāo)跟蹤標(biāo)注或準(zhǔn)備開展數(shù)據(jù)標(biāo)注培訓(xùn)的讀者。通過這份PPT可直觀看到EasyDL目標(biāo)跟蹤標(biāo)注界面的操作節(jié)奏包括矩形框選目標(biāo)、多關(guān)鍵幀跟蹤、消失幀處理等實用技巧同時強化標(biāo)注質(zhì)量對模型精度的重要認(rèn)知有效節(jié)省自行摸索與踩坑時間。1. 視頻數(shù)據(jù)標(biāo)注的難點不在畫框而在時間軸早上打開一份名為數(shù)據(jù)標(biāo)注視頻數(shù)據(jù)標(biāo)注案例.pptx的材料時如果只看到滿屏畫好的框那這份復(fù)盤大概率漏掉了真正重要的環(huán)節(jié)。視頻數(shù)據(jù)標(biāo)注和普通圖片標(biāo)注的差別不在框的數(shù)量而在于時間軸上目標(biāo)身份是否始終一致同一個行人在 25fps 的視頻里被車擋住兩秒標(biāo)注員很容易把它標(biāo)成兩段軌跡后面做跟蹤訓(xùn)練時算法再怎么調(diào)參也補不回來。對算法工程師、標(biāo)注團隊負(fù)責(zé)人和數(shù)據(jù)標(biāo)注行業(yè)的新手來說這篇文章按一線落地順序把鏈路拉通一遍需求維度怎么拆、抽幀和關(guān)鍵幀插值怎么設(shè)、半自動標(biāo)注怎么提效、質(zhì)檢到底查哪幾個指標(biāo)以及最后用回放怎么驗收。2. 視頻數(shù)據(jù)標(biāo)注的工具選型先定規(guī)范再選工具2.1 視頻數(shù)據(jù)標(biāo)注的三個維度空間框、時間流與屬性狀態(tài)視頻數(shù)據(jù)標(biāo)注和圖片數(shù)據(jù)標(biāo)注的本質(zhì)區(qū)別是每次操作都要面對一個隱含的第四維時間。標(biāo)注對象不再是靜止的單幀畫面而是一段連續(xù)動作。按我處理園區(qū)車輛與行人混合視頻標(biāo)注項目的慣例所有視頻數(shù)據(jù)標(biāo)注任務(wù)從需求上都可以拆成三個維度。第一個維度是空間標(biāo)注。目標(biāo)檢測任務(wù)就是邊界框?qū)嵗指钊蝿?wù)就是多邊形語義分割任務(wù)就是像素級掩碼。這個維度和圖片標(biāo)注幾乎一致差別只在于要連續(xù)地在多幀上重復(fù)。第二個維度是時間流標(biāo)注。視頻數(shù)據(jù)標(biāo)注需要記錄目標(biāo)的跨幀軌跡同一個目標(biāo)從第 100 幀進入畫面到第 420 幀離開中間每一幀都要有同一個 track_id。第三個維度是屬性狀態(tài)比如這輛車是否被遮擋這個行人是否在打電話這是后續(xù)做困難樣本挖掘和邏輯召回的關(guān)鍵字段。對三個維度的標(biāo)注深度做決定時數(shù)據(jù)標(biāo)注工具之間才具備真正意義上的可比性。很多團隊把成本估算集中在畫框個數(shù)上忽略了屬性狀態(tài)的字段設(shè)計。一個真實踩過的坑共享單車園區(qū)違規(guī)停放監(jiān)控項目最初沒標(biāo)車籃是否有載物算法訓(xùn)練完無法區(qū)分載物和空載場景最后只能對整個視頻數(shù)據(jù)標(biāo)注任務(wù)回爐補標(biāo)整體返工了兩周。正確做法是在任務(wù)派發(fā)前先定屬性清單比如是否被遮擋是/否/未知動作類型騎行/推行/靜止并寫進任務(wù)說明確保所有標(biāo)注員口徑一致。2.2 數(shù)據(jù)標(biāo)注工具橫向?qū)Ρ菴VAT、Label Studio與X-AnyLabeling視頻數(shù)據(jù)標(biāo)注工具的選型通常不取決于哪個工具畫框手感好而取決于它能否支持關(guān)鍵幀插值、軌跡 ID 管理和視頻幀序列抽取。目前我常用的開源數(shù)據(jù)標(biāo)注工具主要有三個各自的能力邊界不太一樣。工具視頻標(biāo)注能力插值方式適合場景注意點CVAT內(nèi)置視頻軌道標(biāo)注關(guān)鍵幀之間自動插值可接 AI 模型檢測、跟蹤、分割一體部署偏重依賴 DockerLabel Studio視頻幀序列標(biāo)注人工逐幀插件可擴展事件打標(biāo)、動作起止時間視頻目標(biāo)框標(biāo)注體驗一般X-AnyLabeling視頻抽幀 模型預(yù)標(biāo)注SAM 按幀生成掩碼小團隊快速出分割結(jié)果視頻過大需要先單獨抽幀CVAT 的插值模式是視頻數(shù)據(jù)標(biāo)注效率最高的實現(xiàn)方式標(biāo)注員只在選定的關(guān)鍵幀上畫框下一關(guān)鍵幀畫完中間幀由平臺自動補全軌跡。但如果需求主要是動作事件打標(biāo)而不是目標(biāo)跟蹤Label Studio 更輕量不需要起一套重型服務(wù)。X-AnyLabeling 更適合本地小規(guī)??焖俪鲅诖a幾十個 G 的視頻建議先按 3.1 的抽幀邏輯變成圖片序列再導(dǎo)入。2.3 數(shù)據(jù)標(biāo)注規(guī)范任務(wù)怎么拆、幀段怎么切視頻數(shù)據(jù)標(biāo)注規(guī)范不能只寫框住所有目標(biāo)要寫明任務(wù)切分和邊界交接規(guī)則。切視頻時我一般按一個動作閉環(huán)來切不要讓一個視頻文件橫跨兩個光照完全不同的場景。比如行人從室外走進室內(nèi)環(huán)境亮度和背景完全變化應(yīng)該切成兩個任務(wù)段否則標(biāo)注員會因目標(biāo)突然不可見產(chǎn)生困惑track 也容易斷。任務(wù)段的長度也要控制。一個標(biāo)注員每天合理產(chǎn)出大約是 400 到 600 個有效關(guān)鍵幀如果每段抽幀后剩余 100 幀左右每人每天約處理 5 段。拆太短前一個任務(wù)段和后一個任務(wù)段之間的 ID 交接頻繁后處理要花時間合并拆太長單任務(wù)盯太久容易疲勞錯誤率在第二小時明顯上升。人員協(xié)作上要把 ID 一致性作為和框準(zhǔn)確率并列的考核指標(biāo)。多個標(biāo)注員協(xié)作時如果任務(wù)段之間存在同一目標(biāo)的跨段軌跡需要在導(dǎo)出結(jié)果里保留跨段交接字段或者直接在視頻切片時預(yù)留 5 幀重疊后處理腳本再做 ID 歸并。這個細(xì)節(jié)決定了最終數(shù)據(jù)能否訓(xùn)練跟蹤模型。3. 用關(guān)鍵幀插值跑通視頻標(biāo)注前置流程ffmpeg抽幀與任務(wù)打包視頻數(shù)據(jù)標(biāo)注項目的第一步不是打開標(biāo)注平臺而是決定讓標(biāo)注員看到哪些幀。直接把 25fps 的視頻原樣導(dǎo)入工具一個 5 分鐘的視頻就有 7500 幀逐幀標(biāo)注成本完全不可控。常規(guī)做法是抽幀加上關(guān)鍵幀插值先選一部分幀作為人工標(biāo)注幀其余幀由數(shù)據(jù)標(biāo)注工具在時間軸上自動補全。3.1 抽幀策略固定間隔還是場景切分默認(rèn)策略是固定間隔抽幀間隔取 5 到 10 幀。目標(biāo)運動越快、目標(biāo)在畫面里占據(jù)的像素越小間隔就要越短。比如園區(qū)出入口車輛起步慢10 幀間隔足夠但行人突然轉(zhuǎn)身或跑動5 幀間隔下插值更容易貼合實際位置。下面這條命令按每 5 幀抽取一幀輸出的幀號按原視頻時間軸保留下來后續(xù)訓(xùn)練時可以根據(jù)幀號直接換算真實時間戳# 從 input.mp4 中每 5 幀取一幀輸出到 keyframes 目錄 ffmpeg -i input.mp4 -vf selectnot(mod(n,5)),setptsN/FRAME_RATE/TB -vsync 0 keyframes/frame_%06d.jpgselectnot(mod(n,5))里的n是解碼后的幀計數(shù)mod(n,5)取余數(shù)余數(shù)為 0 時保留當(dāng)前幀setptsN/FRAME_RATE/TB把輸出幀的時間戳重置為第 N 幀/幀率保證幀順序正確-vsync 0讓 ffmpeg 不要自作主張補幀或丟幀。很多人漏掉最后這個參數(shù)抽出來的幀序列偶爾會出現(xiàn)重復(fù)幀導(dǎo)致標(biāo)注平臺里軌跡抖動。如果視頻場景切換頻繁固定間隔會浪費大量標(biāo)注工作量在無關(guān)幀上。可以先用鏡頭檢測腳本找出切變點再按切變點分片抽幀# 輸出發(fā)生場景切換的幀時刻用于后續(xù)切分視頻 ffmpeg -i input.mp4 -vf selectgt(scene,0.4),showinfo -f null - 21 | grep pts_time這里的scene分?jǐn)?shù)表示當(dāng)前幀與前一幀畫面的差異程度0.4 是保守閾值鏡頭切換、亮度突變都能捕獲到。拿到pts_time后按時間點把視頻切成短視頻再對每個分段做固定間隔抽幀能省掉場景空白段帶來的無效標(biāo)注。場景類型建議幀間隔原因行人慢速行走10 幀位移小插值誤差小車輛轉(zhuǎn)彎、遮擋頻繁5 幀避免軌跡斷裂和插值偏移快速動作識別3 幀動作起止幀定位更準(zhǔn)攝像頭固定且畫面靜止1 幀即可減少存儲和無效工作量3.2 關(guān)鍵幀插值讓標(biāo)注員只畫 1/5 的幀抽幀完成后把圖片序列導(dǎo)入支持視頻標(biāo)注的工具打開軌跡模式。標(biāo)注員只標(biāo)注第 0、5、10、15 幀也就是原視頻每 25 幀中的 5 幀剩余中間幀由工具根據(jù)相鄰關(guān)鍵幀自動生成插值結(jié)果track_id 保持不變。這是視頻數(shù)據(jù)標(biāo)注區(qū)別于普通圖片標(biāo)注的最大效率來源。在 CVAT 里做插值的常見配置是創(chuàng)建任務(wù)時選擇插值標(biāo)注模式標(biāo)注員在時間軸上定位到關(guān)鍵幀畫框到下一關(guān)鍵幀再調(diào)整框的位置工具會自動生成中間幀。參數(shù)上值得留意的是關(guān)鍵幀間隔不要設(shè)置過大默認(rèn)的 10 幀對快速移動目標(biāo)來說插值誤差偏高我一般手動改成 5 幀以內(nèi)的增量寧可讓人多畫一幀關(guān)鍵幀也不要讓插值結(jié)果在視覺上抖得沒法看。配合模型做自動插值的流程是抽幀后先運行檢測模型生成各幀目標(biāo)框再將檢測框按跟蹤算法關(guān)聯(lián)成軌跡最后把軌跡結(jié)果作為預(yù)標(biāo)注導(dǎo)入數(shù)據(jù)標(biāo)注工具標(biāo)注員負(fù)責(zé)刪除誤檢、補充漏檢、修改類別和屬性。這樣標(biāo)注員每天的實際產(chǎn)出能從 400 幀提升到 1200 幀以上但前提是預(yù)標(biāo)注質(zhì)量本身不能太差。提示如果視頻里目標(biāo)大量相互遮擋預(yù)標(biāo)注軌跡容易發(fā)生 ID 切換。此時不要盲目調(diào)低置信度優(yōu)先檢查跟蹤器的max_age參數(shù)把目標(biāo)丟失后保留軌跡的時間從默認(rèn)值調(diào)大能明顯減少被遮擋物的 ID 跳變。3.3 構(gòu)建可追溯的數(shù)據(jù)標(biāo)注任務(wù)目錄標(biāo)注任務(wù)不是一次性生產(chǎn)產(chǎn)出后還要清洗、合并、回滾。任務(wù)目錄至少要能區(qū)分原始視頻、抽幀圖片、原始標(biāo)注、已檢核標(biāo)注四類文件。我常用下面這套結(jié)構(gòu)PROJECTgate-monitor mkdir -p $PROJECT/videos $PROJECT/frames $PROJECT/raw_anns $PROJECT/verified_anns find $PROJECT/frames/gate01 -name *.jpg | sort $PROJECT/raw_anns/gate01.txtraw_anns里放平臺導(dǎo)出的原始標(biāo)注 JSON文件名和幀號一一對應(yīng)后續(xù)校驗?zāi)_本直接從 JSON 重建標(biāo)注verified_anns只保留通過質(zhì)檢的版本。數(shù)據(jù)標(biāo)注工具導(dǎo)出的結(jié)果如果帶 track_id 字段后處理時一定要保留一旦丟掉后續(xù)要定位某條軌跡在某幀的框時只能回原視頻重看返工成本極高。4. 半自動標(biāo)注與質(zhì)量校驗跑通視頻數(shù)據(jù)標(biāo)注流水線的關(guān)鍵節(jié)點4.1 用跟蹤器和分割模型做視頻預(yù)標(biāo)注視頻數(shù)據(jù)標(biāo)注里最實用的提效手段是預(yù)標(biāo)注。以常見的 YOLO 加 ByteTrack 方案為例先把視頻切成幀列表用檢測模型跑出每一幀的框然后用跟蹤器為框分配穩(wěn)定的 ID把跟蹤結(jié)果導(dǎo)出成標(biāo)注平臺能識別的 JSON 格式標(biāo)注員只需單擊接受。下面的 Python 腳本示意了預(yù)標(biāo)注主流程用的是 ultralytics 庫的 track 接口from ultralytics import YOLO model YOLO(yolov8n.pt) # 檢測模型 results model.track( gate-cam.mp4, persistTrue, trackerbytetrack.yaml, classes[0], # 只保留人這個類別 conf0.25, projectprelabel_out, nametracks, )persistTrue讓跟蹤器跨幀記憶同一個目標(biāo)同一目標(biāo)的框在連續(xù)幀中共享同一個 track_idtrackerbytetrack.yaml指定 ByteTrack 配置它是一個以檢測框為輸入的輕量跟蹤器classes[0]限定模型只輸出人這個類別減少誤檢和無效關(guān)聯(lián)。輸出目錄里會生成一段帶標(biāo)注框的預(yù)覽視頻方便人工快速確認(rèn)預(yù)標(biāo)注效果。預(yù)標(biāo)注的正確使用循環(huán)是今天標(biāo)注、今晚訓(xùn)練、明早預(yù)標(biāo)注拿已標(biāo)注數(shù)據(jù)訓(xùn)一個初版模型第二天讓模型輔助標(biāo)注新的無標(biāo)注視頻如此迭代。半自動標(biāo)注的核心價值不是消滅人工而是把標(biāo)注員的精力集中在修正最難的目標(biāo)上。4.2 質(zhì)量校驗統(tǒng)計標(biāo)注框面積、ID與幀間跳變質(zhì)量校驗我一般寫一個腳本掃批量的標(biāo)注 JSON只檢查四件事track_id 是否連續(xù)覆蓋幀、同一 track 相鄰幀邊界框的重疊率是否突然掉到 0、框是否出現(xiàn)大面積絕對位置偏移、類別名是否超出規(guī)范清單。示例腳本片段如下設(shè)計成無第三方依賴即可運行import json with open(export_anns.json) as f: anns json.load(f) tracks {} for ann in anns: t_id ann[track_id] tracks.setdefault(t_id, []).append(ann) for t_id, frames in tracks.items(): frames.sort(keylambda x: x[frame_id]) for prev, curr in zip(frames, frames[1:]): gap curr[frame_id] - prev[frame_id] if gap 1: print(f[gap] track {t_id} frame {prev[frame_id]} - {curr[frame_id]}) iou compute_iou(prev[bbox], curr[bbox]) if iou 0.3: print(f[shift] track {t_id} frame {curr[frame_id]} iou{iou:.2f})邏輯說明track_id是視頻數(shù)據(jù)標(biāo)注中判斷軌跡是否連續(xù)的錨點gap 1說明中間有幀漏標(biāo)可能是插值任務(wù)沒保存IOU 小于 0.3 說明框在相鄰關(guān)鍵幀之間跳變太大大概率是標(biāo)注員在關(guān)鍵幀之間漏畫了一幀需要回去補。compute_iou函數(shù)按兩個邊界框交并比實現(xiàn)具體公式就是兩個矩形的交集面積除以并集面積。質(zhì)量參數(shù)的合理閾值可以參考下表指標(biāo)閾值動作相鄰關(guān)鍵幀 IOU不低于 0.4小于 0.4 查軌跡轉(zhuǎn)折點track_id 缺失幀 gap0記錄并補標(biāo)類別取值與規(guī)范一致出現(xiàn)未知類別查原始幀邊界框是否出畫不允許裁邊到畫面外視為異常4.3 格式導(dǎo)出與數(shù)據(jù)切分COCO、YOLO與MOT下游任務(wù)不同要的標(biāo)注格式也不同。目標(biāo)檢測用 YOLO 格式最方便實例分割用 COCO多目標(biāo)跟蹤直接吃 MOT 格式。視頻數(shù)據(jù)標(biāo)注工具導(dǎo)出的 JSON 一般都能轉(zhuǎn)成這些格式但切分時最常見的錯誤是隨機切幀導(dǎo)致同一段軌跡的一部分幀進 train一部分進 val評估出來的指標(biāo)虛高。正確做法是按視頻維度整體切分。比如手里 10 個視頻來自同一環(huán)境、光照相似的 4 個放 val其余 6 個放 train不要從同一個視頻里一半一半地切。對跟蹤模型來說MOT 格式必須保留frame_id和track_id兩列一行最小記錄長這樣1, 1, 722.5, 246.0, 88.0, 46, 1, 1, 1, 1字段依次是幀號、track_id、左上角 x、左上角 y、寬、高、置信度、類別、截斷狀態(tài)、保留字段。導(dǎo)出時如果標(biāo)注屬性里有截斷或遮擋就映射到截斷狀態(tài)列別丟掉。核心轉(zhuǎn)換邏輯可以這樣寫def ann_to_mot(ann, frame_id): x, y, w, h ann[bbox] return [frame_id, ann[track_id], round(x,1), round(y,1), round(w,1), round(h,1), 1, ann.get(cls_id, 0), 1, 1]參數(shù)說明bbox是邊界框track_id對應(yīng)跟蹤 IDcls_id是類別的整數(shù)編碼第 7 位的1是置信度占位值人工標(biāo)注通??梢灾苯犹?1。5. 用可視化回放審查視頻數(shù)據(jù)標(biāo)注的時序一致性5.1 插值結(jié)果的常見失真點關(guān)鍵幀插值不是萬能的。目標(biāo)做高速轉(zhuǎn)向時插值框會因為線性假設(shè)偏離目標(biāo)中心遮擋切換時插值框可能跟著背景里的其他目標(biāo)走鏡頭晃動時中間幀的框會在目標(biāo)周圍漂移。這些異常在單張靜態(tài)幀上幾乎看不出問題只有把幀連續(xù)播放起來才會暴露。更隱蔽的是軌跡屬性的連續(xù)性一個行人在第 40 幀被車擋住兩秒如果插值沒有處理遮擋關(guān)系車開走時標(biāo)注工具可能重新創(chuàng)建一個新 ID算法會把同一個人當(dāng)成兩個人。檢查時必須專門盯著這些遮擋切換位置看。5.2 用OpenCV合成帶軌跡框的回放視頻快速驗收我最后一步的做法是把標(biāo)注結(jié)果畫回到每一幀上合成一個和原視頻同幀率、同分辨率的 mp4然后以 1.5 到 2 倍速連續(xù)播放。這個回放視頻就是驗收物比任何統(tǒng)計報表都直接。import cv2 cap cv2.VideoCapture(frames_seq.mp4) out cv2.VideoWriter(review.mp4, cv2.VideoWriter_fourcc(*mp4v), 25, (w, h)) while True: ok, img cap.read() if not ok: break boxes get_boxes_from_ann(img, frame_id) # 從JSON按幀取框 for b in boxes: cv2.rectangle(img, (b[0], b[1]), (b[2], b[3]), (0, 255, 0), 2) cv2.putText(img, str(b[4]), (b[0], b[1] - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) out.write(img) out.release()get_boxes_from_ann負(fù)責(zé)從標(biāo)注 JSON 中按幀號取出所有邊界框b[4]是 track_id把它直接畫在框上方回放時能直觀看到同一目標(biāo)是否從頭到尾用同一個編號。合成速度不用太講究用 25fps 輸出即可因為回放還要調(diào)速看。我通常會把沒有通過回放的視頻段單獨截出來重新導(dǎo)入數(shù)據(jù)標(biāo)注工具用插值修正模式重跑一遍直到連續(xù)回放不再出現(xiàn)視覺跳躍。這個回放不過就重畫的較真動作往往就是視頻數(shù)據(jù)標(biāo)注和圖片標(biāo)注團隊拉開差距的地方。本文還有配套的精品資源點擊獲取