1. 程式人生 > >OpenCV人臉識別的原理 (原文完整版)

OpenCV人臉識別的原理 (原文完整版)

http://www.educity.cn/wenda/358439.html

“人臉識別”是一個在計算機視覺和生物特徵識別領域十分活躍的話題。這個主題已經被給力地研究了25年,並且最終在安全、機器人學、人機互動、數碼攝像機、遊戲和娛樂領域得到了廣泛應用。

  “人臉識別”大致可分為兩個階段:

  1.人臉檢測 搜尋一幅影象,尋找一切人臉區域(此處以綠色矩形顯示),然後進行影象處理,清理臉部影象以便於更好地識別。

  2.人臉識別 把上一階段檢測處理得到的人臉影象與資料174x197庫中的已知人臉進行比對,判定人臉對應的人是誰(此處以紅色文字顯示)。

  2002年後,人臉檢測已經可以相當可靠地運作。比如OpenCV的Face Detector,對於一個人直視攝像頭得到的較清晰圖片,大約有90-95%的準確度。通常來說,當人以側面對準攝像頭或與攝像頭成一定角度時,較難檢測到人臉,有時需要3D Head Pose Estimation。假如圖片亮度不是很好,也較難檢測到人臉。臉部的部分割槽域比另一部分割槽域明亮,帶有陰影,模糊,或者戴眼鏡,也會影響檢測效果。

  然而,人臉識別卻比人臉檢測不可靠得多,一般只有30-70%的準確度。20世紀90年代以來,人臉識別一直是一個很重要的研究領域,但仍然十分不可靠,並且每一年都有更多的識別技術被創造,如文章底部所列出的(Alternatives to Eigenfaces such as 3D face recognition or recognition from video.)

  我將向你展示如何使用“特徵臉”(Eigenfaces),也稱為主元分析法(Principal Component Analysis or PCA)。相對於普通的神經網路方法(Neural Networks)和Fisher Faces方法來說,這是一個簡單和流行的對圖片進行的二維人臉識別的方法。

  要學習特徵臉方法的理論,你需要閱讀Face Recognition With Eigenface from Servo Magazine (April 2007),可能還需要一些數學演算法。

  首先我將向你解釋,怎樣實現特徵臉的命令列離線訓練(offline training from the command-line),基於Servo Magazine tutorial and source-code (May 2007)。

  之後,我將說明如何將此擴充套件成為從網路攝像頭進行實時的線上訓練:-)

  使用OpenCV的Face Detector檢測人臉

  如上所述,人臉識別的第一個階段是人臉檢測。OpenCV庫使得使用它的Haar Cascade Face Detector(也稱為Viola-Jones方法)檢測正面人臉變得相當簡單。

  OpenCV裡的“cvHaarDetectObjects”函式執行人臉檢測,但是這個函式直接用沒有意義,所以最好用這個包裝好的函式:

  // Perform face detection on the input image, using the given Haar Cascade. // Returns a rectangle for the detected region in the given image. CvRect detectFaceInImage(IplImage *inputImg, CvHaarClassifierCascade* cascade) { // Smallest face size. CvSize minFeatureSize = cvSize(20, 20); // Only search for 1 face. int flags = CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH; // How detailed should the search be. float search_scale_factor = 1.1f; IplImage *detectImg; IplImage *greyImg = 0; CvMemStorage* storage; CvRect rc; double t; CvSeq* rects; CvSize size; int i, ms, nFaces; storage = cvCreateMemStorage(0); cvClearMemStorage( storage ); // If the image is color, use a greyscale copy of the image. detectImg = (IplImage*)inputImg; if (inputImg->nChannels > 1) { size = cvSize(inputImg->width, inputImg->height); greyImg = cvCreateImage(size, IPL_DEPTH_8U, 1 ); cvCvtColor( inputImg, greyImg, CV_BGR2GRAY ); detectImg = greyImg; // Use the greyscale image. } // Detect all the faces in the greyscale image. t = (double)cvGetTickCount(); rects = cvHaarDetectObjects( detectImg, cascade, storage, search_scale_factor, 3, flags, minFeatureSize); t = (double)cvGetTickCount() - t; ms = cvRound( t / ((double)cvGetTickFrequency() * 1000.0) ); nFaces = rects->total; printf("Face Detection took %d ms and found %d objectsn", ms, nFaces); // Get the first detected face (the biggest). if (nFaces > 0) rc = *(CvRect*)cvGetSeqElem( rects, 0 ); else rc = cvRect(-1,-1,-1,-1); // Couldn't find the face. if (greyImg) cvReleaseImage( &greyImg ); cvReleaseMemStorage( &storage ); //cvReleaseHaarClassifierCascade( &cascade ); return rc; // Return the biggest face found, or (-1,-1,-1,-1). } // Perform face detection on the input image, using the given Haar Cascade. // Returns a rectangle for the detected region in the given image. CvRect detectFaceInImage(IplImage *inputImg, CvHaarClassifierCascade* cascade) { // Smallest face size. CvSize minFeatureSize = cvSize(20, 20); // Only search for 1 face. int flags = CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH; // How detailed should the search be. float search_scale_factor = 1.1f; IplImage *detectImg; IplImage *greyImg = 0; CvMemStorage* storage; CvRect rc; double t; CvSeq* rects; CvSize size; int i, ms, nFaces; storage = cvCreateMemStorage(0); cvClearMemStorage( storage ); // If the image is color, use a greyscale copy of the image. detectImg = (IplImage*)inputImg; if (inputImg->nChannels > 1) { size = cvSize(inputImg->width, inputImg->height); greyImg = cvCreateImage(size, IPL_DEPTH_8U, 1 ); cvCvtColor( inputImg, greyImg, CV_BGR2GRAY ); detectImg = greyImg; // Use the greyscale image. } // Detect all the faces in the greyscale image. t = (double)cvGetTickCount(); rects = cvHaarDetectObjects( detectImg, cascade, storage, search_scale_factor, 3, flags, minFeatureSize) t = (double)cvGetTickCount() - t; ms = cvRound( t / ((double)cvGetTickFrequency() * 1000.0) ); nFaces = rects->total; printf("Face Detection took %d ms and found %d objectsn", ms, nFaces); // Get the first detected face (the biggest). if (nFaces > 0) rc = *(CvRect*)cvGetSeqElem( rects, 0 ); else rc = cvRect(-1,-1,-1,-1); // Couldn't find the face. if (greyImg) cvReleaseImage( &greyImg ); cvReleaseMemStorage( &storage ); //cvReleaseHaarClassifierCascade( &cascade ); return rc; // Return the biggest face found, or (-1,-1,-1,-1). }



  現在如果你想要在一張圖片裡尋找人臉,只需要簡單地呼叫“detectFaceInImage”函式。你也需要指定OpenCV使用的人臉分類器(Face Classifier)。比如,OpenCV自帶了一些用於正面臉的分類器,也有一些用於側面臉的,還有眼睛檢測,鼻檢測,嘴檢測,全身檢測等等。你實際上可以任意把其它的分類檢測器用於此函式,甚至創造你自己定製的分類檢測器,比如車或人的檢測(閱讀此處),但既然正臉檢測是唯一十分可靠的,這將是我們唯一要討論的。

  對於正面人臉檢測,你應該選取這些OpenCV自帶的haar級聯分類器(Haar Cascade Classifiers,in the “datahaarcascades” folder)。

  • “haarcascade_frontalface_default.xml”
  • “haarcascade_frontalface_alt.xml”
  • “haarcascade_frontalface_alt2.xml”
  • “haarcascade_frontalface_alt_tree.xml”

  每個haar級聯分類器都將給出略微不同的結果,這依賴於你的環境因素,所以你甚至可以用全部分類器,把結果結合在一起(如果你想要做盡可能多地檢測)。有一些更多的用於眼睛,頭部,嘴巴,鼻子的分類器在Modesto’s page下載。

  你可以在你的程式裡這樣做來進行人臉檢測:

  // Haar Cascade file, used for Face Detection. char *faceCascadeFilename = "haarcascade_frontalface_alt.xml"; // Load the HaarCascade classifier for face detection. CvHaarClassifierCascade* faceCascade; faceCascade = (CvHaarClassifierCascade*)cvLoad(faceCascadeFilename, 0, 0, 0); if( !faceCascade ) { printf("Couldnt load Face detector '%s'n", faceCascadeFilename); exit(1); } // Grab the next frame from the camera. IplImage *inputImg = cvQueryFrame(camera); // Perform face detection on the input image, using the given Haar classifier CvRect faceRect = detectFaceInImage(inputImg, faceCascade); // Make sure a valid face was detected. if (faceRect.width > 0) { printf("Detected a face at (%d,%d)!n", faceRect.x, faceRect.y); } .... Use 'faceRect' and 'inputImg' .... // Free the Face Detector resources when the program is finished cvReleaseHaarClassifierCascade( &cascade );

  對臉部影象進行預處理以便於識別

  現在你已經檢測到一張人臉,你可以使用那張人臉圖片進行人臉識別。然而,假如你嘗試這樣簡單地從一張普通圖片直接進行人臉識別的話,你將會至少損失10%的準確率!

  在一個人臉識別系統中,應用多種預處理技術對將要識別的圖片進行標準化處理是極其重要的。多數人臉識別演算法對光照條件十分敏感,所以假如在暗室訓練,在明亮的房間就可能不會被識別出來等等。這個問題可歸於“lumination dependent”,並且還有其它很多例子,比如臉部也應當在圖片的一個十分固定的位置(比如眼睛位置為相同的畫素座標),固定的大小,旋轉角度,頭髮和裝飾,表情(笑,怒等),光照方向(向左或向上等),這就是在進行人臉識別前,使用好的圖片預處理過濾器十分重要的原因。你還應該做一些其它事情,比如去除臉部周圍的多餘畫素(如用橢圓遮罩,只顯示其內部的人臉區域而不是頭髮或圖片背景,因為他們的變化多於臉部區域)。

  為簡單起見,我展示給你的人臉識別系統是使用灰度影象的特徵臉方法。所以我將向你說明怎樣簡單地把彩色影象轉化為灰度影象,並且之後簡單地使用直方圖均衡化(Histogram Equalization)作為一種自動的標準化臉部影象亮度和對比度的方法。為了得到更好的結果,你可以使用彩色人臉識別(color face recognition,ideally with color histogram fitting in HSV or another color space instead of RGB),或者使用更多的預處理,比如邊緣增強(edge enhancement),輪廓檢測(contour detection),手勢檢測(motion detection),等等。這份程式碼把圖片調整成一個標準的大小,但是可能會改變臉的縱橫比(aspect ratio)。你可以閱讀我這裡的教程HERE,來了解怎樣調整影象大小而不改變它的縱橫比。

  你可以看到一個預處理階段的例子:

  343x96

  這是把一幅RGB格式的影象或灰度影象轉變為灰度影象的基本程式碼。它還把影象調整成了固定的維度,然後應用直方圖均衡化來實現固定的亮度和對比度。

  // Either convert the image to greyscale, or use the existing greyscale image. IplImage *imageGrey; if (imageSrc->nChannels == 3) { imageGrey = cvCreateImage( cvGetSize(imageSrc), IPL_DEPTH_8U, 1 ); // Convert from RGB (actually it is BGR) to Greyscale. cvCvtColor( imageSrc, imageGrey, CV_BGR2GRAY ); } else { // Just use the input image, since it is already Greyscale. imageGrey = imageSrc; } // Resize the image to be a consistent size, even if the aspect ratio changes. IplImage *imageProcessed; imageProcessed = cvCreateImage(cvSize(width, height), IPL_DEPTH_8U, 1); // Make the image a fixed size. // CV_INTER_CUBIC or CV_INTER_LINEAR is good for enlarging, and // CV_INTER_AREA is good for shrinking / decimation, but bad at enlarging. cvResize(imageGrey, imageProcessed, CV_INTER_LINEAR); // Give the image a standard brightness and contrast. cvEqualizeHist(imageProcessed, imageProcessed); ..... Use 'imageProcessed' for Face Recognition .... if (imageGrey) cvReleaseImage(&imageGrey); if (imageProcessed) cvReleaseImage(&imageProcessed);



  把“特徵臉”用於人臉識別

  現在你已經有了一張經過預處理後的臉部圖片,你可以使用特徵臉(PCA)進行人臉識別。OpenCV自帶了執行PCA操作的”cvEigenDecomposite()”函式,然而你需要一個圖片資料庫(訓練集)告訴機器怎樣識別當中的人。

  所以你應該收集每個人的一組預處理後的臉部圖片用於識別。比如,假如你想要從10人的班級當中識別某個人,你可以為每個人儲存20張圖片,總共就有200張大小相同(如100×100畫素)的經預處理的臉部圖片。

  特徵臉的理論在Servo Magazine的兩篇文章(Face Recognition with Eigenface)中解釋了,但我仍會在這裡嘗試著向你解釋。

  我們使用“主元分析”把你的200張訓練圖片轉換成一個代表這些訓練圖片主要區別的“特徵臉”集。首先它將會通過獲取每個畫素的平均值,生成這些圖片的“平均人臉圖片”。然後特徵臉將會與“平均人臉”比較。第一個特徵臉是最主要的臉部區別,第二個特徵臉是第二重要的臉部區別,等等……直到你有了大約50張代表大多數訓練集圖片的區別的特徵臉。

  130x150130x150130x150

  在上面這些示例圖片中你可以看到平均人臉和第一個以及最後一個特徵臉。它們是從一個四人的每人30幅圖片的訓練集中生成的。注意到,平均人臉顯示的是一個普通人的平滑臉部結構,排在最前的一些特徵臉顯示了一些主要的臉部特徵,而最後的特徵臉(比如Eigenface 119)主要是影象噪聲。你可以在下面看到前32張特徵臉。

  532x307

  使用主元分析法進行人臉識別

  簡單地說,特徵臉方法(Principal Component Analysis)計算出了訓練集中圖片的主要區別,並且用這些“區別”的組合來代表每幅訓練圖片。

  比如,一張訓練圖片可能是如下的組成:

  (averageFace) + (13.5% of eigenface0) – (34.3% of eigenface1) + (4.7% of eigenface2) + … + (0.0% of eigenface199).

  一旦計算出來,就可以認為這張訓練圖片是這200個比率(ratio):

  {13.5, -34.3, 4.7, …, 0.0}.

  用特徵臉圖片分別乘以這些比率,並加上平均人臉圖片 (average face),從這200個比率還原這張訓練圖片是完全可以做到的。但是既然很多排在後面的特徵臉是影象噪聲或者不會對圖片有太大作用,這個比率表可以被降低到只剩下最主要的,比如前30個,不會對影象質量有很大影響。所以現在可以用30個特徵臉,平均人臉圖片,和一個含有30個比率的表,來代表全部的200張訓練圖片。

  有趣的是,這意味著,我們已經找到了一種方法把200張圖片壓縮成31張圖片再加上一點點資料,而不丟失很多的影象質量。但是這個教程是關於人臉識別的,而不是影象壓縮的,所以我們將會忽略它:-)

  在另一幅圖片中識別一個人,可以應用相同的PCA計算,使用相同的200個特徵臉來尋找200個代表輸入圖片的比率。並且仍然可以只保留前30個比率而忽略其餘的比率,因為它們是次要的。然後通過搜尋這些比率的表,尋找在資料庫中已知的20個人,來看誰的前30個比率與輸入圖片的前30個比率最接近。這就是尋找與輸入圖片最相似的訓練圖片的基本方法,總共提供了200張訓練圖片。

  離線命令列訓練的實現

  為了實現離線訓練,也就是通過命令列(command-line)使用檔案作為輸入輸出,我使用了與Servo Magazine裡Face Recognition with Eigenface相同的實現,所以你可以先閱讀這篇文章,但是我做了一些小的改動。

  基本上,從訓練圖片建立一個人臉識別資料庫,就是建立一個列出圖片檔案和每個檔案代表的人的文字檔案。

  比如,你可以把這些輸入一個名為”4_images_of_2_people.txt”的文字檔案:

  1 Shervin dataShervinShervin1.bmp 1 Shervin dataShervinShervin2.bmp 1 Shervin dataShervinShervin3.bmp 1 Shervin dataShervinShervin4.bmp 2 Chandan dataChandanChandan1.bmp 2 Chandan dataChandanChandan2.bmp 2 Chandan dataChandanChandan3.bmp 2 Chandan dataChandanChandan4.bmp

  它告訴這個程式,第一個人的名字叫“Shervin”,而Shervin的四張預處理後的臉部影象在”dataShervin”資料夾,第二個人的名字叫”Chandan”,在”dataChandan”中有她的四張圖片。這個程式可以使用”loadFaceImgArray()”函式把這些圖片載入到一個圖片陣列中。注意,為了簡單起見,它不允許空格或特殊字元出現在人名中,< >所以你可能想要實現這一功能,或者把人名中的空格用下劃線代替(比如 Shervin_Emami)。

  為了從這些載入好的圖片中建立一個數據庫,你可以使用OpenCV的”cvCalcEigenObjects()”和”cvEigenDecomposite()”函式,比如:

  // Tell PCA to quit when it has enough eigenfaces. CvTermCriteria calcLimit = cvTermCriteria( CV_TERMCRIT_ITER, nEigens, 1); // Compute average image, eigenvectors (eigenfaces) and eigenvalues (ratios). cvCalcEigenObjects(nTrainFaces, (void*)faceImgArr, (void*)eigenVectArr, CV_EIGOBJ_NO_CALLBACK, 0, 0, &calcLimit, pAvgTrainImg, eigenValMat->data.fl); // Normalize the matrix of eigenvalues. cvNormalize(eigenValMat, eigenValMat, 1, 0, CV_L1, 0); // Project each training image onto the PCA subspace. CvMat projectedTrainFaceMat = cvCreateMat( nTrainFaces, nEigens, CV_32FC1 ); int offset = projectedTrainFaceMat->step / sizeof(float); for(int i=0; i<nTrainFaces; i++) { cvEigenDecomposite(faceImgArr[i], nEigens, eigenVectArr, 0, 0, pAvgTrainImg, projectedTrainFaceMat->data.fl + i*offset); }



  現在你有了:

  • 平均人臉圖片”pAvgTrainImg”,
  • 包含特徵臉圖片的陣列”eigenVectArr[]“(如:假如你使用了nEigens=200 張訓練圖片,將得到200 個特徵臉),
  • 特徵值矩陣 (即特徵臉的比率,eigenface ratios) 每張圖片的”projectedTrainFaceMat” 。

  現在這些可以被儲存成一個檔案,也就是人臉識別的資料庫。程式碼中的”storeTrainingData()”函式將會把這些資料儲存到”facedata.xml“檔案裡,它可以隨時被重新載入來識別經訓練過的人。程式碼中也有一個”storeEigenfaceImages()”的函式,生成前面提到的圖片,平均人臉圖片被儲存到”out_averageImage.bmp”,特徵臉被儲存到”out_eigenfaces.bmp”。

  離線命令列識別的實現

  在離線訓練階段,系統嘗試從一個文字檔案中的列表讀取若干張影象中的人臉,並進行識別。為了實現它,我仍然使用Servo Magazine的Face Recognition with Eigenface的實現,在此基礎上擴充套件。

  用於離線訓練的相同格式的文字檔案也可用於離線識別。這個文字檔案列出了用於測試的影象檔案和對應於這張影象的正確的人名。隨後這個程式就對每一幅圖片進行識別,並且檢驗文字檔案中的真實值(圖片對應的正確人名)來確認其是否識別正確,並統計它的準確率。

  離線識別的實現幾乎與離線訓練完全相同:

  1. 讀取原來的用於訓練的文字檔案(現在用於識別),把若干個圖片檔案(預處理後的臉部圖片)和名字載入一個圖片陣列。這些在程式碼中用“loadFaceImgArray()”函式執行。

  2. 平均人臉,特徵臉和特徵值(比率)使用函式“loadTrainingData()” 從人臉識別資料庫檔案(the face recognition database fil)“facedata.xml”載入。

  3. 使用OpenCV的函式“cvEigenDecomposite()”,每張輸入的圖片都被投影到PCA子空間,來觀察哪些特徵臉的比率最適合於代表這張圖片。

  4. 現在有了特徵值(特徵臉圖片的比率)代表這張輸入圖片,程式需要查詢原始的訓練圖片,找出擁有最相似比率的圖片。這些用數學的方法在“findNearestNeighbor()”函式中執行,採用的是“歐幾里得距離(Euclidean Distance)”,但是它只是基本地檢查輸入圖片與每張訓練圖片的相似性,找到最相似的一張:一張在歐幾里得空間上與輸入圖片距離最近的圖片。就像在 Servo Magazine的文章上提到的那樣,如果使用馬氏距離( the Mahalanobis space,需要在程式碼裡定義 USE_MAHALANOBIS_DISTANCE),你可以得到更準確的結果。

  5. 在輸入圖片與最相似圖片之間的距離用於確定可信度(confidence),作為是否識別出某人的指導。1.0的可信度意味著完全相同,0.0或者負的可信度意味著非常不相似。但是需要注意,我在程式碼中用到的可信度公式只是一個非常基本的可信度測量,不是很可靠,但是我覺得多數人會想要看到一個粗略的可信度值。你可能發現它對你的圖片給出錯誤的值,所以你可以禁用它(比如:把可信度設為恆定的1.0)。

  一旦指導哪張訓練圖片和輸入圖片最相似,並假定可信度值不是太低(應該至少是0.6或更高),那麼它就指出了那個人是誰,換句話說,它識別出了那個人!

  攝像頭實時識別的實現

  要讓一個攝像頭視訊流輸入取代檔案列表是十分簡單的。基本上,你只要從攝像頭抓取一幀,而不是讀取一個檔案,並且一直執行下去直到使用者退出,而不是等待檔案讀取到頭就行了。OpenCV為此提供了“cvCreateCameraCapture()”函式(或cvCaptureFromCAM())。

  從攝像頭抓取一幀可以簡單地用下面的函式實現:

  // Grab the next camera frame. Waits until the next frame is ready, and // provides direct access to it, so do NOT modify or free the returned image! // Will automatically initialize the camera on the first frame. IplImage* getCameraFrame(CvCapture* &camera) { IplImage *frame; int w, h; // If the camera hasn't been initialized, then open it. if (!camera) { printf("Acessing the camera ...\n"); camera = cvCreateCameraCapture( 0 ); if (!camera) { printf("Couldn't access the camera.\n"); exit(1); } // Try to set the camera resolution to 320 x 240. cvSetCaptureProperty(camera, CV_CAP_PROP_FRAME_WIDTH, 320); cvSetCaptureProperty(camera, CV_CAP_PROP_FRAME_HEIGHT, 240); // Get the first frame, to make sure the camera is initialized. frame = cvQueryFrame( camera ); if (frame) { w = frame->width; h = frame->height; printf("Got the camera at %dx%d resolution.\n", w, h); } // Wait a little, so that the camera can auto-adjust its brightness. Sleep(1000); // (in milliseconds) } // Wait until the next camera frame is ready, then grab it. frame = cvQueryFrame( camera ); if (!frame) { printf("Couldn't grab a camera frame.\n"); exit(1); } return frame; }



  這個函式可以這樣用:

  CvCapture* camera = 0; // The camera device. while ( cvWaitKey(10) != 27 ) { // Quit on "Escape" key. IplImage *frame = getCameraFrame(camera); ... } // Free the camera. cvReleaseCapture( &camera );



  請注意,假如你是為windows作業系統開發,你可以使用 Theo Watson 的 videoInput Library v0.1995 達到兩倍於這些程式碼的速度。它使用了DirectShow硬體加速,然而OpenCV使用VFW已經15年不變了!
