人脸识别《一》opencv人脸识别之人脸检测

opencv中已经有人脸识别的功能了,所以来看看整个流程以及具体实现吧。

人脸识别:就是给一个已知人脸贴上一个标签。

上面这句简单的话,其实包含的信息量好大啊,这说明首先你要知道这是一张脸,然后你还要识别出来这个脸属于哪个的。

所以人脸识别具体分为以下几个步骤:

1,人脸检测:从一张图中定位出人脸的位置,只关心这个区域是不是人脸,并不关心这个人是谁。

2,人脸预处理:对人脸做一些预处理,包括人脸图像大小的调整,去噪,亮度对比度均衡,彩色转灰度等,为了下一步得到更好地结果。

3,收集人脸并且学习: 收集已经预处理的统一大小的人脸图像,然后建立学习模型,使用这些数据学习怎样识别出人脸。

4,人脸识别:通过上面的学习模型,对人脸图像识别出待检测图像跟数据库中哪张人脸是最接近的。3是模型的训练,4就是模型的测试

一,人脸检测

     人脸检测首先就是2001 Viola &Jones 发表的Haar-based cascade classifier for object detection, 2002 Lienhart &Maydt对该方法进行了速度和稳定度的改进,正脸正确率可达差不多95%。并且Lienhart 写了opencv可用的检测器可以检测正面人脸,侧脸,眼,鼻,嘴,公司logo等等。之后opencv2.0又扩展了Ahonen, Hadid and Pietikäinen in 2006发表的基于LBP特征的检测器,LBP要比类Haar特征检测器要快很多,并且没有版权问题。

         类Haar特征人脸检测器的基本思想是:如果你观察大多数的人脸区域,会发现眼睛区域的颜色应该比额头和脸颊区域的颜色深,并且嘴巴区域比脸颊区域颜色深等等。它典型的要运行20个阶段这种类似的比较来决定是否是人脸,并且要在每张图像的每个可能位置对每个可能是人脸的尺寸进行检查,所以经常需要对一张图像进行上千次的检查。LBP特征人脸检测器与类Haar类似,但是它使用像素密度对比的直方图,比如边缘,角点以及平坦区域。

         这两个检测器都可以使用XML文件中存储的信息来自动的用大量图像训练从而检测出人脸,典型的,这些级联分类器检测器都要使用1000个人脸图像和1000个非人脸图像来训练,这个训练过程对于多核桌面系统要消耗大量的时间(LBP几个小时,但是类Harr要一周)。opencv中有训练好的Haar和LBP检测器可以使用,可以把级联分类器XML文件加载到物体检测器中,来分别检测正脸,侧脸,眼,鼻,嘴。


分别存储在data\haarcascades data\lbpcascades中,但是opencv中的LBP级联检测器训练的不如Haar,所以如果想要效果好的话就要自己训练LBP,或者使用类Haar。

main.cpp

#include "detectFace.h"

int main(){

	CascadeClassifier facedetector;
	string facecascadeXML = "F:\\opencv\\data\\lbpcascades\\lbpcascade_frontalface.xml";
	try{
		facedetector.load(facecascadeXML);
	}
	catch (Exception e){}
	if (facedetector.empty()){
		cerr<<"ERROR: could not open facedetector :" <<facecascadeXML<<endl;
		exit(1);
	}

	VideoCapture camera;
	camera.open(0);
	if (!camera.isOpened()){
		cerr<<"ERROR: could not open camera "<<endl;
		exit(1);
	}
	camera.set(CV_CAP_PROP_FRAME_HEIGHT,480);
	camera.set(CV_CAP_PROP_FRAME_WIDTH,640);

	while(true){
		Mat cameraFrame;
		camera>>cameraFrame;
		if (cameraFrame.empty()){
			cerr<<"ERROR: could not open cameraframe" <<endl;
			exit(1);
		}
		Rect detectObject;
		detectLargestObject(cameraFrame,facedetector,detectObject);
		rectangle(cameraFrame,Point(detectObject.x,detectObject.y),Point(detectObject.x +detectObject.width,detectObject.y+detectObject.height),Scalar(0,0,255));
		imshow("detect",cameraFrame);
		waitKey(20);
	}
	
}

detectFace.cpp

#include "detectFace.h"       // Easily detect faces or eyes (using LBP or Haar Cascades).


