目标识别:如何从人脸图片中扣出眼图,实时人脸人眼检测和识别

一、了解opencv级联多级分类器

我们使用opencv级联多级分类器进行解读:

1.基本概念 
opencv中的人脸检测使用基于Harr的级联分类和基于LBP的级联分类。 
Harr是在2001年,由Viola和Jones等人提出的,它的脸部检测的基本思想是:对于面部正面的大部分区域而言,会有眼睛所在的区域比前额和脸颊更暗,嘴巴应该比脸颊更暗等情况。和这样类似的比较大约有20个,通过这样的比较决定该区域是否为人脸。 
LBP是在2006年由Ahonen等人提出的,相比于Harr,LBP有更快的速度。通过比较想读亮度直方图来确定是否为人脸。但是对于稳定性,LBP要弱于前者。 
Opencv自带训练好的人脸检测模型,存储在sources/data/haarcascades文件夹和sources/data/lbpcascades文件夹下。其中几个.xml文件如下: 
人脸检测器(默认):haarcascade_frontalface_default.xml 
人脸检测器(快速Harr):haarcascade_frontalface_alt2.xml 
人脸检测器(侧视):haarcascade_profileface.xml 
眼部检测器(左眼):haarcascade_lefteye_2splits.xml 
眼部检测器(右眼):haarcascade_righteye_2splits.xml 
嘴部检测器:haarcascade_mcs_mouth.xml 
鼻子检测器:haarcascade_mcs_nose.xml 
身体检测器:haarcascade_fullbody.xml 
人脸检测器(快速LBP):lbpcascade_frontalface.xml
--------------------- 

2.如何使用

2.1 加载一个检测器:应用CascadeClassifier并实例化,写入文件路径并加载。

CascadeClassifier face_cascade;
String face_cascade_name = "C:\\Program Files\\OpenCV2.4.11\\opencv\\sources\\data\\lbpcascades\\lbpcascade_frontalface.xml";  
face_cascade.load( face_cascade_name );

2.2 图像预处理:灰度变换,收缩尺寸和直方图均衡化

cvtColor( frame, frame_gray, CV_BGR2GRAY );
const int DETECTION_WIDTH = 320;
Mat smallImg;
float scale = frame_gray.cols/(float)DETECTION_WIDTH;
if (frame_gray.cols>DETECTION_WIDTH)
{
    int scaledHeight = cvRound(frame_gray.rows/scale);
    resize(frame_gray,smallImg.size(DETECTION_WIDTH,scaledHeight));
}
else
{
    smallImg = frame_gray;
}
Mat equalizedImg;
equalizeHist( smallImg , equalizedImg);

2.3人脸检测

std::vector faces;
face_cascade.detectMultiScale( equalizedImg, faces, 1.1, 2, 0, Size(80, 80) );

此时检测结果保存在faces这个vector容器中。

3.几个使用技巧 
3.1 在加载检测器时通常由于路径问题容易产生错误,最好有一个提醒或异常捕获机制。

    face_cascade.load( face_cascade_name );
    if( !face_cascade.load( face_cascade_name ) )
    { printf("--(!)Error loading\n"); return -1; };

或者

    try {   
        face_cascade.load( face_cascade_name );
    } catch (cv::Exception &e) {}
    if ( face_cascade_name.empty() ) {
        printf("--(!)Error loading\n"); return -1; 
        exit(1);
    }

3.2根据情况设置参数 
detectMultiScale函数原型如下:

 CV_WRAP virtual void detectMultiScale( const Mat& image,
                      CV_OUT vector& objects,
                      double scaleFactor=1.1,
                      int minNeighbors=3, int flags=0,
                      Size minSize=Size(),
                      Size maxSize=Size() );

其中: 
minSize=Size()和maxSize=Size(): 决定了检测到的最小和最大的人脸大小,如果图片中人脸距离相机较远,把minSize参数设置为=Size(20,20) 
scaleFactor:参数决定由多少不同大小的人脸要搜索,通常为1.1 
minNeighbors: 决定着人脸检测器如何确定人脸已经被找到,默认值是3,如果改为4的话,将会使检测的正确率增加,但是漏检率也可能增加,可以理解为参数越大,判断的条件越苛刻。 
flags:是否要检测所有人脸。
--------------------- 
作者:chaibubble 
来源:CSDN 
原文:https://blog.csdn.net/chaipp0607/article/details/54234663 
 

 

第一种方法:

