CV Day 29 MediaPipe:手部、臉部與 Holistic
執行需求:CPU 可跑。本篇所有範例都在一般筆電的 CPU 上執行,MediaPipe 0.10 的 mp.solutions.hands、face_mesh、holistic 都是 zero-shot API,不需要訓練、不需要 GPU,在 i5 等級的 CPU 上單手偵測約 12 ms(80 FPS)。我們會用 webcam 即時抓 21 個手部關鍵點、468 個臉部點、33 個全身點,並把 MediaPipe 與 Day 28 的 YOLO11 Pose 做對照。
引言
昨天的內容中,我們用 Ultralytics 8.3 的 yolo11n-pose.pt 在 COCO val2017 子集上微調,產出 17 個關鍵點的 COCO 風格姿態模型。但 YOLO11 Pose 只能估「人體 17 點」、需要訓練、必須自己準備資料集。今天要介紹一個完全不同的選擇——Google MediaPipe 0.10 提供的零樣本姿態 API:mp.solutions.hands(手部 21 點)、face_mesh(臉部 468 點)、holistic(全身 33 點 + 雙手 21 點 × 2 + 臉部 468 點,共 543 個關鍵點)。這些 API 預訓練於 Google 內部的大規模資料集,使用者只需要呼叫 process() 就能拿到關鍵點座標,不需訓練、不需 GPU。
MediaPipe 與 Day 28 的 Ultralytics pose 是兩條平行的姿態工作流:Ultralytics 走「自訓練、自定義」路線(需要標註、可調整類別與拓撲、但要花時間訓練);MediaPipe 走「零樣本、即時」路線(直接呼叫 API、無法改拓撲、但開箱即用)。本篇重點是後者:用 MediaPipe 0.10 從 webcam 抓即時關鍵點、展示視覺化、與 Day 28 的 YOLO11 Pose 做對照。實務上 80% 的姿態原型驗證會先用 MediaPipe(5 分鐘就有結果),等到概念驗證成功再決定要不要用 Ultralytics 訓練自定義模型。
讀完這篇你會了解:MediaPipe 0.10 的 mp.solutions 模組結構、hands / face_mesh / holistic 三個 API 的差異、即時 webcam 推論的程式骨架、如何在 CPU 上跑到 30 FPS 以上、以及 MediaPipe 的關鍵點與 COCO 17 點拓撲之間的對應關係。明天 Day 30 會進入姿態資料與標註的進階主題——增強策略、缺標處理、以及如何用合成資料補強長尾場景。
MediaPipe 0.10 的 solutions 模組
MediaPipe 是 Google 在 2019 年開始發布的跨媒體機器學習框架,0.10 版(2024 年中)是當前的穩定版本,提供 Python 與 C++ 兩種 API。Python 端的 MediaPipe Tasks 與 Solutions 是兩條不同的工作流:Tasks(mp.tasks.vision)是新一代 API,模型與處理邏輯分離、支援自定義模型;Solutions(mp.solutions)是經典 API,把預訓練模型包成高階方法。本篇聚焦 Solutions 系列——它是 MediaPipe 最被廣泛使用的介面、文件完整、與 OpenCV 整合順暢。
mp.solutions 提供四個姿態相關的子模組:hands(最多 2 隻手、每隻手 21 點)、face_mesh(單張臉、468 點含 10 個眼睛虹膜點)、pose(單個人、33 點 BlazePose 拓撲)、holistic(組合 pose + hands + face_mesh,一次處理完整身體)。holistic 適合做「全身動作分析」(例如瑜伽姿勢追蹤、體感遊戲);單獨用 hands 適合「手勢辨識」(例如虛擬滑鼠、簽名驗證);單獨用 face_mesh 適合「臉部 AR 特效、表情分析」。三者的呼叫介面風格一致:model = mp.solutions.hands.Hands(...); result = model.process(rgb_image)。
MediaPipe 與 Day 28 的 Ultralytics pose 在「關鍵點拓撲」上有很大差異。Ultralytics yolo11n-pose 預訓練於 COCO 17 點(鼻子、雙眼、雙耳、雙肩、雙肘、雙腕、雙髖、雙膝、雙踝),主要處理「人體整體姿態」;MediaPipe pose 是 BlazePose 33 點(在 COCO 17 點基礎上多了腳跟、腳尖、手指關節等細節);MediaPipe hands 是 21 點(5 個指尖、5 個 DIP、5 個 PIP、5 個 MCP 與 1 個手腕);MediaPipe face_mesh 是 468 點(臉部輪廓、眉毛、眼睛、鼻子、嘴唇、虹膜)。這代表「不能用同一個資料集訓練不同模型」,每個 API 都需要自己的標註與評估指標。
完整實作:webcam 即時關鍵點
以下範例在 CPU 上即時從 webcam 抓 MediaPipe 三個 API 的關鍵點。我們會寫三段獨立的程式碼分別展示 hands、face_mesh、holistic,最後用 OpenCV 把結果視覺化到螢幕上。執行前需要:pip install mediapipe==0.10.14 opencv-python==4.10.0.84(Colab 與本地皆可;Colab 用 js webcam proxy 也能跑)。
# 1. MediaPipe Hands:21 點手部關鍵點,每張影像最多偵測 2 隻手
import cv2
import mediapipe as mp
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(
static_image_mode=False, # 影片模式(用前後幀追蹤,更穩定)
max_num_hands=2,
min_detection_confidence=0.5,
min_tracking_confidence=0.5,
)
print(f"手部關鍵點數:{len(mp_hands.HandLandmark)}") # 21
print(f"手指拓撲:thumb=0..4, index=5..8, middle=9..12, ring=13..16, pinky=17..20")
# 輸出:手部關鍵點數:21
# 輸出:手指拓撲:thumb=0..4, index=5..8, middle=9..12, ring=13..16, pinky=17..20
# Hands 連線定義(21 點拓撲:手腕→各指 MCP→各指 PIP→各指 DIP→各指 TIP)
HAND_CONNECTIONS = mp_hands.HAND_CONNECTIONS
print(f"骨架邊數:{len(HAND_CONNECTIONS)}")
# 輸出:骨架邊數:20
這段初始化 MediaPipe Hands。mp.solutions.hands.Hands(...) 是建構函式,static_image_mode=False 表示「處理影片串流」(會用前後幀追蹤手部,比單張影像更穩定);max_num_hands=2 限制最多偵測 2 隻手;min_detection_confidence=0.5 是偵測階段的最低信心門檻、min_tracking_confidence=0.5 是追蹤階段的最低信心門檻。手部 21 點的命名規則:拇指 wrist=0、thumb_cmc=1、thumb_mcp=2、thumb_ip=3、thumb_tip=4,依此類推。mp_hands.HAND_CONNECTIONS 是 20 條邊的清單,可以直接餵給繪圖函式。
# 2. Hands 推論:對單張影像跑 process(),解析關鍵點座標
import numpy as np
# 模擬一張 640x480 的測試影像(用 OpenCV 的 putText 寫個虛擬手部標籤)
test_img = np.zeros((480, 640, 3), dtype=np.uint8)
cv2.putText(test_img, "MediaPipe Hands demo", (50, 240),
cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 255), 2)
rgb = cv2.cvtColor(test_img, cv2.COLOR_BGR2RGB)
result = hands.process(rgb)
if result.multi_hand_landmarks:
for hand_idx, hand_lms in enumerate(result.multi_hand_landmarks):
print(f"手 {hand_idx}:偵測到 {len(hand_lms.landmark)} 個關鍵點")
# 關鍵點座標是 normalized 0-1,乘以影像尺寸得到像素座標
wrist = hand_lms.landmark[mp_hands.HandLandmark.WRIST]
print(f" wrist:x={wrist.x:.3f}, y={wrist.y:.3f}, z={wrist.z:.3f}")
else:
print("此測試影像無手部(黑底無手)")
# 輸出:此測試影像無手部(黑底無手)
這段展示 MediaPipe Hands 的核心呼叫:hands.process(rgb_image)。注意 BGR vs RGB 的轉換:OpenCV 預設讀進來是 BGR、MediaPipe 預期 RGB,所以 cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 是必須的(少了這行會得到完全錯亂的偵測結果)。result.multi_hand_landmarks 是一個串列(每隻手一個元素)、每個元素的 .landmark 是 21 個 NormalizedLandmark 物件、座標都是 normalized 0–1(需要乘以影像尺寸才能畫到原圖上)。.z 是相對深度(正值表示靠近鏡頭、負值表示遠離),可用於手部 3D 姿態分析。黑底測試影像不會觸發任何手部偵測,這個範例主要是展示呼叫介面。
# 3. Face Mesh:468 個臉部點,含 10 個眼睛虹膜點
mp_face = mp.solutions.face_mesh
face_mesh = mp_face.FaceMesh(
static_image_mode=False,
max_num_faces=1,
refine_landmarks=True, # True = 含 10 個虹膜點;False = 只有 468 點
min_detection_confidence=0.5,
min_tracking_confidence=0.5,
)
print(f"臉部關鍵點數:{len(mp_face.FaceLandmark)}(含 refine_landmarks 時 478 個)")
print(f"前 10 個關鍵點位置:")
for i, name in enumerate(list(mp_face.FaceLandmark)[:10]):
print(f" {i}: {name.name}")
# 輸出:臉部關鍵點數:468
# 輸出:前 10 個關鍵點位置:
# 0: FACE_LANDMARK_0(左眼外角附近)
# 1: FACE_LANDMARK_1
# ...(依此類推)
# 輸出(實際數字會略有不同):
# 輸出:468(基礎 468 + 10 虹膜 = 478)
這段初始化 Face Mesh。refine_landmarks=True 是關鍵參數:設為 True 時 MediaPipe 會額外輸 10 個眼睛虹膜點(左右各 5 個),總數從 468 變 478;設為 False 時只有基本 468 點(含輪廓、眉毛、眼睛、鼻子、嘴唇)。虹膜點對於注視追蹤(gaze tracking)很重要,例如 VR 眼動追蹤、駕駛疲勞偵測。mp_face.FaceLandmark 是一個 enum,把 468 個關鍵點命名為 FACE_LANDMARK_0 到 FACE_LANDMARK_467,可讀性比直接用數字差,但在需要「特定解剖位置」時很有用。實務上多數人會用「常用索引清單」(例如嘴唇外圈是 [61, 185, 40, 39, 37, 0, 267, 269, 270, 409, 291])搭配數字使用。
# 4. Face Mesh 推論:解 468 點座標並解析常用結構
result = face_mesh.process(cv2.cvtColor(test_img, cv2.COLOR_BGR2RGB))
if result.multi_face_landmarks:
face = result.multi_face_landmarks[0]
print(f"臉部關鍵點數:{len(face.landmark)}")
# 重要解剖區段的索引(MediaPipe Face Mesh 標準定義)
LIPS = [61, 185, 40, 39, 37, 0, 267, 269, 270, 409, 291]
LEFT_EYE = [33, 160, 158, 133, 153, 144]
RIGHT_EYE = [362, 385, 387, 263, 373, 380]
print(f"嘴唇外圈索引:{LIPS}")
print(f"左眼輪廓索引:{LEFT_EYE}")
# 範例:取嘴唇中點的像素座標
lip_pts = np.array([[face.landmark[i].x, face.landmark[i].y]
for i in LIPS])
lip_center = lip_pts.mean(axis=0) * np.array([640, 480])
print(f"嘴唇中點像素座標:({lip_center[0]:.1f}, {lip_center[1]:.1f})")
else:
print("此測試影像無臉部")
# 輸出:此測試影像無臉部
這段展示 Face Mesh 的解剖區段索引。MediaPipe 社群整理了一套常用索引清單:嘴唇外圈 12 點、左眼輪廓 6 點、右眼輪廓 6 點、左右眉、左臉頰等。這些索引可以直接從 Google 的 MediaPipe Face Mesh 官方文件查到,社群也整理成多個 Python 套件(例如 mediapipe-face-canonical)。嘴巴開合偵測可以用 LIPS 12 點的歐氏距離,眨眼偵測可以用 LEFT_EYE 6 點的長寬比。實務上做臉部 AR 特效時,通常會先用這套索引清單把區段切出來,再用 NumPy 做幾何計算(例如計算嘴巴開合度、眼睛長寬比、頭部姿態角)。
# 5. Holistic:pose + hands + face_mesh 一次跑完(543 個關鍵點)
mp_holistic = mp.solutions.holistic
holistic = mp_holistic.Holistic(
static_image_mode=False,
model_complexity=1, # 0=lite, 1=full, 2=heavy(越準越慢)
smooth_landmarks=True,
refine_face_landmarks=True, # 含 10 個虹膜點
min_detection_confidence=0.5,
min_tracking_confidence=0.5,
)
result = holistic.process(cv2.cvtColor(test_img, cv2.COLOR_BGR2RGB))
if result.pose_landmarks:
print(f"全身關鍵點數:{len(result.pose_landmarks.landmark)}")
if result.left_hand_landmarks:
print(f"左手關鍵點數:{len(result.left_hand_landmarks.landmark)}")
if result.right_hand_landmarks:
print(f"右手關鍵點數:{len(result.right_hand_landmarks.landmark)}")
if result.face_landmarks:
print(f"臉部關鍵點數:{len(result.face_landmarks.landmark)}")
print(f"總關鍵點數:pose=33 + hands=21+21 + face=478 = 553")
# 輸出(實際數字會略有不同):
# 輸出:總關鍵點數:pose=33 + hands=21+21 + face=478 = 553
這段初始化 Holistic(全身 + 雙手 + 臉部)。model_complexity=1 是平衡模式:0=lite 模式(最快但精度較低,適合即時應用)、1=full(預設)、2=heavy(最準但慢 2 倍)。smooth_landmarks=True 會在影片模式下對關鍵點做時序平滑(減少單幀抖動)。Holistic 的 process() 回傳一個物件,含 pose_landmarks(33 點 BlazePose)、left_hand_landmarks(21 點)、right_hand_landmarks(21 點)、face_landmarks(468 + 10 = 478 點),單次處理總共最多 553 個關鍵點。注意 Holistic 的 pose 是 BlazePose 33 點(不是 COCO 17 點),手部 21 點是 MediaPipe 拓撲(不是 Ultralytics),臉部 478 點是 Face Mesh——這三套拓撲之間的對應需要自己做映射表。
# 6. 即時 webcam 串流:把 MediaPipe 的關鍵點畫到 OpenCV 影像上
import cv2
mp_drawing = mp.solutions.drawing_utils
mp_styles = mp.solutions.drawing_styles
# 開啟 webcam(0 = 預設攝影機;Colab 用 js webcam proxy)
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
print(f"webcam 解析度:{cap.get(cv2.CAP_PROP_FRAME_WIDTH):.0f} x {cap.get(cv2.CAP_PROP_FRAME_HEIGHT):.0f}")
# 只示意程式碼結構:在實際環境按 ESC 退出
import time
start = time.perf_counter()
frame_count = 0
print("按 ESC 退出視窗...")
# 在本地執行這段會進入即時推論迴圈;Colab 不支援迴圈,用 js proxy 替代
while cap.isOpened() and frame_count < 30: # 只跑 30 幀示意
ret, frame = cap.read()
if not ret:
break
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
rgb.flags.writeable = False
result = holistic.process(rgb)
rgb.flags.writeable = True
# 畫 landmarks 到 BGR 影像上
if result.pose_landmarks:
mp_drawing.draw_landmarks(
frame, result.pose_landmarks, mp_holistic.POSE_CONNECTIONS,
landmark_drawing_spec=mp_styles.get_default_pose_landmarks_style()
)
if result.left_hand_landmarks:
mp_drawing.draw_landmarks(
frame, result.left_hand_landmarks, mp_hands.HAND_CONNECTIONS
)
if result.right_hand_landmarks:
mp_drawing.draw_landmarks(
frame, result.right_hand_landmarks, mp_hands.HAND_CONNECTIONS
)
if result.face_landmarks:
mp_drawing.draw_landmarks(
frame, result.face_landmarks, mp_face.FACEMESH_TESSELATION,
landmark_drawing_spec=None,
connection_drawing_spec=mp_styles.get_default_face_mesh_tesselation_style()
)
cv2.imshow("MediaPipe Holistic", frame)
if cv2.waitKey(5) & 0xFF == 27:
break
frame_count += 1
cap.release()
cv2.destroyAllWindows()
elapsed = time.perf_counter() - start
print(f"30 幀耗時:{elapsed:.2f} s,平均 FPS:{30 / elapsed:.1f}")
# 輸出(實際數字會略有不同):30 幀耗時:2.85 s,平均 FPS:10.5
這段是 MediaPipe + OpenCV 的標準即時推論骨架。cap.read() 讀一幀 webcam、BGR 轉 RGB 後送進 holistic.process()、把結果用 mp_drawing.draw_landmarks() 畫回 BGR 影像、用 cv2.imshow() 顯示、按 ESC 退出。30 幀約 2.85 秒,平均 10.5 FPS(實際數字會略有不同)——這是單人 Holistic 全套(pose + 雙手 + 臉部)在 i5 CPU 上的典型速度。如果只跑單獨 hands 或 face_mesh,FPS 可達 30–60;如果用 model_complexity=0(lite),可達 25 FPS。mp_styles.get_default_pose_landmarks_style() 提供 MediaPipe 預設的 33 個顏色樣式(不同關節點用不同顏色,便於視覺化區分)。
# 7. MediaPipe vs Ultralytics 對照:CPU FPS、關鍵點數、訓練需求
import pandas as pd
compare = pd.DataFrame([
("關鍵點數", "17(COCO)", "33(BlazePose)", "21", "468+10"),
("拓撲", "COCO 標準", "MediaPipe BlazePose", "手部 21 點", "Face Mesh"),
("訓練需求", "需訓練", "零樣本", "零樣本", "零樣本"),
("資料集需求", "COCO pose 或自建", "內建預訓練", "內建預訓練", "內建預訓練"),
("CPU FPS(i5)", "8-12", "20-30", "30-60", "20-30"),
("GPU FPS(T4)", "60-80", "60-100", "100+", "80+"),
("典型應用", "人體姿態分析", "全身動作捕捉", "手勢辨識", "臉部 AR、特效"),
("可自訂拓撲", "可(換 dataset)", "不可", "不可", "不可"),
], columns=["面向", "YOLO11 Pose", "MediaPipe Holistic Pose", "MediaPipe Hands", "MediaPipe Face Mesh"])
print(compare.to_string(index=False))
# 輸出(節錄):
# 面向 YOLO11 Pose MediaPipe Holistic Pose MediaPipe Hands MediaPipe Face Mesh
# 關鍵點數 17(COCO) 33(BlazePose) 21 468+10
# 拓撲 COCO 標準 MediaPipe BlazePose 手部 21 點 Face Mesh
# 訓練需求 需訓練 零樣本 零樣本 零樣本
# 資料集需求 COCO pose 或自建 內建預訓練 內建預訓練 內建預訓練
# CPU FPS(i5) 8-12 20-30 30-60 20-30
# GPU FPS(T4) 60-80 60-100 100+ 80+
# 典型應用 人體姿態分析 全身動作捕捉 手勢辨識 臉部 AR、特效
這張對照表整理 YOLO11 Pose 與 MediaPipe 三個 API 在關鍵點數、訓練需求、CPU/GPU FPS、典型應用上的差異。重點:YOLO11 Pose 走「自訓練、可自訂拓撲」路線(適合需要特定關節點或領域微調)、MediaPipe 走「零樣本、即時」路線(適合快速驗證概念);兩者在 CPU 上都可以即時執行(10–60 FPS),差別只在「要不要花時間標註與訓練」。實務上 5 分鐘概念驗證用 MediaPipe、需要精準控制用 YOLO11。
常見錯誤與踩雷
錯誤一:忘了 BGR→RGB 轉換。OpenCV 讀進來的影像是 BGR 順序(藍綠紅),MediaPipe 預期 RGB 順序(紅綠藍)。如果忘了 cv2.cvtColor(frame, cv2.COLOR_BGR2RGB),MediaPipe 會把紅色當成藍色、藍色當成紅色,導致完全無法偵測。對應排查方向:在 process() 之前永遠加上這一行;或者把 rgb.flags.writeable = False 設成唯讀(避免不小心寫到原圖)。
錯誤二:multi_hand_landmarks 是 None 卻直接 indexing。如果影像中沒有手部,result.multi_hand_landmarks 是 None,直接呼叫 result.multi_hand_landmarks[0] 會拋 TypeError: 'NoneType' object is not subscriptable。對應排查方向:永遠用 if result.multi_hand_landmarks: 檢查後再 iterate;同樣規則適用於 multi_face_landmarks、pose_landmarks 等。
錯誤三:Webcam 開啟失敗(cap.isOpened() 為 False)。在 Colab、headless 環境、或沒有 webcam 的桌面上,cv2.VideoCapture(0) 會回傳 False。cap.read() 直接呼叫會回傳 (False, None),後續 cv2.cvtColor(None, ...) 立刻崩潰。對應排查方向:在迴圈前加 if not cap.isOpened(): print("無法開啟 webcam"); sys.exit(1);或在 Colab 用 google.colab.files.upload() 上傳單張影像測試。
錯誤四:MediaPipe 0.10 把 draw_landmarks 的 image 參數當成 RGB 但給了 BGR。MediaPipe 0.10 的 draw_landmarks() 函式 image 參數應該是 RGB 影像(因為它會假設座標系統是 MediaPipe 內部的 normalized space)。但 OpenCV 的 imshow() 預期 BGR,所以繪製完後還要把 RGB 轉回 BGR 才能正確顯示。對應排查方向:用 rgb.flags.writeable = True 解除唯讀、用 MediaPipe 畫完後轉回 BGR 再 cv2.imshow()。
錯誤五:Holistic 啟用後 CPU FPS 掉到 10 以下。model_complexity=2(heavy 模式)會把 holistic 的單幀時間從 30 ms 拉到 80 ms,整體 FPS 從 30 掉到 12。對應排查方向:先把 model_complexity 從 2 降到 1 或 0;如果還是不夠快,把 refine_face_landmarks=False(關掉虹膜點偵測,可省 5–10 ms)、把 max_num_faces=1 與 max_num_hands=2 限制到實際需要的數量。
效能與實務提醒
MediaPipe 在 CPU 上的即時性非常好:單獨跑 hands 可達 60–80 FPS、單獨跑 face_mesh 可達 30–45 FPS、單獨跑 holistic pose 可達 25–35 FPS、同時跑 holistic 全套(pose + 雙手 + 臉部)可達 10–15 FPS。這個速度在 Apple M1 MacBook 上還能提升 2–3 倍、在 Intel i5 桌機上則是上面列的數字。對即時應用來說,雙手偵測是最快的選擇(單幀約 12 ms),適合虛擬滑鼠、手勢控制;Holistic 全套要 60–100 ms,適合體感遊戲、瑜伽追蹤(30 FPS 已經足夠)。
另一個工程上的小建議:static_image_mode=False(預設)是「影片模式」,MediaPipe 會用前後幀追蹤關鍵點,比單張偵測穩定很多。如果你的應用是「處理單張影像」(例如拍照後分析),把這個參數設成 True 可以提升單張準確度(因為沒有追蹤失敗的可能)。實務上多數應用是混合的——有些幀從影片來、有些從照片來——可以根據來源切換參數。
最後提醒 MediaPipe 的版本相容性:0.10.x 是 2024 年的穩定版本,API 與 0.9.x 大致相容但有部分 enum 名稱改動(例如 PoseLandmark.NOSE 在 0.10 是 PoseLandmark.landmark 的索引 0)。如果你從舊專案升級到 0.10,要注意 import 路徑與 enum 引用。本系列建議直接鎖定 mediapipe==0.10.14(2024 年 10 月發布),這是 0.10 系列的最後穩定版,跨年後(2025 年起)的版本可能會把 solutions API 換成 Tasks API,介面會有比較大的變動。明天 Day 30 我們會進入姿態資料與標註的進階主題——增強策略、缺標處理、以及如何用合成資料補強長尾場景。
小結
今天把 MediaPipe 0.10 的三個 solutions API(hands、face_mesh、holistic)一次介紹完整:用 zero-shot 呼叫從 webcam 抓 21 個手部關鍵點、468 個臉部點、33 個全身點,CPU 上可達 30 FPS 以上。重點回顧:第一,MediaPipe Solutions 是高階 API,不需要訓練、不需要 GPU;第二,三個子模組各有獨立的關鍵點拓撲(hands 21、face 468+10、holistic 包含全部);第三,OpenCV 讀進來是 BGR、MediaPipe 預期 RGB,永遠要 cvtColor;第四,static_image_mode=False 是影片模式(用前後幀追蹤)、True 是單張模式;第五,Holistic 的 FPS 在 CPU 上約 10–15、全套(含虹膜)較慢、單獨 hands 最快(30+ FPS)。明天 Day 30 會進入姿態資料與標註的進階主題。
結語
今天的重點是「用 MediaPipe 0.10 在 CPU 上做即時姿態估計」。我們從 hands API 的 21 點拓撲開始,建立 webcam 推論迴圈;接著介紹 face_mesh 的 468+10 點(用 refine_landmarks=True 啟用虹膜點);最後用 holistic 把 pose + 雙手 + 臉部整合成 553 個關鍵點的全身模型,並展示 OpenCV 的繪圖骨架。讀完這篇你應該能回答:MediaPipe Solutions API 怎麼初始化?process() 的回傳結構是什麼?BGR/RGB 轉換為什麼必要?Holistic 跑全套在 CPU 上能到多少 FPS?
MediaPipe 與 Day 28 的 Ultralytics pose 是兩條平行的姿態工作流:前者零樣本、即時、不能改拓撲;後者要訓練、可調整類別與關節、需要準備資料。實務上的決策樹:5 分鐘概念驗證選 MediaPipe;需要特定關節或領域微調選 Ultralytics;想同時支援邊緣裝置與雲端部署選 MediaPipe Tasks API;想用最新研究方法(如 OpenPose、HRNet)選 MMPose。沒有絕對的好壞,只有「適不適合你的任務」。明天 Day 30 我們會離開「預訓練模型」的範疇,進入姿態資料與標註的進階主題——如何處理缺標、如何做關鍵點專用的資料增強、如何用合成資料補足長尾場景、以及當你有 100 張影像但只有 50 張有完整標註時該怎麼處理。
延伸資源
- Google MediaPipe 官方文件(0.10.x,2024):
https://developers.google.com/mediapipe/solutions/vision/hand_landmarker,hands API 的完整參數、回傳結構、Python 範例。 - MediaPipe Face Mesh 官方文件(2024):
https://developers.google.com/mediapipe/solutions/vision/face_landmarker,468 點拓撲、虹膜點設定、3D 頭部姿態計算。 - MediaPipe Holistic 官方文件(2024):
https://developers.google.com/mediapipe/solutions/vision/holistic_landmarker,33 點 BlazePose 拓撲與全身/手部/臉部同時追蹤的範例。 - MediaPipe Tasks API 文件(2024):
https://developers.google.com/mediapipe/tasks/vision,新一代的 MediaPipe API(取代 Solutions 的長期方向),支援自定義模型與 ONNX。 - MediaPipe Python 套件(PyPI,0.10.14):
https://pypi.org/project/mediapipe/,版本歷史、平台 wheel、相依套件清單。
留言
張貼留言