「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


平移/傾斜伺服裝置,幫助攝像機使用視覺自動跟蹤顏色對象。


「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


  1. 簡介


現在我們將使用我們的設備幫助相機自動跟蹤顏色對象,如下所示:

「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


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打造一臺自動視覺目標跟蹤系統


一旦你在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打造一臺自動視覺目標跟蹤系統



4.使用OpenCV在Python中進行顏色檢測

我們將嘗試完成的一件事是檢測和跟蹤某個顏色對象。為此,我們必須更多地瞭解OpenCV如何解釋顏色。

Henri Dang用OpenCV編寫了一篇關於Python中的顏色檢測的精彩教程。

通常,我們的相機將使用RGB顏色模式,可以通過將其視為可以由紅色,綠色和藍色的三種彩色燈製成的所有可能顏色來理解。我們將在這裡使用BGR(藍色,綠色,紅色)。

如上所述,對於BGR,像素由3個參數表示,藍色,綠色和紅色。每個參數的值通常為0-255(或以十六進制表示的O到FF)。例如,計算機屏幕上的純藍色像素的B值為255,G值為0,R值為0。


「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


OpenCV與HSV(色調,飽和度,值)顏色模型一起使用,它是RGB顏色模型的替代表示,由計算機圖形學研究人員在20世紀70年代設計,以更加貼近人類視覺感知顏色製作屬性的方式:


「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


因此,如果要使用OpenCV跟蹤某種顏色,則必須使用HSV模型對其進行定義。

假設我必須跟蹤黃色物體,如上圖所示的塑料盒。易用部分是找到它的BGR元素。您可以使用任何設計程序來查找它(我使用PowerPoint)。


「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


在我的情況下,我發現:

藍色: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打造一臺自動視覺目標跟蹤系統


最後,但並非最不重要的,讓我們看看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打造一臺自動視覺目標跟蹤系統


上面的圖片將顯示原始圖像(“圖像”)以及在應用蒙版之後對象將如何顯示(“蒙版”)。

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的內容:

「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


基本上,除了“視頻垂直翻轉”之外,它與Adrian的代碼相同,我用這條線:


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

另請注意,使用的掩碼邊界是我們在上一步中獲得的掩碼邊界。

6.測試GPIO

現在我們已經使用了OpenCV的基礎知識,讓我們為我們的RPi安裝一個LED並開始與我們的GPIO進行交互。


「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


按照上面的電氣圖: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打造一臺自動視覺目標跟蹤系統


上面的終端打印屏幕顯示結果(當然您應該確認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打造一臺自動視覺目標跟蹤系統


現在我們已經使用了OpenCV和GPIO的基礎知識,讓我們安裝我們的Pan / tilt機制。


「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


伺服電機應連接到外部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度。


「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


文件

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打造一臺自動視覺目標跟蹤系統


現在我們必須使用這些座標作為我們的Pan / Tilt跟蹤系統的起點


「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


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打造一臺自動視覺目標跟蹤系統


上圖顯示了幾何方面的示例。

想想泛相機將如何操作。請注意,屏幕沒有鏡像,這意味著如果您將對象移動到“左側”,一旦您與相機相反,它將在屏幕上移動“右側”。

函數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顯示了我們項目工作的一個例子:

「乾貨」用Opencv打造一臺自動視覺目標跟蹤系統


11.結論

一如既往,我希望這個項目可以幫助其他人進入激動人心的電子世界!


分享到:


相關文章: