用Opencv打造一台自动视觉目标跟踪系统

平移/倾斜伺服装置,帮助摄像机使用视觉自动跟踪颜色对象。

用Opencv打造一台自动视觉目标跟踪系统_第1张图片

  1. 简介

现在我们将使用我们的设备帮助相机自动跟踪颜色对象,如下所示:

OpenCV可免费用于学术和商业用途。它具有C ++,C,Python和Java接口,并支持Windows,Linux,Mac OS,iOS和Android。在我的一系列OpenCV教程中,我们将专注于Raspberry Pi(因此,Raspbian as OS)和Python。OpenCV专为提高计算效率而设计,专注于实时应用。因此,它非常适合物理计算项目!

2.安装OpenCV 3软件包

我正在使用Raspberry Pi V3更新到最新版本的Raspbian(Stretch),因此安装OpenCV的最佳方法是遵循Adrian Rosebrock开发的优秀教程:Raspbian Stretch:在Raspberry Pi上安装OpenCV 3 + Python 。

我尝试了几个不同的指南在我的Pi上安装OpenCV。阿德里安的教程是最好的。我建议你按照他的指导方针一步一步地做同样的事情。

完成Adrian的教程后,您应该准备好在您的Pi上运行我们的实验的OpenCV虚拟环境。

让我们转到我们的虚拟环境并确认OpenCV 3已正确安装。

Adrian建议每次打开新终端时运行命令“source”以确保系统变量已正确设置。

source ~/.profile

接下来,让我们进入我们的虚拟环境:

workon cv

如果您在提示符前面看到文本(cv),那么您就在cv virtualenvironment中:

(cv) pi@raspberry:~$

Adrian提请注意,cv Python虚拟环境完全独立,并与Raspbian Stretch下载中包含的默认Python版本隔离。因此,全局site-packages目录中的任何Python包都不可用于cv虚拟环境。同样,安装在cv的site-packages中的任何Python包都不可用于全局安装的Python。

现在,输入你的Python解释器:

python

并确认您运行的是3.5(或更高版本)版本

在解释器内部(将出现“>>>”),导入OpenCV库:

import cv2

如果没有出现错误消息,则在您的PYTHON VIRTUAL ENVIRONMENT上正确安装OpenCV。

您还可以检查安装的OpenCV版本:

cv2.__version__

应该出现3.3.0(或者可以在将来发布的高级版本)。上述终端PrintScreen显示前面的步骤。

3. Testing Your Camera

用Opencv打造一台自动视觉目标跟踪系统_第2张图片

一旦你在RPi中安装了OpenCV,让我们测试你的相机是否正常工作。

我假设您的Raspberry Pi上已经安装了PiCam。

在IDE上输入以下Python代码:

import numpy as np

import cv2

cap = cv2.VideoCapture(0)while(True):

ret, frame = cap.read()

frame = cv2.flip(frame, -1) # Flip camera vertically

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

cv2.imshow('frame', frame)

cv2.imshow('gray', gray)

if cv2.waitKey(1) & 0xFF == ord('q'):

breakcap.release()

cv2.destroyAllWindows()

上面的代码将捕获将由您的PiCam生成的视频流,以BGR颜色和灰色模式显示它们。

请注意,由于组装方式,我将相机垂直旋转。如果不是您的情况,请评论或删除“翻转”命令行。

您也可以从我的GitHub:https://github.com/Mjrovai/OpenCV-Object-Face-Tracking/blob/master/simpleCamTest.py下载代码

要执行,请输入命令:

python simpleCamTest.py

要完成程序,您必须按键盘上的[q] [Ctrl] + [C]键

图为结果。

用Opencv打造一台自动视觉目标跟踪系统_第3张图片

4.使用OpenCV在Python中进行颜色检测

我们将尝试完成的一件事是检测和跟踪某个颜色对象。为此,我们必须更多地了解OpenCV如何解释颜色。

Henri Dang用OpenCV编写了一篇关于Python中的颜色检测的精彩教程。

通常,我们的相机将使用RGB颜色模式,可以通过将其视为可以由红色,绿色和蓝色的三种彩色灯制成的所有可能颜色来理解。我们将在这里使用BGR(蓝色,绿色,红色)。

如上所述,对于BGR,像素由3个参数表示,蓝色,绿色和红色。每个参数的值通常为0-255(或以十六进制表示的O到FF)。例如,计算机屏幕上的纯蓝色像素的B值为255,G值为0,R值为0。

用Opencv打造一台自动视觉目标跟踪系统_第4张图片

OpenCV与HSV(色调,饱和度,值)颜色模型一起使用,它是RGB颜色模型的替代表示,由计算机图形学研究人员在20世纪70年代设计,以更加贴近人类视觉感知颜色制作属性的方式:

用Opencv打造一台自动视觉目标跟踪系统_第5张图片

