การตรวจจับและติดตามวัตถุ
UAT 307 การมองเห็นด้วยคอมพิวเตอร์และเทคโนโลยีการรับรู้
บทเรียน
เมื่อเรียนจบโมดูลนี้ ผู้เรียนจะสามารถ
- อธิบายการติดตามแบบตรวจจับทุกเฟรมแล้วจับคู่ (tracking-by-detection)
- เขียนตัวกรองคาลมานแบบความเร็วคงที่สำหรับติดตามตำแหน่งวัตถุ
- จับคู่กรอบระหว่างเฟรมด้วย IoU และนับการสลับหมายเลข
- ประเมินการติดตามด้วย MOTA
ทำไมต้องรู้
ตัวตรวจจับบอกว่าในเฟรมนี้มีวัตถุอยู่ตรงไหน แต่งานโดรนหลายงานต้องรู้ว่า วัตถุเดิมเคลื่อนไปทางไหน เช่น นับรถที่ผ่านแยก ติดตามคนในงานค้นหา หรือเฝ้าสัตว์ในพื้นที่อนุรักษ์ หน่วยความรู้เรื่องการวิเคราะห์วิดีโออัจฉริยะของคลังความรู้โดรนครอบคลุมการตรวจจับ ติดตาม นับ และแจ้งเตือนแบบเวลาจริง แนวทางที่ใช้กันแพร่หลายคือ tracking-by-detection เช่น SORT (Bewley และคณะ, 2016) ซึ่งใช้ตัวกรองคาลมานแบบความเร็วคงที่ทำนายตำแหน่ง แล้วจับคู่กับผลตรวจจับด้วย IoU ผ่านวิธี Hungarian กรณีของโมดูลนี้คือโดรนเฝ้าลานจอดรถ ข้อมูลเป็นข้อมูลจำลอง
ทำนายตำแหน่งด้วยตัวกรองคาลมาน
ตัวกรองคาลมานที่เรียนใน UAT 305 ใช้ติดตามวัตถุในภาพได้ สถานะคือตำแหน่งและความเร็วในภาพ ขั้นทำนายเลื่อนตำแหน่งตามความเร็ว ขั้นปรับแก้ใช้กรอบที่ตัวตรวจจับให้มา เมื่อตัวตรวจจับพลาดบางเฟรม เช่น รถถูกต้นไม้บัง ตัวกรองยังทำนายต่อได้ แต่ความไม่แน่นอนจะโตขึ้นทุกเฟรมที่ไม่มีข้อมูล
ตัวอย่างที่ 1 ติดตามรถที่ถูกบังสามเฟรม
รถเคลื่อนที่ 3 พิกเซลต่อเฟรมในแนวนอนและ 1.5 พิกเซลในแนวตั้ง ตัวตรวจจับมีความคลาดเคลื่อนราว 2 พิกเซล และพลาดเฟรมที่ 5–7
import math
import numpy as np
dt = 0.1
F = np.array([[1, 0, dt, 0], [0, 1, 0, dt], [0, 0, 1, 0], [0, 0, 0, 1]]) # [x, y, vx, vy]
Hm = np.eye(2, 4)
Q, R = np.eye(4) * 0.5, np.eye(2) * 4.0
truth = [(10 + 3 * k, 50 + 1.5 * k) for k in range(12)]
rng = np.random.default_rng(6)
meas = [(x + rng.normal(0, 2), y + rng.normal(0, 2)) for x, y in truth]
missing = {5, 6, 7} # เฟรมที่ถูกบัง
x = np.array([meas[0][0], meas[0][1], 0.0, 0.0])
P = np.diag([4.0, 4.0, 100.0, 100.0])
for k in range(1, 12):
x, P = F @ x, F @ P @ F.T + Q
if k not in missing:
S = Hm @ P @ Hm.T + R
K = P @ Hm.T @ np.linalg.inv(S)
x = x + K @ (np.array(meas[k]) - Hm @ x)
P = (np.eye(4) - K @ Hm) @ P
err = math.dist(x[:2], truth[k])
print(f"frame {k:>2} {'predict only' if k in missing else 'updated '} error {err:4.2f} px, position sigma {math.sqrt(P[0, 0]):.2f} px")
frame 1 updated error 3.41 px, position sigma 1.52 px
frame 2 updated error 2.30 px, position sigma 1.46 px
frame 3 updated error 1.95 px, position sigma 1.46 px
frame 4 updated error 1.31 px, position sigma 1.44 px
frame 5 predict only error 1.75 px, position sigma 2.00 px
frame 6 predict only error 2.57 px, position sigma 2.58 px
frame 7 predict only error 3.51 px, position sigma 3.17 px
frame 8 updated error 2.69 px, position sigma 1.77 px
frame 9 updated error 2.63 px, position sigma 1.47 px
frame 10 updated error 0.93 px, position sigma 1.35 px
frame 11 updated error 0.66 px, position sigma 1.29 px
ช่วงที่ถูกบัง ความไม่แน่นอนโตขึ้นและความคลาดเคลื่อนเพิ่มขึ้นทีละเฟรม เมื่อได้ผลตรวจจับกลับมา ตัวกรองดึงตำแหน่งกลับได้ภายในไม่กี่เฟรม ความไม่แน่นอนที่โตขึ้นนี้ใช้ขยายเขตค้นหาเพื่อจับคู่กับวัตถุเดิมเมื่อกลับมาปรากฏ ถ้าถูกบังนานเกินไป ระบบควรปิดเส้นทางนั้นแทนการทำนายไปเรื่อย ๆ
จับคู่และประเมินด้วย MOTA
เมื่อมีหลายวัตถุ ต้องจับคู่กรอบในเฟรมใหม่กับเส้นทางเดิม ถ้าจับคู่ผิด วัตถุสองตัวจะสลับหมายเลขกัน (ID switch) ซึ่งทำให้การนับผิด ตัวชี้วัด MOTA ของ CLEAR MOT (Bernardin และ Stiefelhagen, 2008) รวมความผิดพลาดสามแบบ คือ พลาดวัตถุ (FN) ตรวจพบสิ่งที่ไม่มี (FP) และสลับหมายเลข (IDSW) หารด้วยจำนวนวัตถุจริงทั้งหมด
ตัวอย่างที่ 2 รถสองคันแล่นสวนกัน
รถ A และ B แล่นเข้าหากันห้าเฟรม เทียบผลของตัวติดตามกับคำตอบ ถือว่าจับคู่ได้เมื่อ IoU ตั้งแต่ 0.5 (ข้อมูลจำลอง)
def iou(p, q):
ix = max(0, min(p[2], q[2]) - max(p[0], q[0]))
iy = max(0, min(p[3], q[3]) - max(p[1], q[1]))
inter = ix * iy
return inter / ((p[2] - p[0]) * (p[3] - p[1]) + (q[2] - q[0]) * (q[3] - q[1]) - inter)
gt = {1: [("A", (10, 10, 30, 40)), ("B", (60, 10, 80, 40))], 2: [("A", (14, 10, 34, 40)), ("B", (56, 10, 76, 40))],
3: [("A", (18, 10, 38, 40)), ("B", (52, 10, 72, 40))], 4: [("A", (22, 10, 42, 40)), ("B", (48, 10, 68, 40))],
5: [("A", (26, 10, 46, 40)), ("B", (44, 10, 64, 40))]}
tracks = {1: [(1, (11, 11, 31, 41)), (2, (59, 10, 79, 40))], 2: [(1, (15, 10, 35, 41)), (2, (55, 11, 75, 40))],
3: [(1, (19, 10, 39, 40))], 4: [(2, (22, 11, 42, 40)), (1, (47, 10, 67, 41))],
5: [(2, (27, 10, 47, 40)), (1, (43, 10, 63, 40)), (3, (90, 50, 110, 80))]}
last, fn, fp, idsw, total = {}, 0, 0, 0, 0
for f in sorted(gt):
total += len(gt[f])
used = set()
for gid, gbox in gt[f]:
best = max(((iou(gbox, tb), tid) for tid, tb in tracks[f] if tid not in used), default=(0, None))
if best[0] >= 0.5:
used.add(best[1])
if gid in last and last[gid] != best[1]:
idsw += 1
print(f"frame {f}: {gid} switched from track {last[gid]} to track {best[1]}")
last[gid] = best[1]
else:
fn += 1
fp += sum(1 for tid, _ in tracks[f] if tid not in used)
print(f"FN {fn}, FP {fp}, IDSW {idsw}, objects {total} -> MOTA {1 - (fn + fp + idsw) / total:.2f}")
frame 4: A switched from track 1 to track 2
frame 4: B switched from track 2 to track 1
FN 1, FP 1, IDSW 2, objects 10 -> MOTA 0.60
ตัวติดตามพลาดรถ B หนึ่งเฟรม มีกรอบเกินหนึ่งกรอบ และสลับหมายเลขของรถทั้งสองคันเมื่อแล่นใกล้กัน MOTA จึงเหลือ 0.60 ทั้งที่แต่ละเฟรมตรวจพบรถเกือบครบ ถ้าใช้ผลนี้นับรถ รถแต่ละคันจะถูกนับผิดทิศทาง การใช้ความเร็วจากตัวกรองคาลมานช่วยจับคู่ และลักษณะภาพของวัตถุ ช่วยลดการสลับหมายเลขได้
ปฏิบัติการประจำโมดูล
ปฏิบัติการ: ติดตามรถในวิดีโอจากโดรน
- รันตัวตรวจจับจากวิชา UAT 306 บนวิดีโอลานจอดรถทุกเฟรม บันทึกกรอบ
- เขียนตัวติดตามจากตัวอย่างที่ 1 และการจับคู่ด้วย IoU
- ติด label เส้นทางจริง 100 เฟรม แล้วคำนวณ MOTA ด้วยตัวอย่างที่ 2
- ทดลองเปลี่ยนขีดแบ่ง IoU ของการจับคู่และจำนวนเฟรมที่ยอมให้หายก่อนปิดเส้นทาง
- นับรถที่ผ่านเส้นกำหนด เทียบกับการนับด้วยตา
ข้อผิดพลาดที่พบบ่อย
ระวัง
- ประเมินแค่การตรวจจับรายเฟรม โดยไม่ดูการสลับหมายเลข
- ทำนายต่อไปเรื่อย ๆ เมื่อวัตถุหายนาน
- ตั้งขีดแบ่ง IoU สูงเกินไป กับวัตถุที่เคลื่อนเร็ว
- ไม่ชดเชยการเคลื่อนของโดรน ทำให้ทุกวัตถุดูเหมือนเคลื่อนที่
- นับวัตถุจากหมายเลขเส้นทาง โดยไม่ตรวจการสลับ
สรุป
- tracking-by-detection ทำนายตำแหน่งด้วยตัวกรองคาลมาน แล้วจับคู่กับผลตรวจจับ
- ความไม่แน่นอนโตขึ้นเมื่อวัตถุถูกบัง ใช้ขยายเขตค้นหาและตัดสินใจปิดเส้นทาง
- การสลับหมายเลขทำให้การนับและการวิเคราะห์เส้นทางผิด
- MOTA รวม FN, FP และ IDSW หารด้วยจำนวนวัตถุจริง
แบบฝึกตรวจความเข้าใจ
- วัตถุอยู่ที่ x = 100 px ความเร็ว 20 px/s ทำนายหลัง 0.5 s ได้ที่ใด
- FN 5 FP 3 IDSW 2 วัตถุจริงรวม 50 MOTA เท่าใด
- ทำไมความไม่แน่นอนจึงโตขึ้นเมื่อไม่มีผลตรวจจับ
- ID switch คืออะไร
- ทำไมต้องชดเชยการเคลื่อนของโดรนเมื่อติดตามวัตถุบนพื้น
เฉลย
- px
- ขั้นทำนายเพิ่ม ทุกเฟรม แต่ไม่มีขั้นปรับแก้ลดความไม่แน่นอน
- วัตถุจริงตัวเดิมถูกจับคู่กับหมายเลขเส้นทางต่างจากเฟรมก่อน
- ภาพทั้งภาพเลื่อนเมื่อโดรนเคลื่อน วัตถุที่หยุดนิ่งจะดูเหมือนเคลื่อนที่
สรุปสูตรสำคัญ
| แบบจำลองความเร็วคงที่ | |
| MOTA |
แหล่งอ้างอิงหลัก
- Bewley, A., Ge, Z., Ott, L., Ramos, F., & Upcroft, B. (2016). Simple online and realtime tracking. In 2016 IEEE International Conference on Image Processing (pp. 3464–3468). link
- Bernardin, K., & Stiefelhagen, R. (2008). Evaluating multiple object tracking performance: The CLEAR MOT metrics. EURASIP Journal on Image and Video Processing, 2008, 246309. link
- Szeliski, R. (2022). Computer vision: Algorithms and applications (2nd ed.). Springer. link
- Corke, P. (2023). Robotics, vision and control: Fundamental algorithms in Python. Springer. link
อ่านเพิ่มเติม
ศึกษาหน่วยความรู้ที่กำหนดล่วงหน้า ดูสื่อประกอบ และทำ quiz ประจำโมดูล
ในชั้นเรียน / ภาคสนาม
ปฏิบัติการในห้องแล็บหรือภาคสนามตามใบงาน พร้อม checklist ความปลอดภัย
หลักฐานการเรียนรู้: ใบงานที่ผ่านการตรวจและผล quiz