import numpy as np
import argparse
import time
import cv2
# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video",
help = "path to the (optional) video file")
args = vars(ap.parse_args())
# define the upper and lower boundaries for a color
# to be considered "blue"
blueLower = np.array([100,67,0],dtype="uint8")
blueUpper = np.array([255,128,50],dtype="uint8")
# load the video
if not args.get("video"):
camera = cv2.VideoCapture(0)
else:
camera = cv2.VideoCapture(args["video"])
我們将使用NumPy進行數值處理,使用argparse解析指令行參數,使用cv2進行OpenCV綁定。time包是可選的。
我們隻需要一個指令行參數,--video,也就是我們視訊的路徑。
我們将在視訊中追蹤的對象是藍色物體。由于除了該物體外,藍色在視訊中的任何其他位置都不常見,是以我們希望跟蹤藍色陰影。為了完成這種顔色跟蹤,我們定義了藍色陰影的下限和上限。請記住,OpenCV表示RGB顔色空間中的像素,但順序相反。
在這種情況下,如果大于R=0,G=67,B=100且小于R=50,G=128,B=255,則将顔色定義為“藍色”。
最後,我們打開視訊檔案并使用cv2.VideoCapture函數擷取對它的引用。我們将此引用指派給變量camera。
# keep looping
while True:
# grab the current frame
(grabbed,frame) = camera.read()
# check to see if we have reached the end of the video
if args.get("video") and not grabbed:
break
# determine which pixels fall within the blue boundaries
# and then blur the binary image
blue = cv2.inRange(frame,blueLower,blueUpper)
blue = cv2.GaussianBlur(blue,(3,3),0)
現在我們有了對視訊的引用,便可以開始處理幀。
我們開始循環周遊幀,一次一個。調用read()方法的調用抓取視訊中的下一幀,傳回具有兩個值的元組。第一個是grabbed,是一個布爾值,表示是否從視訊檔案中成功讀取了幀。第二個frame,是幀本身。
然後,我們檢查frame是否成功讀取。如果未讀取架構,則表示已到達視訊的末尾,我們break掉while循環。
為了在frame中找到藍色陰影,我們必須使用cv2.inRange函數。該函數有三個參數。第一個是我們想要檢查的frame。第二個是RGB像素的lower threshold,第三個是上限門檻值(upper threshold)。調用此函數的結果是門檻值圖像,像素落在上下範圍内設定為白色,像素不屬于此範圍 設為黑色。
最後,我們對門檻值圖像進行高斯模糊處理,以使查找輪廓更準确。
# find contours in the image
(_,cnts,_) = cv2.findContours(blue.copy(),cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# check to see if any contours were found
if len(cnts) > 0:
# sort the contours and find the largest one --
# we will assume this contour coorespondes to the
# area of my phone
cnt = sorted(cnts,key=cv2.contourArea,reverse=True)[0]
# compute the (rotated) bounding box around then
# contour and then draw it
rect = np.int32(cv2.boxPoints(cv2.minAreaRect(cnt)))
cv2.drawContours(frame,[rect],-1,(0,255,0),2)
# show the frame and the binary image
cv2.imshow("Traccking",frame)
cv2.imshow("Binary",blue)
# if your machine is fast, it may display the frames in
# what appears to be 'fast forward' since more than 32
# frames per second are being displayed -- a simple hack
# is just to sleep for a tiny bit in between frames;
# however, if your computer is slow, you probably want to
# comment out this line
time.sleep(0.025)
# if the 'q' key is pressed, stop the loop
if cv2.waitKey(1) & 0xFF == ord("q"):
break
# cleanup the camera and close any open windows
camera.release()
cv2.destroyAllWindows()
現在我們有了門檻值圖像,那麼我們需要找到圖像中最大的輪廓,假設最大輪廓對應于我們想要跟蹤的藍色物體輪廓。
我們調用cv2.findContours會在門檻值圖像中找到輪廓。我們使用copy()方法克隆門檻值圖像,因為cv2.findContour函數對傳入的NumPy數組具有破壞性。
然後檢查以確定實際發現輪廓。如果輪廓清單的長度為零,則沒有找到藍色區域。如果輪廓清單的長度大于零,那麼我們需要找到最大的輪廓。這裡,輪廓按相反的順序排序(最大的第一個),使用cv2.contourArea函數來 計算輪廓的面積。具有較大區域的輪廓存儲在清單的前面。在這種情況下,抓住具有最大面積的輪廓,再次假設該輪廓對應于藍色物體的輪廓。
現在我們有了藍色的輪廓,但我們需要在它周圍繪制一個邊界框。
調用cv2.minAreaRect計算輪廓周圍的最小邊界框。然後,cv2.boxPoints将邊界框重新定義為點清單。
注意
:在OpenCV 2.4.X中,我們将使用cv2.BoxPoints函數來計算輪廓的旋轉邊界框。但是,在OpenCV 3.0+中,此函數已移至cv2.boxPoints。兩個函數執行相同的任務,隻是略有不同的命名空間。
最後,我們使用cv2.drawContours函數繪制邊界框。
具有檢測到的藍色物體的frame顯示在第一個imshow,并且門檻值圖像(落入藍色像素的下/上範圍的像素)顯示在第二個imshow。
上面,time.sleep(0.025)可選的。在許多較新型号的機器上,系統可能足夠快以處理>32幀/秒。如果是這種情況,找到可接受的睡眠時間将減慢處理速度并将其降低到更正常的速度。
執行我們的腳本
python track.py
結果:
或者指定視訊路徑
python track.py --video "video\2018-11-27 18-38-15-927.mp4"
也是可以的。
部落格位址(有完整代碼):https://0leo0.github.io/2018/case_study_03.html
關注不迷路哦!!