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