因此,如果要使用OpenCV跟踪某种颜色,则必须使用HSV模型对其进行定义。

假设我必须跟踪黄色物体,如上图所示的塑料盒。易用部分是找到它的BGR元素。您可以使用任何设计程序来查找它(我使用PowerPoint)。

用Opencv打造一台自动视觉目标跟踪系统_第6张图片

在我的情况下,我发现:

蓝色:71

绿色:234

红色:213

接下来,我们必须将BGR(71,234,213)模型转换为HSV模型,该模型将使用上限和下限范围进行定义。为此,让我们运行以下代码:

import sys

import numpy as np

import cv2blue = sys.argv[1]

green = sys.argv[2]

red = sys.argv[3] color = np.uint8([[[blue, green, red]]])

hsv_color = cv2.cvtColor(color, cv2.COLOR_BGR2HSV)

hue = hsv_color[0][0][0]print("Lower bound is :"),

print("[" + str(hue-10) + ", 100, 100]\n")

print("Upper bound is :"),

print("[" + str(hue + 10) + ", 255, 255]")

您也可以从我的GitHub下载代码:https://github.com/Mjrovai/OpenCV-Object-Face-Tracking/blob/master/bgr_hsv_converter.py

要执行,请输入以下命令,其中包含之前找到的BGR值作为参数:

python bgr_hsv_converter.py 71 234 213

程序将打印对象颜色的上下边界。

在这种情况下:

lower bound: [24, 100, 100]

upper bound: [44, 255, 255]

终端打印屏幕显示结果。

用Opencv打造一台自动视觉目标跟踪系统_第7张图片

最后,但并非最不重要的,让我们看看OpenCV在确定其颜色后如何“掩盖”我们的对象:

import cv2

import numpy as np# Read the picure - The 1 means we want the image in BGR

img = cv2.imread('yellow_object.JPG', 1) # resize imag to 20% in each axis

img = cv2.resize(img, (0,0), fx=0.2, fy=0.2)# convert BGR image to a HSV image

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # NumPy to create arrays to hold lower and upper range

# The “dtype = np.uint8” means that data type is an 8 bit integer

lower_range = np.array([24, 100, 100], dtype=np.uint8)

upper_range = np.array([44, 255, 255], dtype=np.uint8)# create a mask for image

mask = cv2.inRange(hsv, lower_range, upper_range)# display both the mask and the image side-by-side

cv2.imshow('mask',mask)

cv2.imshow('image', img)# wait to user to press [ ESC ]

while(1):

k = cv2.waitKey(0)

if(k == 27):

breakcv2.destroyAllWindows()

您也可以从我的GitHub:https://github.com/Mjrovai/OpenCV-Object-Face-Tracking/blob/master/colorDetection.py下载代码

要执行,请在目录中输入以下命令,其中包含目标对象的照片(在我的情况下:yellow_object.JPG):

python colorDetection.py

用Opencv打造一台自动视觉目标跟踪系统_第8张图片

上面的图片将显示原始图像(“图像”)以及在应用蒙版之后对象将如何显示(“蒙版”)。

5.物体移动跟踪

现在我们知道如何使用蒙版“选择”我们的对象,让我们使用相机实时跟踪它的移动。为此,我将我的代码基于Adrian Rosebrock的Ball Tracking with OpenCV教程。

我强烈建议您详细阅读Adrian的教程。

首先,确认您是否安装了imutils库。这是Adrian的OpenCV便利功能集合,可以更轻松地完成一些基本任务(如调整大小或翻转屏幕)。如果没有,请输入以下命令在虚拟Python环境中安装库:

pip install imutils

接下来,从我的GitHub下载代码https://github.com/Mjrovai/OpenCV-Object-Face-Tracking/blob/master/ball_tracking.py,并使用以下命令执行它:

python ball_traking.py

因此,您将看到类似于以下gif的内容:

基本上,除了“视频垂直翻转”之外,它与Adrian的代码相同,我用这条线:

frame = imutils.rotate(frame, angle=180)

另请注意,使用的掩码边界是我们在上一步中获得的掩码边界。

6.测试GPIO

现在我们已经使用了OpenCV的基础知识,让我们为我们的RPi安装一个LED并开始与我们的GPIO进行交互。

用Opencv打造一台自动视觉目标跟踪系统_第9张图片

按照上面的电气图:LED的阴极将通过一个220欧姆的电阻连接到GPIO 21,其阳极连接到GND。

让我们在虚拟Python环境中测试我们的LED。

请记住,在Python虚拟环境中可能没有安装RPi.GPIO!要解决此问题,一旦您在那里(记得确认(cv)在您的终端中),您需要使用pip将其安装到您的虚拟环境中:

pip install RPi.GPIO

让我们使用python脚本执行一个简单的测试:

