
當鏡頭學會觀察,可以用來創作甚麼樣的企劃?
想像一下:機械臂看見杯子後,自動把它送到指定位置;互動裝置偵測到桌上的物件後,立刻觸發燈光、音效或遊戲機關;甚至讓電腦畫面中的角色,跟隨真實物件移動。這些看似科幻的小魔法,第一步往往只是——讓程式知道物件在畫面中的哪裡。
這次會使用 Python、OpenCV 與 MediaPipe,透過電腦鏡頭偵測物件,並將物件中心的螢幕座標即時顯示出來。範例設定為 Cup,因此先拿一個輪廓清晰的杯子來試最理想;成功後,你可以再探索其他 MediaPipe Objectron 支援的模型。
這個程式能做到甚麼?
MediaPipe Objectron 是一個可在即時影像中預測物件 3D 邊界框地標的方案。它會回傳物件的多個 2D 地標;本範例把這些點的平均值換算成影像像素座標,因此可得到杯子在畫面中的中心位置 X、Y。
大家要留意一個重要分別:畫面上顯示的 X 與 Y 是攝影機影像的像素座標,例如 X: 960, Y: 540,並不是以公分量度的真實世界座標。若想讓機械人精準地抓取物件,下一步還要進行鏡頭校正、平面轉換或深度估算;但作為互動創作與電腦視覺入門,這已是非常有力的第一步。
範例程式:找出物件的畫面座標
這個 Python 程式透過 Mediapipe 去偵察物件的位置,至於是甚麼物件則可以在程式第 7 行 model_name 設定。
至於為甚麼這個程式內是 “Cup”,大家可以到 https://mediapipe-studio.webapps.google.com/studio/demo/object_detector 試用一下 Medipipe 的 Object Detection Demo 便會明白 ^_^
執行以下的 Python 程式前還有一些準備工作:
1. 請到 python.org 下載及安裝 3.7.9 版本
2. 在 DOS Prompt 執行 pip install mediapipe 安裝 mediapipe library
3. 以系統管理員身分執行 IDLE, 然後在 IDLE 打開或新增以下的 Python 程式
import cv2
import mediapipe as mp
import numpy as np
mp_objectron = mp.solutions.objectron
mp_drawing = mp.solutions.drawing_utils
objectron = mp_objectron.Objectron(static_image_mode=False, max_num_objects=1, min_detection_confidence=0.05, min_tracking_confidence=0.05, model_name='Cup')
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920) # Capture width = 1920
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) # Capture height = 1080
cv2.namedWindow('MediaPipe', cv2.WINDOW_NORMAL) # 創建一個視窗
cv2.setWindowProperty('MediaPipe', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN) # 設定視窗屬性為全屏
while cap.isOpened():
ret, image = cap.read()
results = objectron.process(image) # 進行偵測
# 繪製偵測結果
if results.detected_objects:
for detected_object in results.detected_objects:
# 取得物件的座標點
landmarks = np.array([[mark.x, mark.y, mark.z] for mark in detected_object.landmarks_2d.landmark])
# 計算物件的中心點位置
center_x, center_y = np.mean(landmarks[:, :2], axis=0)
center_x = int(center_x * image.shape[1])
center_y = int(center_y * image.shape[0])
# 在圖片上畫出中心點並標註 X, Y
cv2.circle(image, (center_x, center_y), 5, (255, 255, 255), -1)
cv2.putText(image, f'X: {center_x}, Y: {center_y}', (center_x+20, center_y-20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2, cv2.LINE_AA)
# 畫邊界線
cv2.line(image, (20, 50), (20, 1030), (255, 255, 255), 1)
cv2.line(image, (960, 50), (960, 1030), (255, 255, 255), 1)
cv2.line(image, (1900, 50), (1900, 1030), (255, 255, 255), 1)
cv2.line(image, (20, 540), (1900, 540), (255, 255, 255), 1)
cv2.imshow('MediaPipe', image) # 顯示總輸出畫面
if cv2.waitKey(1) & 0xFF == 27: # 按 Esc 關閉程式及視窗
break
cv2.destroyAllWindows()
cap.release()
