原文:http://blog.csdn.net/mr_curry/article/details/51098311
第一次寫博客哈哈,有些小激動,還請各位大神多多包涵~
最近的項目需要用到人臉識別,作為一個車輛工程的二年級本科生是崩潰的(一是沒有很好的編程基礎,只會編一下C與C#;二是…我是車輛工程的啊喂…)
不過自己還是對計算機視覺這方面還是很感興趣的,因為做競賽的緣由,以前多多少少有一點小基礎,但要完全做出來還是感覺有些難度。調了一段時間的代碼,嘿嘿實現了。這個里面有兩點有些“與眾不同”(自認為)1.我用Mat代替了IplImage;2.將其用MFC進行表達。(廢話少說)接下來貼程序……
先說一下我的版本,我是用的VS2013與Opencv2.4.9。首先我們需要在VS中新建一個MFC的框架。
然后點擊完成就可以了。接下來我們需要在窗口里面拉幾個控件。一個picture control、一個button控件,一個Static Text控件。下面其實是我后來又想做人臉匹配,加了一些功能(好吧我並不會做)。
修改ID:picture control——–face_picture;
button——————StartWatch;
Static Text————-TIME_NEW;
把我的ID貼出來,方便大家理解。然后就是要為Static Text添加變量,剛開始以為這個和C#的框架差不多,可以直接用什么”label.Text=”,后來才知道先要添加變量,一通亂搞,還翻了書,暈死。
如圖,增添這個我是主要想顯示人臉識別的函數運行速度如何,是多少秒。接下來我們雙擊button控件,進入代碼頁。
代碼如下:首先是一個你需要引用的頭文件:
#include "stdafx.h" #include "人臉識別與特征匹配.h" #include "人臉識別與特征匹配Dlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
第二步:
using namespace std; using namespace cv;
- 1
- 2
- 1
- 2
然后我們先聲明“detectAndDisplay”函數,這里我是用Mat類進行實現,沒有用IplImage什么指針的進行實現,一句話,不會管理內存。而后的 haarcascade_frontalface_alt.xml、haarcascade_eye_tree_eyeglasses.xml這兩個級聯分類器(我也不知道這玩意是不是這么叫的)可以在OpenCV的文件夾里面找到,我是把他們移到了桌面上。
// 用於應用程序“關於”菜單項的 CAboutDlg 對話框 void detectAndDisplay(Mat frame);//聲明函數 String face_cascade_name = "C:\\Users\\strstr\\Desktop\\haarcascade_frontalface_alt.xml";//人臉的訓練數據 String eyes_cascade_name = "C:\\Users\\strstr\\Desktop\\haarcascade_eye_tree_eyeglasses.xml";//人眼的訓練數據 CascadeClassifier face_cascade; CascadeClassifier eyes_cascade; string window_name = "人臉識別與檢測"; RNG rng(12345); Mat Allframe;//用於點擊button存儲照片,同學們可以無視
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
接下來,我將一路貼代碼。有一些是MFC預留的,關鍵的是button里面的內容和detectAndDisplay函數。
class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 對話框數據 enum { IDD = IDD_ABOUTBOX }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 實現 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() // C人臉識別與特征匹配Dlg 對話框 C人臉識別與特征匹配Dlg::C人臉識別與特征匹配Dlg(CWnd* pParent /*=NULL*/) : CDialogEx(C人臉識別與特征匹配Dlg::IDD, pParent) , face_time(_T("")) , face_name(_T("")) , face_no_name(_T("")) , face_time_new(0) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void C人臉識別與特征匹配Dlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Text(pDX, TIME, face_time); DDX_Text(pDX, Result, face_name); DDX_Text(pDX, THEname, face_no_name); DDX_Text(pDX, TIME_NEW, face_time_new); } BEGIN_MESSAGE_MAP(C人臉識別與特征匹配Dlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(StartWatch, &C人臉識別與特征匹配Dlg::OnBnClickedStartwatch) ON_BN_CLICKED(face_read, &C人臉識別與特征匹配Dlg::OnBnClickedread) ON_BN_CLICKED(face_openvideo, &C人臉識別與特征匹配Dlg::OnBnClickedopenvideo) ON_BN_CLICKED(Save, &C人臉識別與特征匹配Dlg::OnBnClickedSave) END_MESSAGE_MAP() // C人臉識別與特征匹配Dlg 消息處理程序 BOOL C人臉識別與特征匹配Dlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 將“關於...”菜單項添加到系統菜單中。 // IDM_ABOUTBOX 必須在系統命令范圍內。 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); } } // 設置此對話框的圖標。 當應用程序主窗口不是對話框時,框架將自動 // 執行此操作 SetIcon(m_hIcon, TRUE); // 設置大圖標 SetIcon(m_hIcon, FALSE); // 設置小圖標 // TODO: 在此添加額外的初始化代碼 return TRUE; // 除非將焦點設置到控件,否則返回 TRUE } void C人臉識別與特征匹配Dlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialogEx::OnSysCommand(nID, lParam); } } // 如果向對話框添加最小化按鈕,則需要下面的代碼 // 來繪制該圖標。 對於使用文檔/視圖模型的 MFC 應用程序, // 這將由框架自動完成。 void C人臉識別與特征匹配Dlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用於繪制的設備上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使圖標在工作區矩形中居中 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; // 繪制圖標 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //當用戶拖動最小化窗口時系統調用此函數取得光標 //顯示。 HCURSOR C人臉識別與特征匹配Dlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
以下是Button里的代碼:
void C人臉識別與特征匹配Dlg::OnBnClickedStartwatch() { face_time = "秒"; double t = 0; double facelook_time = 0;//用於計算函數運行時間 VideoCapture capture(1);//捕獲外部攝像頭 Mat frame,newframe;//建立兩個Mat,一個用來顯示視頻,另一個給全局里的Allframe namedWindow("view", WINDOW_AUTOSIZE); HWND hWnd = (HWND)cvGetWindowHandle("view"); HWND hParent = ::GetParent(hWnd); ::SetParent(hWnd, GetDlgItem(face_picture)->m_hWnd); ::ShowWindow(hParent, SW_HIDE);//隱藏運行程序框,並且把它“畫”到MFC上 if (!face_cascade.load(face_cascade_name)){ printf("--(!)Error loading\n");}; if (!eyes_cascade.load(eyes_cascade_name)){ printf("--(!)Error loading\n");};//加載分類器的 if (capture.isOpened()) { for (;;)//循環以達到視頻的效果 { capture >> frame; capture >> newframe; Allframe = newframe; if (!frame.empty()) { t = (double)cvGetTickCount(); detectAndDisplay(frame);//識別的函數 t = (double)cvGetTickCount() - t;//用來計算算法執行時間 facelook_time = t / 1000 / ((double)cvGetTickFrequency()*1000.);//檢測時間 face_time_new = facelook_time;//輸出到static text中 imshow("view", frame); UpdateData(FALSE); } else { printf(" --(!) No captured frame -- Break!"); break; } waitKey(10); } } } void detectAndDisplay(Mat frame)//識別人臉函數 { std::vector<Rect> faces; Mat frame_gray; cvtColor(frame, frame_gray, COLOR_BGR2GRAY);//轉換成灰度圖像 equalizeHist(frame_gray, frame_gray);//直方圖均衡化 //1.1表示每次圖像尺寸減小的比例為1.1,2表示每一個目標至少要被檢測到3次才算是真的目標(因為周圍的像素和不同的窗口大小都可以檢測到人臉),CV_HAAR_SCALE_IMAGE表示不是縮放分類器來檢測,而是縮放圖像,Size(30, 30)為目標的最小最大尺寸 face_cascade.detectMultiScale(frame_gray, faces, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); for (size_t i = 0; i < faces.size(); i++) { Point center(faces[i].x + faces[i].width / 2, faces[i].y + faces[i].height / 2); ellipse(frame, center, Size(faces[i].width / 2, faces[i].height / 2), 0, 0, 360, Scalar(255, 0, 255), 2, 8, 0);//畫橢圓 Mat faceROI = frame_gray(faces[i]); std::vector<Rect> eyes; //-- In each face, detect eyes eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); for (size_t j = 0; j < eyes.size(); j++)//檢測眼睛 { Point eye_center(faces[i].x + eyes[j].x + eyes[j].width / 2, faces[i].y + eyes[j].y + eyes[j].height / 2); int radius = cvRound((eyes[j].width + eyes[j].height)*0.25); circle(frame, eye_center, radius, Scalar(255, 0, 0), 3, 8, 0); } } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
好了,貼一張運行成功的截圖,怕丑到各位,打了些馬賽克: