背景
假設要實現人的面部或手部的運動檢測。
方法:先對攝像頭輸入的圖像進行處理,只保留符合人體膚色的像素,再計算視頻中此幀和上一幀圖像數據的差異。差異超過一定閾值即認爲畫面中的人體產生了運動。
代碼
from cv2 import cv2
import matplotlib.pyplot as plt
def cvt(img): # 膚色提取
YCrCb = cv2.cvtColor(img, cv2.COLOR_BGR2YCR_CB) # 轉換至YCrCb空間
# 人體膚色在YCrCb空間的粗略映射
skin = cv2.inRange(YCrCb, np.array([0, 133, 77]), np.array([255, 173, 127]))
res = cv2.bitwise_and(YCrCb, YCrCb, mask=skin)
return res
cap = cv2.VideoCapture(0)
cap.set(3, 640)
cap.set(4, 480)
firstlaunch = True # 首次運行的標誌
prev_frame = None # 用於保存上一幀圖像
plt.ion() # 交互模式,使繪製的直方圖可以不斷變化
while True:
ret, frame_read = cap.read()
frame_read = cv2.flip(frame_read, 1)
frame_read = cv2.medianBlur(frame_read, 5)
frame_read = cv2.GaussianBlur(frame_read, (5, 5), 0)
# 提取膚色,然後再轉化爲灰度圖
present_frame = cvt(frame_read)
present_frame = cv2.cvtColor(present_frame, cv2.COLOR_YCrCb2BGR)
present_frame = cv2.cvtColor(present_frame, cv2.COLOR_BGR2GRAY)
if not firstlaunch:
sub = cv2.subtract(present_frame, prev_frame)
hist = cv2.calcHist([sub], [0], None, [256], [0, 255])
# 只統計灰度值6-100的部分,這只是隨意取的
# 可以自己實驗調整找到適合的範圍
diff = np.sum(hist[6:100]) # 統計產生變化的像素點個數
print(diff)
plt.plot(hist[6:100], color='red') # 繪製直方圖
plt.ylim([0, 6000])
plt.show()
cv2.imshow('preview', sub)
else:
firstlaunch = False # 首次運行的標誌
cv2.waitKey(10)
if not firstlaunch:
plt.clf() # 清除直方圖圖像
prev_frame = present_frame.copy() # 存儲此幀
plt.close('all')
cap.release()
效果
當人頭部基本保持靜止時,統計數值基本不超過10000
當人的頭部或手部產生運動時,統計數值上升爲一萬至數萬。