眼球中心定位
现在截取出了眼部ROI图像,就到了之前提到的那个论文的方法了,《Accurate eye centre localisation by means of gradients》。其实它用到的方法很好理解,一副图像,每个像素点都可以计算出梯度,而梯度包含了幅值和方向。对于眼部图像而言,越是靠近眼球中心的位置,灰度值就越低,就会有更多的梯度方向的连线交于那个点。
 

眼球中心定位跟踪算法—eyelike

 





第二种方法:

 

// 1-Face_Eye.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"

#include "opencv.hpp"
#include "highgui.h"
#include 
#include 
using namespace cv;

CascadeClassifier face_cascade;
CascadeClassifier eye_cascade;
//  人眼检测
int detectEye(cv::Mat& im, cv::Mat& tpl, cv::Rect& rect)
{
	std::vector faces, eyes;
	// 多尺度人脸检测
	face_cascade.detectMultiScale(im, faces,
		1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, cv::Size(30, 30));
	// 遍历人脸检测结果查找人眼目标
	for (int i = 0; i < faces.size(); i++)
	{
		cv::Mat face = im(faces[i]);
		// 多尺度人眼检测
		eye_cascade.detectMultiScale(face, eyes,
			1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, cv::Size(20, 20));
		// 人眼检测区域输出
		if (eyes.size())
		{
			rect = eyes[0] + cv::Point(faces[i].x, faces[i].y);
			tpl = im(rect);
		}
	}
	return eyes.size();
}
// 人眼跟踪
void trackEye(cv::Mat& im, cv::Mat& tpl, cv::Rect& rect)
{
	// 人眼位置
	cv::Size pSize(rect.width * 2, rect.height * 2);
	// 矩形区域
	cv::Rect tRect(rect + pSize -
		cv::Point(pSize.width / 2, pSize.height / 2));
	tRect &= cv::Rect(0, 0, im.cols, im.rows);
	// 匹配模板生成
	cv::Mat tempMat(tRect.width - tpl.rows + 1,
		tRect.height - tpl.cols + 1, CV_32FC1);
	// 模板匹配
	cv::matchTemplate(im(tRect), tpl, tempMat,
		CV_TM_SQDIFF_NORMED);
	// 计算最小最大值
	double minval, maxval;
	cv::Point minloc, maxloc;
	cv::minMaxLoc(tempMat, &minval, &maxval,
		&minloc, &maxloc);
	// 区域检测判断
	if (minval <= 0.2)
	{
		rect.x = tRect.x + minloc.x;
		rect.y = tRect.y + minloc.y;
	}
	else
		rect.x = rect.y = rect.width = rect.height = 0;
}
int main()
{

	// 初始化摄像头读取视频流
	cv::VideoCapture cap(0);
	// 宽高设置为320*256
	cap.set(CV_CAP_PROP_FRAME_WIDTH, 420);
	cap.set(CV_CAP_PROP_FRAME_HEIGHT, 400);
	// 读取级联分类器
	// 文件存放在opencv\sources\data\haarcascades
	bool flagGlasses = false;
	if (flagGlasses)
	{
		face_cascade.load("haarcascade_frontalface_alt2.xml");
		eye_cascade.load("haarcascade_eye.xml");
	}
	else
	{
		face_cascade.load("haarcascade_frontalface_alt2.xml");
		eye_cascade.load("haarcascade_eye_tree_eyeglasses.xml");
	}
	// 判断初始化设置是否正常
	if (face_cascade.empty() || eye_cascade.empty()
		|| !cap.isOpened())
		return 1;
	// 视频流操作
	cv::Mat frame, eyeMat;
	cv::Rect eyeRect;
	while (cv::waitKey(10) != 'q')
	{
		cap >> frame;
		if (frame.empty())
			break;
		// 水平翻转
		cv::flip(frame, frame, 1);
		// 灰度转换
		cv::Mat gray;
		cv::cvtColor(frame, gray, CV_BGR2GRAY);
		// 人眼检测尺寸判断 若不符合则需要重新检测
		if (eyeRect.width <= 2 || eyeRect.height <= 2)
		{
			// 人眼检测
			detectEye(gray, eyeMat, eyeRect);
		}
		else // 符合则进行人眼跟踪
		{
			// 人眼跟踪
			trackEye(gray, eyeMat, eyeRect);
			// 人眼结果绘制
			cv::rectangle(frame, eyeRect, CV_RGB(0, 255, 0));
		}
		cv::imshow("video", frame);
	}
}

发现无法调用摄像头驱动,出现错误:

目标识别:如何从人脸图片中扣出眼图,实时人脸人眼检测和识别_第1张图片

解决:

Win32): 已加载“C:\Windows\System32\ntdll.dll”。无法查找或打开 PDB 文件。

解决办法:

目标识别:如何从人脸图片中扣出眼图,实时人脸人眼检测和识别_第2张图片

点击:选项——>调试——>常规——>启用源服务支持

目标识别:如何从人脸图片中扣出眼图,实时人脸人眼检测和识别_第3张图片

目标识别:如何从人脸图片中扣出眼图,实时人脸人眼检测和识别_第4张图片

点击:选项——>调试——>符号——>Microsoft服务符号器

目标识别:如何从人脸图片中扣出眼图,实时人脸人眼检测和识别_第5张图片

目标识别:如何从人脸图片中扣出眼图,实时人脸人眼检测和识别_第6张图片

 

 

 


基于开源项目OpenCV的人脸识别Demo版整理(不仅可以识别人脸,还可以识别眼睛鼻子嘴等)【模式识别中的翘楚】

https://blog.csdn.net/gywtzh0889/article/details/53337989

 

这是载入图像后再通过图像识别,找到人脸,画出人脸区域的红圈后的效果。

人脸识别程序编写。

1.首先创建一个机遇对话框的MFC工程FaceDetection2。

文件如图:

目标识别:如何从人脸图片中扣出眼图,实时人脸人眼检测和识别_第7张图片

2.将对话框修改成如图所示

3.按照如下步骤配置用到的lib

  • 选择Solution Explorer里的FaceDetection2项目,点击鼠标右键,选择Properties,在[链接器 LINKER]的[输入INPUT]中:
  • 为项目的Debug配置增加 [依赖的库 Additional Dependencies]:cxcore200d.lib cv200d.lib highgui200d.lib(注意,文件名cv200d.lib 可能是cv***d.lib等形式,具体应查看D:\Program Files\OpenCV2.0\vc2008\lib。如果使用的是OpenCV2.1,应输入:cxcore210d.lib cv210d.lib highgui210d.lib )
  • 为项目的Release配置增加[依赖的库 Additional Dependencies]:cxcore200.lib cv200.lib highgui200.lib (注意:如果使用的是OpenCV2.1,应输入:cxcore210.lib cv210.lib highgui210.lib)
  • 在 [配置属性 Configuration Properties]- [General] -[字符集 Character Set] 修改为使用“多字节字符集” (由于2008默认是以Unicode字符集编译的

4.然后编辑FaceDetection2Dlg.cpp文件,源码如下

// FaceDetection2Dlg.cpp : implementation file
//

#include "stdafx.h"
#include "FaceDetection2.h"
#include "FaceDetection2Dlg.h"
#include
#include



#ifdef _DEBUG
#define new DEBUG_NEW
#endif

using namespace std;

const char* cascade_name="haarcascade_frontalface_alt2.xml";//分类器的名称
const char* cascade_name1="haarcascade_eye_tree_eyeglasses.xml";//分类器的名称
const char* cascade_name2="haarcascade_frontalface_alt_tree.xml";//分类器的名称
const char* cascade_name3="haarcascade_mcs_mouth.xml";//分类器的名称
const char* cascade_name4="haarcascade_mcs_nose.xml";//分类器的名称

// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
    CAboutDlg();
    
// Dialog Data
    enum { IDD = IDD_ABOUTBOX };

    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
    DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CFaceDetection2Dlg dialog




CFaceDetection2Dlg::CFaceDetection2Dlg(CWnd* pParent /*=NULL*/)
    : CDialog(CFaceDetection2Dlg::IDD, pParent)
{
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CFaceDetection2Dlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CFaceDetection2Dlg, CDialog)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
    ON_BN_CLICKED(ID_FaceDetected, &CFaceDetection2Dlg::OnBnClickedFacedetected)
END_MESSAGE_MAP()


// CFaceDetection2Dlg message handlers

BOOL CFaceDetection2Dlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);            // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    // TODO: Add extra initialization here

    return TRUE;  // return TRUE  unless you set the focus to a control
}

void CFaceDetection2Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CFaceDetection2Dlg::OnPaint()
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting

        SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0);

        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;

        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CFaceDetection2Dlg::OnQueryDragIcon()
{
    return static_cast(m_hIcon);
}

