摄像头实时,并提醒动态物体的出现
之前在学习动态物体的检测时,就想到要编写一个软件,实现远程监控家里的情况,如果自己不在家,却有人进入家里,软件便会自动给我的手机发出警报,基于这个目的,我做出了如下构想
1.判断拍摄到的画面是否发生变化时,要考虑到光线的变化,小动物像虫子等的进入带来的误差,所以我采用了判断前后两张图片的相似度来判断变化。
2.要实现远程连接,必须要经过网络,自己还不具备编写这样软件的能力,那么不妨利用现有的工具,站在巨人的肩膀上总会容易些,所以我利用了qq的上线提醒功能,即电脑登陆qq时,在手机端会有消息提醒。
所以我用了三个函数来实现了这个软件
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include<stdlib.h>
#include<stdio.h>
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
int circle(Mat background, Mat frame);
int semple(Mat m1, Mat m2);
int main()
{
int shiyong,flag=0;
VideoCapture video(0);
//VideoCapture video("bike.mp4");
if (!video.isOpened()) //对video进行异常检测
{
cout << "video open error!" << endl;
return 0;
}
Mat frame;//存储最新帧
Mat frame1;//读取帧
Mat frame2;//读取帧
Mat background;//存储背景帧
int framePosition = 0;//判断当前帧数
while (1)
{
video >> frame1;//读帧进frame
framePosition++;
if (framePosition == 1.0)
{
video >> frame2;//读帧进frame
framePosition++;
background = frame1.clone();//复制
frame = frame2.clone();
}
else
frame = frame1.clone();
shiyong=circle(background, frame);//循环相减
if (shiyong==1&&flag==0&& framePosition>100)//如果图像变化,并且qq没有运行过则运行qq
{
system("D://Bin//QQ.exe");//运行qq
//perror("poweroff");
flag++;
}
background = frame.clone();
if (waitKey(30) == 27) //Esc键退出
{
break;
}
}
return 0;
}
int circle(Mat background, Mat frame)
{
bool re = false;
Mat diff,diffbi;//用diff来存储差图
Mat er;//看看二值图
Mat diff_thresh = background.clone();//用于在background上显示结果
diff.create(frame.size(), frame.type());
diffbi.create(frame.size(), frame.type());
absdiff(background, frame, diff);//减
// 对差值图diff进行阈值化处理
cvtColor(diff, diff, CV_BGR2GRAY);//转化为灰度图
medianBlur(diff, diff, 5);//模糊
threshold(diff, diff, 50, 255, CV_THRESH_BINARY);//灰度图二值化50->128不行
// 对差值图dif进行运算,开运算改为了闭运算。
Mat kernel_erode = getStructuringElement(MORPH_RECT, Size(4, 4));//腐蚀3->5
Mat kernel_dilate = getStructuringElement(MORPH_RECT, Size(14, 14));//膨胀15->14
// 对差值图dif进行膨胀
dilate(diff, diff, kernel_dilate);//膨胀
// 对差值图dif进行腐蚀
erode(diff, diff, kernel_erode);//腐蚀
er = diff.clone();
// 用findContours查找轮廓并用drawContours绘制轮廓
vector<vector<Point>> contours;//contours被定义成二维浮点型向量,用来存储找到的边界的(x,y)坐标。
vector<Vec4i> hierarchy;
findContours(diff, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);//检测轮廓
//drawContours(diff_thresh, contours, -1, Scalar(0, 255, 0), 1, 8);//绘制表面轮廓
//7.查找正外接矩形
int width = 0;
int height = 0;
int x = 0;
int y = 0;
vector<Rect> boundRect(contours.size());
for (int i = 0; i < contours.size(); i++)
{
boundRect[i] = boundingRect(Mat(contours[i]));
// 获得正外接矩形的左上角坐标及宽高
width = boundRect[i].width;
height = boundRect[i].height;
x = boundRect[i].x;
y = boundRect[i].y;
rectangle(diff_thresh, boundRect[i], Scalar(0, 255, 0), 2);//在dif_thresh上绘制正外接矩形
}
//显示图片
imshow("二值图", er);
imshow("差图", diff_thresh);
if(semple(background,frame)==0)
return 0;
else return 1;
}
int semple(Mat background,Mat frame)//判断两张图片的相似度
{
Mat matSrc1, matSrc2;
//CV_Assert(matSrc.channels() == 3);
resize(background, matSrc1, Size(357, 419), 0, 0, INTER_NEAREST);
resize(frame, matSrc2, Size(357, 419), 0, 0, INTER_LANCZOS4);
Mat matDst1, matDst2;
resize(matSrc1, matDst1, Size(8, 8), 0, 0, INTER_CUBIC);
resize(matSrc2, matDst2, Size(8, 8), 0, 0, INTER_CUBIC);
cvtColor(matDst1, matDst1, CV_BGR2GRAY);
cvtColor(matDst2, matDst2, CV_BGR2GRAY);
int iAvg1 = 0, iAvg2 = 0;
int arr1[64], arr2[64];
for (int i = 0; i < 8; i++)
{
uchar* data1 = matDst1.ptr<uchar>(i);
uchar* data2 = matDst2.ptr<uchar>(i);
int tmp = i * 8;
for (int j = 0; j < 8; j++)
{
int tmp1 = tmp + j;
arr1[tmp1] = data1[j] / 4 * 4;
arr2[tmp1] = data2[j] / 4 * 4;
iAvg1 += arr1[tmp1];
iAvg2 += arr2[tmp1];
}
}
iAvg1 /= 64;
iAvg2 /= 64;
for (int i = 0; i < 64; i++)
{
arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;
arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;
}
int iDiffNum = 0;
for (int i = 0; i < 64; i++)
if (arr1[i] != arr2[i])
++iDiffNum;
cout << "iDiffNum = " << iDiffNum << endl;
if (iDiffNum <= 5)
return 0;//相同
else
return 1;//不同
}