import sys

import time

import RPi.GPIO as GPIO# initialize GPIO and variables

redLed = int(sys.argv[1])

freq = int(sys.argv[2])

GPIO.setmode(GPIO.BCM)

GPIO.setup(redLed, GPIO.OUT)

GPIO.setwarnings(False)print("\n [INFO] Blinking LED (5 times) connected at GPIO {0} \

at every {1} second(s)".format(redLed, freq))

for i in range(5):

GPIO.output(redLed, GPIO.LOW)

time.sleep(freq)

GPIO.output(redLed, GPIO.HIGH)

time.sleep(freq)# do a bit of cleanup

print("\n [INFO] Exiting Program and cleanup stuff \n")

GPIO.cleanup()

此代码将接收GPIO编号作为参数,以及LED应闪烁的频率(以秒为单位)。LED将闪烁5次,程序将终止。请注意,在终止之前,我们将释放GPIO。

因此,要执行脚本,必须输入参数,LED GPIO和频率。

例如:

python LED_simple_test.py 21 1

上述命令将每隔“1”秒闪烁5次连接到“GPIO 21”的红色LED。

可以从我的GitHub下载文件https://github.com/Mjrovai/OpenCV-Object-Face-Tracking/blob/master/GPIO_LED_test.py

用Opencv打造一台自动视觉目标跟踪系统_第10张图片

上面的终端打印屏幕显示结果(当然您应该确认LED闪烁。

现在,让我们使用OpenCV和一些基本的GPIO。

7.识别颜色和GPIO交互

让我们开始将我们的OpenCV代码与GPIO交互集成。我们将从最后的OpenCV代码开始,我们将在其上集成GPIO-RPI库,因此我们将在相机找到彩色物体的任何时候打开红色LED。此步骤中使用的代码基于Adrian的优秀教程OpenCV,RPi.GPIO和Raspberry Pi上的GPIO Zero:

首先要做的是“创建”我们的LED,将其连接到特定的GPIO:

import RPi.GPIO as GPIO

redLed = 21

GPIO.setmode(GPIO.BCM)

GPIO.setwarnings(False)

GPIO.setup(redLed, GPIO.OUT)

其次,我们必须初始化我们的LED(关闭):

GPIO.output(redLed, GPIO.LOW)

ledOn = False

现在,在循环内部,当找到对象时创建“圆圈”,我们将打开LED:

GPIO.output(redLed, GPIO.HIGH)

ledOn = True

让我们从我的GitHub下载完整的代码:

https://github.com/Mjrovai/OpenCV-Object-Face-Tracking/blob/master/object_detection_LED.py

使用以下命令运行代码:

python object_detection_LED.py

结果如下。请注意,每次检测到物体时,LED(左下角)都会亮起:

尝试使用不同的对象(颜色和格式)。您将看到,一旦掩模边界内的颜色匹配,LED就会亮起。

以下视频显示了一些经验。请注意,只会检测到位于颜色范围内的黄色物体,从而打开LED。忽略具有不同颜色的对象。

我们只在这里使用LED,如上一步所述。当我拍摄视频时,我的Pan Tilt已经组装完毕,所以请忽略它。我们将在下一步处理PAN / TILT机制。

8.泛倾斜机制

用Opencv打造一台自动视觉目标跟踪系统_第11张图片

现在我们已经使用了OpenCV和GPIO的基础知识,让我们安装我们的Pan / tilt机制。

用Opencv打造一台自动视觉目标跟踪系统_第12张图片

伺服电机应连接到外部5V电源,其数据引脚(在我的情况下,它们的黄色接线)连接到Raspberry Pi GPIO,如下所示:

GPIO 17 ==>倾斜伺服

GPIO 27 ==> Pan Servo

不要忘记将GND连接在一起==> Raspberry Pi - Servos - 外部电源)

您可以选择在Raspberry Pi GPIO和服务器数据输入引脚之间串联一个1K欧姆的电阻。这可以在发生伺服问题时保护您的RPi。

让我们也利用这个机会,在我们的虚拟Python环境中测试我们的伺服器。

让我们使用Python脚本用我们的驱动程序执行一些测试:

from time import sleep

import RPi.GPIO as GPIOGPIO.setmode(GPIO.BCM)

GPIO.setwarnings(False)def setServoAngle(servo, angle):

pwm = GPIO.PWM(servo, 50)

pwm.start(8)

dutyCycle = angle / 18. + 3.

pwm.ChangeDutyCycle(dutyCycle)

sleep(0.3)

pwm.stop()if __name__ == '__main__':

import sys

servo = int(sys.argv[1])

GPIO.setup(servo, GPIO.OUT)

setServoAngle(servo, int(sys.argv[2]))

GPIO.cleanup()

上面代码的核心是函数setServoAngle(伺服,角度)。该功能接收伺服GPIO编号作为参数,以及伺服必须定位的角度值。一旦此函数的输入为“角度”,我们必须将其转换为等效的占空比。

要执行脚本,必须输入参数,伺服GPIO和角度。

例如:

python angleServoCtrl.py 17 45

上述命令将连接在GPIO 17上的伺服(“倾斜”)与“仰角”成45度。

文件

https://github.com/Mjrovai/OpenCV-Object-Face-Tracking/blob/master/angleServoCtrl.py

可以从我的GitHub下载

9.查找对象实时位置

这里的想法是使用平移/倾斜机制将对象定位在屏幕中间。坏消息是,为了开始我们必须实时知道对象的位置。但好消息是,一旦我们已经拥有了对象中心的坐标,这很容易。

首先,让我们使用之前使用的“object_detect_LED”代码并修改它以打印已创建对象的x,y坐标。

从我的GitHub下载代码:objectDetectCoord.py

代码的“核心”是我们找到对象并在其上绘制一个圆圈的部分,其中心有一个红点。

# only proceed if the radius meets a minimum size

if radius > 10:

# draw the circle and centroid on the frame,

# then update the list of tracked points

cv2.circle(frame, (int(x), int(y)), int(radius),

(0, 255, 255), 2)

cv2.circle(frame, center, 5, (0, 0, 255), -1)

# print center of circle coordinates

mapObjectPosition(int(x), int(y))

# if the led is not already on, turn the LED on

if not ledOn:

GPIO.output(redLed, GPIO.HIGH)

ledOn = True

让我们将中心坐标“导出”到mapObjectPosition(int(x),int(y))函数以打印其坐标。功能下方:

def mapObjectPosition (x, y):

print ("[INFO] Object Center coordinates at \

X0 = {0} and Y0 = {1}".format(x, y))

运行程序,我们将在终端上看到(x,y)位置坐标,如上所示。移动对象并观察坐标。我们将意识到x从0到500(从左到右),y从o到350(从上到下)。见上图。

用Opencv打造一台自动视觉目标跟踪系统_第13张图片

现在我们必须使用这些坐标作为我们的Pan / Tilt跟踪系统的起点

用Opencv打造一台自动视觉目标跟踪系统_第14张图片

10.物体位置跟踪系统

我们希望我们的对象始终以屏幕为中心。所以,让我们定义一个例子,如果符合以下情况我们会认为我们的对象是“居中的”:

220

160

在这些边界之外,我们必须移动我们的Pan / Tilt机制以补偿偏差。基于此,我们可以构建函数mapServoPosition(x,y),如下所示。请注意,此函数中用作参数的“x”和“y”与我们之前用于打印中心位置的参数相同:

# position servos to present object at center of the frame

def mapServoPosition (x, y):

global panAngle

global tiltAngle

if (x < 220):

panAngle += 10

if panAngle > 140:

panAngle = 140

positionServo (panServo, panAngle)

if (x > 280):

panAngle -= 10

if panAngle < 40:

panAngle = 40

positionServo (panServo, panAngle)

if (y < 160):

tiltAngle += 10

if tiltAngle > 140:

tiltAngle = 140

positionServo (tiltServo, tiltAngle)

if (y > 210):

tiltAngle -= 10

if tiltAngle < 40:

tiltAngle = 40

positionServo (tiltServo, tiltAngle)

基于(x,y)坐标,使用函数positionServo(伺服,角度)生成伺服位置命令。例如,假设y位置是“50”,这意味着我们的对象几乎位于屏幕的顶部,可以转换为“相机视线”为“低”(假设倾角为120度) 所以我们必须“减少”倾斜角度(让我们说100度),所以相机视线将“向上”并且物体将在屏幕上“向下”(y将增加,比方说,190)。

用Opencv打造一台自动视觉目标跟踪系统_第15张图片

上图显示了几何方面的示例。

想想泛相机将如何操作。请注意,屏幕没有镜像,这意味着如果您将对象移动到“左侧”,一旦您与相机相反,它将在屏幕上移动“右侧”。

函数positionServo(伺服,角度)可写为:

def positionServo (servo, angle):

os.system("python angleServoCtrl.py " + str(servo) + " " +

str(angle))

print("[INFO] Positioning servo at GPIO {0} to {1} \

degrees\n".format(servo, angle))

我们将调用之前显示的脚本进行伺服定位。

请注意,angleServoCtrl.py必须与objectDetectTrac.py位于同一目录中

完整的代码可以从我的GitHub:objectDetectTrack.py下载

下面的gif显示了我们项目工作的一个例子:

11.结论

一如既往,我希望这个项目可以帮助其他人进入激动人心的电子世界!

相关整套源码关注微信公众号:“图像算法”或者微信搜索账号imalg_cn关注公众号

你可能感兴趣的:(图像算法)