void CFaceDetection2Dlg::OnBnClickedFacedetected()
{
    // TODO: 在此添加命令处理程序代码
    CString fileName;
    //打开文件对话窗口
    CFileDialog OpenDlg( TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR, L"图像文件格式JPG file format (*.jpg)|*.jpg|(*.bmp) |*.bmp|", NULL);
    //从文件对话窗口中打开图像
    if(OpenDlg.DoModal()!=IDOK)
        return ;
    //获得文件名
    fileName = OpenDlg.GetPathName();

    //必要的类型转换
    std::string tempName = (LPCSTR)CStringA(fileName);
    const char* tmp = tempName.c_str();
    //打开文件,若失败则返回
    if((src=cvLoadImage(tmp,CV_LOAD_IMAGE_ANYCOLOR))==0)
        return ;
    //加载(分类器层叠)训练库
    cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name2, 0, 0, 0 );
    //加载不成功则显示错误讯息,并退出
    if(cascade)
    {
        storage = cvCreateMemStorage(0);
        cvNamedWindow( "人脸检测", CV_WINDOW_AUTOSIZE ); //创建窗口
        //如果图片存在则分析并显示结果,否则退出程序
        if(src)
            detect_and_draw(src);//调用人脸检与标示事件
        cvReleaseImage(&src);
        cvReleaseMemStorage( &storage );
    }else{
        AfxMessageBox(L"无法加载分类器,请确认后重试!");
    }
    cvReleaseHaarClassifierCascade( &cascade );
}


void CFaceDetection2Dlg::detect_and_draw(IplImage *img)
{
    static CvScalar color[] = {{0,0,255},{0,128,255},{0,255,255},{0,255,0},{0,128,255},{255,128,0},{255,255,0},{255,0,0},{255,0,255}};//用于设置标示图像中人脸的颜色
    double scale = 1.3;
    IplImage* gray = cvCreateImage(cvSize(img->width,img->height),8,1);
    IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale),cvRound (img->height/scale)),8,1 );
    int i;
    cvCvtColor( img, gray, CV_BGR2GRAY );
    cvResize( gray, small_img, CV_INTER_LINEAR );
    cvEqualizeHist( small_img, small_img );
    cvClearMemStorage( storage );
    if( cascade )
    {
        //检测人脸
        CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage, 1.1, 2, 0, cvSize(30, 30) );
        for( i = 0; i < (faces ? faces->total : 0); i++ )
        {
            CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
            CvPoint center;
            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);
            cvCircle( img, center, radius, color[i], 3, 8, 0 );
        }
    }
    cvShowImage( "人脸检测", img );
    cvReleaseImage( &gray );
    cvReleaseImage( &small_img );
}

 

其中OnBnClickedFacedetected()为按钮FaceDetect的监听方法

detect_and_draw(IplImage *img)方法用于检测人脸

 

 

5.运行观察结果

目标识别:如何从人脸图片中扣出眼图,实时人脸人眼检测和识别_第8张图片

 

三、总结

在源码中,

const char* cascade_name="haarcascade_frontalface_alt2.xml";//分类器的名称
const char* cascade_name1="haarcascade_eye_tree_eyeglasses.xml";//分类器的名称
const char* cascade_name2="haarcascade_frontalface_alt_tree.xml";//分类器的名称
const char* cascade_name3="haarcascade_mcs_mouth.xml";//分类器的名称
const char* cascade_name4="haarcascade_mcs_nose.xml";//分类器的名称

这是不同的分类器,你可以在你安装的OpenCV中找到。如D:\Program Files\OpenCV2.0\vs2008\data\haarcascades

不同分类器能够帮助你识别不同的部分,如眼睛,鼻子和嘴,更多的需要自己去探索吧。

 


选择框架:caffe、tensorflow等

选择模板:(待考虑)

选择语言:C++、opencv、python

整理数据:待检测目标图像的数据集收集、整理、标注;

                  或:直接找出相关的人脸识别的数据集,拿出一部分来标注;

                   60%:training;(标注)

                   20%:testing;(不标)

                   20%:matching;(不标)

每次写一点,下次整合……


 

参考文章:

 

1,以SVM和HOG特性实现实时人脸检测和识别

2,[机器学习]基于级联分类器的多目标检测

3,使用OpenCV自带的级联分类器进行目标检测

4,Opencv目标检测之级联分类器训练与测试

5,级联分级器目标检测objdect

6,OpenCV学习笔记(二十六)——小试SVM算法ml OpenCV学习笔记(二十七)——基于级联分类器的目标检测objdect OpenCV学习笔记(二十八)——光流法对运动目标跟踪Video Ope

7,人脸、人眼检测与跟踪

8,眼球中心定位跟踪算法—eyelike

9,OpenCV 人脸检测级联分类器解读

 

你可能感兴趣的:(C++,深度学习,虹膜识别,人脸识别)