OpenCV 跟蹤
本演示旨在學習如何使用 Python 和 OpenCV 建立一個非常基本且簡單的運動檢測和跟蹤系統。我們在本文末尾實現了用矩形邊界框跟蹤每個人。
使用 Python 和 OpenCV 建立運動檢測和跟蹤系統
首先,我們需要從 CAP
例項中讀取兩個幀。
ret, F1 = CAP.read()
同樣,我們將閱讀第二幀。
ret, F2 = CAP.read()
現在我們將宣告一個名為 DF
的變數並使用 absdiff()
函式。absdiff()
幫助找到幀之間的絕對差異,第一個 F1
和第二個 F2
。
while CAP.isOpened():
if ret == False:
print(ret)
break
DF = cv2.absdiff(F1, F2)
使用 cvtColor()
方法將此差異轉換為灰度模式。第一個引數是 DF
。
第二個引數將是 COLOR_BGR2GRAY
,這將有助於將幀顏色 BGR 轉換為灰度模式;為什麼我們要找出灰度模式?
因為我們會在後期找到輪廓,所以灰度模式比彩色模式更容易找到輪廓。
Gray_Scale = cv2.cvtColor(DF, cv2.COLOR_BGR2GRAY)
一旦我們有了灰度模式,我們需要使用 GaussianBlur()
方法來模糊我們的灰度幀。它需要一些引數;第一個是 Gray_Scale
,第二個引數是核心大小 5x5
,第三個引數是 Sigma X
值。
BL = cv2.GaussianBlur(Gray_Scale, (5, 5), 0)
我們需要使用 threshold()
方法來確定閾值。它返回兩個物件;我們定義 _
,因為我們不需要第一個變數,然後第二個變數將是 thresh
。
在第一個引數中,我們將我們的模糊影象作為源傳遞,然後第二個引數將是閾值 20。最大閾值為 255;型別將是 THRESH_BINARY
。
_, thresh = cv2.threshold(BL, 20, 255, cv2.THRESH_BINARY)
我們需要擴大閾值影象以填充所有孔;這將幫助我們找到更好的輪廓。dilate()
方法有幾個引數;第一個引數將是定義的閾值,第二個引數將是核心大小,但我們將其傳遞給 None
。
第三個引數是迭代次數為 3。如果不起作用,你可以增加或減少迭代次數。
DL = cv2.dilate(thresh, None, iterations=3)
在下一步中,我們將找出輪廓,findContours()
方法為我們提供了兩個結果;一個是輪廓,另一個是層次結構,但我們不打算使用第二個結果。我們將在膨脹影象上找到輪廓。
所以我們在第一個引數中傳遞擴張影象,接下來是最常用的 RETR_TREE
模式。下一個引數將是 CHAIN_APPROX_SIMPLE
方法。
CTS, _ = cv2.findContours(DL, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
在下一步中,我們要繪製矩形,因此我們將使用 for
迴圈遍歷所有輪廓。CTS
是一個列表,我們正在迭代這個列表,所以第一步是使用 boundingRect()
方法儲存輪廓的所有座標。
下一步,我們將找出輪廓區域,如果這個區域小於某個值,我們將不會繪製矩形。在 for
迴圈中,我們將定義如果輪廓面積小於 700,我們將繼續迭代;否則,繪製矩形。
要繪製矩形,我們需要使用 cv2.rectangle()
方法,這裡的第一個引數將是源,即 F1
;第二個引數將是點 1 (x,y)
。第三個引數是點 2,下一個引數是作為顏色值的元組,下一個引數是厚度。
for CT in CTS:
(x, y, w, h) = cv2.boundingRect(CT)
if cv2.contourArea(CT) < 900:
continue
cv2.rectangle(F1, (x, y), (x + w, y + h), (0, 255, 0), 2)
如果觀察到一些移動,我們將在影象上放置一些文字。我們將使用 cv2.putText()
方法;此方法將採用 F1
,第二個將是文字,下一個引數引數將是我們要放置此文字的原點。
下一個引數是字型 FONT_HERSHEY_SIMPLEX
;下一個引數將是字型比例。接下來是字型的顏色;然後,最後一個引數將是文字的粗細。
cv2.putText(
F1,
"Status: {}".format("Movement"),
(10, 20),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(0, 0, 255),
3,
)
現在我們將在迴圈之外編寫一些程式碼。首先,我們將編寫輸出影象以儲存輸出,然後顯示 F1
,即應用輪廓後的結果。
在下一行中,我們正在讀取變數 F2
中的新幀,在讀取新幀之前,我們將 F2
的值分配給 F1
。這樣,我們正在閱讀並找到兩個框架之間的差異。
OP.write(IMG)
cv2.imshow("feed", F1)
F1 = F2
ret, F2 = CAP.read()
完整的原始碼:
import cv2
import numpy as np
CAP = cv2.VideoCapture("input.avi")
FR_W = int(CAP.get(cv2.CAP_PROP_FRAME_WIDTH))
FR_H = int(CAP.get(cv2.CAP_PROP_FRAME_HEIGHT))
FRC = cv2.VideoWriter_fourcc("X", "V", "I", "D")
OP = cv2.VideoWriter("output.avi", FRC, 5.0, (1280, 720))
ret, F1 = CAP.read()
ret, F2 = CAP.read()
print(F1.shape)
while CAP.isOpened():
if ret == False:
print(ret)
break
DF = cv2.absdiff(F1, F2)
Gray_Scale = cv2.cvtColor(DF, cv2.COLOR_BGR2GRAY)
BL = cv2.GaussianBlur(Gray_Scale, (5, 5), 0)
_, thresh = cv2.threshold(BL, 20, 255, cv2.THRESH_BINARY)
DL = cv2.dilate(thresh, None, iterations=3)
CTS, _ = cv2.findContours(DL, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for CT in CTS:
(x, y, w, h) = cv2.boundingRect(CT)
if cv2.contourArea(CT) < 900:
continue
cv2.rectangle(F1, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.putText(
F1,
"Status: {}".format("Movement"),
(10, 20),
cv2.FONT_HERSHEY_SIMPLEX,
1,
(0, 0, 255),
3,
)
IMG = cv2.resize(F1, (1280, 720))
OP.write(IMG)
cv2.imshow("feed", F1)
F1 = F2
ret, F2 = CAP.read()
if cv2.waitKey(40) == 27:
break
cv2.destroyAllWindows()
CAP.release()
OP.release()
我們可以看到狀態顯示移動,因為所有人都在移動。我們還可以檢視圍繞移動的人繪製的矩形。
Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.
LinkedIn