检测接近物体
我看了这篇博客,里面讲到用激光和网络摄像头来估算纸板离摄像头的距离。
我有个不同的想法。我不想计算摄像头和物体之间的距离。
我想检查一个物体是否在靠近摄像头。我的算法大概是这样的:
- 在摄像头的视频中检测物体。
- 如果物体在靠近摄像头,它在视频中的大小会越来越大。
- 利用这些数据进行进一步的计算。
因为我想检测随机的物体,所以我使用了findContours()
方法来找到视频中的轮廓。通过这个方法,我至少可以得到视频中物体的轮廓。源代码如下:
import numpy as np
import cv2
vid=cv2.VideoCapture(0)
ans, instant=vid.read()
average=np.float32(instant)
cv2.accumulateWeighted(instant, average, 0.01)
background=cv2.convertScaleAbs(average)
while(1):
_,f=vid.read()
imgray=cv2.cvtColor(f, cv2.COLOR_BGR2GRAY)
ret, thresh=cv2.threshold(imgray,127,255,0)
diff=cv2.absdiff(f, background)
cv2.imshow("input", f)
cv2.imshow("Difference", diff)
if cv2.waitKey(5)==27:
break
cv2.destroyAllWindows()
输出结果是:
我现在卡住了。我已经把轮廓存储在一个数组里。当轮廓的大小增加时,我该怎么处理?接下来该怎么做呢?
2 个回答
Detect the object in the webcam feed. If the object is approaching the webcam it'll grow larger and larger in the video feed. Use this data for further calculations.
这个主意不错。
如果你想用轮廓检测的方法,可以这样做:
- 你有一系列的图片,比如 I1, I2, ... In。
- 对每张图片进行轮廓检测,得到 C1, C2, ..., Cn(在 OpenCV 中,轮廓是一些点的集合)。
- 在你的图片 i 和 i+1 上取一个足够大的样本:S_i ≤ C_i,i 的范围是 1 到 n。
- 检查样本中的所有点,找出它们在 i+1 上最近的点。这样你就得到了所有点的轨迹。
- 检查这些轨迹上的点是否大多指向外部(这部分有点棘手;)
- 如果在足够多的帧中这些点都指向外部,那么你的轮廓就变大了。
另外,你也可以尝试去掉那些不属于正确轮廓的点,然后用一个覆盖的矩形来处理。这种方法检查大小非常简单,但我不知道选择“正确”点会有多简单。
这里的一个问题是如何识别和区分视频中移动的物体和其他东西。一个方法是让相机“学习”没有物体时的背景样子。然后你可以不断地将相机拍到的画面和这个背景进行比较。获取背景的一种方式是使用运行平均值。
如果有任何差异超过一个小的阈值,就意味着有一个移动的物体。如果你不断显示这个差异,基本上就得到了一个运动追踪器。物体的大小可以通过所有非零(超过阈值的)像素的总和,或者它们的边界矩形来计算。你可以追踪这个大小,并用它来猜测物体是靠近还是远离。形态学操作可以帮助将轮廓组合成一个整体的物体。
由于它会追踪任何运动,如果有两个物体,它们会一起被计算。这时你可以利用轮廓来找到和追踪单独的物体,比如使用轮廓的边界或中心点。你也可以通过颜色来分开它们。
以下是使用这种策略的一些结果(灰色的块是我的手):
实际上,它在猜测我的手移动方向方面做得相当不错。
代码:
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)
显然,这在识别、选择和追踪物体等方面还需要更多的工作(目前如果背景有其他东西在动,它的表现会很糟糕)。还有很多参数可以调整和优化(设置的参数是我系统中效果好的)。不过这部分就留给你自己去探索了。
一些链接:
如果你想在背景去除方面更高科技一点,可以看看这里: