OpenCV实现监控移动侦测

前言

固定监控,需要快速标记全天候出现画面变化的时间段,需要使用到运动侦测的方法,本文主要使用帧差法进行计算。

点跟踪:

这类方法通常在连续帧中检测到的目标被表达为点。再引入其它方法来进行目标检测。其问题可以用帧与帧之间检测到的目标点之间的关系来表达。方法可分为两大类:确定性方法和统计性方法。前者通常用定性的运动限制方法,后者用目标检测和不确定性的建模来建立关联。(1)确定性的方法定义了在一系列约束条件下,关联t时刻和t-1时刻图像帧中每个目标的成本。关联成本的最小化规划为一个优化组合问题。可以用最优分配方法求解,如匈牙利算法,贪婪搜索算法。(2)统计性方法在目标状态估计中考虑了观测噪声和模型不确定性,用状态空间方法建模速度、位置、加速度等目标属性。对于单个目标的情况,状态可简单估计得到;对于多目标的情况,则需要将观测域相应目标对应起来。

对于单目标状态估计:如果状态转移矩阵和观测矩阵都是线性的,状态和噪声是高斯分布的,则最优的状态估计方法是卡尔曼滤波。本博客最后的结果也是使用的卡尔曼滤波实现的,结果显示,对于但目标的追踪上,准确率还可以,多各目标时效果并不是太好。

对于 多目标状态估计:广泛采用的两种方法是Joint Probability Data Association Filtering (JPDAF)和Multiple Hypothesis Tracking (MHT)

核跟踪:

核函数可以是关联与一个直方图的矩形或椭圆模板,通过在连续帧中计算核的运动来跟踪。运动可以是参数形式的平移、旋转或仿射等。核跟踪的目标表达通常用原始的目标区域来表达,跟踪由计算目标运动来实现的。目标运动以参数形式的运动(如平移、仿射等)或计算得到的连续帧的密度流区域描述。这些算法在外观表达的运动、跟踪的目标数目、运动估计使用的方法等方面有所差异。核跟踪算法可分为两类:分别是基于模板和概率密度的外观模型的跟踪,和基于多视角外观模型跟踪。

单目标跟踪这类算法中最常用的是模板匹配。在图像中搜索类似于预定义模板的区域,通过相似性度量(比如cross correlation)判断目标位置。主要问题在于计算量大。可以用邻域范围限定等方法来减少搜索半径。除了模板匹配外,还可以用颜色直方图、混合模型等来表达外观模型。

多目标跟踪:这类算法通常对整个图像进行建模,包括背景和每个目标。

用多视角外观模型跟踪:对多个视角的目标进行离线学习,使能够处理重大视角变化情况跟踪问题。Black and Jepson[1998]提出基于子空间的方法。先用PCA建立目标外观的子空间表达,然后将图像转化到特征子空间中。Avidan [2001]使用了SVM分类器对多视角进行分类,并跟踪。

轮廓跟踪:

基于轮廓的方法提供了较为准确的形状描述。这类方法的主要思想是用先前帧建立的目标模型找到当前帧的目标区域。其中目标模型可以是颜色直方图、目标边缘或者轮廓。基于轮廓的跟踪方法可以分为两类:形状匹配方法和轮廓跟踪方法。前者在当前帧中搜索目标性状,后者则通过状态空间模型或直接的能量最小化函数推演初始轮廓在当前帧中的新位置。

形状匹配方法:这种方法类似于基于模板的跟踪,在当前帧中搜索目标的轮廓和相关模型。  另一种匹配形状的方法是在连续两帧中寻找关联轮廓,建立轮廓关联,或称为轮廓匹配,是类似于点匹配的一种方法。这种方法使用了目标的外观特征。轮廓检测通常由背景减除实现。轮廓被提取后,匹配由计算目标模型和每个轮廓之间的距离。目标模型可以使密度函数(颜色或边缘直方图)、轮廓边界、目标边缘或这些信息的组合。

自己实现的单目标追踪实验结果,主要是用的opencv中的函数,高斯混合模型提取前景,经过简单的处理得到轮廓和质心,再加上卡尔曼函数实现的。网上代码一大堆,有需要的可以可以提供。

 

算法的主要流程如下:

  1. 计算帧间的距离(Pythagorean distance)
  2. 在计算出来的距离矩阵上应用高斯模糊
  3. 使用一定的阈值进行过滤
  4. 计算标准差
  5. 标准差大于一定的阈值,认为检测到了运动,输出信息

本文将给出 Python 语言的实现。

运行环境


编程环境:Python 3.7.6OpenCV 3.3.0,IDEA

Python 实现

import numpy as np
import cv2

sdThresh = 10
font = cv2.FONT_HERSHEY_SIMPLEX

def distMap(frame1, frame2):
    """outputs pythagorean distance between two frames"""
    frame1_32 = np.float32(frame1)
    frame2_32 = np.float32(frame2)
    diff32 = frame1_32 - frame2_32
    norm32 = np.sqrt(diff32[:,:,0]**2 + diff32[:,:,1]**2 + \
             diff32[:,:,2]**2)/np.sqrt(255**2 + 255**2 + 255**2)
    dist = np.uint8(norm32*255)
    return dist

cv2.namedWindow('frame')
cv2.namedWindow('dist')

#capture video stream from camera source. 0 refers to first camera, 1 referes to 2nd and so on.
cap = cv2.VideoCapture(0)

_, frame1 = cap.read()
_, frame2 = cap.read()

facecount = 0
while(True):
    _, frame3 = cap.read()
    rows, cols, _ = np.shape(frame3)
    cv2.imshow('dist', frame3)
    dist = distMap(frame1, frame3)

    frame1 = frame2
    frame2 = frame3

    # apply Gaussian smoothing
    mod = cv2.GaussianBlur(dist, (9,9), 0)

    # apply thresholding
    _, thresh = cv2.threshold(mod, 100, 255, 0)

    # calculate st dev test
    _, stDev = cv2.meanStdDev(mod)

    cv2.imshow('dist', mod)
    cv2.putText(frame2, "Standard Deviation - {}".format(round(stDev[0][0],0)), \
                (70, 70), font, 1, (255, 0, 255), 1, cv2.LINE_AA)
    if stDev > sdThresh:
            print("Motion detected.. Do something!!!");

    cv2.imshow('frame', frame2)
    if cv2.waitKey(1) & 0xFF == 27:
        break

cap.release()
cv2.destroyAllWindows()

 

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于OpenCV移动侦测程序的C++实现示例,它可以检测视频中的运动物体并在图像中绘制一个边框: ```c++ #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { // 读取视频文件 VideoCapture cap("video.mp4"); // 检查视频是否打开成功 if (!cap.isOpened()) { cout << "Error: Could not open video file." << endl; return -1; } // 定义前一帧图像和当前帧图像 Mat frame1, frame2; // 从视频中读取第一帧图像 cap >> frame1; // 转换为灰度图像 cvtColor(frame1, frame1, COLOR_BGR2GRAY); // 循环遍历视频中的每一帧 while (true) { // 从视频中读取下一帧图像 cap >> frame2; // 如果视频结束,则退出循环 if (frame2.empty()) { break; } // 转换为灰度图像 cvtColor(frame2, frame2, COLOR_BGR2GRAY); // 计算前一帧图像和当前帧图像的差异 Mat diff; absdiff(frame1, frame2, diff); // 进行二值化处理 threshold(diff, diff, 30, 255, THRESH_BINARY); // 进行腐蚀和膨胀操作,以去除噪声和填充空洞 Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5)); erode(diff, diff, kernel); dilate(diff, diff, kernel); // 查找轮廓并绘制边框 vector<vector<Point>> contours; findContours(diff, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); for (size_t i = 0; i < contours.size(); i++) { Rect rect = boundingRect(contours[i]); rectangle(frame2, rect, Scalar(0, 255, 0), 2); } // 显示当前帧图像 imshow("Motion Detection", frame2); // 将当前帧图像保存为前一帧图像 frame1 = frame2.clone(); // 等待按键 if (waitKey(30) == 27) { break; } } // 释放视频文件 cap.release(); // 销毁窗口 destroyAllWindows(); return 0; } ``` 注意,这只是一个简单的实现示例,可能需要进行优化和改进才能应用于实际场景中的移动侦测
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值