把我已經解釋的這些部分放到一起,人臉識別系統執行步驟如下:

  1. 從攝像頭抓取一幀圖片。

  2. 轉換彩色圖片幀為灰度圖片幀。

  3. 檢測灰度圖片幀的人臉。

  4. 處理圖片以顯示人臉區域(使用 cvSetImageROI() 和 cvCopyImage())。

  5. 預處理臉部圖片。

  6. 識別圖片中的人。

  攝像頭實時訓練的實現

  現在你已經有了一個用攝像頭實時識別人臉的方法,但是要學習新人臉,你不得不關閉這個程式,把攝像頭的圖片儲存成圖片檔案,更新圖片列表,使用離線命令列訓練的方法,然後以實時攝像頭識別的模式再次執行這個程式。所以實際上,你完全可以用程式來執行實時的攝像頭訓練!

  這裡就是用攝像頭視訊流把一個新的人加入人臉識別資料庫而不關閉程式的一個最簡單的方法:

  1. 從攝像頭收集一些圖片(預處理後的臉部圖片),也可以同時執行人臉識別。

  2. 用“cvSaveImage()”函式儲存這些臉部圖片作為圖片檔案存入磁碟。

  3. 加入每張臉部圖片的檔名到訓練圖片列表(用於離線命令列訓練的文字檔案)的底部。

  4. 一旦你準備實時訓練,你將從所有圖片檔案形成的資料庫重新訓練。這個文字檔案列出了新加入的訓練圖片檔案,並且這些圖片被電腦存為了圖片檔案,所以實時訓練工作起來跟離線訓練一樣。

  5. 但是在重新訓練之前,釋放任何正在使用的資源和重新初始化也很必要。應該像你重新啟動了這個程式一樣。比如,在圖片被儲存成檔案並且加入訓練列表的文字檔案後,你應該再執行相同的離線訓練(包括從訓練列表檔案載入圖片,用PCA方法找出新訓練集的特徵臉和比率)之前釋放特徵臉陣列。 這個實時訓練的方法相當低效,因為假如在訓練集中有50個人,而你多加了一個人,它將為51個人重新訓練,這是非常不好的,因為訓練的時間隨著使用者或圖片數量的增加呈指數級增長。但是假如你只是處理百來張圖片,它不需要多少秒就可以完成。

  檔案下載請轉到原文。

  The article source is