本文将介绍如何利用 C++ 和强大的计算机视觉库 OpenCV,从零开始创建一个基础的智能监控程序。该程序可以从视频文件或实时摄像头中捕捉画面,并自动检测、标记出其中“可疑”的移动物体。
这个项目的核心思想是背景减除法 (Background Subtraction),这是一种在静态摄像头场景下检测运动物体的经典且高效的算法。
我们的检测逻辑分为以下几个步骤:
在开始编码前,请确保你的开发环境已经配置好:
sudo apt-get install libopencv-dev
安装。下面是完整的 C++ 代码实现。代码中有详细的注释来解释每一步的操作。
#include
#include
#include
int main() {
// 1. 初始化视频捕捉
// 可以是视频文件路径,也可以是摄像头ID (0代表默认摄像头)
cv::VideoCapture cap("your_video.mp4");
// cv::VideoCapture cap(0);
if (!cap.isOpened()) {
std::cerr << "错误: 无法打开视频源" << std::endl;
return -1;
}
// 2. 创建背景减除器 (MOG2)
// MOG2 是一种基于高斯混合模型的背景/前景分割算法
cv::Ptr<cv::BackgroundSubtractorMOG2> pMOG2 = cv::createBackgroundSubtractorMOG2();
// 定义一个“可疑区域”或“禁区”
// 这里我们假设视频的左上角 300x200 的区域是禁区
cv::Rect suspiciousArea(0, 0, 300, 200);
cv::Mat frame, fgMask;
// 3. 逐帧处理视频
while (true) {
// 读取新的一帧
if (!cap.read(frame)) {
std::cout << "视频播放完毕" << std::endl;
break;
}
// 4. 应用背景减除器,得到前景蒙版
pMOG2->apply(frame, fgMask);
// 5. 形态学处理,去除噪声
// 腐蚀操作可以去除小的白色噪点
cv::erode(fgMask, fgMask, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5)));
// 膨胀操作可以填充物体内部的空洞,使轮廓更完整
cv::dilate(fgMask, fgMask, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5)));
// 6. 发现前景物体轮廓
std::vector<std::vector<cv::Point>> contours;
cv::findContours(fgMask, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
// 绘制禁区矩形以供观察
cv::rectangle(frame, suspiciousArea, cv::Scalar(0, 255, 255), 2); // 黄色矩形
// 7. 遍历所有轮廓
for (const auto& contour : contours) {
// 根据面积过滤掉太小的轮廓
if (cv::contourArea(contour) < 800) {
continue;
}
// 获取轮廓的边界框
cv::Rect boundingBox = cv::boundingRect(contour);
// 默认绘制绿色矩形
cv::Scalar boxColor(0, 255, 0); // 绿色
std::string label = "Moving Object";
// 8. 判断是否可疑 (是否与禁区相交)
// (boundingBox & suspiciousArea).area() > 0 表示两个矩形有重叠部分
if ((boundingBox & suspiciousArea).area() > 0) {
boxColor = cv::Scalar(0, 0, 255); // 红色
label = "SUSPICIOUS!";
}
// 在原图上绘制边界框和标签
cv::rectangle(frame, boundingBox, boxColor, 2);
cv::putText(frame, label, cv::Point(boundingBox.x, boundingBox.y - 10),
cv::FONT_HERSHEY_SIMPLEX, 0.5, boxColor, 2);
}
// 9. 显示结果
cv::imshow("Original Frame", frame);
cv::imshow("Foreground Mask", fgMask);
// 按下 'q' 键退出循环
if (cv::waitKey(30) == 'q') {
break;
}
}
// 释放资源
cap.release();
cv::destroyAllWindows();
return 0;
}
在终端中,使用以下命令进行编译(请确保你的 OpenCV 库链接正确):
g++ main.cpp -o motion_detector $(pkg-config --cflags --libs opencv4)
然后运行:
./motion_detector
创建一个 CMakeLists.txt
文件:
cmake_minimum_required(VERSION 3.10)
project(MotionDetector)
set(CMAKE_CXX_STANDARD 11)
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(motion_detector main.cpp)
target_link_libraries(motion_detector ${OpenCV_LIBS})
编译项目:
mkdir build
cd build
cmake ..
make
运行程序:
./motion_detector
程序运行时,你将看到两个窗口:一个显示原始视频和检测框,另一个显示黑白的前景蒙版。当有物体进入预设的黄色矩形禁区时,其检测框会变为红色并标记为 “SUSPICIOUS!”。
这个程序实现了一个基础但有效的可疑物体检测系统。你可以通过调整以下参数来优化它以适应不同场景:
cv::contourArea(contour) < 800
中的 800
,用于过滤不同大小的物体。cv::Size(5, 5)
,影响噪声去除的程度。suspiciousArea
的位置和大小。未来可扩展的方向包括: