【问题标题】:Detecting an approaching object检测接近的物体
【发布时间】:2014-08-14 07:00:33
【问题描述】:

我阅读了this 博客文章,其中他使用激光和网络摄像头来估计纸板与网络摄像头的距离。

我对此有另一个想法。我不想计算与网络摄像头的距离。

我想检查是否有物体正在接近网络摄像头。根据我的说法,该算法将类似于:

  1. 检测网络摄像头源中的对象。
  2. 如果对象接近网络摄像头,它会在视频源中变得越来越大。
  3. 使用此数据进行进一步计算。

由于我想检测随机对象,我使用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()

输出是:

我被困在这里。我将轮廓存储在一个数组中。当尺寸增加时我该怎么办?我该如何进行?

【问题讨论】:

  • 只是为了激发你的好奇心,甚至还有一个acoustical way 可以做到这一点;)

标签: python c++ opencv object-detection


【解决方案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)

显然,这需要在识别、选择和跟踪对象等方面做更多的工作(目前,如果背景中有其他东西在移动,这会很糟糕)。还有许多参数可以改变和调整(设置的参数对我的系统很有效)。不过我会留给你。

一些链接:

background extraction

motion tracking

如果您想通过背景去除获得更多高科技,请看这里:

wallflower

【讨论】:

  • 所以基本上程序需要一些时间来初始化,然后(通过适当的修改)能够跟踪背景前面的对象?哇! :)
  • 理论上 :) 希望所需的修改不会太挑剔……
  • 好的,所以我实现了accumulateWeight() 函数。我正在捕捉背景。这就是初始化。接下来我该怎么做?我将更新问题中的源代码和图像。如何计算差异?
  • openCV 有一个 absdiff 函数,它应该可以解决问题。不幸的是我在工作所以无法测试它:(虽然更新了答案。
  • PS 我本来打算定期更新背景,所以它应该在你的循环中。这个想法是任何静态的东西都会消失。
【解决方案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.

好主意。 如果你想使用轮廓检测​​方法,你可以这样做:

  1. 您有一系列图像 I1、I2、...
  2. 对每一个进行轮廓检测。 C1, C2, ..., Cn(轮廓是 OpenCV 中的一组点)
  3. 在图像 i 和 i+1 上采集足够大的样本:S_i \leq C_i, i \in 1...n
  4. 检查样本中的所有点以查找 i+1 上最近的点。然后,您将追踪所有点。
  5. 检查此轨迹是否主要指向外部(棘手的部分;)
  6. 如果它们向外显示足够多的帧数,您的轮廓就会变大。

或者,您可以尝试修剪不属于正确轮廓的点并使用覆盖矩形。以这种方式检查大小非常容易,但我不知道选择“正确”点有多容易。

【讨论】:

  • 5.确实很棘手!一个问题是对象是否比背景大得多。在这种情况下,轮廓可能会围绕一块背景形成,随着对象变大,轮廓会缩小。
  • @PokeyMcPokerson:您可以反转接触超过 30%-60% 边界的轮廓
  • 如果对象不适合屏幕怎么办?然后它也会接触到边界。
猜你喜欢
  • 2013-12-23
  • 2018-04-10
  • 1970-01-01
  • 2013-12-15
  • 2011-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多