如何在Python中使用OpenCV发现传递的对象

135 阅读6分钟

在Python中使用OpenCV发现传递的对象

2022年3月9日

追踪和发现移动的物体在我们今天的生活中已经变得至关重要。谈到安全问题,摄像机在检测和跟踪移动物体方面对我们有很大的帮助。

在本教程中,我们将学习如何使用计算机视觉来发现一个经过的物体并实时返回被发现的物体。

前提条件

  • 你应该对Python有一个基本的了解。
  • 对计算机视觉的简单概述和先前的知识会有所帮助。
  • 你的笔记本电脑上应该有一个网络摄像头。

有了这些,我们就能解决我们的项目了。让我们开始行动吧。

安装

安装OpenCV

首先,我们必须安装OpenCV ,以处理和操作网络摄像头的图像或视频。它也有助于计算机视觉相关的解决方案来处理图像和实时视频。

在你的工作环境中,打开终端并粘贴下面的命令,让OpenCV同时下载和安装。

pip install OpenCV-Python

这个库允许安装诸如cv2 等模块。由于它是一个跨平台的库,它包含了各种读取和处理图像的功能。

安装NumPy

NumPy是用来将数据表达为多维数组的。在我们的例子中,我们把图像的像素值表示为数组。

你可以在这个文档中阅读更多关于NumPy的内容。

pip install numpy

安装imutils

imutils 库来帮助旋转、调整大小,并与OpenCV一起对图像进行镂空处理。

你可以在这里了解更多关于imutils

pip install imutils

安装成功后,我们现在将跳到代码区。

实施

导入外部库

正如我们前面所讨论的,我们将把上述所有的库导入我们的Python代码中,如图所示。

import cv2
import numpy as np
import datetime
import imutils

datetime 库返回当前的日期和时间。在我们的案例中,它有助于跟踪实时数据。

初始化变量

我们将不得不初始化帮助我们捕捉和记录视频数据的对象,如图所示。

rec = cv2.VideoCapture(0)
sto, mapping1 = rec.read()
sto, mapping2 = rec.read()

从上面的代码来看。

  • 第一个映射是用来存储初始帧的。
  • 第二个映射是用来存储后续的帧。
  • 在函数VideoCapture ,我们使用0 ,因为它表示对网络摄像头的访问。

检测并将帧转换为灰度

一个视频可以被定义为一系列具有时间差异的连续图像。因此,我们必须首先识别和确认帧,然后对它们进行处理。

图像帧被转换为灰度,以提高检测关键特征的准确性,并消除可能的遗漏。

while rec.isOpened():
    sub = cv2.absdiff(mapping1, mapping2)
    convclr = cv2.cvtColor(sub, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(convclr, (3, 3), 1)
    _, thresh = cv2.threshold(blur, 20, 255, cv2.THRESH_BINARY)
    enlarged = cv2.dilate(thresh, None, iterations=1)
    contours, _ = cv2.findContours(enlarged, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

在上面的代码中。

  • 我们将把sub 赋给第一个和第二个映射之间的差异。
  • 在指定cv2.COLOR_BGR2GRAY ,调用cvtColor 方法,将sub 转换为灰度。
  • 然后我们调用GaussianBlur 函数对sub 进行模糊处理。
  • 在上述操作之后,我们调用dilate 函数来放大sub ,从而通过消除中间的所有空隙来提高其准确性。
  • 迭代之后,我们得到了所得到的轮廓线。

模糊框架

GaussianBlur 来自 ,负责对图像进行模糊处理。它对像素进行平滑处理,并对像素高度和宽度的强度进行平均,从而过滤掉高强度的噪声。cv2

让我们来实现它,如下图所示。

if mapping1 is None:
	break

mapping1 = imutils.resize(mapping1, width=700)
convclr1 = cv2.cvtColor(mapping1, cv2.COLOR_BGR2GRAY)
convclr2 = cv2.GaussianBlur(convclr1,(21, 21), 0)

在上面的代码中。

  • 进行模糊处理是为了去除图像中的高频成分。
  • 我们发现第一和第二帧已经被转换为灰度。
  • 使用imutils ,我们将帧的大小调整为所需的大小,即700 像素宽。

找出delta帧之间的差异

由于我们将第一帧存储在mapping1 ,我们将能够使用mapping2 ,计算出后面几帧的差异,如图所示。

if mapping1 is None:
	mapping1 = convclr2
	continue

frameDelta = cv2.absdiff(convclr2, convclr1)
thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1]

在上述代码中。

  • mapping1mapping2 中的像素矩阵的绝对差值,获取像素强度的绝对值frameDelta
  • THRESH_BINARY 函数有助于将经过的对象的颜色变成白色,同时将背景的颜色设为黑色。

查找轮廓线

为了放大图像,我们从cv2 中调用一个dilate 函数,如图所示。

thresh = cv2.dilate(thresh, None, iterations=2)
count = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
count = imutils.grab_contours(count)

在上面的代码中。

  • 我们使用findContours 函数来获得轮廓线。
  • 两个参数被传递给该函数来检索和近似,从而通过删除重复的点和压缩它们来节省内存。
  • dilate 函数接受两个输入,其中一个是我们的输入图像,另一个被称为结构化元素或内核,它决定了操作的性质。
  • 扩张图像有助于增加对象的大小。

格式化可显示的文本和时间布局

为了能够在镜头上写文字,你必须调用一个cv2 函数putText

它定义了文字的字体、颜色、大小、深度和家族。为了显示当前时间或实时数据,我们使用datetime 模块,如图所示。

for count in contours:
    (x, y, w, h)=cv2.boundingRect(count)
    if cv2.contourArea(count)<700:
        continue
		cv2.rectangle(mapping1, (x, y), (x + w, y + h), (0, 0, 255), 2)
    cv2.putText(mapping1, "REPORT: {}".format('PASSING OBJECT DETECTED'), (5, 30), cv2.FONT_HERSHEY_DUPLEX, 1, (255, 0, 0), 4)
    cv2.putText(mapping1, datetime.datetime.now().strftime("%A %d %B %Y %I:%M:%S%p"), (10, mapping1.shape[0]-10),cv2.FONT_HERSHEY_DUPLEX, 0.9, (0, 255, 0), 3)

显示图像和镜头

cv2 函数imshow 允许我们显示并返回被调用的图像或视频资料,这些资料被存储在早期实例化的数值中,如图所示。

cv2.imshow("FOOTAGE", mapping1)
cv2.imshow("MARGIN", thresh)
cv2.imshow("DIFFERENCE OF DELTA FRAMES", frameDelta)

mapping1=mapping2
sto, mapping2=rec.read()

包裹它

我们将需要指定一个键来记录按键,并终止我们的程序。在终止程序时,我们清理网络摄像头并释放任何正在使用的资源。

最后,我们销毁所有由OpenCV 构建的窗口。

if cv2.waitKey(50)==50:
	break

cv2.destroyAllWindows()

结果

下面是我们程序的预期输出和结果。

THRESH 的输出。margin

FRAMEDELTA 的输出。framedelta

FOOTAGE 的输出。footage

结论

在本教程中,我们已经学习了几个概念,这些概念有助于使用OpenCV和其他重要的相关工具来发现经过的物体。

我们学习了所需库的安装和cv2 模块的使用。我们还学习了如何计算帧的德尔塔和格式化要显示的文本布局。