注意,我使用的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绝对是喜欢折腾的人必要掌握的一个库了,以后肯定还会继续研究这块东西。