// Search for objects such as faces in the image using the given parameters, storing the multiple cv::Rects into 'objects'.
// Can use Haar cascades or LBP cascades for Face Detection, or even eye, mouth, or car detection.
// Input is temporarily shrunk to 'scaledWidth' for much faster detection, since 200 is enough to find faces.
void detectObjectsCustom(const Mat &img, CascadeClassifier &cascade, vector<Rect> &objects, int scaledWidth, int flags, Size minFeatureSize, float searchScaleFactor, int minNeighbors)
{
	// If the input image is not grayscale, then convert the BGR or BGRA color image to grayscale.
	Mat gray;
	if (img.channels() == 3) {
		cvtColor(img, gray, CV_BGR2GRAY);
	}
	else if (img.channels() == 4) {
		cvtColor(img, gray, CV_BGRA2GRAY);
	}
	else {
		// Access the input image directly, since it is already grayscale.
		gray = img;
	}

	// Possibly shrink the image, to run much faster.
	Mat inputImg;
	float scale = img.cols / (float)scaledWidth;
	if (img.cols > scaledWidth) {
		// Shrink the image while keeping the same aspect ratio.
		int scaledHeight = cvRound(img.rows / scale);
		resize(gray, inputImg, Size(scaledWidth, scaledHeight));
	}
	else {
		// Access the input image directly, since it is already small.
		inputImg = gray;
	}

	// Standardize the brightness and contrast to improve dark images.
	Mat equalizedImg;
	equalizeHist(inputImg, equalizedImg);

	// Detect objects in the small grayscale image.
	cascade.detectMultiScale(equalizedImg, objects, searchScaleFactor, minNeighbors, flags, minFeatureSize);

	// Enlarge the results if the image was temporarily shrunk before detection.
	if (img.cols > scaledWidth) {
		for (int i = 0; i < (int)objects.size(); i++ ) {
			objects[i].x = cvRound(objects[i].x * scale);
			objects[i].y = cvRound(objects[i].y * scale);
			objects[i].width = cvRound(objects[i].width * scale);
			objects[i].height = cvRound(objects[i].height * scale);
		}
	}

	// Make sure the object is completely within the image, in case it was on a border.
	for (int i = 0; i < (int)objects.size(); i++ ) {
		if (objects[i].x < 0)
			objects[i].x = 0;
		if (objects[i].y < 0)
			objects[i].y = 0;
		if (objects[i].x + objects[i].width > img.cols)
			objects[i].x = img.cols - objects[i].width;
		if (objects[i].y + objects[i].height > img.rows)
			objects[i].y = img.rows - objects[i].height;
	}

	// Return with the detected face rectangles stored in "objects".
}


// Search for just a single object in the image, such as the largest face, storing the result into 'largestObject'.
// Can use Haar cascades or LBP cascades for Face Detection, or even eye, mouth, or car detection.
// Input is temporarily shrunk to 'scaledWidth' for much faster detection, since 200 is enough to find faces.
// Note: detectLargestObject() should be faster than detectManyObjects().
void detectLargestObject(const Mat &img, CascadeClassifier &cascade, Rect &largestObject, int scaledWidth)
{
	// Only search for just 1 object (the biggest in the image).
	int flags = CASCADE_FIND_BIGGEST_OBJECT;// | CASCADE_DO_ROUGH_SEARCH;
	// Smallest object size.
	Size minFeatureSize = Size(20, 20);
	// How detailed should the search be. Must be larger than 1.0.
	float searchScaleFactor = 1.1f;
	// How much the detections should be filtered out. This should depend on how bad false detections are to your system.
	// minNeighbors=2 means lots of good+bad detections, and minNeighbors=6 means only good detections are given but some are missed.
	int minNeighbors = 4;

	// Perform Object or Face Detection, looking for just 1 object (the biggest in the image).
	vector<Rect> objects;
	detectObjectsCustom(img, cascade, objects, scaledWidth, flags, minFeatureSize, searchScaleFactor, minNeighbors);
	if (objects.size() > 0) {
		// Return the only detected object.
		largestObject = (Rect)objects.at(0);
	}
	else {
		// Return an invalid rect.
		largestObject = Rect(-1,-1,-1,-1);
	}
}
效果图

光线条件不好的情况下,检测结果很差,开灯之后改善很多,我用的是电脑自带的摄像机,检测结果以及实时性都一般吧。


发布了33 篇原创文章 · 获赞 9 · 访问量 5万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章