注意,我使用的OpenCV 版本是 3.0, 低版本就有可能出現第一條評論裡的報錯
在檢測出運動的物體之後,我還需要知道運動的方向,使用了上一節中的辦法檢測運動我發現很難去計算運動方向,開始考慮通過計算輪廓的中點的變化來實現,但是因為每次檢測出得輪廓的數量不穩定,所以這個辦法會讓誤差不可控。
這時我發現了 goodFeaturesToTrack
函式,簡直是救了我,goodFeaturesToTrack
函式可以獲取影象中的最大特徵值的角點,以下是我的思路:
Tips: 看程式碼之前請先看看我下面寫的實現思路,另外還有程式碼裡的註釋也對於理解程式碼會有所幫助
- 對兩幀影象做一個
absdiff
得到新影象。 - 對新影象做灰度和二值化處理。
- 使用
goodFeaturesToTrack
函式得到最大特徵值的角點。 - 計算角點的平均點,寫入佇列。(通過計算平均點的解決辦法類似物理中剛體問題抽象成質點解決的思路)
- 維護一個長度為 10 的佇列,佇列滿時計算佇列中資料的增減情況,來確定運動方向。
程式碼示例(只實現了左右移動的判斷):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
#!usr/bin/env python #coding=utf-8 import cv2 import numpy as np import Queue camera = cv2.VideoCapture(0) width = int(camera.get(3)) height = int(camera.get(4)) firstFrame = None lastDec = None firstThresh = None feature_params = dict( maxCorners = 100, qualityLevel = 0.3, minDistance = 7, blockSize = 7 ) lk_params = dict( winSize = (15,15), maxLevel = 2, criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)) color = np.random.randint(0,255,(100,3)) num = 0 q_x = Queue.Queue(maxsize = 10) q_y = Queue.Queue(maxsize = 10) while True: (grabbed, frame) = camera.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (21, 21), 0) if firstFrame is None: firstFrame = gray continue # 對兩幀影象進行 absdiff 操作 frameDelta = cv2.absdiff(firstFrame, gray) # diff 之後的影象進行二值化 thresh = cv2.threshold(frameDelta, 25, 255, cv2.THRESH_BINARY)[1] # 下面的是幾種不同的二值化的方法,感覺對我來說效果都差不多 # thresh = cv2.adaptiveThreshold(frameDelta,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\ # cv2.THRESH_BINARY,11,2) # thresh = cv2.adaptiveThreshold(frameDelta,255,cv2.ADAPTIVE_THRESH_MEAN_C,\ # cv2.THRESH_BINARY,11,2) thresh = cv2.dilate(thresh, None, iterations=2) # 識別角點 p0 = cv2.goodFeaturesToTrack(thresh, mask = None, **feature_params) if p0 is not None: x_sum = 0 y_sum = 0 for i, old in enumerate(p0): x, y = old.ravel() x_sum += x y_sum += y # 計算出所有角點的平均值 x_avg = x_sum / len(p0) y_avg = y_sum / len(p0) # 寫入固定長度的佇列 if q_x.full(): # 如果佇列滿了,就計算這個佇列中元素的增減情況 qx_list = list(q_x.queue) key = 0 diffx_sum = 0 for item_x in qx_list: key +=1 if key < 10: # 下一個元素減去上一個元素 diff_x = item_x - qx_list[key] diffx_sum += diff_x # 加和小於0,表明佇列中的元素在遞增 if diffx_sum < 0: print "left" cv2.putText(frame, "some coming form left", (100,100), 0, 0.5, (0,0,255),2) else: print "right" print x_avg q_x.get() q_x.put(x_avg) cv2.putText(frame, str(x_avg), (300,100), 0, 0.5, (0,0,255),2) frame = cv2.circle(frame,(int(x_avg),int(y_avg)),5,color[i].tolist(),-1) cv2.imshow("Security Feed", frame) firstFrame = gray.copy() camera.release() cv2.destroyAllWindows() |
總的來講作為一個影象處理的小白,不斷地折騰和嘗試,終於搞出了自己想要的東西,OpenCV絕對是喜歡折騰的人必要掌握的一個庫了,以後肯定還會繼續研究這塊東西。