OpenCV摄像头图像采集、运动目标跟踪与人脸识别系统
基于OpenCV的系统,实现了摄像头图像采集、运动目标跟踪和人脸识别功能。
#include <opencv2/opencv.hpp>
#include <opencv2/face.hpp>
#include <opencv2/tracking.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
#include <iostream>
#include <vector>
#include <map>
#include <deque>
#include <ctime>
#include <sstream>
#include <fstream>
using namespace cv;
using namespace cv::face;
using namespace std;
// 运动目标跟踪类
class MotionTracker {
public:
MotionTracker() : trackerType("KCF") {}
void initTracker(const Rect2d& roi, Mat& frame) {
if (tracker) delete tracker;
if (trackerType == "BOOSTING") tracker = TrackerBoosting::create();
else if (trackerType == "MIL") tracker = TrackerMIL::create();
else if (trackerType == "KCF") tracker = TrackerKCF::create();
else if (trackerType == "TLD") tracker = TrackerTLD::create();
else if (trackerType == "MEDIANFLOW") tracker = TrackerMedianFlow::create();
else if (trackerType == "GOTURN") tracker = TrackerGOTURN::create();
else if (trackerType == "MOSSE") tracker = TrackerMOSSE::create();
else if (trackerType == "CSRT") tracker = TrackerCSRT::create();
tracker->init(frame, roi);
}
bool updateTracker(Mat& frame, Rect2d& roi) {
return tracker->update(frame, roi);
}
void setTrackerType(const string& type) {
trackerType = type;
}
private:
Ptr<Tracker> tracker;
string trackerType;
};
// 人脸识别系统类
class FaceRecognitionSystem {
public:
FaceRecognitionSystem(const string& cascadePath, const string& recognizerPath = "")
: faceDetector(cascadePath), ready(false) {
if (!recognizerPath.empty()) {
model = LBPHFaceRecognizer::create();
model->read(recognizerPath);
ready = true;
}
}
vector<Rect> detectFaces(Mat& frame) {
Mat gray;
cvtColor(frame, gray, COLOR_BGR2GRAY);
equalizeHist(gray, gray);
vector<Rect> faces;
faceDetector.detectMultiScale(gray, faces, 1.1, 3, 0, Size(100, 100));
return faces;
}
void trainRecognizer(const vector<Mat>& images, const vector<int>& labels) {
model = LBPHFaceRecognizer::create();
model->train(images, labels);
ready = true;
}
int recognizeFace(Mat& faceROI) {
if (!ready) return -1;
Mat gray;
if (faceROI.channels() == 3) {
cvtColor(faceROI, gray, COLOR_BGR2GRAY);
} else {
gray = faceROI.clone();
}
equalizeHist(gray, gray);
int predictedLabel = -1;
double confidence = 0.0;
model->predict(gray, predictedLabel, confidence);
// 置信度阈值,低于此值认为是未知人脸
if (confidence > 80.0) return -1;
return predictedLabel;
}
void saveModel(const string& path) {
if (ready) model->write(path);
}
private:
CascadeClassifier faceDetector;
Ptr<LBPHFaceRecognizer> model;
bool ready;
};
// 运动检测类
class MotionDetector {
public:
MotionDetector(float threshold = 30.0, int history = 500, float varThreshold = 16.0)
: historySize(history), varThreshold(varThreshold), threshold(threshold) {
pMOG2 = createBackgroundSubtractorMOG2(historySize, varThreshold, true);
pMOG2->setDetectShadows(false);
}
Mat detectMotion(Mat& frame) {
Mat fgMask;
pMOG2->apply(frame, fgMask);
// 二值化
threshold(fgMask, fgMask, threshold, 255, THRESH_BINARY);
// 形态学操作去除噪声
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
morphologyEx(fgMask, fgMask, MORPH_OPEN, kernel);
morphologyEx(fgMask, fgMask, MORPH_CLOSE, kernel);
return fgMask;
}
private:
Ptr<BackgroundSubtractorMOG2> pMOG2;
int historySize;
float varThreshold;
float threshold;
};
// 主应用程序类
class SurveillanceApp {
public:
SurveillanceApp(const string& faceCascadePath, const string& faceRecognizerPath = "")
: capture(0), motionDetector(30.0, 500, 16.0), faceSystem(faceCascadePath, faceRecognizerPath),
trackingActive(false), recording(false), frameCount(0), fps(0), startTime(clock()) {
if (!capture.isOpened()) {
cerr << "ERROR: Could not open camera" << endl;
exit(1);
}
// 初始化跟踪器
motionTracker.setTrackerType("KCF");
// 创建窗口
namedWindow("Surveillance System", WINDOW_NORMAL);
resizeWindow("Surveillance System", 1280, 720);
// 创建控制面板
createControlPanel();
// 初始化变量
prevFrame = Mat::zeros(480, 640, CV_8UC3);
}
void run() {
while (true) {
// 读取帧
capture >> frame;
if (frame.empty()) break;
// 更新FPS
updateFPS();
// 处理帧
processFrame();
// 显示结果
displayResults();
// 处理键盘输入
handleKeyPress();
}
// 清理
if (recording) {
videoWriter.release();
}
capture.release();
destroyAllWindows();
}
private:
void processFrame() {
// 运动检测
Mat motionMask = motionDetector.detectMotion(frame);
// 运动目标检测
vector<Rect> motionROIs;
if (trackingActive) {
// 更新跟踪器
Rect2d trackedROI;
if (motionTracker.updateTracker(frame, trackedROI)) {
motionROIs.push_back(Rect(trackedROI));
} else {
trackingActive = false;
}
} else {
// 检测新运动目标
detectMotionROIs(motionMask, motionROIs);
}
// 人脸检测
vector<Rect> faces = faceSystem.detectFaces(frame);
vector<int> faceLabels;
vector<string> faceNames;
// 人脸识别
for (const Rect& face : faces) {
Mat faceROI = frame(face);
int label = faceSystem.recognizeFace(faceROI);
faceLabels.push_back(label);
if (label == -1) {
faceNames.push_back("Unknown");
} else {
ostringstream oss;
oss << "Person " << label;
faceNames.push_back(oss.str());
}
}
// 更新跟踪目标
if (!trackingActive && !motionROIs.empty()) {
// 选择最大的运动目标
auto maxIt = max_element(motionROIs.begin(), motionROIs.end(),
[](const Rect& a, const Rect& b) { return a.area() < b.area(); });
motionTracker.initTracker(*maxIt, frame);
trackingActive = true;
}
// 存储处理结果
processedFrame = frame.clone();
currentMotionMask = motionMask;
currentMotionROIs = motionROIs;
currentFaces = faces;
currentFaceLabels = faceLabels;
currentFaceNames = faceNames;
}
void detectMotionROIs(Mat& motionMask, vector<Rect>& rois) {
// 查找轮廓
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(motionMask, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
// 过滤小区域
for (const auto& contour : contours) {
double area = contourArea(contour);
if (area > 500) { // 最小面积阈值
rois.push_back(boundingRect(contour));
}
}
}
void displayResults() {
Mat display = processedFrame.clone();
// 绘制运动目标
for (const Rect& roi : currentMotionROIs) {
rectangle(display, roi, Scalar(0, 0, 255), 2);
putText(display, "Moving Object", Point(roi.x, roi.y - 5),
FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 255), 1);
}
// 绘制人脸
for (size_t i = 0; i < currentFaces.size(); i++) {
rectangle(display, currentFaces[i], Scalar(0, 255, 0), 2);
putText(display, currentFaceNames[i],
Point(currentFaces[i].x, currentFaces[i].y - 5),
FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 255, 0), 1);
}
// 显示FPS
putText(display, format("FPS: %.2f", fps), Point(10, 30),
FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 255, 0), 2);
// 显示状态
string status = "Status: ";
status += trackingActive ? "Tracking" : "Searching";
putText(display, status, Point(10, 60),
FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 255, 255), 2);
// 显示录制状态
if (recording) {
putText(display, "RECORDING", Point(display.cols - 150, 30),
FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 0, 255), 2);
}
// 显示控制面板
displayControlPanel(display);
// 显示结果
imshow("Surveillance System", display);
// 录制视频
if (recording) {
videoWriter.write(display);
}
}
void createControlPanel() {
// 创建控制面板窗口
namedWindow("Control Panel", WINDOW_NORMAL);
resizeWindow("Control Panel", 400, 300);
// 创建按钮
createButton("Start Tracking", Point(20, 30), [&]() {
if (!currentMotionROIs.empty()) {
motionTracker.initTracker(currentMotionROIs[0], frame);
trackingActive = true;
}
});
createButton("Stop Tracking", Point(20, 70), [&]() {
trackingActive = false;
});
createButton("Start Recording", Point(20, 110), [&]() {
startRecording();
});
createButton("Stop Recording", Point(20, 150), [&]() {
stopRecording();
});
createButton("Save Snapshot", Point(20, 190), [&]() {
saveSnapshot();
});
createButton("Exit", Point(20, 230), [&]() {
running = false;
});
}
void createButton(const string& text, Point pos, function<void()> action) {
// 在实际实现中,这里会创建按钮并绑定事件
// 为简化,我们只存储按钮信息
buttons.push_back({text, pos, action});
}
void displayControlPanel(Mat& display) {
// 在实际实现中,这里会绘制控制面板
// 为简化,我们只显示一个简单的状态栏
rectangle(display, Point(0, display.rows - 100), Point(display.cols, display.rows),
Scalar(50, 50, 50), FILLED);
putText(display, "Controls: [S] Start Tracking, [T] Stop Tracking, [R] Record, [P] Snapshot, [Q] Quit",
Point(10, display.rows - 70), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255, 255, 255), 1);
}
void startRecording() {
if (recording) return;
ostringstream oss;
time_t now = time(0);
tm* ltm = localtime(&now);
oss << "recording_"
<< (ltm->tm_year + 1900) << "-"
<< (ltm->tm_mon + 1) << "-"
<< ltm->tm_mday << "_"
<< ltm->tm_hour << "-"
<< ltm->tm_min << "-"
<< ltm->tm_sec << ".avi";
int fourcc = VideoWriter::fourcc('M', 'J', 'P', 'G');
videoWriter.open(oss.str(), fourcc, 20.0, Size(frame.cols, frame.rows), true);
if (videoWriter.isOpened()) {
recording = true;
cout << "Started recording: " << oss.str() << endl;
} else {
cerr << "Failed to start recording" << endl;
}
}
void stopRecording() {
if (recording) {
videoWriter.release();
recording = false;
cout << "Recording stopped" << endl;
}
}
void saveSnapshot() {
ostringstream oss;
time_t now = time(0);
tm* ltm = localtime(&now);
oss << "snapshot_"
<< (ltm->tm_year + 1900) << "-"
<< (ltm->tm_mon + 1) << "-"
<< ltm->tm_mday << "_"
<< ltm->tm_hour << "-"
<< ltm->tm_min << "-"
<< ltm->tm_sec << ".jpg";
imwrite(oss.str(), processedFrame);
cout << "Snapshot saved: " << oss.str() << endl;
}
void updateFPS() {
frameCount++;
clock_t now = clock();
double elapsed = (double)(now - startTime) / CLOCKS_PER_SEC;
if (elapsed > 1.0) {
fps = frameCount / elapsed;
frameCount = 0;
startTime = now;
}
}
void handleKeyPress() {
char key = (char)waitKey(1);
switch (key) {
case 'q':
case 27: // ESC
running = false;
break;
case 's':
if (!currentMotionROIs.empty()) {
motionTracker.initTracker(currentMotionROIs[0], frame);
trackingActive = true;
}
break;
case 't':
trackingActive = false;
break;
case 'r':
if (recording) stopRecording();
else startRecording();
break;
case 'p':
saveSnapshot();
break;
case ' ':
// 空格键切换跟踪/搜索模式
trackingActive = !trackingActive;
if (trackingActive && !currentMotionROIs.empty()) {
motionTracker.initTracker(currentMotionROIs[0], frame);
}
break;
}
}
// 成员变量
VideoCapture capture;
Mat frame, prevFrame, processedFrame, currentMotionMask;
vector<Rect> currentMotionROIs;
vector<Rect> currentFaces;
vector<int> currentFaceLabels;
vector<string> currentFaceNames;
MotionDetector motionDetector;
MotionTracker motionTracker;
FaceRecognitionSystem faceSystem;
bool trackingActive;
bool recording;
int frameCount;
double fps;
clock_t startTime;
bool running;
VideoWriter videoWriter;
// 控制面板相关
struct Button { string text; Point pos; function<void()> action; };
vector<Button> buttons;
};
int main(int argc, char** argv) {
// 加载人脸检测器和识别器
string faceCascadePath = "haarcascade_frontalface_default.xml";
string faceRecognizerPath = ""; // 如果有预训练模型,可以指定路径
// 检查命令行参数
if (argc > 1) {
faceCascadePath = argv[1];
}
if (argc > 2) {
faceRecognizerPath = argv[2];
}
// 创建并运行应用
SurveillanceApp app(faceCascadePath, faceRecognizerPath);
app.run();
return 0;
}
系统功能与特点
核心功能
- 实时视频采集:从摄像头捕获实时视频流
- 运动目标检测:使用背景减除算法检测运动物体
- 目标跟踪:集成多种跟踪算法(KCF、MIL、CSRT等)
- 人脸检测:使用Haar级联分类器检测人脸
- 人脸识别:使用LBPH算法进行人脸识别
- 视频录制:支持实时录制视频
- 快照功能:保存当前帧为图像文件
- 性能监控:实时显示FPS和处理状态
系统特点
- 多算法集成:支持多种目标跟踪算法
- 模块化设计:各功能模块解耦,便于扩展
- 实时处理:优化处理流程,确保实时性能
- 用户友好界面:直观的控制面板和状态显示
- 灵活配置:支持命令行参数配置
- 数据持久化:支持模型保存和加载
技术实现细节
1. 运动目标检测
使用MOG2背景减除算法:
Ptr<BackgroundSubtractorMOG2> pMOG2 = createBackgroundSubtractorMOG2(500, 16.0, true);
pMOG2->apply(frame, fgMask);
2. 目标跟踪
支持多种跟踪算法:
// 创建KCF跟踪器
Ptr<Tracker> tracker = TrackerKCF::create();
tracker->init(frame, roi);
bool success = tracker->update(frame, roi);
3. 人脸检测
使用Haar级联分类器:
CascadeClassifier faceDetector;
faceDetector.load("haarcascade_frontalface_default.xml");
faceDetector.detectMultiScale(gray, faces, 1.1, 3, 0, Size(100, 100));
4. 人脸识别
使用LBPH算法:
Ptr<LBPHFaceRecognizer> model = LBPHFaceRecognizer::create();
model->train(images, labels);
int label = model->predict(faceROI);
参考代码 OPENCV基于摄像头图像采集运动目标跟踪及人脸识别技术 www.youwenfan.com/contentcns/122471.html
系统优化建议
-
性能优化:
// 使用GPU加速 cv::cuda::GpuMat d_frame, d_gray; d_frame.upload(frame); cv::cuda::cvtColor(d_frame, d_gray, COLOR_BGR2GRAY); -
多目标跟踪:
// 使用SORT或DeepSORT算法 vector<STrack> tracks = sort.update(detections); -
深度学习集成:
// 使用DNN模块进行人脸检测 Net net = readNetFromTensorflow("opencv_face_detector_uint8.pb", "opencv_face_detector.pbtxt"); -
光照归一化:
// 使用CLAHE增强对比度 Ptr<CLAHE> clahe = createCLAHE(2.0, Size(8, 8)); clahe->apply(gray, enhancedGray); -
阴影处理:
// 在HSV空间处理阴影 Mat hsv; cvtColor(frame, hsv, COLOR_BGR2HSV); vector<Mat> channels; split(hsv, channels); // 使用亮度通道进行阴影检测
使用说明
系统要求
- OpenCV 3.4+ 或 4.x
- C++11兼容编译器
- 摄像头设备
- 人脸检测模型文件(haarcascade_frontalface_default.xml)
编译与运行
# 安装依赖
sudo apt-get install libopencv-dev
# 编译命令
g++ -std=c++11 surveillance_system.cpp -o surveillance_system `pkg-config --cflags --libs opencv4`
# 运行程序
./surveillance_system
控制按键
- S:开始跟踪运动目标
- T:停止跟踪
- R:开始/停止录制视频
- P:保存当前帧为快照
- 空格键:切换跟踪/搜索模式
- Q/ESC:退出程序
参数调整
-
运动检测灵敏度:
MotionDetector motionDetector(30.0, 500, 16.0); // 阈值, 历史长度, 方差阈值 -
跟踪算法选择:
motionTracker.setTrackerType("CSRT"); // 可选: BOOSTING, MIL, KCF, TLD, MEDIANFLOW, GOTURN, MOSSE, CSRT -
人脸检测参数:
faceDetector.detectMultiScale(gray, faces, 1.1, 3, 0, Size(100, 100)); // 参数: 缩放因子, 邻近数, 标志, 最小尺寸
扩展功能
-
多摄像头支持:
vector<VideoCapture> captures; for (int i = 0; i < numCameras; i++) { captures.push_back(VideoCapture(i)); } -
运动历史增强:
Ptr<MotionHistory> mh = createMotionHistory(/* 参数 */); mh->update(motionMask); -
行为分析:
// 分析目标运动模式 enum Behavior { STATIONARY, MOVING, APPROACHING, LEAVING }; Behavior analyzeBehavior(const vector<Point>& trajectory); -
云台控制:
// 根据目标位置控制摄像头 void controlPTZ(int pan, int tilt, int zoom); -
报警系统:
// 检测到异常时触发报警 void triggerAlarm(const string& reason);
实际部署建议
-
硬件选择:
- 高分辨率摄像头(1080p或更高)
- 专用GPU(用于深度学习模型)
- 充足的内存和存储空间
-
环境适应:
- 室内:使用广角镜头
- 室外:使用变焦镜头和防护罩
- 低光照:添加红外照明
-
隐私保护:
- 匿名化处理敏感数据
- 符合GDPR等隐私法规
- 提供数据访问控制
-
系统监控:
- 实现心跳机制
- 资源使用监控
- 自动故障恢复
-
用户界面:
- 开发Web管理界面
- 提供移动端应用
- 实现多语言支持