0.概述
背景减法是一种广泛使用的方法,用于检测静态摄像机视频中的移动对象。这个想法是通过从背景模型中减去当前帧来提取移动对象。
1.背景减法
1.1 理论基础
概念:想象一下,你用手机拍了一段视频,你按下一个按钮,相机就开始录制视频。在手机的摄像头捕捉图像的速度非常快,当你观看视频时,你会看到一张接一张的图像,但你不会注意到,因为这个过程发生得非常快。在一秒钟内,你的手机会显示30多张照片。如果你比较这些图像并找到它们之间的差异,你可以检测到移动的物体,这正是背景减法的工作原理。
Def. 背景减法是计算机视觉中的一项基本技术,用于将视频流中的运动物体从背景中分离出来。
通过将视频的每一帧与背景模型进行比较,可以将差异显著的区域识别为潜在的前景对象。
这些前景信息可以用于各种目的,包括目标检测和跟踪。背景减法通常是许多目标跟踪和检测算法中的关键步骤。
如何基于背景减法中解决背景问题,特别是背景图像不是恒定的,这个是背景减法应用的关键。
由于光照变化、物体运动和场景动态等各种因素,它会随着时间而变化。
背景减除算法的目标是自适应地对背景进行建模和更新,从而在不断变化的环境中准确地检测出前景目标。这样就解决了背景问题。
在OpenCV中,背景减法器可以检测阴影,并且通过阈值处理,它可以从减法器检测到的对象中排除阴影。
这确实是准确检测物体的一个非常重要的功能,因为未识别的阴影区域可能会被减法器错误地解释为单独的移动物体,这是不可取的。
1.2 opencv使用
OpenCV 提供了几种背景减法方法,其中最常见的两种是:
- MOG2(高斯混合 2):此方法使用多个高斯分布来模拟每个像素的背景。它能很好地适应不同的照明条件。
- KNN(K-最近邻):它使用 K 最近邻来决定像素是否是背景的一部分。它还可以适应不同的照明条件。
使用 MOG2 和 KNN 检测视频中的移动对象,
1. 初始化:初始化K个高斯混合来模拟场景的背景。每个像素的背景模型由高斯函数的混合表示,其中K是一个预定义的参数。
2. 适应:随着时间的推移更新每个像素的背景模型,调整高斯分布的参数以适应场景的变化。
3. 前景检测:基于高斯混合模型计算每个像素属于背景的概率。概率低的像素被分类为前景。
4. 更新背景:对于分类为背景的像素,更新高斯分布以纳入新的观测值并适应场景的变化。
5. 后处理:应用形态学操作(腐蚀、膨胀等)或其他技术来细化前景mask并去除噪声。
case 1:
#include <iostream>
#include <opencv2/opencv.hpp>
int main(int argc, char** argv) {
if(argc != 2) {
std::cerr << "Usage: " << argv[0] << " <video_path>" << std::endl;
return -1;
}
// Create a VideoCapture object to read from video file
cv::VideoCapture cap(argv[1]);
if(!cap.isOpened()) {
std::cerr << "Error: Couldn't open the video file." << std::endl;
return -1;
}
// Create background subtractor objects
cv::Ptr<cv::BackgroundSubtractor> mog2 = cv::createBackgroundSubtractorMOG2();
cv::Ptr<cv::BackgroundSubtractor> knn = cv::createBackgroundSubtractorKNN();
cv::namedWindow("Original Video", cv::WINDOW_NORMAL);
cv::namedWindow("MOG2 Foreground", cv::WINDOW_NORMAL);
cv::namedWindow("KNN Foreground", cv::WINDOW_NORMAL);
while(true) {
cv::Mat frame, fgMaskMOG2, fgMaskKNN;
bool success = cap.read(frame);
if (!success) {
break;
}
// Apply background subtraction to get the foreground masks
mog2->apply(frame, fgMaskMOG2);
knn->apply(frame, fgMaskKNN);
// Display the frames and masks
cv::imshow("Original Video", frame);
cv::imshow("MOG2 Foreground", fgMaskMOG2);
cv::imshow("KNN Foreground", fgMaskKNN);
if(cv::waitKey(30) == 27) { // Exit on pressing 'Esc' key
break;
}
}
cap.release();
cv::destroyAllWindows();
return 0;
}
在此示例中,使用 MOG2 和 KNN 方法检测并突出显示视频的移动对象。通过直观比较每种方法的有效性。根据特定的视频和感兴趣的对象,一种方法可能比另一种方法性能更好。调整背景减法的参数也可以微调结果。
case 2:
# import libraries
import cv2
import numpy as np
# KNN
KNN_subtractor = cv2.createBackgroundSubtractorKNN(detectShadows = True) # detectShadows=True : exclude shadow areas from the objects you detected
# MOG2
MOG2_subtractor = cv2.createBackgroundSubtractorMOG2(detectShadows = True) # exclude shadow areas from the objects you detected
# choose your subtractor
bg_subtractor=MOG2_subtractor
camera = cv2.VideoCapture("resources/run.mp4")
while True:
ret, frame = camera.read()
# Every frame is used both for calculating the foreground mask and for updating the background.
foreground_mask = bg_subtractor.apply(frame)
# threshold if it is bigger than 240 pixel is equal to 255 if smaller pixel is equal to 0
# create binary image , it contains only white and black pixels
ret , treshold = cv2.threshold(foreground_mask.copy(), 120, 255,cv2.THRESH_BINARY)
# dilation expands or thickens regions of interest in an image.
dilated = cv2.dilate(treshold,cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)),iterations = 2)
# find contours
contours, hier = cv2.findContours(dilated,cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# check every contour if are exceed certain value draw bounding boxes
for contour in contours:
# if area exceed certain value then draw bounding boxes
if cv2.contourArea(contour) > 50:
(x,y,w,h) = cv2.boundingRect(contour)
cv2.rectangle(frame, (x,y), (x+w, y+h), (255, 255, 0), 2)
cv2.imshow("Subtractor", foreground_mask)
cv2.imshow("threshold", treshold)
cv2.imshow("detection", frame)
if cv2.waitKey(30) & 0xff == 27:
break
camera.release()
cv2.destroyAllWindows()
···