一个问题是需要识别和区分视频中的移动物体和其他内容。一种方法是让相机“学习”没有物体的背景,然后不断将其输入与该背景进行比较。获取背景的一种方法是使用运行平均值。
任何大于小阈值的差异都意味着有移动物体。如果您不断显示这种差异,基本上就有了运动跟踪器。对象的大小只是所有非零(经过阈值处理)像素或它们的边界矩形的总和。您可以跟踪此大小并使用它来猜测对象是否靠近或远离。形态学操作可以帮助将轮廓组合成一个连贯的对象。
由于它将跟踪任何运动,如果有两个对象,它们将被一起计算。在这里,您可以使用轮廓来查找和跟踪单个对象,例如使用轮廓边界或质心。您还可以通过颜色可能将它们分开。
以下是使用此策略的一些结果(灰色斑点是我的手):
它实际上做得相当不错,猜测我的手移动的方向。
代码:
import cv2
import numpy as np
AVERAGE_ALPHA = 0.2
MOVEMENT_THRESHOLD = 30
REDUCED_SIZE = (400, 600)
MORPH_KERNEL = np.ones((10, 10), np.uint8)
def reduce_image(input_image):
"""Make the image easier to deal with."""
reduced = cv2.resize(input_image, REDUCED_SIZE)
reduced = cv2.cvtColor(reduced, cv2.COLOR_BGR2GRAY)
return reduced
vid = cv2.VideoCapture(0)
average = None
old_sizes = np.zeros(20)
size_update_index = 0
while (True):
got_frame, frame = vid.read()
if got_frame:
reduced = reduce_image(frame)
if average is None: average = np.float32(reduced)
cv2.accumulateWeighted(reduced, average, AVERAGE_ALPHA)
background = cv2.convertScaleAbs(average)
movement = cv2.absdiff(reduced, background)
_, threshold = cv2.threshold(movement, MOVEMENT_THRESHOLD, 255, cv2.THRESH_BINARY)
dilated = cv2.dilate(threshold, MORPH_KERNEL, iterations=10)
closed = cv2.morphologyEx(dilated, cv2.MORPH_CLOSE, MORPH_KERNEL)
contours, _ = cv2.findContours(closed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(closed, contours, -1, (150, 150, 150), -1)
areas = [cv2.contourArea(c) for c in contours]
if (areas != list()):
max_index = np.argmax(areas)
max_cont = contours[max_index]
x, y, w, h = cv2.boundingRect(max_cont)
cv2.rectangle(closed, (x, y), (x+w, y+h), (255, 255, 255), 5)
size = w*h
if size > old_sizes.mean():
print "Towards"
else:
print "Away"
old_sizes[size_update_index] = size
size_update_index += 1
if (size_update_index) >= len(old_sizes): size_update_index = 0
cv2.imshow('RaptorVision', closed)
显然,在识别、选择和跟踪对象方面还需要更多的工作(如果背景中有其他移动物体,目前的效果非常糟糕)。还有许多参数可以变化和调整(设置的参数适用于我的系统)。不过这些都由你来决定。
一些链接:
背景提取
运动跟踪
如果您想在背景去除方面更加高科技,请看这里:
Wallflower