基于OpenCV讀取攝像頭實(shí)現(xiàn)單個(gè)人臉驗(yàn)證MFC程序
與上一篇博客類似,這篇博客介紹使用OpenCV實(shí)現(xiàn)的MFC程序,可以實(shí)現(xiàn)單個(gè)人臉的驗(yàn)證,并在圖像和界面給出識(shí)別結(jié)果。效果圖如下:
置信度一欄可以填寫判定的閾值,默認(rèn)為70。打開攝像頭才能進(jìn)行驗(yàn)證或拍照,拍照之前可以清除之前拍攝的訓(xùn)練圖片,可以拍攝多張用于識(shí)別。其中mfc中的圖像顯示需要用到CvImage.cpp和CvImage.h兩個(gè)文件,該代碼在比較新的OpenCV內(nèi)已經(jīng)沒有了,所以可以直接用我代碼里的。
有人說代碼的檢測(cè)率不高,其實(shí)可以歸結(jié)為兩方面的原因,第一人臉檢測(cè)率不高,這個(gè)可以通過嵌套檢測(cè)嘴角、眼睛等來降低,或者背景、光照固定的話可以通過圖像差分來解決;第二是識(shí)別方法本身的問題,如果想提高識(shí)別率,可以添加多張不同姿態(tài)、光照下的人臉作為訓(xùn)練的樣本,如果有時(shí)間的話可以在采集圖像時(shí)給出一個(gè)人臉框,引導(dǎo)用戶對(duì)齊人臉進(jìn)行采集,三星手機(jī)解除鎖屏就有這么一個(gè)功能。
下面貼一下主要的代碼:
VideoMFCDlg.cpp
// VideoMFCDlg.cpp : implementation file
//
#include "stdafx.h"
#include "VideoMFC.h"
#include "VideoMFCDlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CvCapture* capture;
CRect rect;
CDC *pDC;
HDC hDC;
CWnd *pwnd;
CvVideoWriter* writer = 0;
IplImage *resizeRes;//存放檢測(cè)到的人臉
IplImage* faceGray;//存放檢測(cè)到的人臉 灰度圖像
bool bool_cameOpen = false;//全局變量 標(biāo)志攝像頭是否打開
bool bool_picNum = false;//全局變量 標(biāo)志訓(xùn)練圖片是否為空
bool bool_detec_reco = false;//全局變量
double dConfidence = 0;//置信度
int predictedLabel = 100000;
CvMemStorage* storage = 0;
CvHaarClassifierCascade* cascade = 0;
CvHaarClassifierCascade* nested_cascade = 0;
int use_nested_cascade = 0;
const char* cascade_name =
"../data/haarcascades/haarcascade_frontalface_alt.xml";
const char* nested_cascade_name =
"../data/haarcascade_eye_tree_eyeglasses.xml";
double scale = 1;
int num_components = 9;
double facethreshold = 9.0;
//cv::Ptr<cv::FaceRecognizer> model = cv::createFisherFaceRecognizer();
cv::Ptr<cv::FaceRecognizer> model = cv::createLBPHFaceRecognizer();//LBP的這個(gè)方法在單個(gè)人臉驗(yàn)證方面效果最好
//cv::Ptr<cv::FaceRecognizer> model = cv::createEigenFaceRecognizer();
vector<Mat> images;
vector<int> labels;
IplImage *frame, *frame_copy = 0;
IplImage *image = 0;
const char* scale_opt = "--scale="; // 分類器選項(xiàng)指示符號(hào)
int scale_opt_len = (int)strlen(scale_opt);
const char* cascade_opt = "--cascade=";
int cascade_opt_len = (int)strlen(cascade_opt);
const char* nested_cascade_opt = "--nested-cascade";
int nested_cascade_opt_len = (int)strlen(nested_cascade_opt);
int i;
const char* input_name = 0;
// CAboutDlg dialog used for App About
CString strConfidence = "70";
CEdit* pEdtConfidence;
CString strTip = "";
CEdit* pTip;
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// Dialog Data
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// CVideoMFCDlg dialog
CVideoMFCDlg::CVideoMFCDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CVideoMFCDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CVideoMFCDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CVideoMFCDlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &CVideoMFCDlg::OnBnClickedButton1)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_BUTTON2, &CVideoMFCDlg::OnBnClickedButton2)
ON_WM_CLOSE()
ON_EN_CHANGE(IDC_EdtConfidence, &CVideoMFCDlg::OnEnChangeEdtconfidence)
ON_BN_CLICKED(IDC_Photograph, &CVideoMFCDlg::OnBnClickedPhotograph)
ON_BN_CLICKED(IDC_Recognize, &CVideoMFCDlg::OnBnClickedRecognize)
ON_BN_CLICKED(IDC_ClearPictures, &CVideoMFCDlg::OnBnClickedClearpictures)
END_MESSAGE_MAP()
// CVideoMFCDlg message handlers
BOOL CVideoMFCDlg::OnDestroy()
{
cvReleaseImage( &resizeRes );
cvReleaseImage( &faceGray );
return TRUE;
}
BOOL CVideoMFCDlg::OnInitDialog()
{
CDialogEx::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)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
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
pwnd = GetDlgItem(IDC_ShowImage);
//pwnd->MoveWindow(35,30,352,288);
pDC =pwnd->GetDC();
//pDC =GetDC();
hDC= pDC->GetSafeHdc();
pwnd->GetClientRect(&rect);
GetDlgItem(IDC_BUTTON2)->EnableWindow(false);
GetDlgItem(IDC_Photograph)->EnableWindow(false);
GetDlgItem(IDC_Recognize)->EnableWindow(false);
pEdtConfidence = (CEdit*) GetDlgItem(IDC_EdtConfidence);
pTip = (CEdit*) GetDlgItem(IDC_Tip);
pEdtConfidence->SetWindowText("70");
pEdtConfidence->GetWindowText(strConfidence);
pTip->SetWindowText( strTip );
if(read_img_number()>0)
bool_picNum = true;
else
bool_picNum = false;
return TRUE; // return TRUE unless you set the focus to a control
}
void CVideoMFCDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::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 CVideoMFCDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(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
{
CDialogEx::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CVideoMFCDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
/*****************************************打開攝像頭*******************************************/
void CVideoMFCDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
//AfxMessageBox("OK");
if(!capture)
{
capture = cvCaptureFromCAM(0);
//AfxMessageBox("OK");
}
if (!capture)
{
AfxMessageBox("無法打開攝像頭");
return;
}
//writer=cvCreateVideoWriter("MyVideo.avi",CV_FOURCC('x','v','I','D'),25,cvSize(640,480));
// 測(cè)試
IplImage* m_Frame;
m_Frame=cvQueryFrame(capture);
CvvImage m_CvvImage;
m_CvvImage.CopyOf(m_Frame,1);
if (true)
{
m_CvvImage.DrawToHDC(hDC, &rect);
//cvWaitKey(10);
}
// 設(shè)置計(jì)時(shí)器,每10ms觸發(fā)一次事件
SetTimer(1,10,NULL);
cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); // 加載分類器
if( !cascade )
{
MessageBox("無法加載分類器文件,請(qǐng)確認(rèn)!");
}
storage = cvCreateMemStorage(0); // 創(chuàng)建內(nèi)存存儲(chǔ)器
//if( !input_name || (isdigit(input_name[0]) && input_name[1] == '\0') ) // 判斷輸入?yún)?shù)是視頻序號(hào),還是文件
capture = cvCaptureFromCAM( !input_name ? 0 : input_name[0] - '0' ); // 創(chuàng)建視頻讀取結(jié)構(gòu)
/*
else if( input_name )
{
image = cvLoadImage( input_name, 1 ); // 如果是圖像則加載
if( !image )
{
capture = cvCaptureFromAVI( input_name ); // 不是圖像則嘗試視頻讀取
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 640);
cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 480); ////////////////////////////////////////////////////////////////////
}
}*/
//else
// image = cvLoadImage( "lena.bmp", 1 ); //都沒有則調(diào)用程序所在目錄的lena.jpg圖片
//cvNamedWindow( "result", 1 );
GetDlgItem(IDC_BUTTON1)->EnableWindow(false);
GetDlgItem(IDC_BUTTON2)->EnableWindow(true);
GetDlgItem(IDC_Photograph)->EnableWindow(true);
GetDlgItem(IDC_Recognize)->EnableWindow(true);
bool_detec_reco = false;
bool_cameOpen = true;
}
/********************************************設(shè)置定時(shí)器*********************************************/
void CVideoMFCDlg::OnTimer(UINT_PTR nIDEvent)
{
//顯示攝像頭
IplImage* m_Frame;
m_Frame=cvQueryFrame(capture);
//AllocConsole();
//判斷是檢測(cè)還是識(shí)別人臉
if(bool_cameOpen)
{
if(!bool_detec_reco)//false只為識(shí)別
{
detect_and_draw(m_Frame);//檢測(cè)人臉
//_cprintf("%s\n", "jiance");
}
else if(bool_picNum)//false代表訓(xùn)練圖片為空
recog_and_draw(m_Frame);//檢測(cè)和識(shí)別人臉
}
CvvImage m_CvvImage;
m_CvvImage.CopyOf(m_Frame,1);
if (true)
{
m_CvvImage.DrawToHDC(hDC, &rect);
//cvWriteFrame(writer,m_Frame); //將幀圖像通過writer寫入文件
//cvWaitKey(10);
}
if(bool_detec_reco)
{
if(predictedLabel <= dConfidence)
{
CString tipPhoto = strTip + "\r\n驗(yàn)證成功??!";
pTip->SetWindowText( tipPhoto );
}
else
{
CString tipPhoto = strTip + "\r\n驗(yàn)證失?。。?;
pTip->SetWindowText( tipPhoto );
}
}
CDialogEx::OnTimer(nIDEvent);
}
//關(guān)閉攝像頭按鈕
void CVideoMFCDlg::OnBnClickedButton2()
{
// TODO: Add your control notification handler code here
cvReleaseVideoWriter(&writer);
cvReleaseCapture(&capture);
CDC MemDC;
CBitmap m_Bitmap1;
m_Bitmap1.LoadBitmap(IDB_BITMAP1);
MemDC.CreateCompatibleDC(NULL);
MemDC.SelectObject(&m_Bitmap1);
pDC->StretchBlt(rect.left,rect.top,rect.Width(),rect.Height(),&MemDC,0,0,48,48,SRCCOPY);
GetDlgItem(IDC_BUTTON1)->EnableWindow(true);
GetDlgItem(IDC_BUTTON2)->EnableWindow(false);
GetDlgItem(IDC_Photograph)->EnableWindow(false);
GetDlgItem(IDC_Recognize)->EnableWindow(false);
bool_cameOpen = false;
}
//關(guān)閉窗體
void CVideoMFCDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
cvReleaseCapture(&capture);
CDialogEx::OnClose();
}
void CVideoMFCDlg::OnEnChangeEdtconfidence()
{
}
//拍照按鈕
void CVideoMFCDlg::OnBnClickedPhotograph()
{
// TODO: 在此添加控件通知處理程序代碼
if (!faceGray)
{
pTip->GetWindowText(strTip);
CString tipPhoto = strTip + "\r\n拍照失敗,請(qǐng)將攝像頭對(duì)準(zhǔn)人臉";
pTip->SetWindowText( tipPhoto );
return;
}
Mat img(faceGray,0);
stringstream ss;
ss << (read_img_number()+1);
string faceImgName = "..//einfacedata//trainingdata//"+ss.str()+".jpg";
imwrite(faceImgName,img);
//pTip->GetWindowText(strTip);
CString tipPhoto = strTip + "\r\n拍照成功!已存為" + ("/einfacedata/trainingdata/"+ss.str()+".jpg").c_str();
pTip->SetWindowText( tipPhoto );
//MessageBox("OK");
}
//開始驗(yàn)證按鈕
void CVideoMFCDlg::OnBnClickedRecognize()
{
// TODO: 在此添加控件通知處理程序代碼
images.clear();
labels.clear();
pEdtConfidence->GetWindowText(strConfidence);
try
{
dConfidence = atoi((const char *)strConfidence);
}
catch(cv::Exception &e)
{
MessageBox("置信度請(qǐng)輸入整數(shù)!");
return;
}
model->set("threshold", dConfidence);
//string output_folder;
//output_folder = string("../einfacedata");
//讀取你的CSV文件路徑
//string fn_csv = string("../einfacedata/at.txt");
//兩個(gè)容器來存放圖像數(shù)據(jù)和對(duì)應(yīng)的標(biāo)簽
/*
try
{
read_csv(fn_csv, images, labels);
}
catch(cv::Exception &e)
{
cerr<<"Error opening file "<<fn_csv<<". Reason: "<<e.msg<<endl;
exit(1);
}
*/
if(!read_img(images, labels))
{
AfxMessageBox("Error in reading images!");
//MessageBox("Error in reading images!");
images.clear();
labels.clear();
return;
}
//如果沒有讀到足夠的圖片,就退出
if(images.size() < 1)
{
MessageBox("This demo needs at least 1 images to work!");
return;
}
//training
model->train(images, labels);
bool_detec_reco = true;
bool_picNum = true;
}
//清除訓(xùn)練圖片
void CVideoMFCDlg::OnBnClickedClearpictures()
{
// TODO: 在此添加控件通知處理程序代碼
if(delete_img())
{
//pTip->GetWindowText(strTip);
CString tipPhoto = strTip + "\r\n刪除成功!";
pTip->SetWindowText( tipPhoto );
bool_detec_reco = false;
bool_picNum = false;
}
else
{
//pTip->GetWindowText(strTip);
CString tipPhoto = strTip + "\r\n刪除失?。?;
pTip->SetWindowText( tipPhoto );
}
}
detect_recog.cpp和上一篇博客類似
#include "stdafx.h"
#include "cv.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 "detect_recog.h"
#include <opencv2\contrib\contrib.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdio.h>
#include <io.h>
#include <direct.h>
#include <sys/types.h>
#include <conio.h>
using namespace std;
using namespace cv;
void detect_and_draw( IplImage* img ) // 只是檢測(cè),并圈出人臉
{
static CvScalar colors[] =
{
{{0,0,255}},
{{0,128,255}},
{{0,255,255}},
{{0,255,0}},
{{255,128,0}},
{{255,255,0}},
{{255,0,0}},
{{255,0,255}}
};
IplImage *gray, *small_img;
int i, j;
gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
small_img = cvCreateImage( cvSize( cvRound (img->width/scale),
cvRound (img->height/scale)), 8, 1 );
cvCvtColor( img, gray, CV_BGR2GRAY ); // 彩色RGB圖像轉(zhuǎn)為灰度圖像
cvResize( gray, small_img, CV_INTER_LINEAR );
cvEqualizeHist( small_img, small_img ); // 直方圖均衡化
cvClearMemStorage( storage );
if( cascade )
{
double t = (double)cvGetTickCount();
CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
1.1, 2, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
|CV_HAAR_DO_ROUGH_SEARCH
//|CV_HAAR_DO_CANNY_PRUNING
//|CV_HAAR_SCALE_IMAGE
,
cvSize(30, 30) );
t = (double)cvGetTickCount() - t; // 統(tǒng)計(jì)檢測(cè)使用時(shí)間
//printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) );
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem( faces, i ); // 將faces數(shù)據(jù)從CvSeq轉(zhuǎn)為CvRect
CvMat small_img_roi;
CvSeq* nested_objects;
CvPoint center,recPt1,recPt2;
CvScalar color = colors[i%8]; // 使用不同顏色繪制各個(gè)face,共八種色
int radius;
center.x = cvRound((r->x + r->width*0.5)*scale); // 找出faces中心
center.y = cvRound((r->y + r->height*0.5)*scale);
recPt1.x = cvRound((r->x)*scale);
recPt1.y = cvRound((r->y)*scale);
recPt2.x = cvRound((r->x + r->width)*scale);
recPt2.y = cvRound((r->y + r->height)*scale);
radius = cvRound((r->width + r->height)*0.25*scale);
cvGetSubRect( small_img, &small_img_roi, *r );
IplImage *result;
CvRect roi;
roi = *r;
result = cvCreateImage( cvSize(r->width, r->height), img->depth, img->nChannels );
cvSetImageROI(img,roi);
// 創(chuàng)建子圖像
cvCopy(img,result);
cvResetImageROI(img);
//IplImage *resizeRes;
CvSize dst_cvsize;
dst_cvsize.width=(int)(100);
dst_cvsize.height=(int)(100);
resizeRes=cvCreateImage(dst_cvsize,result->depth,result->nChannels);
cvResize(result,resizeRes,CV_INTER_NN);
faceGray = cvCreateImage(cvGetSize(resizeRes), IPL_DEPTH_8U, 1);//創(chuàng)建目標(biāo)圖像
cvCvtColor(resizeRes,faceGray,CV_BGR2GRAY);//cvCvtColor(src,des,CV_BGR2GRAY)
cvShowImage( "resize", resizeRes );
cvRectangle(img,recPt1,recPt2,color,1, 8,0);
//rectangle(img,recPt1,recPt2,color,1,8,0);
//cvCircle( img, center, radius, color, 3, 8, 0 ); // 從中心位置畫圓,圈出臉部區(qū)域
if( !nested_cascade )
continue;
nested_objects = cvHaarDetectObjects( &small_img_roi, nested_cascade, storage,
1.1, 2, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
//|CV_HAAR_DO_CANNY_PRUNING
//|CV_HAAR_SCALE_IMAGE
,
cvSize(0, 0) );
for( j = 0; j < (nested_objects ? nested_objects->total : 0); j++ )
{
CvRect* nr = (CvRect*)cvGetSeqElem( nested_objects, j );
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);
cvCircle( img, center, radius, color, 3, 8, 0 );
}
}
}
//cvShowImage( "result", img );
cvReleaseImage( &gray );
cvReleaseImage( &small_img );
}
//檢測(cè)并識(shí)別人臉,并在每幀圖片上寫入結(jié)果
void recog_and_draw( IplImage* img )
{
static CvScalar colors[] =
{
{{0,0,255}},
{{0,128,255}},
{{0,255,255}},
{{0,255,0}},
{{255,128,0}},
{{255,255,0}},
{{255,0,0}},
{{255,0,255}}
};
IplImage *gray, *small_img;
int i, j;
gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
small_img = cvCreateImage( cvSize( cvRound (img->width/scale),
cvRound (img->height/scale)), 8, 1 );
cvCvtColor( img, gray, CV_BGR2GRAY ); // 彩色RGB圖像轉(zhuǎn)為灰度圖像
cvResize( gray, small_img, CV_INTER_LINEAR );
cvEqualizeHist( small_img, small_img ); // 直方圖均衡化
cvClearMemStorage( storage );
if( cascade )
{
double t = (double)cvGetTickCount();
CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
1.1, 2, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
|CV_HAAR_DO_CANNY_PRUNING
//|CV_HAAR_SCALE_IMAGE
,
cvSize(30, 30) );
t = (double)cvGetTickCount() - t; // 統(tǒng)計(jì)檢測(cè)使用時(shí)間
//printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) );
for( i = 0; i < (faces ? faces->total : 0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem( faces, i ); // 將faces數(shù)據(jù)從CvSeq轉(zhuǎn)為CvRect
CvMat small_img_roi;
CvSeq* nested_objects;
CvPoint center,recPt1,recPt2;
CvScalar color = colors[i%8]; // 使用不同顏色繪制各個(gè)face,共八種色
int radius;
center.x = cvRound((r->x + r->width*0.5)*scale); // 找出faces中心
center.y = cvRound((r->y + r->height*0.5)*scale);
recPt1.x = cvRound((r->x)*scale);
recPt1.y = cvRound((r->y)*scale);
recPt2.x = cvRound((r->x + r->width)*scale);
recPt2.y = cvRound((r->y + r->height)*scale);
radius = cvRound((r->width + r->height)*0.25*scale);
cvGetSubRect( small_img, &small_img_roi, *r );
IplImage *result;
CvRect roi;
roi = *r;
result = cvCreateImage( cvSize(r->width, r->height), img->depth, img->nChannels );
cvSetImageROI(img,roi);
// 創(chuàng)建子圖像
cvCopy(img,result);
cvResetImageROI(img);
//IplImage *resizeRes;
CvSize dst_cvsize;
dst_cvsize.width=(int)(100);
dst_cvsize.height=(int)(100);
resizeRes=cvCreateImage(dst_cvsize,result->depth,result->nChannels);
cvResize(result,resizeRes,CV_INTER_NN);
faceGray = cvCreateImage(cvGetSize(resizeRes), IPL_DEPTH_8U, 1);//創(chuàng)建目標(biāo)圖像
cvCvtColor(resizeRes,faceGray,CV_BGR2GRAY);//cvCvtColor(src,des,CV_BGR2GRAY)
cvShowImage( "resize", resizeRes );
cvRectangle(img,recPt1,recPt2,color,3, 8,0);
//cvCircle( img, center, radius, color, 3, 8, 0 ); // 從中心位置畫圓,圈出臉部區(qū)域
Mat test = faceGray;
//images[images.size() - 1] = test;
model->train(images, labels);
//predictedLabel = model->predict(test);
double predicted_confidence = 0.0;
model->predict(test,predictedLabel,predicted_confidence);
stringstream strStream;
strStream<<predicted_confidence;
string ss = strStream.str();
cvText(img, ss.c_str(), r->x+r->width*0.5, r->y);
if(predicted_confidence <= dConfidence)
cvText(img, "Result:YES", 0, 30);
else
cvText(img, "Result:NO", 0, 30);
//cout << "predict:"<<model->predict(test) << endl;
//cout << "predict:"<< predictedLabel << "\nconfidence:" << predicted_confidence << endl;
if( !nested_cascade )
continue;
nested_objects = cvHaarDetectObjects( &small_img_roi, nested_cascade, storage,
1.1, 2, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
//|CV_HAAR_DO_CANNY_PRUNING
//|CV_HAAR_SCALE_IMAGE
,
cvSize(0, 0) );
for( j = 0; j < (nested_objects ? nested_objects->total : 0); j++ )
{
CvRect* nr = (CvRect*)cvGetSeqElem( nested_objects, j );
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);
cvCircle( img, center, radius, color, 3, 8, 0 );
}
}
}
//cvShowImage( "result", img );
cvReleaseImage( &gray );
cvReleaseImage( &small_img );
}
void cvText(IplImage* img, const char* text, int x, int y)
{
CvFont font;
double hscale = 1.0;
double vscale = 1.0;
int linewidth = 2;
cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX | CV_FONT_ITALIC,hscale,vscale,0,linewidth);
CvScalar textColor =cvScalar(0,255,255);
CvPoint textPos =cvPoint(x, y);
cvPutText(img, text, textPos, &font,textColor);
}
Mat norm_0_255(cv::InputArray _src)
{
Mat src = _src.getMat();
Mat dst;
switch(src.channels())
{
case 1:
cv::normalize(_src, dst, 0, 255, cv::NORM_MINMAX, CV_8UC1);
break;
case 3:
cv::normalize(_src, dst, 0, 255, cv::NORM_MINMAX, CV_8UC3);
break;
default:
src.copyTo(dst);
break;
}
return dst;
}
void read_csv(const string &filename, vector<Mat> &images, vector<int> &labels, char separator)
{
std::ifstream file(filename.c_str(), ifstream::in);
if(!file)
{
string error_message = "No valid input file was given.";
CV_Error(CV_StsBadArg, error_message);
}
string line, path, classlabel;
while(getline(file, line))
{
stringstream liness(line);
getline(liness, path, separator); //遇到分號(hào)就結(jié)束
getline(liness, classlabel); //繼續(xù)從分號(hào)后面開始,遇到換行結(jié)束
if(!path.empty() && !classlabel.empty())
{
images.push_back(imread(path, 0));
labels.push_back(atoi(classlabel.c_str()));
}
}
}
//實(shí)現(xiàn)了從trainningdata 目錄下直接讀取jpg文件作為訓(xùn)練集
bool read_img(vector<Mat> &images, vector<int> &labels)
{
long file;
struct _finddata_t find;
//AllocConsole();
string path = "..//einfacedata//trainingdata/";
char filepath[60];
//_chdir("..//einfacedata//trainingdata");
if((file=_findfirst("..//einfacedata//trainingdata/*.jpg", &find))==-1L)
{
AfxMessageBox("Cannot find the dir");
return false;
}
int i = 0;
images.push_back(imread(path+find.name, 0));
labels.push_back(0);
while(_findnext(file, &find)==0)
{
//_cprintf("%s\n", path+find.name);
//_cprintf("%d\n", i++);
images.push_back(imread(path+find.name, 0));
labels.push_back(0);
}
_findclose(file);
return true;
}
//實(shí)現(xiàn)了從trainningdata 目錄下讀取jpg文件數(shù)目
int read_img_number()
{
long file;
int i = 0;
struct _finddata_t find;
//AllocConsole();
string path = "..//einfacedata//trainingdata/";
char filepath[60];
if((file=_findfirst("..//einfacedata//trainingdata/*.jpg", &find))==-1L)
return i;
i++;
while(_findnext(file, &find)==0)
{
i++;
}
_findclose(file);
return i;
}
bool delete_img()
{
system( "del ..\\einfacedata\\trainingdata\\" );
return true;
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:C語言中access/_access函數(shù)的使用實(shí)例詳解
欄 目:C語言
下一篇:C++中進(jìn)行txt文件讀入和寫入的方法示例
本文標(biāo)題:基于OpenCV讀取攝像頭實(shí)現(xiàn)單個(gè)人臉驗(yàn)證MFC程序
本文地址:http://www.jygsgssxh.com/a1/Cyuyan/209.html
您可能感興趣的文章
- 01-10基于atoi()與itoa()函數(shù)的內(nèi)部實(shí)現(xiàn)方法詳解
- 01-10基于C語言sprintf函數(shù)的深入理解
- 01-10基于C程序啟動(dòng)代碼的深入分析
- 01-10基于getline()函數(shù)的深入理解
- 01-10基于C語言fflush()函數(shù)的使用詳解
- 01-10基于linux下獲取時(shí)間函數(shù)的詳解
- 01-10基于C語言指令的深入分析
- 01-10基于c中使用ftruncate()前需要fflush(),使用后需要rewind()的深入探討
- 01-10基于C++ list中erase與remove函數(shù)的使用詳解
- 01-10基于C++輸出指針自增(++)運(yùn)算的示例分析


閱讀排行
- 1C語言 while語句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語言實(shí)現(xiàn)“百馬百擔(dān)”問題方法
- 4C語言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對(duì)數(shù)函數(shù)的表達(dá)式 c語言中對(duì)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10delphi制作wav文件的方法
- 04-02jquery與jsp,用jquery


