【问题标题】:OpenCV detect movement in pythonOpenCV检测python中的运动
【发布时间】:2017-03-23 16:59:59
【问题描述】:

我的目标是检测 IP 摄像机流上特定区域的移动。我设法编写了工作代码,但这是基于我个人的理解。

import cv2
import numpy as np
import os
import time
import datetime
import urllib
import pynotify

stream=urllib.urlopen('http://user:pass@192.168.198.120/video.mjpg')
bytes=''
fgbg = cv2.createBackgroundSubtractorMOG2()

while True:
    bytes+=stream.read(16384)
    a = bytes.find('\xff\xd8')
    b = bytes.find('\xff\xd9')
    if a!=-1 and b!=-1:
        jpg = bytes[a:b+2]
        bytes= bytes[b+2:]
        img = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8),cv2.IMREAD_COLOR)
        rows,cols,c = img.shape
        mask = np.zeros(img.shape, dtype=np.uint8)
        roi_corners = np.array([[(940,220),(1080,240), (1080,310), (940,290)]], dtype=np.int32)
        channel_count = img.shape[2]
        ignore_mask_color = (255,)*channel_count
        cv2.fillPoly(mask, roi_corners, ignore_mask_color)
        masked_image = cv2.bitwise_and(img, mask)

        fgmask = fgbg.apply(masked_image)
        iii = fgmask[220:310,940:1080]

        hist,bins = np.histogram(iii.ravel(),256,[0,256])

        black, white, cnt1, cnt2 = 0,0,0,0


        for i in range(0,127):
            black += hist[i]
            cnt1+=1
        bl = float(black / cnt1)

        for i in range(128,256):
            white += hist[i]
            cnt2+=1
        wh = float(white / cnt2)

        finalResult = ((bl+1) / (wh+1))/10

    if finalResult < 1.0:
        pynotify.init("cv2alert")
            notice = pynotify.Notification('Alert', 'Alert text')
            try:
                notice.show()
            except gio.Error:
                print "Error"

此代码有效,但由于我不太了解直方图,我没有设法直接获取值,但有一些“黑客”,例如直方图的左侧是黑色,右侧是白色,black / white给出我想要的结果。我知道这不太正确,但是当没有人在 ROI 中时它给了我 4-9 的结果,当有人进入这个 ROI 时它给了我 0.5-2.0 的结果。

我的问题是: 有没有其他方法可以读取直方图和比较数据,或者其他方法?阅读文档对我没有帮助。

【问题讨论】:

  • 感兴趣的区域是否已预定义且稳定?如果我理解正确,您正在使用灰度图片/视频,并且您想要检测运动,例如“像素值的快速变化”?
  • 是的,这个区域是预定义的。我试图从直方图中提取值,因为只有两种颜色(黑色和白色),但没有运气。因此,黑色直方图的前半部分和白色的第二部分。我的问题是,是否存在另一种实现这一目标的方法?我的主要目标是尽可能简单地检测特定区域的运动,并通知用户。
  • 我认为几乎有无数种不同的方法。例如,您可以保留最后 x 帧的分数并计算“平均”图片,然后您可以使用它来计算差异图片。如果任何区域(例如 n*m 块)的差异高于阈值,则可以将其称为运动并进行报告。这也可以用于识别运动区域,而无需明确定义 ROI

标签: python opencv motion-detection


【解决方案1】:

检测运动的一种方法是使用cv2.accumulateWeighted 保持场景的运行平均值。然后,使用cv2.absdiff 将每个新帧与平均值进行比较,以获得指示场景变化的图像。

我在a video processing project 中正是这样做的。查看文件diffavg1.py 中的主循环,我在其中运行累加器并执行差异。

(该项目的研究是利用多核CPU架构实现实时视频处理,所以后来的版本diffavg2.pydiffavg3.pydiffavg4.py是性能逐步提高的实现,但底层的accumulate-diff算法是一样的。)

【讨论】:

  • 不错的一个。我设法获得了一些价值,但我的问题需要很少的工作。我注意到 CPU 和内存使用率低于我的自定义脚本。
【解决方案2】:

差分图像是两个图像相减的结果

所以差分图像显示了两个图像之间的差异。使用这些图像,您可以使运动可见。

在下面的脚本中,我们使用从三个连续图像计算的差分图像,和。这样做的好处是从结果中删除了无趣的背景。

OpenCV 提供了将两个图像相减的可能性 使用 absdiff()。对两个图像的逻辑运算也已经存在 实施的。我们使用bitwise_and()的方法来实现最终的 差分图像。在python中它看起来像这样:

def diffImg(t0, t1, t2):
  d1 = cv2.absdiff(t2, t1)
  d2 = cv2.absdiff(t1, t0)
  return cv2.bitwise_and(d1, d2)

我们要做的最后一件事是将差分图像函数带入我们之前的脚本中。 在循环开始之前,我们读取前三个图像 t_minus、t 和 t_plus 并将它们转换为灰度图像,因为我们不需要颜色信息。有了这些图像,就可以开始计算差分图像。显示差分图像后,我们只需摆脱最旧的图像并读取下一个图像。最终脚本如下所示:

import cv2

def diffImg(t0, t1, t2):
  d1 = cv2.absdiff(t2, t1)
  d2 = cv2.absdiff(t1, t0)
  return cv2.bitwise_and(d1, d2)

cam = cv2.VideoCapture(0)

winName = "Movement Indicator"
cv2.namedWindow(winName, cv2.WINDOW_AUTOSIZE)

# Read three images first:
t_minus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
t = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
t_plus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)

while True:
  cv2.imshow( winName, diffImg(t_minus, t, t_plus) )

  # Read next image
  t_minus = t
  t = t_plus
  t_plus = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)

  key = cv2.waitKey(10)
  if key == 27:
    cv2.destroyWindow(winName)
    break

print("Goodbye")

Here you will find more elaborative answer, for what you are looking for.

【讨论】:

  • 在稍微修改了 Adrian 的代码并删除了不必要的东西之后,我设法完成了这项工作。简单有效,对资源的影响很小(1% CPU 和 30 Mb 内存)。而不是在屏幕上显示图像,通知作品就像他剧本的第 69 行中的魅力一样。谢谢你。我认为这段代码可以针对我的目的进行一些优化,但目前可以使用。
【解决方案3】:

可以通过ecapture来完成。

安装

pip install ecapture

代码

from ecapture import motion as md

md.motion_detect(0,"x")
print("detected")

这段代码会打印出来

detected

一旦相机视野发生移动

【讨论】:

    猜你喜欢
    • 2012-11-15
    • 2011-05-28
    • 1970-01-01
    • 2023-03-30
    • 2013-11-23
    • 2017-06-13
    • 2011-10-24
    • 1970-01-01
    • 2014-07-15
    相关资源
    最近更新 更多