最近发现一篇报道,十分好玩,有兴趣的可以点击下面的链接
然后就写了这个小视频或者摄像头监控Demo玩玩。
1.主要使用OpenCv
2.帧差法与Cascade相结合
Demo主要利用帧差法(主要是CvSub和cvAbsDiff,感兴趣的同学可以搜搜)实现移动物体检测,后利用cascade分类器检测路人。十分简单。
1.第一步利用帧差法,做移动物体检测
bool MoveCheck(IplImage *PreImg,IplImage*Currnet,CvRect& rc)
{
//cvNamedWindow("diff", CV_WINDOW_AUTOSIZE);
vector<CvPoint2D32f> bPt;
bPt.clear();
int n = 0;
if (PreImg->width != Currnet->width || PreImg->height != Currnet->height)
{
return false;
}
IplImage* bImage1 = nullptr;
IplImage* bImage2 = nullptr;
IplImage *dImage = nullptr;
IplImage *bImage = nullptr;
//使用openmp 加快处理速度
#pragma omp sections
{
#pragma omp section
{
if (PreImg->nChannels = 3)
{
bImage1 = cvCreateImage(cvSize(PreImg->width, PreImg->height), 8, 1);
cvCvtColor(PreImg, bImage1, CV_BGR2GRAY);
}
else
{
bImage1 = cvCloneImage(PreImg);
}
cvSmooth(bImage1, bImage1);
bImage = cvCreateImage(cvSize(PreImg->width, PreImg->height), 8, 1);
}
#pragma omp section
{
if (Currnet->nChannels = 3)
{
bImage2 = cvCreateImage(cvSize(Currnet->width, Currnet->height), 8, 1);
cvCvtColor(Currnet, bImage2, CV_BGR2GRAY);
}
else
{
bImage2 = cvCloneImage(Currnet);
}
cvSmooth(bImage2, bImage2);
dImage = cvCreateImage(cvSize(PreImg->width, PreImg->height), 8, 1);
}
}
int MinThre = 80;
IplImage *rImage = cvCreateImage(cvSize(PreImg->width, PreImg->height), 8, 1);
//帧差法
cvSub(bImage1, bImage2, bImage);
cvAbsDiff(bImage1, bImage2, dImage);
//加一个add 增强一下效果
cvAdd(bImage, dImage, rImage);
cvThreshold(rImage, rImage, 80, 255, CV_THRESH_BINARY);
cvErode(rImage, rImage);
IplConvKernel *pele = cvCreateStructuringElementEx(4,4,2,2,CV_SHAPE_ELLIPSE);
//突出一下关机点
cvDilate(rImage, rImage, pele);
cvReleaseStructuringElement(&pele);
//cvShowImage("diff", rImage);
//cvWaitKey(10);
CvMemStorage *pStorage = cvCreateMemStorage(0);
CvSeq *pContour = nullptr;
cvFindContours(rImage, pStorage, &pContour);
for (CvSeq *bSeq = pContour; bSeq != NULL;bSeq=bSeq->h_next)
{
if (bSeq->total < 6)
{
continue;
}
#pragma omp for
for (int i = 0; i < bSeq->total;i++)
{
CvPoint bPt1 = *(CvPoint*)cvGetSeqElem(bSeq, i);
bPt.push_back(cvPoint2D32f(bPt1.x, bPt1.y));
}
}
if (bPt.size() > 0)
{
int minX, maxX, minY, maxY;
//找最大的x和最小的x
sort(bPt.begin(), bPt.end(), Max_x);
maxX = (int)bPt.at(0).x;
minX = (int)bPt.at(bPt.size() - 1).x;
//找最大的y和最小的y
sort(bPt.begin(), bPt.end(), Max_y);
maxY = (int)bPt.at(0).y;
minY = (int)bPt.at(bPt.size() - 1).y;
rc.x = minX;
rc.y = minY;
rc.width = maxX - minX;
rc.height = maxY - minY;
if (rc.width < 5)
{
rc.width = 20;
}
if (rc.height < 5)
{
rc.height = 20;
}
}
cvReleaseMemStorage(&pStorage);
cvReleaseImage(&bImage1);
cvReleaseImage(&bImage2);
cvReleaseImage(&bImage);
cvReleaseImage(&dImage);
cvReleaseImage(&rImage);
return true;
}
第二步,用CvHaarClassifierCascade做人体检测
int PeopleDetection(CvHaarClassifierCascade* body_Classifier, IplImage *src, CvRect *bRect)
{
int num = -1;
IplImage *cvtImage = cvCreateImage(cvSize(src->width, src->height), 8, 1);
// = (CvHaarClassifierCascade*)cvLoad(faceCascadeFilename, 0, 0, 0);
if (src->nChannels != 1)
{
cvCvtColor(src, cvtImage, CV_BGR2GRAY);
}
else
{
cvtImage = cvCloneImage(src);
}
cvCvtColor(src, cvtImage, CV_BGR2GRAY);
//加快运算速度,图像缩小一半
IplImage *ReImage = cvCreateImage(cvSize(src->width/2, src->height/2), 8, 1);
cvResize(cvtImage, ReImage);
CvMemStorage *pStorage = cvCreateMemStorage(0);
const double scale_factore = 1.1f;
const int flag = CV_HAAR_DO_CANNY_PRUNING;
CvSeq *pSeq = cvHaarDetectObjects(ReImage, body_Classifier, pStorage, scale_factore, 3, flag, cvSize(20, 20));
num = pSeq->total;
for (int i = 0; i < (pSeq->total); i++)
{
bRect[i] = *(CvRect *)cvGetSeqElem(pSeq, i);
bRect[i].x *= 2;
bRect[i].y *= 2;
bRect[i].width *= 2;
bRect[i].height *= 2;
}
cvReleaseImage(&ReImage);
cvReleaseImage(&cvtImage);
cvReleaseMemStorage(&pStorage);
return num;
}
然后,分类的效果很不理想老是会误检,不过只是一个demo,不影响
下面给出整个工程代码
// Demo.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
#include "cv.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\objdetect\objdetect.hpp>
#include "opencv2/core/internal.hpp"
#include <string>
#include <fstream>
#include<windows.h>
using namespace std;
using namespace cv;
//定义路径
const char *faceCascadeFilename = "haarcascade_frontalface_alt_tree.xml";
const char* bodyCascadeFilename = "haarcascade_fullbody.xml";
const char* UpbodyCascadeFilename = "haarcascade_upperbody.xml";
#define TEST 1
bool Max_x(CvPoint2D32f p1, CvPoint2D32f p2)
{
return p1.x > p2.x;
}
bool Max_y(CvPoint2D32f p1, CvPoint2D32f p2)
{
return p1.y > p2.y;
}
int FaceDetection(CvHaarClassifierCascade* face_Classifier,IplImage *src, CvRect *bRect)
{
int num = -1;
IplImage *cvtImage = cvCreateImage(cvSize(src->width, src->height), 8, 1);;
// = (CvHaarClassifierCascade*)cvLoad(faceCascadeFilename, 0, 0, 0);
if (src->nChannels != 1)
{
cvCvtColor(src, cvtImage, CV_BGR2GRAY);
}
else
{
cvtImage = cvCloneImage(src);
}
cvCvtColor(src, cvtImage, CV_BGR2GRAY);
//整张脸
CvMemStorage *pStorage = cvCreateMemStorage(0);
const double scale_factore = 1.1f;
const int flag = CV_HAAR_DO_CANNY_PRUNING;
CvSeq *pSeq = cvHaarDetectObjects(cvtImage, face_Classifier, pStorage, scale_factore, 3, flag, cvSize(20, 20));
num = pSeq->total;
for (int i = 0; i < (pSeq->total); i++)
{
bRect[i] = *(CvRect *)cvGetSeqElem(pSeq, i);
}
cvReleaseImage(&cvtImage);
cvReleaseMemStorage(&pStorage);
return num;
}
int PeopleDetection(CvHaarClassifierCascade* body_Classifier, IplImage *src, CvRect *bRect)
{
int num = -1;
IplImage *cvtImage = cvCreateImage(cvSize(src->width, src->height), 8, 1);
// = (CvHaarClassifierCascade*)cvLoad(faceCascadeFilename, 0, 0, 0);
if (src->nChannels != 1)
{
cvCvtColor(src, cvtImage, CV_BGR2GRAY);
}
else
{
cvtImage = cvCloneImage(src);
}
cvCvtColor(src, cvtImage, CV_BGR2GRAY);
IplImage *ReImage = cvCreateImage(cvSize(src->width/2, src->height/2), 8, 1);
cvResize(cvtImage, ReImage);
//整张脸
CvMemStorage *pStorage = cvCreateMemStorage(0);
const double scale_factore = 1.1f;
const int flag = CV_HAAR_DO_CANNY_PRUNING;
CvSeq *pSeq = cvHaarDetectObjects(ReImage, body_Classifier, pStorage, scale_factore, 3, flag, cvSize(20, 20));
num = pSeq->total;
for (int i = 0; i < (pSeq->total); i++)
{
bRect[i] = *(CvRect *)cvGetSeqElem(pSeq, i);
bRect[i].x *= 2;
bRect[i].y *= 2;
bRect[i].width *= 2;
bRect[i].height *= 2;
}
cvReleaseImage(&ReImage);
cvReleaseImage(&cvtImage);
cvReleaseMemStorage(&pStorage);
return num;
}
int PeopleDetection(HOGDescriptor hog,IplImage *src, CvRect *bRect)
{
IplImage *cvtImage = cvCreateImage(cvSize(src->width, src->height), 8, 1);;
// = (CvHaarClassifierCascade*)cvLoad(faceCascadeFilename, 0, 0, 0);
if (src->nChannels != 1)
{
cvCvtColor(src, cvtImage, CV_BGR2GRAY);
}
else
{
cvtImage = cvCloneImage(src);
}
int num = -1;
vector<Rect> found;
Mat bMat(cvtImage, true);
hog.detectMultiScale(bMat, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);
if (found.size() == 0)
{
return num;
}
num = found.size();
for (int i = 0; i < num;i++)
{
bRect[i].x = found.at(i).tl().x;
bRect[i].y = found.at(i).tl().y;
bRect[i].width = found.at(i).width;
bRect[i].height = found.at(i).height;
}
cvReleaseImage(&cvtImage);
return num;
}
bool MoveCheck(IplImage *PreImg,IplImage*Currnet,CvRect& rc)
{
//cvNamedWindow("diff", CV_WINDOW_AUTOSIZE);
vector<CvPoint2D32f> bPt;
bPt.clear();
int n = 0;
if (PreImg->width != Currnet->width || PreImg->height != Currnet->height)
{
return false;
}
IplImage* bImage1 = nullptr;
IplImage* bImage2 = nullptr;
IplImage *dImage = nullptr;
IplImage *bImage = nullptr;
#pragma omp sections
{
#pragma omp section
{
if (PreImg->nChannels = 3)
{
bImage1 = cvCreateImage(cvSize(PreImg->width, PreImg->height), 8, 1);
cvCvtColor(PreImg, bImage1, CV_BGR2GRAY);
}
else
{
bImage1 = cvCloneImage(PreImg);
}
cvSmooth(bImage1, bImage1);
bImage = cvCreateImage(cvSize(PreImg->width, PreImg->height), 8, 1);
}
#pragma omp section
{
if (Currnet->nChannels = 3)
{
bImage2 = cvCreateImage(cvSize(Currnet->width, Currnet->height), 8, 1);
cvCvtColor(Currnet, bImage2, CV_BGR2GRAY);
}
else
{
bImage2 = cvCloneImage(Currnet);
}
cvSmooth(bImage2, bImage2);
dImage = cvCreateImage(cvSize(PreImg->width, PreImg->height), 8, 1);
}
}
int MinThre = 80;
IplImage *rImage = cvCreateImage(cvSize(PreImg->width, PreImg->height), 8, 1);
cvSub(bImage1, bImage2, bImage);
cvAbsDiff(bImage1, bImage2, dImage);
cvAdd(bImage, dImage, rImage);
cvThreshold(rImage, rImage, 80, 255, CV_THRESH_BINARY);
cvErode(rImage, rImage);
IplConvKernel *pele = cvCreateStructuringElementEx(4,4,2,2,CV_SHAPE_ELLIPSE);
cvDilate(rImage, rImage, pele);
cvReleaseStructuringElement(&pele);
//cvShowImage("diff", rImage);
//cvWaitKey(10);
CvMemStorage *pStorage = cvCreateMemStorage(0);
CvSeq *pContour = nullptr;
cvFindContours(rImage, pStorage, &pContour);
for (CvSeq *bSeq = pContour; bSeq != NULL;bSeq=bSeq->h_next)
{
if (bSeq->total < 6)
{
continue;
}
#pragma omp for
for (int i = 0; i < bSeq->total;i++)
{
CvPoint bPt1 = *(CvPoint*)cvGetSeqElem(bSeq, i);
bPt.push_back(cvPoint2D32f(bPt1.x, bPt1.y));
}
}
if (bPt.size() > 0)
{
int minX, maxX, minY, maxY;
sort(bPt.begin(), bPt.end(), Max_x);
maxX = (int)bPt.at(0).x;
minX = (int)bPt.at(bPt.size() - 1).x;
sort(bPt.begin(), bPt.end(), Max_y);
maxY = (int)bPt.at(0).y;
minY = (int)bPt.at(bPt.size() - 1).y;
rc.x = minX;
rc.y = minY;
rc.width = maxX - minX;
rc.height = maxY - minY;
if (rc.width < 5)
{
rc.width = 20;
}
if (rc.height < 5)
{
rc.height = 20;
}
}
cvReleaseMemStorage(&pStorage);
cvReleaseImage(&bImage1);
cvReleaseImage(&bImage2);
cvReleaseImage(&bImage);
cvReleaseImage(&dImage);
cvReleaseImage(&rImage);
return true;
}
int main(int argc, _TCHAR* argv[])
{
cvNamedWindow("frame", CV_WINDOW_AUTOSIZE);
CvHaarClassifierCascade* face_Classifier = (CvHaarClassifierCascade*)cvLoad(faceCascadeFilename, 0, 0, 0);
CvHaarClassifierCascade* body_Classifier = (CvHaarClassifierCascade*)cvLoad(bodyCascadeFilename, 0, 0, 0);
CvHaarClassifierCascade* car_Classifier = (CvHaarClassifierCascade*)cvLoad("cascade1203_20.xml");
//stop area;
CvRect StopRect = cvRect(200, 100, 300, 300);
HOGDescriptor hog;
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
CvRect bRect;
//这部分可以换成摄像机
CvCapture* capture = cvCreateFileCapture("vtest.avi");
IplImage* PreFrame = nullptr;
IplImage* CurrentImg = nullptr;
IplImage* ShowImg = nullptr;
int num = 0;
while (true)
{
if (CurrentImg!=nullptr)
{
cvReleaseImage(&CurrentImg);
}
CurrentImg = cvCloneImage(cvQueryFrame(capture));
if (CurrentImg==NULL)
{
break;
}
if (ShowImg != nullptr)
{
cvReleaseImage(&ShowImg);
}
ShowImg = cvCloneImage(CurrentImg);
if (num==0)
{
if (PreFrame != nullptr)
{
cvReleaseImage(&PreFrame);
}
PreFrame = cvCloneImage(CurrentImg);
num = 1;
continue;
}
CvPoint2D32f Pt[1000];
cvRectangle(ShowImg, cvPoint(StopRect.x, StopRect.y), cvPoint(StopRect.x + StopRect.width, StopRect.y + StopRect.height), cvScalar(0, 0, 255));
int Num = 0;
double start = (double)GetTickCount();
if (MoveCheck(PreFrame, CurrentImg, bRect))
{
double end = (double)GetTickCount();
printf("Move Check Cost:%f\n", end - start);
printf("SomeThing is Moving\n");
cvRectangle(ShowImg, cvPoint(bRect.x, bRect.y), cvPoint(bRect.x + bRect.width, bRect.y + bRect.height), cvScalar(255, 0, 0));
//开始行人检测
CvRect PRect[100];
double bStart = (double)GetTickCount();
//int total = PeopleDetection(hog,CurrentImg, PRect);
int total = PeopleDetection(body_Classifier, CurrentImg, PRect);
double bEnd = (double)GetTickCount();
printf("PeopleDetection Cost:%f\n", bEnd-bStart);
if (total>0)
{
printf("there is %d people\n", total);
#pragma omp parallel for
for (int i = 0; i < total;i++)
{
if (PRect[i].x >= StopRect.x&&PRect[i].x < StopRect.x + StopRect.width&PRect[i].y >= StopRect.y&&PRect[i].x < StopRect.y + StopRect.height)
{
cvRectangle(ShowImg, cvPoint(PRect[i].x, PRect[i].y), cvPoint(PRect[i].x + PRect[i].width, PRect[i].y + PRect[i].height), cvScalar(0, 0, 255));
}
else
{
cvRectangle(ShowImg, cvPoint(PRect[i].x, PRect[i].y), cvPoint(PRect[i].x + PRect[i].width, PRect[i].y + PRect[i].height), cvScalar(0, 255, 0));
}
}
}
if (PreFrame != nullptr)
{
cvReleaseImage(&PreFrame);
}
PreFrame = cvCloneImage(CurrentImg);
}
else
{
//printf("Safe\n");
}
cvShowImage("frame", ShowImg);
cvWaitKey(10);
}
return 0;
}
检测效果如下,感觉还不错
自己买一个,高清摄像头就可以当做监控使用了,后面你还可以自己加上视频保存啊,人脸识别啊等等。