这里的一个问题是识别视频源中的移动物体并将其与其他物体区分开来。一种方法可能是让相机在没有物体的情况下“学习”背景的样子。然后,您可以不断地将其输入与此背景进行比较。获取背景的一种方法是使用运行平均值。
任何大于小阈值的差异都意味着存在移动对象。如果你不断地显示这种差异,你基本上就拥有了一个运动跟踪器。对象的大小只是所有非零(阈值)像素或其边界矩形的总和。您可以跟踪此大小并使用它来猜测对象是否移动得更近或更远。形态学操作可以帮助将轮廓组合成一个有凝聚力的对象。
由于它将跟踪任何运动,如果有两个对象,它们将被一起计算。在这里您可以使用轮廓来查找和跟踪单个对象,例如使用轮廓边界或质心。您也可以按颜色将它们分开。
以下是使用此策略的一些结果(灰色斑点是我的手):
它实际上在猜测我的手向哪个方向移动方面做得相当好。
代码:
import cv2
import numpy as np
AVERAGE_ALPHA = 0.2 # 0-1 where 0 never adapts, and 1 instantly adapts
MOVEMENT_THRESHOLD = 30 # Lower values pick up more movement
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
# Initialise
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:
# Reduce image
reduced = reduce_image(frame)
if average is None: average = np.float32(reduced)
# Get background
cv2.accumulateWeighted(reduced, average, AVERAGE_ALPHA)
background = cv2.convertScaleAbs(average)
# Get thresholded difference image
movement = cv2.absdiff(reduced, background)
_, threshold = cv2.threshold(movement, MOVEMENT_THRESHOLD, 255, cv2.THRESH_BINARY)
# Apply morphology to help find object
dilated = cv2.dilate(threshold, MORPH_KERNEL, iterations=10)
closed = cv2.morphologyEx(dilated, cv2.MORPH_CLOSE, MORPH_KERNEL)
# Get contours
contours, _ = cv2.findContours(closed, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(closed, contours, -1, (150, 150, 150), -1)
# Find biggest bounding rectangle
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)
# Guess movement direction
size = w*h
if size > old_sizes.mean():
print "Towards"
else:
print "Away"
# Update object size
old_sizes[size_update_index] = size
size_update_index += 1
if (size_update_index) >= len(old_sizes): size_update_index = 0
# Display image
cv2.imshow('RaptorVision', closed)
显然,这需要在识别、选择和跟踪对象等方面做更多的工作(目前,如果背景中有其他东西在移动,这会很糟糕)。还有许多参数可以改变和调整(设置的参数对我的系统很有效)。不过我会留给你。
一些链接:
background extraction
motion tracking
如果您想通过背景去除获得更多高科技,请看这里:
wallflower