#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/ml/ml.hpp"
#include "cv.h"
#include <iostream>
#include <stdio.h>
//#include "stdlib.h "
using namespace std;
using namespace cv;
static CvMemStorage* storage = 0;
void detectAndDraw(IplImage* img,
CascadeClassifier& cascade, CascadeClassifier& nestedCascade,
double scale);
//String cascadeName = "./lbpcascade_frontalface.xml";//人脸检测器(快速的LBP)
//String cascadeName = "./haarcascade_frontalface_default.xml";//人脸检测器(默认)
String cascadeName = "./haarcascade_frontalface_alt2.xml";//人脸检测器(快速的Haar)
//String nestedCascadeName = "./haarcascade_eye_tree_eyeglasses.xml";//戴眼镜人眼的训练数据
String nestedCascadeName = "./haarcascade_mcs_lefteye.xml";
//String nestedCascadeName = "./haarcascade_eye.xml";//人眼的训练数据
//一、检测区域
//可用来检测睁开或闭着的眼睛:
//haarcascade_mcs_lefteye.xml
//haarcascade_lefteye_2splits.xml
//仅可以检测睁开的眼睛:
//haarcascade_eye.xml
//haarcascade_eye_tree_eyeglasses.xml [仅在带被检测者戴眼镜时方可检测]
//二、使用区别
//1)、在训练检测器中,眼睛睁开、闭合或者左眼还是右眼的数据都是单独训练的。所以我们在使用的时候要使用不同的检测器。
//2)、上述四个检测器的可靠性也是从上往下逐渐降低的,所以我们在不考虑戴眼镜的情况下检测眼镜的时候,第一个检测器是最好的。
//3)、如果对于眼部周围很窄的区域搜索,则haarcascade_eye.xml 的检测效果最好
//4)、如果对于眼部周围较大区域,用haarcascade_mcs_lefteye.xml 、haarcascade_lefteye_2splits.xml 会更好。
int eyesopen = 0;
int eyesclose = 0;
int main(int argc, const char** argv)
{
CvCapture *capture = 0;
IplImage *frame, *frame_copy = 0;
int optlen = strlen("--cascade=");
//const char* input_name;
Mat image;
CascadeClassifier cascade, nestedCascade;//创建级联分类器对象
double scale = 4;
if (!cascade.load(cascadeName))//从指定的文件目录中加载级联分类器
{
cerr << "ERROR: Could not load classifier cascade唉唉出错了" << endl;
return 0;
}
if (!nestedCascade.load(nestedCascadeName))
{
cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
return 0;
}
storage = cvCreateMemStorage(0);
cvNamedWindow("result", 1);
//检测视频
capture = cvCaptureFromAVI("1.mp4");
if (capture)
{
for (;;)
{
if (!cvGrabFrame(capture))
break;
frame = cvRetrieveFrame(capture);
if (!frame)
break;
if (!frame_copy)
frame_copy = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, frame->nChannels);
if (frame->origin == IPL_ORIGIN_TL)
cvCopy(frame, frame_copy, 0);
else
cvFlip(frame, frame_copy, 0);
IplImage *equ = cvCreateImage(cvGetSize(frame_copy), 8, 1);
IplImage *gray = cvCreateImage(cvGetSize(frame_copy), 8, 1);
cvCvtColor(frame_copy, gray, CV_BGR2GRAY);
cvEqualizeHist(gray,equ);
detectAndDraw(frame_copy, cascade, nestedCascade, scale);
if (cvWaitKey(10) >= 0)
break;
}
cvReleaseImage(&frame_copy);
cvReleaseCapture(&capture);
}
cvWaitKey(-1);
//system("pause");
return 0;
}
void detectAndDraw(IplImage* img1,
CascadeClassifier& cascade, CascadeClassifier& nestedCascade,
double scale)
{
cv::Mat img(img1, 0);
int i = 0;//框图颜色
double t = 0;
vector<Rect> faces;
const static Scalar colors[] =
{ CV_RGB(0, 0, 255),
//CV_RGB(0, 128, 255),
//CV_RGB(0, 255, 255),
//CV_RGB(0, 255, 0),
//CV_RGB(255, 128, 0),
//CV_RGB(255, 255, 0),
//CV_RGB(255, 0, 0),
//CV_RGB(255, 0, 255)
};//用不同的颜色表示不同的人脸
Mat gray, smallImg(cvRound(img.rows / scale), cvRound(img.cols / scale), CV_8UC1);//将图片缩小,加快检测速度
cvtColor(img, gray, CV_BGR2GRAY);//因为用的是类haar特征,所以都是基于灰度图像的,这里要转换成灰度图像
resize(gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR);//将尺寸缩小到1/scale,用线性插值
equalizeHist(smallImg, smallImg);//直方图均衡
t = (double)cvGetTickCount();//用来计算算法执行时间
//检测人脸
//detectMultiScale函数中smallImg表示的是要检测的输入图像为smallImg,faces表示检测到的人脸目标序列,1.1表示
//每次图像尺寸减小的比例为1.1,2表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大
//小都可以检测到人脸),CV_HAAR_SCALE_IMAGE表示不是缩放分类器来检测,而是缩放图像,Size(30, 30)为目标的
//最小最大尺寸
cascade.detectMultiScale(smallImg, faces,
1.1, 2, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
| CV_HAAR_SCALE_IMAGE
,
Size(30, 30));
t = (double)cvGetTickCount() - t;//相减为算法执行的时间
printf("detection time = %g ms\n", t / ((double)cvGetTickFrequency()*1000.));
for (vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++)
{
Mat smallImgROI;
vector<Rect> nestedObjects;
Point center;
Scalar color = colors[i % 8];//i%8
int radius;
center.x = cvRound((r->x + r->width*0.5)*scale);//还原成原来的大小
center.y = cvRound((r->y + r->height*0.5)*scale);
radius = cvRound((r->width + r->height)*0.25*scale);
circle(img, center, radius, color, 3, 8, 0);
//检测人眼,在每幅人脸图上画出人眼
if (nestedCascade.empty())
continue;
smallImgROI = smallImg(*r);
//和上面的函数功能一样
nestedCascade.detectMultiScale(smallImgROI, nestedObjects,
1.1, 2, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
//|CV_HAAR_DO_CANNY_PRUNING
| CV_HAAR_SCALE_IMAGE
,
Size(30, 30));
if (nestedObjects.empty())
eyesclose++;
else
eyesopen++;
for (vector<Rect>::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++)
{
center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);
center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);
radius = cvRound((nr->width + nr->height)*0.25*scale);
circle(img, center, radius, color, 3, 8, 0);//将眼睛也画出来,和对应人脸的图形是一样的 radius
//eyesopen++;
}
}
cv::imshow("result", img);
}