基於OpenCV的讀取攝像頭實現單個人臉驗證MFC程式
阿新 • • 發佈:2019-01-05
與上一篇部落格類似,這篇部落格介紹使用OpenCV實現的MFC程式,可以實現單個人臉的驗
證,並在影象和介面給出識別結果。效果圖如下:
有人說程式碼的檢測率不高,其實可以歸結為兩方面的原因,第一人臉檢測率不高,這個可以通過巢狀檢測嘴角、眼睛等來降低,或者背景、光照固定的話可以通過影象差分來解決;第二是識別方法本身的問題,如果想提高識別率,可以新增多張不同姿態、光照下的人臉作為訓練的樣本,如果有時間的話可以在採集影象時給出一個人臉框,引導使用者對齊人臉進行採集,三星手機解除鎖屏就有這麼一個功能。
下面貼一下主要的程式碼:
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;//存放檢測到的人臉 IplImage* faceGray;//存放檢測到的人臉 灰度影象 bool bool_cameOpen = false;//全域性變數 標誌攝像頭是否開啟 bool bool_picNum = false;//全域性變數 標誌訓練圖片是否為空 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的這個方法在單個人臉驗證方面效果最好 //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="; // 分類器選項指示符號 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)); // 測試 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); } // 設定計時器,每10ms觸發一次事件 SetTimer(1,10,NULL); cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); // 載入分類器 if( !cascade ) { MessageBox("無法載入分類器檔案,請確認!"); } storage = cvCreateMemStorage(0); // 建立記憶體儲存器 //if( !input_name || (isdigit(input_name[0]) && input_name[1] == '\0') ) // 判斷輸入引數是視訊序號,還是檔案 capture = cvCaptureFromCAM( !input_name ? 0 : input_name[0] - '0' ); // 建立視訊讀取結構 /* 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 ); //都沒有則呼叫程式所在目錄的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; } /********************************************設定定時器*********************************************/ void CVideoMFCDlg::OnTimer(UINT_PTR nIDEvent) { //顯示攝像頭 IplImage* m_Frame; m_Frame=cvQueryFrame(capture); //AllocConsole(); //判斷是檢測還是識別人臉 if(bool_cameOpen) { if(!bool_detec_reco)//false只為識別 { detect_and_draw(m_Frame);//檢測人臉 //_cprintf("%s\n", "jiance"); } else if(bool_picNum)//false代表訓練圖片為空 recog_and_draw(m_Frame);//檢測和識別人臉 } 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驗證成功!!"; pTip->SetWindowText( tipPhoto ); } else { CString tipPhoto = strTip + "\r\n驗證失敗!!"; pTip->SetWindowText( tipPhoto ); } } CDialogEx::OnTimer(nIDEvent); } //關閉攝像頭按鈕 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; } //關閉窗體 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拍照失敗,請將攝像頭對準人臉"; 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"); } //開始驗證按鈕 void CVideoMFCDlg::OnBnClickedRecognize() { // TODO: 在此新增控制元件通知處理程式程式碼 images.clear(); labels.clear(); pEdtConfidence->GetWindowText(strConfidence); try { dConfidence = atoi((const char *)strConfidence); } catch(cv::Exception &e) { MessageBox("置信度請輸入整數!"); return; } model->set("threshold", dConfidence); //string output_folder; //output_folder = string("../einfacedata"); //讀取你的CSV檔案路徑 //string fn_csv = string("../einfacedata/at.txt"); //兩個容器來存放影象資料和對應的標籤 /* 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; } //清除訓練圖片 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 ) // 只是檢測,並圈出人臉 { 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影象轉為灰度影象 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; // 統計檢測使用時間 //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資料從CvSeq轉為CvRect CvMat small_img_roi; CvSeq* nested_objects; CvPoint center,recPt1,recPt2; CvScalar color = colors[i%8]; // 使用不同顏色繪製各個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); // 建立子影象 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);//建立目標影象 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 ); // 從中心位置畫圓,圈出臉部區域 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 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影象轉為灰度影象 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; // 統計檢測使用時間 //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資料從CvSeq轉為CvRect CvMat small_img_roi; CvSeq* nested_objects; CvPoint center,recPt1,recPt2; CvScalar color = colors[i%8]; // 使用不同顏色繪製各個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); // 建立子影象 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);//建立目標影象 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 ); // 從中心位置畫圓,圈出臉部區域 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); //遇到分號就結束 getline(liness, classlabel); //繼續從分號後面開始,遇到換行結束 if(!path.empty() && !classlabel.empty()) { images.push_back(imread(path, 0)); labels.push_back(atoi(classlabel.c_str())); } } } //實現了從trainningdata 目錄下直接讀取jpg檔案作為訓練集 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; } //實現了從trainningdata 目錄下讀取jpg檔案數目 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; }