OpenCV 跟蹤

Salman Mehmood 2022年6月2日
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()

我們可以看到狀態顯示移動,因為所有人都在移動。我們還可以檢視圍繞移動的人繪製的矩形。

OpenCV 跟蹤

Salman Mehmood avatar Salman Mehmood avatar

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

相關文章 - Python OpenCV