在本文中,将探讨如何开发一个低成本的视频监控系统,该系统可以利用现有的摄像头作为安全摄像头使用。这个系统不仅能够录制特定摄像头的视频到本地存储设备,还提供了运动检测、在运动时发出蜂鸣声和自动录制运动等功能。
该应用程序的基本思想是为小型场所(例如小型商店)创建一个低成本或免费的的视频安全程序,它覆盖了基本的数字视频录像机(DVR)功能,如运动检测和录制。
"CameraMonitor" 类是这个应用程序的核心,它提供了控制 "VideoCaptureDevice" 以及视频录制和运动检测等其他功能的接口。
以下是类的公共成员和属性:
new CameraMonitor(
PictureBox display,
string monikerString,
string cameraName
);
"CameraMonitor" 首先使用传递给它的 "monikerString" 创建 "VideoCaptureDevice",然后设置新传入帧的事件处理程序,最后开始视频捕获。
cam = new VideoCaptureDevice(monikerString);
cam.NewFrame += new NewFrameEventHandler(cam_NewFrame);
cam.Start();
它还创建了 "MotionDetector":
md = new MotionDetector(
new TwoFramesDifferenceDetector(),
new MotionAreaHighlighting()
);
当检测到 "NewFrameEvent" 时,"cam_NewFrame" 方法准备好处理它,首先从新帧中获取 "BitMap",然后将其显示在 "PictureBox" 上供用户查看。
Bitmap bit = (Bitmap)eventArgs.Frame.Clone();
this.display.Image = (Bitmap)bit.Clone();
如果用户启用了运动检测,"cam_NewFrame" 执行以下代码:
if (this.MotionDetection && !this.motionDetected) {
Bitmap bit2 = (Bitmap)bit.Clone();
if (md.ProcessFrame(bit2) > 0.001) {
if (this.calibrateAndResume > 3) {
Thread th = new Thread(MotionReaction);
th.Start();
} else {
this.calibrateAndResume++;
}
}
}
注意:"calibrateAndResume" 计数器被添加以确保确实有运动发生(在连续三个帧内)。
如果检测到运动,将启动一个新线程来执行需要执行的操作(显示消息和/或发出蜂鸣声和/或开始录制)。
private void MotionReaction() {
this.motionDetected = true;
if (this.RecordOnMotion) {
this.StartRecording();
}
if (this.BeepOnMotion) {
System.Console.Beep(400, 500);
System.Console.Beep(800, 500);
}
Thread.Sleep(10000);
calibrateAndResume = 0;
this.motionDetected = false;
Thread.Sleep(3000);
if (!this.forceRecord && this.motionDetected == false) {
this.StopRecording();
}
}
录制视频时,使用一个位图队列来存储来自摄像头的帧,然后录制器线程将逐帧出队并将它们写入文件,使用 "VideoFileWriter"。
private void DoRecord() {
VideoFileWriter writer = new VideoFileWriter();
writer.Open(RecordingPath + "\\" + this.cameraName + String.Format("{0:_dd-M-yyyy_hh-mm-ss}", DateTime.Now) + ".avi", this.Width, this.Height, 30);
while (IsRecording) {
if (frames.Count > 0) {
Bitmap bmp = frames.Dequeue();
writer.WriteVideoFrame(bmp);
}
}
writer.Close();
}
注意:总是可以通过公共属性 "RecordingPath" 设置录制路径。
使用 CameraMonitor
当表单加载时,它获取包含启动 "VideoCaptureDevice" 所需的 "monikerString" 字符串的 "FilterInfoCollection" 数组。此时,可用的摄像头将开始工作,并在传递给它们的 "PictureBox" 控件上显示视频。
webcam = new FilterInfoCollection(FilterCategory.VideoInputDevice);
for (int i = 0; i < webcam.Count && i < 4; i++) {
this.CamMonitor[i] = new CameraMonitor(this.DisplayReference[i], webcam[i].MonikerString, "Camera" + (i + 1));
this.camPanels[i].Enabled = true;
this.camOptions[i].Enabled = true;
}
最后一部分是使应用程序记住诸如录制路径或检测运动的摄像头等信息,以便当用户运行应用程序时,他不必手动重置所有选项。为此,创建了一个 "Config DataSet",它存储关联(KEY => VALUE),将在应用程序退出时保存用户选项,并在应用程序运行时使用 DataSet.WriteXml() 和 DataSet.ReadXml() 加载它们。
try {
DataRow r = this.config.Options.Select("Key = 'Camera1'")[0];
r[1] = ((!this.MotionDetection1.Checked) ? "0" : "1") + ((!this.AutoRecord1.Checked) ? "0" : "1") + ((!this.BeepOnMotionCheck1.Checked) ? "0" : "1");
} catch (Exception ex) {
this.config.Options.AddOptionsRow("Camera1", ((!this.MotionDetection1.Checked) ? "0" : "1") + ((!this.AutoRecord1.Checked) ? "0" : "1") + ((!this.BeepOnMotionCheck1.Checked) ? "0" : "1"));
}
this.config.WriteXml("config.xml");