OpenCV实现简单摄像头视频监控程序

时间:2022-11-23 19:35:02

如何在冗长的监控录像中找到关键点?我们知道,监控录像中大部分信息都是没用的,那些信息就等同于一幅静态图像。我们要等待监控的范围内出现异常情况时再跟踪。

这其实是一个最简单的计算机图像处理程序。简单的思路是这样的:首先给摄像头取景采样,当背景稳定时,以该图片作为基准图片。然后在监控过程中,若出现了和基准图片反差较大的视频帧,那么启动捕捉程序,并标出异常区域。

程序如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <cv.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <highgui.h>
 
#define ESC 0x1b
 
#define TRUE 1
#define FALSE 0
 
// 检测图像异常,仅在采样时调用。
// 返回真表示已检测到异常,需要重新采样。
// 返回假表示未检测到异常,在一定时间后即可获取基准图像。
int detect(CvCapture* capture, IplImage* std, IplImage* frm, CvRect* rect);
 
// 图像采样,确定基准图像,以便监测场景变化
// 返回真表示采样成功,返回假表示采样失败
int gather(CvCapture* capture, IplImage* std, CvRect* rect);
 
// 摄像机监视,用矩形框标示出和基准图像反差较大的图像范围。
void monitor(CvCapture* capture, IplImage* std, CvRect* rect);
 
// 求 x 的平方
int square(int x);
 
int main(int argc, char* argv[])
{
 CvCapture* capture;   // 摄像机源
 IplImage* std;     // 基准图像
 CvRect rect;      // 异常位置矩形标识
 
 capture = cvCreateCameraCapture(0);
 if (!capture) return -1;
 
 std = cvQueryFrame(capture);
 rect = cvRect(-1, -1, 0, 0);
 
 std = cvCloneImage(std);
 
 cvNamedWindow("Monitor Screen");
 
 if (gather(capture, std, &rect))
 {
 monitor(capture, std, &rect);
 }
 
 cvDestroyWindow("Monitor Screen");
 cvReleaseImage(&std);
 cvReleaseCapture(&capture);
 
 return 0;
}
 
int detect(CvCapture* capture, IplImage* std, IplImage* frm, CvRect* rect)
{
 int x, y;            // 循环变量
 int f = FALSE;         // 检测到异常的标识
 int x1 = -1, x2 = 0;      // 异常区域矩形横坐标范围
 int y1 = -1, y2 = 0;      // 异常区域矩形纵坐标范围
 
 uchar *ptr1b, *ptr1g, *ptr1r;  // 基准图像的每个像素的三个颜色通道的值
 uchar *ptr2b, *ptr2g, *ptr2r;  // 实时图像的每个像素的三个颜色通道的值
 
 int squaresum;         // 计算 RGB 差值平方和
 
 // 遍历图像中的每一个点,将实时采样图与基准图做比较,检测两者的每一个
 // 像素点的 RGB 差值平方和。当该值大于 8192 时(换算成灰度值则意味着
 // 两者的灰度差大于 90)则立即报告出现异常,只有遍历完毕后仍未找到异
 // 常才报告没有异常。
 
 for (y = 0; y < std->height; y++)
 {
 for (x = 0; x < std->width; x++)
 {
  ptr1b = cvPtr2D(std, y, x) + 0; ptr2b = cvPtr2D(frm, y, x) + 0;
  ptr1g = cvPtr2D(std, y, x) + 1; ptr2g = cvPtr2D(frm, y, x) + 1;
  ptr1r = cvPtr2D(std, y, x) + 2; ptr2r = cvPtr2D(frm, y, x) + 2;
 
  squaresum =
  square(*ptr1b - *ptr2b) +
  square(*ptr1g - *ptr2g) +
  square(*ptr1r - *ptr2r);
 
  if (squaresum > 8192)
  {
  if (f)
  {
   if (x < x1) x1 = x; else if (x > x2) x2 = x;
   if (y < y1) y1 = y; else if (y > y2) y2 = y;
  }
  else
  {
   f = TRUE;
 
   x1 = x; y1 = y;
   x2 = x; y2 = y;
  }
  }
 }
 }
 
 if (x2 - x1 > frm->width / 4 || y2 - y1 > frm->height / 4)
 {
 f = TRUE;
 }
 else
 {
 f = FALSE;
 }
 
 *rect = cvRect(x1, y1, x2 - x1, y2 - y1);
 return f;
}
 
int gather(CvCapture* capture, IplImage* std, CvRect* rect)
{
 IplImage* frm;
 int except = FALSE;       // 检测到异常的标识
 int finish = FALSE;       // 采样已完成的标识
 clock_t start_time, real_time; // 时间段监测
 
 start_time = clock();
 
 while (!finish)
 {
 frm = cvQueryFrame(capture);
 cvShowImage("Monitor Screen", frm);
 
 except = detect(capture, std, frm, rect);
 
 if (except)
 {
  start_time = clock();
  cvCopyImage(frm, std);
 }
 
 if (cvWaitKey(15) == ESC) break;
 
 real_time = clock();
 if (real_time - start_time >= 3000)
 {
  finish = TRUE;
 }
 }
 
 return finish;
}
 
void monitor(CvCapture* capture, IplImage* std, CvRect* rect)
{
 IplImage* frm;
 int except = FALSE;
 int finish = FALSE;
 
 while (!finish)
 {
 frm = cvQueryFrame(capture);
 
 except = detect(capture, std, frm, rect);
 
 if (except)
 {
  cvRectangle(
  frm,
  cvPoint(rect->x, rect->y),
  cvPoint(rect->x + rect->width, rect->y + rect->height),
  cvScalar(0, 0, 255),
  4);
 }
 cvShowImage("Monitor Screen", frm);
 
 if (cvWaitKey(15) == ESC)
 {
  finish = TRUE;
 }
 }
}
 
int square(int x)
{
 return x * x;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/smallyang0613/article/details/38331233