摄像头实时,并提醒动态物体的出现

之前在学习动态物体的检测时,就想到要编写一个软件,实现远程监控家里的情况,如果自己不在家,却有人进入家里,软件便会自动给我的手机发出警报,基于这个目的,我做出了如下构想

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;//不同
}

摄像头实时,并提醒动态物体的出现