OpenCV实现屏保智能控制
by 郭世龙
介 绍
通常我们结束屏幕保护程序的方式是晃动鼠标或敲击键盘,有没有不动手的方法呢?比如说声音,最好是我们坐到到电脑前就自动结束屏保。这篇文章将介绍利用摄像头来实现自动控制屏幕保护的方法。原理上很简单,通过检测摄像头捕捉到的是否人脸,如果是则判断屏保程序是否正在运行,如果是则结束屏保程序。屏幕保护程序的控制方法我在
前面的文章 中已经介绍了并提供了C++封装的源代码。人脸检测的部分使用了OpenCV库中的haar人脸检测例程。
实 现
程序由主对话框类、
屏保控制类 、人脸检测封装类构成。主对话框负责设置屏幕保护控制参数包括是否关闭,等待时间,查询时间;屏保控制类完成对屏幕控制的功能;人脸检测负责检测摄像头捕捉到的是否是人脸。主对话框开启一个定时器,每1秒钟发送WM_TIMER消息,在定时器的消息响应函数中有一个计数器负责在对话框动态显示目前经过的时间(自动查询屏保周期),经过一个查询屏保周期之后查询屏幕保护程序是否在运行,如果是则检测人脸检测线程是否开启,如果开启则查询是否检测到人脸,否则开启线程、查询是否检测到人脸。
人脸检测功能封装类
关于OpenCV的这个例程参看
OpenCV中国 这里就不详细介绍了。下面是功能的C++封装代码。
头文件
#ifndef _FaceDetecting_
#define _FaceDetecting_
#define _FaceDetecting_
#include "cv.h"
#include "highgui.h"
#include "highgui.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <time.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <time.h>
#include <ctype.h>
class FaceDetecting
{
public:
FaceDetecting();
~FaceDetecting();
int DetectingFace();
void StopDetecting(bool isStop);
bool isFace();
private:
void detect_and_draw( IplImage* img );
bool isStop;
bool isface;
CvCapture* capture;
FILE *stream; //for running log
IplImage *frame, *frame_copy ;
const char* cascade_name ;
static CvMemStorage* storage ;
static CvHaarClassifierCascade* cascade;
static int faceCounter;
{
public:
FaceDetecting();
~FaceDetecting();
int DetectingFace();
void StopDetecting(bool isStop);
bool isFace();
private:
void detect_and_draw( IplImage* img );
bool isStop;
bool isface;
CvCapture* capture;
FILE *stream; //for running log
IplImage *frame, *frame_copy ;
const char* cascade_name ;
static CvMemStorage* storage ;
static CvHaarClassifierCascade* cascade;
static int faceCounter;
};
#endif
实现文件
#include "stdafx.h"
#include "facedetecting.h"
#include "stdio.h"
#include "facedetecting.h"
#include "stdio.h"
CvMemStorage* FaceDetecting::storage = 0;
CvHaarClassifierCascade* FaceDetecting::cascade = 0;
int FaceDetecting::faceCounter=0;
CvHaarClassifierCascade* FaceDetecting::cascade = 0;
int FaceDetecting::faceCounter=0;
FaceDetecting::FaceDetecting():capture(0),frame(0),frame_copy(0)
,isface(false),isStop(false)
,cascade_name("haarcascade_frontalface_alt.xml")
//haarcascade_frontalface_alt.xml是训练文件
//在Opencv安装目录下的../../data/haarcascades/文
//件夹中。需要拷贝到当前目录中。
{
capture = cvCaptureFromCAM( 0 ); //0 代表设备 id
}
{
capture = cvCaptureFromCAM( 0 ); //0 代表设备 id
}
FaceDetecting::~FaceDetecting()
{
if(NULL!=capture)cvReleaseCapture( &capture );
}
{
if(NULL!=capture)cvReleaseCapture( &capture );
}
int FaceDetecting::DetectingFace()
{
isStop=false;
cascade = (CvHaarClassifierCascade*)cvLoad(cascade_name, 0, 0, 0 );
if( !cascade )
{
stream = fopen( "log.out", "w" );
fprintf( stream, "ERROR: Could not load classifier cascade/n" );
fclose(stream);
return -1;
}
storage = cvCreateMemStorage(0);
// capture = cvCaptureFromCAM( 0 );
//cvNamedWindow( "result", 1 );
{
isStop=false;
cascade = (CvHaarClassifierCascade*)cvLoad(cascade_name, 0, 0, 0 );
if( !cascade )
{
stream = fopen( "log.out", "w" );
fprintf( stream, "ERROR: Could not load classifier cascade/n" );
fclose(stream);
return -1;
}
storage = cvCreateMemStorage(0);
// capture = cvCaptureFromCAM( 0 );
//cvNamedWindow( "result", 1 );
//capture = cvCaptureFromAVI("homes.avi");
//capture = cvCaptureFromFile("homes.avi");
// cvNamedWindow( "result", 1 );
if( capture )
{
stream = fopen( "log.out", "w" );
fprintf( stream, "capture is ok!/n" );
fclose(stream);
//capture = cvCaptureFromFile("homes.avi");
// cvNamedWindow( "result", 1 );
if( capture )
{
stream = fopen( "log.out", "w" );
fprintf( stream, "capture is ok!/n" );
fclose(stream);
for(;;)
{
if(isStop) //外部用来结束人脸检测线程
{
stream = fopen( "log.out", "a" );
fprintf( stream, "Thread is stop!/n" );
fclose(stream);
break;
{
if(isStop) //外部用来结束人脸检测线程
{
stream = fopen( "log.out", "a" );
fprintf( stream, "Thread is stop!/n" );
fclose(stream);
break;
}
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 );
detect_and_draw( frame_copy );
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 );
detect_and_draw( frame_copy );
if( cvWaitKey( 10 ) >= 0 )
break;
}
break;
}
cvReleaseImage( &frame_copy );
// cvReleaseCapture( &capture );
}
// cvDestroyWindow("result");
return 0;
}
// cvReleaseCapture( &capture );
}
// cvDestroyWindow("result");
return 0;
}
//共外部调用插叙是否检测到人脸
bool FaceDetecting::isFace()
{
if(isface) //保证同一次结果不被返回两次
{
isface=false;
return true;
}
return false;
}
bool FaceDetecting::isFace()
{
if(isface) //保证同一次结果不被返回两次
{
isface=false;
return true;
}
return false;
}
void FaceDetecting::detect_and_draw( IplImage* img )
{
int scale = 1;
CvSeq* faces =0;
IplImage* temp = cvCreateImage( cvSize(img->width/scale,img->height/scale), 8, 3 );
CvPoint pt1, pt2;
int i;
//cvPyrDown( img, temp, CV_GAUSSIAN_5x5 );
cvClearMemStorage( storage );
cvClearMemStorage( storage );
if( cascade )
{
faces = cvHaarDetectObjects( img, cascade, storage,
1.1, 2, /*CV_HAAR_DO_CANNY_PRUNING*/0,
cvSize(40, 40) );
stream = fopen( "log.out", "a" );
fprintf( stream, "detect_and_draw may be ok!/n" );
fclose(stream);
{
faces = cvHaarDetectObjects( img, cascade, storage,
1.1, 2, /*CV_HAAR_DO_CANNY_PRUNING*/0,
cvSize(40, 40) );
stream = fopen( "log.out", "a" );
fprintf( stream, "detect_and_draw may be ok!/n" );
fclose(stream);
// isface=faces ? true : false;
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
pt1.x = r->x*scale;
pt2.x = (r->x+r->width)*scale;
pt1.y = r->y*scale;
pt2.y = (r->y+r->height)*scale;
cvRectangle( img, pt1, pt2, CV_RGB(255,0,0), 3, 8, 0 );
}
//如果faces不为空则表示检测到人脸 连续检测到2帧脸则设置真
if(faces->total)
{
//faceCounter++;
if(2==++faceCounter)
{
faceCounter=0;
isface=true;
//Sleep(1000);
}
else
{
isface=false;
}
}
else
{
// faceCounter=0;
isface=false;
}
}
if(faces->total)
{
//faceCounter++;
if(2==++faceCounter)
{
faceCounter=0;
isface=true;
//Sleep(1000);
}
else
{
isface=false;
}
}
else
{
// faceCounter=0;
isface=false;
}
}
// cvShowImage( "result", img );
cvSaveImage("result.bmp", img);
cvReleaseImage( &temp );
}
cvSaveImage("result.bmp", img);
cvReleaseImage( &temp );
}
//外部调用停止检测
void FaceDetecting::StopDetecting(bool isStop)
{
this->isStop=isStop;
void FaceDetecting::StopDetecting(bool isStop)
{
this->isStop=isStop;
}
其 他
这个程序使用了托盘功能,程序启动之后自动在托盘上显示图表并开始执行,支持托盘的右键控制,托盘
图标的功能参见我
以前的文章以及源码 。

这个程序是在以前屏幕保护API测试的程序的基础之上完成的,所以两个程序UI是一样的:)。
这里只提供了release程序的下载,如果需要源程序请留言。