项目场景:对于高空抛物、在无人仓库内检测是否有动物入侵。、
实现需求:检测到事件发出事件告警,标出物体坐标和图片。
附上源码一份:
#include"opencv2/opencv.hpp"
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <zmq.h>
#define NUM 200 // images save max num
using namespace std;
string path = "/home/nvidia/Desktop/Veolia/animalRecognize2/imgs/";
void saveImg(string& savePath, Mat &frame);
//运动物体检测函数声明
Mat MoveDetect(int &flag, Mat temp, Mat frame);
int main(int argcs, char** argvs)
{
/*------------------------*/
// create publisher
char tcp[100] = "tcp://*:";
strcat(tcp,argvs[2]);
printf("tcp:%s\n",tcp);
void *context = zmq_ctx_new();
// create publisher
void *publisher = zmq_socket(context, ZMQ_PUB);
// bind pub to localhost
// int ret = zmq_bind(publisher, "tcp://*:5555");
int ret = zmq_bind(publisher, tcp);
assert(ret == 0);
printf("publisher created!\n");
/*------------------------*/
//读取帧、平滑、帧差或背景差、二值化、膨胀、腐蚀。
VideoCapture video(argvs[1]);
if (!video.isOpened())
return -1;
int i = 0;
//int frameCount = video.get(CAP_PROP_FRAME_COUNT);//获取帧数
double FPS = video.get(CAP_PROP_FPS);//获取FPS
int interval = 1000.0 / FPS;
Mat frame;//存储帧
Mat temp;//存储前一帧图像
Mat result;//存储结果图像
int frameCount = 0;
int flag = 0; //index wether detect movement
while (video.isOpened())
{
// for (int i = 0; i < frameCount; i++)
// {
//读取帧
video >> frame;//读帧进frame
// jump one frame
frameCount ++;
if(frameCount>10000) frameCount=1;
if ((frameCount % 3) != 0) continue;
//if(i%2)continue;
if (frame.empty())//对帧进行异常检测
{
cout << "frame is empty!" << endl;
while(1){
VideoCapture video(argvs[1]);
video >> frame;
if (!video.isOpened())return -1;
if(!frame.empty())break;
}
}
// resize
Size dsize = Size(800, 600);
resize(frame, frame, dsize, INTER_LINEAR);
// cout<<"w: "<<frame.cols<<", h: "<<frame.rows<<endl;
//处理帧
flag = 0;
if (i == 0)//如果为第一帧(temp还为空)
{
//cout<<"first frame "<<endl;
//调用MoveDetect()进行运动物体检测,返回值存入result
result = MoveDetect(flag, frame, frame);
}
else//若不是第一帧(temp有值了)
{
//cout<<"frame id : "<<i<<endl;
result = MoveDetect(flag, temp, frame);//调用MoveDetect()进行运动物体检测,返回值存入result
// cout<<"i: "<<i<<endl;
}
imshow("result", result);
/*-------------------------*/
if (flag == 1){
int n = i%NUM;
string savePath = path + to_string(n) + ".jpg";
saveImg(savePath, result);
// send msg
// msg.trigger = flag;
// msg.address = savePath;
char send_buf[256];
sprintf(send_buf, "community:%s;type:animal;cameraid:%s;url:%s;imageUrl:",argvs[3], argvs[4],argvs[1]);
strcat(send_buf,savePath.c_str());
cout << send_buf << endl;
int ret = zmq_send(publisher, send_buf, strlen(send_buf)+1, 0);
}
if (waitKey(interval) == 27)//按原FPS显示
{
cout << "ESC退出!" << endl;
break;
}
// temp = frame.clone();
temp = frame;
// imshow("temp", temp);
i++;
if (i>1000) i=1;
// }
}
destroyAllWindows();
zmq_close(publisher);
zmq_ctx_destroy(context);
return 0;
}
Mat MoveDetect(int &flag, Mat temp, Mat frame)
{
//平滑、帧差或背景差、二值化、膨胀、腐蚀。
Mat result = frame.clone();
//将background和frame转为灰度图
Mat gray1, gray2;
cvtColor(temp, gray1, COLOR_BGR2GRAY);
cvtColor(frame, gray2, COLOR_BGR2GRAY);
//将background和frame做差
Mat diff;
absdiff(gray1, gray2, diff);
//imshow("帧差图", diff);
//对差值图diff_thresh进行阈值化处理 二值化
Mat diff_thresh;
Mat kernel_erode = getStructuringElement(MORPH_RECT, Size(3, 3));
Mat kernel_dilate = getStructuringElement(MORPH_RECT, Size(18, 18));
//进行二值化处理,选择50,255为阈值
threshold(diff, diff_thresh, 50, 255, THRESH_BINARY);
//imshow("二值化处理后", diff_thresh);
//腐蚀
erode(diff_thresh, diff_thresh, kernel_erode);
//膨胀
dilate(diff_thresh, diff_thresh, kernel_dilate);
//imshow("膨胀处理后", diff_thresh);
//imshow("腐蚀处理后", diff_thresh);
//查找轮廓并绘制轮廓
vector<vector<Point> > contours;
findContours(diff_thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_NONE);//找轮廓函数
drawContours(result, contours, -1, Scalar(0, 0, 255), 2);//在result上绘制轮廓
// drawContours(frame, contours, -1, Scalar(0, 0, 255), 2);//在result上绘制轮廓
//查找正外接矩形
vector<Rect> boundRect(contours.size());
Rect result_bbox;
double area = 0;
for (int i = 0; i < contours.size(); i++)
{
boundRect[i] = boundingRect(contours[i]);
if(boundRect[i].width<30 || boundRect[i].height<30)continue;
//if(boundRect[i].width*boundRect[i].height>area) result_bbox = boundRect[i];
rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);//在result上绘制正外接矩形 green
// rectangle(frame, boundRect[i], Scalar(0, 255, 0), 2);//在result上绘制正外接矩形 green
flag = 1; // movement detected
}
//rectangle(result, boundRect[i], Scalar(0, 255, 0), 2);
return result;//返回result
}
void saveImg(string& savePath, Mat &frame){
// int n = i%NUM;
// string savePath = path + to_string(n) + ".jpg";
if (access(savePath.c_str(),0) != -1){
// cout<< "file exists" << savePath << endl;
// delete
remove(savePath.c_str());
//save
imwrite(savePath, frame);
}
else{
// cout<<"file not exist"<< savePath <<endl;
//save
imwrite(savePath, frame);
}
}