OPENCV之人眼检测
来源:互联网 发布:企业管理优化建议 编辑:程序博客网 时间:2024/05/10 01:20
本篇博客主要是对前段时间数字图像课程大作业-疲劳检测所做工作的一次总结整理。主要涉及到的内容有1、基于图片的人脸、人眼检测;2、利用OPENCV实现本地视频与图片帧之间的相互转换;3、基于本地视频的人脸、人眼检测;4、操作笔记本摄像头,实现人脸、人眼检测。
源代码及haar检测器下载见http://download.csdn.net/detail/u011345885/9444335
1、基于图片的人脸、人眼检测
原理: OpenCV利用样本的Haar特征进行分类器训练,得到级联boosted分类器(CascadeClassification),可以检测图片中的眼睛(还支持的有人脸、嘴、鼻子、身体)。
具体操作步骤: 1、将分类器.xml文件放到源程序工程下与你的代码文件处于同一文件(这样在代码中定义路径时,可以免去其他硬盘路径,当然也可以放在任何位置,自己知道位置即可,在代码中做相应路径修改即可)。这些分类器.xml文件在opencv安装包文件下即可找到,以我的电脑为例:opencv-2.4.8->opencv->sources->data->haarcascades;也可以从此处下载:
然后就可以加载分类器进行,特征检测具体代码如下:
// face_detect.cpp : 定义控制台应用程序的入口点。////#include "stdafx.h"#include "opencv2/objdetect/objdetect.hpp"#include "opencv2/highgui/highgui.hpp"#include "opencv2/imgproc/imgproc.hpp"#include "opencv2/ml/ml.hpp"#include <iostream>#include <stdio.h>using namespace std;using namespace cv;void detectAndDraw(Mat& img, CascadeClassifier& cascade, CascadeClassifier& nestedCascade, double scale);String cascadeName = "./haarcascade_frontalface_alt2.xml";//人脸的训练数据//String nestedCascadeName = "./haarcascade_eye_tree_eyeglasses.xml";//人眼的训练数据String nestedCascadeName = "./haarcascade_eye.xml";//人眼的训练数据int main(int argc, const char** argv){ Mat image; CascadeClassifier cascade, nestedCascade;//创建级联分类器对象 double scale = 1.3; //image = imread( "lena.jpg", 1 );//读入lena图片 image = imread("2.jpg", 1); namedWindow("result", 1);//opencv2.0以后用namedWindow函数会自动销毁窗口 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; } if (!image.empty())//读取图片数据不能为空 { detectAndDraw(image, cascade, nestedCascade, scale); waitKey(0); } return 0;}void detectAndDraw(Mat& img, CascadeClassifier& cascade, CascadeClassifier& nestedCascade, double scale){ 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]; 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)); 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);//将眼睛也画出来,和对应人脸的图形是一样的 } } cv::imshow("result", img);}
2.利用OPENCV实现本地视频与图片帧之间的相互转换
直接上代码:
// test3.cpp // // 该程序实现视频和图片的相互转换. // Image_to_video()函数将一组图片合成AVI视频文件. // Video_to_image()函数将AVI视频文件读入,将每一帧存储为jpg文件. // //////////////////////////////////////////////////////////////////////// //#include "stdafx.h"#include <stdlib.h> #include <stdio.h> #include <math.h> #include <cv.h> #include <highgui.h> #define NUM_FRAME 300 //只处理前300帧,根据视频帧数可修改 void Video_to_image(char* filename){ printf("------------- video to image ... ----------------n"); //初始化一个视频文件捕捉器 CvCapture* capture = cvCaptureFromAVI(filename); //获取视频信息 cvQueryFrame(capture); int frameH = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT); int frameW = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH); int fps = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); int numFrames = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT); printf("tvideo height : %dntvideo width : %dntfps : %dntframe numbers : %dn", frameH, frameW, fps, numFrames); //定义和初始化变量 int i = 0; IplImage* img = 0; char image_name[13]; cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE); //读取和显示 while (1) { img = cvQueryFrame(capture); //获取一帧图片 cvShowImage("mainWin", img); //将其显示 char key = cvWaitKey(20); sprintf(image_name, "%s%d%s", "image", ++i, ".jpg");//保存的图片名 cvSaveImage(image_name, img); //保存一帧图片 if (i == NUM_FRAME) break; } cvReleaseCapture(&capture); cvDestroyWindow("mainWin");}void Image_to_video(){ int i = 0; IplImage* img = 0; char image_name[13]; printf("------------- image to video ... ----------------n"); //初始化视频编写器,参数根据实际视频文件修改 CvVideoWriter *writer = 0; int isColor = 1; int fps = 30; // or 25 int frameW = 400; // 744 for firewire cameras int frameH = 240; // 480 for firewire cameras writer = cvCreateVideoWriter("out.avi", CV_FOURCC('X', 'V', 'I', 'D'), fps, cvSize(frameW, frameH), isColor); printf("tvideo height : %dntvideo width : %dntfps : %dn", frameH, frameW, fps); //创建窗口 cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE); while (i<NUM_FRAME) { sprintf(image_name, "%s%d%s", "image", ++i, ".jpg"); img = cvLoadImage(image_name); if (!img) { printf("Could not load image file...n"); exit(0); } cvShowImage("mainWin", img); char key = cvWaitKey(20); cvWriteFrame(writer, img); } cvReleaseVideoWriter(&writer); cvDestroyWindow("mainWin");}int main(int argc, char *argv[]){ char filename[13] = "tree.avi"; Video_to_image(filename); //视频转图片 Image_to_video(); //图片转视频 return 0;}
3.基于本地视频的人脸、人眼检测,事实上是1和2的结合,将视频转换为一帧、一帧的图片帧,再进行人脸、人眼检测。
// face_detect.cpp : 定义控制台应用程序的入口点。 //该程序是读取本地文件视频并识别视频中人脸和眼睛,目前已经成功//#include "stdafx.h" #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> using namespace std;using namespace cv;static CvMemStorage* storage = 0;void detectAndDraw(IplImage* img, CascadeClassifier& cascade, CascadeClassifier& nestedCascade, double scale);String cascadeName = "./haarcascade_frontalface_alt2.xml";//人脸的训练数据 //String nestedCascadeName = "./haarcascade_eye_tree_eyeglasses.xml";//人眼的训练数据 String nestedCascadeName = "./haarcascade_eye.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("tree.avi"); 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); } //image = imread( "lena.jpg", 1 );//读入lena图片 //image = imread("lena.jpg", 1); //namedWindow("result", 1);//opencv2.0以后用namedWindow函数会自动销毁窗口 //if (!image.empty())//读取图片数据不能为空 //{ // detectAndDraw(image, cascade, nestedCascade, scale); // waitKey(0); //} //cout << "eye close:" << eyesclose<<endl<<"eye open:"<<eyesopen<<endl; cvWaitKey(-1); 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]; 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);//将眼睛也画出来,和对应人脸的图形是一样的 //eyesopen++; } } cv::imshow("result", img);}
4.opencv操作摄像头实现人脸和人眼的检测
//#include “stdafx.h”
include
include
include
include
include “opencv2/objdetect/objdetect.hpp”//人脸识别的接口
using namespace cv;//必须加入,否则无法检找到OPENCV的各个函数
using namespace std;
string face_cascade_name = “haarcascade_frontalface_alt2.xml”;
string eye_cascade_name = “./haarcascade_eye.xml”;
CascadeClassifier face_cascade;
CascadeClassifier eye_cascade;
string window_name = “疲劳检测”;
double scale = 2;//在检测本地视频时发现该值为4时,效果比较好,但在摄像头实时视频中取2值比较好
void detectAndDisplay(Mat frame){
std::vector faces;
std::vector eyes;
Mat frame_gray,smallframe_gray(cvRound(frame.rows/scale),cvRound(frame.cols/scale),CV_8UC1);//将图片缩小,加快检测速度
cvtColor(frame, frame_gray, CV_BGR2GRAY);equalizeHist(frame_gray, frame_gray);resize(frame_gray, smallframe_gray, smallframe_gray.size(), 0, 0, INTER_LINEAR);//将尺寸缩小到1/scale,用线性差值face_cascade.detectMultiScale(smallframe_gray, faces, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));for (int i = 0; i < faces.size(); i++){ Point center(cvRound((faces[i].x + faces[i].width*0.5)*scale), cvRound((faces[i].y + faces[i].height*0.5)*scale)); ellipse(frame, center, Size(faces[i].width*0.5*scale, faces[i].height*0.5*scale), 0, 0, 360, Scalar(255, 0, 255), 4, 8, 0); eye_cascade.detectMultiScale(smallframe_gray, eyes, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); for (int i = 0; i < eyes.size(); i++){ Point center(cvRound((eyes[i].x + eyes[i].width*0.5)*scale), cvRound((eyes[i].y + eyes[i].height*0.5)*scale)); ellipse(frame, center, Size(eyes[i].width*0.5*scale, eyes[i].height*0.5*scale), 0, 0, 360, Scalar(255, 0, 255), 4, 8, 0); }}imshow(window_name, frame);
}
int main()
{
//double scale = 4;
VideoCapture cap(0); // open the default camera
if (!cap.isOpened()) // check if we succeeded
return -1;
Mat edges;//namedWindow("edges", 1);if (!face_cascade.load(face_cascade_name)){ printf("[error] 无法加载face级联分类器文件!\n"); return -1;}if (!eye_cascade.load(eye_cascade_name)){ printf("[error] 无法加载eye级联分类器文件!\n"); return -1;}int nTick = 0;for (;;){ if (!cap.isOpened()) {//等等摄像头打开 continue; } Mat frame; nTick = getTickCount(); cap >> frame; // get a new frame from camera if (frame.data == NULL) {//等到捕获到数据 continue; } cvtColor(frame, edges, CV_BGR2BGRA); detectAndDisplay(edges); if (waitKey(30) >= 0) break;}return 0;
}
- OPENCV之人眼检测
- openCV之人脸检测
- 【OpenCV笔记 16-2】OpenCV人脸检测和人眼检测之LBP分类器
- opencv人眼检测识别
- 人眼疲劳检测之opencv人眼检测xml说明
- opencv例程之人脸检测
- Opencv之人脸肤色检测总结
- opencv提高之人脸检测
- opencv之边缘检测
- OpenCV 之 边缘检测
- opencv之边缘检测
- OpenCV之轮廓检测
- opencv之人脸检测之cv2.CascadeClassifier
- opencv轮廓检测之椭圆检测
- opencv特征检测之角点检测
- opencv-人眼检测,人眼跟踪
- opencv之矩形物体检测
- opencv之灰度图强角点检测
- 关于iOS多线程
- My架构师之路
- CSS水平/垂直居中方法一览
- js基础
- UVA 230(p136)----Borrowers
- OPENCV之人眼检测
- Linux精讲——cp命令
- 喊啥--主页面代码
- Spring Aop 表达式匹配
- UVA 247(p365)----Calling Circles
- leetcode随笔II
- Objective-C Runtime
- Java游戏服务端编程心得
- UVA 253(p97)----Cube painting