OpenCV nhận dạng face Recognition
I. Introduction Khi bắt đầu với lĩnh vực nhận dạng mặt (Face Recognition-FR, không phải Face detetion-phát hiện khuôn mặt người trong ảnh), tôi đã mất khá nhiều thời gian cho các thuật toán cơ bản của nhận dạng mặt: PCA, WPCA, LDA, 2DPCA, KPCA, LBP … hay các câu hỏi đại loại như: dùng ...
I. Introduction
Khi bắt đầu với lĩnh vực nhận dạng mặt (Face Recognition-FR, không phải Face detetion-phát hiện khuôn mặt người trong ảnh), tôi đã mất khá nhiều thời gian cho các thuật toán cơ bản của nhận dạng mặt: PCA, WPCA, LDA, 2DPCA, KPCA, LBP … hay các câu hỏi đại loại như: dùng ngôn ngữ và công cụ gì để cài đặt thuật toán, Matlab, Python, C++ hay C#? Cuối cùng thấy rằng việc chọn Matlab là thích hợp nhất (cho việc nghiên cứu thôi, tất nhiên) và việc hiểu được cặn kẽ các thuật toán cơ bản như PCA là rất quan trọng cho những ai bắt đầu, vì vậy hy vọng bài viết này sẽ có ích cho ai muốn tìm hiểu về nhận dạng mặt người.
Nhận dạng mặt người (Face recognition) là một lĩnh vực nghiên cứu của ngành Computer Vision, và cũng được xem là một lĩnh vực nghiên cứu của ngành Biometrics (tương tự như nhận dạng vân tay – Fingerprint recognition, hay nhận dạng mống mắt – Iris recognition). Xét về nguyên tắc chung, nhận dạng mặt có sự tương đồng rất lớn với nhận dạng vân tay và nhận dạng mống mắt, tuy nhiên sự khác biệt nằm ở bước trích chọn đặt trưng (feature extraction) của mỗi lĩnh vực. Trong khi nhận dạng vân tay và mống mắt đã đạt tới độ chín, tức là có thể áp dụng trên thực tế một cách rộng rãi thì nhận dạng mặt người vẫn còn nhiều thách thức và vẫn là một lĩnh vực nghiên cứu thú vị với nhiều người. So với nhận dạng vân tay và mống mắt, nhận dạng mặt có nguồn dữ liệu phong phú hơn (bạn có thể nhìn thấy mặt người ở bất cứ tấm ảnh, video clip nào liên quan tới con người trên mạng) và ít đòi hỏi sự tương tác có kiểm soát hơn (để thực hiện nhận dạng vân tay hay mống mắt, dữ liệu input lấy từ con người đòi hỏi có sự hợp tác trong môi trường có kiểm soát). Hiện nay các phương pháp nhận dạng mặt được chia thành nhiều hướng theo các tiêu chí khác nhau: nhận dạng với dữ liệu đầu vào là ảnh tĩnh 2D(still image based FR) là phổ biến nhất, tuy nhiên tương lai có lẽ sẽ là 3D FR (vì việc bố trí nhiều camera 2D sẽ cho dữ liệu 3D và đem lại kết quả tốt hơn, đáng tin cậy hơn), cũng có thể chia thành 2 hướng là: làm với dữ liệu ảnh và làm với dữ liệu video. Trên thực tế người ta hay chia các phương pháp nhận dạng mặt ra làm 3 loại: phương pháp tiếp cận toàn cục (global, như Eigenfaces-PCA, Fisherfaces-LDA), phương pháp tiếp cận dựa trên các đặc điểm cục bộ (local feature based, như LBP, Gabor wavelets) và phương pháp lai (hybrid, là sự kết hợp của hai phương pháp toàn cục và local feature). Phương pháp dựa trên các đặc điểm cục bộ đã được chứng minh là ưu việt hơn khi làm việc trong các điều kiện không có kiểm soát và có thể nói rằng lịch sử phát triển của nhận dạng mặt (A never ending story) là sự phát triển của các phương pháp trích chọn đặc trưng (feature extractrion methods) được sử dụng trong các hệ thống dựa trên feature based. Các ứng dụng cụ thể của nhận dạng mặt dựa trên 2 mô hình nhận dạng: identification (xác định danh tính, bài toán 1-N), và verification (xác thực danh tính, bài toán 1-1). Trong bài toán identification, ta cần xác định danh tính của ảnh kiểm tra, còn trong bài toán verification ta cần xác định 2 ảnh có cùng thuộc về một người hay không.
Các pha trong một hệ thống nhận dạng mặt: để xây dựng một hệ thống nhận dạng mặt, cũng không hề đơn giản, bước đầu tiên cần thực hiện là face detection, tức là phát hiện phần ảnh mặt trong dữ liệu input (CSDL ảnh, video …) và cắt lấy phần ảnh mặt để thực hiện nhận dạng (face cropping), bước thứ hai là tiền xử lý ảnh (preprocessing) bao gồm các bước căn chỉnh ảnh (face image alignment) và chuẩn hóa ánh sáng (illumination normalization) (ở đây tôi đang nói tới các ảnh có góc nhìn thẳng – frontal view face image), tiếp đến là bước trích chọn đặc điểm (feature extraction), ở bước này một phương pháp trích chọn đặc điểm nào đó (mẫu nhị phân cục bộ – Local Binary Pattern – LBP, Gabor wavelets, …) sẽ được sử dụng với ảnh mặt để trích xuất các thông tin đặc trưng cho ảnh, kết quả là mỗi ảnh sẽ được biểu diễn dưới dạng một vector đặc điểm (feature vector), bước tiếp theo là bước nhận dạng (recognition) hay phân lớp (classification), tức là xác định danh tính (identity) hay nhãn (label) của ảnh – đó là ảnh của ai. Ở bước classification, thường thì phương pháp k-láng giềng gần nhất (k-nearest neighbor:kNN) sẽ được sử dụng, thực tế cho thấy việc dùng SVM (Support Vector Machine) không mang lại hiệu quả cao hơn mà còn chậm hơn. Dữ liệu cho một hệ thống nhận dạng mặt được chia làm 3 tập: tập huấn luyện (training set), tập tham chiếu (reference set hay gallery set) và tập để nhận dạng (probe set hay query set, đôi khi còn gọi là test set). Trong nhiều hệ thống, tập training trùng với tập reference. Tập training gồm các ảnh được dùng để huấn luyện (hay học-learning), thông thường tập này được dùng để sinh ra một không gian con (projection subspace) là một ma trận và phương pháp hay được sử dụng là PCA (Principal Component Analysis), WPCA (Whitened PCA), LDA (Linear Discriminant Analysis), KPCA (Kernel PCA). Tập reference gồm các ảnh đã biết danh tính được chiếu (projected) vào không gian con ở bước training. Bước training nhằm 2 mục đích: giảm số chiều (dimension reduction) của các vector đặc điểm (feature vector) vì các vector này thường có độ dài khá lớn (vài nghìn tới vài trăm nghìn) nên nếu để nguyên thì việc tính toán sẽ rất rất lâu, thứ hai là làm tăng tính phân biệt (discriminative) giữa các ảnh khác lớp (định danh khác nhau), ngoài ra có thể làm giảm tính phân biệt giữa các ảnh thuộc về một lớp (tùy theo phương pháp, ví dụ như Linear Discriminant Analysis LDA- còn gọi là Fisher Linear Discriminant Analysis-Fisherface là một phương pháp làm việc với tập training mà mỗi đối tượng có nhiều ảnh mặt ở các điều kiện khác nhau). Sau khi thực hiện chiếu tập reference vào không gian con, hệ thống lưu lại kết quả là một ma trận với mỗi cột của ma trận là một vector tương ứng với ảnh (định danh đã biết) để thực hiện nhận dạng (hay phân lớp). Nhận dạng (hay phân lớp) được thực hiện với tập các ảnh probe, sau khi tiền xử lý xong, mỗi ảnh sẽ được áp dụng phương pháp trích chọn đặc điểm (như với các ảnh thuộc tập training và reference) và được chiếu vào không gian con. Tiếp đến việc phân lớp sẽ dựa trên phương pháp k-NN, định danh của một ảnh cần xác định sẽ được gán là định danh của ảnh có khoảng cách (distance) gần với nó nhất. Ở đây cần lưu ý là mỗi ảnh là một vector nên có thể dùng khái niệm hàm khoảng cách giữa hai vector để đo sự khác biệt giữa các ảnh.
II.Làm thế nào để xử lý trước ảnh mặt để nhận diện khuôn mặt:
Bây giờ bạn đã phát hiện một khuôn mặt, bạn có thể sử dụng hình ảnh khuôn mặt cho nhận diện khuôn mặt. Tuy nhiên, nếu bạn đã cố gắng để đơn giản là thực hiện nhận dạng khuôn mặt trực tiếp trên một hình ảnh hình ảnh bình thường, có thể bạn sẽ nhận được ít hơn độ chính xác 10%! Nó là vô cùng quan trọng để áp dụng các kỹ thuật hình ảnh trước khi chế biến khác nhau để tiêu chuẩn hóa các hình ảnh mà bạn cung cấp cho một nhận dạng khuôn mặt hệ thống. Hầu hết các thuật toán nhận dạng khuôn mặt cực kỳ nhạy cảm với điều kiện ánh sáng, do đó nếu nó được huấn luyện để nhận ra một người khi họ đang ở trong một căn phòng tối, thì có lẽ nó wont nhận ra họ trong một căn phòng sáng, vv Vấn đề này được gọi là "lumination phụ thuộc ", và cũng có nhiều vấn đề khác, chẳng hạn như mặt cũng phải ở trong một vị trí rất phù hợp trong những hình ảnh (như mắt là trong cùng một điểm ảnh tọa độ), kích thước phù hợp, góc quay, tóc và trang điểm, cảm xúc ( mỉm cười, giận dữ, vv), vị trí của đèn (bên trái hoặc bên trên, vv). Đây là lý do tại sao nó là rất quan trọng để sử dụng một bộ lọc hình ảnh tốt tiền xử lý trước khi áp dụng nhận dạng khuôn mặt. Bạn cũng nên làm những việc như loại bỏ các điểm ảnh xung quanh khuôn mặt mà không được sử dụng, chẳng hạn như với một mặt nạ hình elip để chỉ hiển thị các khu vực mặt bên trong, không phải là tóc và hình nền, kể từ khi họ thay đổi nhiều so với khuôn mặt không. Để đơn giản , hệ thống nhận diện khuôn mặt tôi sẽ cho bạn thấy là Eigenfaces sử dụng hình ảnh thang độ xám. Vì vậy, tôi sẽ cho bạn thấy làm thế nào để dễ dàng chuyển đổi hình ảnh màu xám (còn được gọi là "màu xám"), và sau đó dễ dàng áp dụng Histogram Equalization là một phương pháp rất đơn giản của tự động tiêu chuẩn hóa độ sáng và độ tương phản của hình ảnh gương mặt của bạn. Để có kết quả tốt hơn, bạn có thể sử dụng màu sắc nhận diện khuôn mặt (lý tưởng với phụ kiện màu sắc biểu đồ trong HSV hoặc một không gian màu thay vì RGB), hoặc áp dụng nhiều công đoạn chế biến như tăng cường cạnh, phát hiện đường viền, phát hiện chuyển động, vv Ngoài ra, mã này là thay đổi kích thước hình ảnh đến một kích thước tiêu chuẩn, nhưng điều này có thể thay đổi tỷ lệ khía cạnh của khuôn mặt.
// Hoặc chuyển đổi hình ảnh để thang màu xám, hoặc sử dụng các hình ảnh màu xám hiện có. IplImage * imageGrey; if (imageSrc-> nChannels == 3) { imageGrey = cvCreateImage (cvGetSize (imageSrc), IPL_DEPTH_8U, 1); // Chuyển đổi từ RGB (thực ra nó là BGR) để Greyscale. cvCvtColor (imageSrc, imageGrey, CV_BGR2GRAY); } else { // Chỉ cần sử dụng các hình ảnh đầu vào, vì nó đã là Greyscale. imageGrey = imageSrc; } // Thay đổi kích thước hình ảnh là một kích thước phù hợp , ngay cả khi những thay đổi tỉ lệ. IplImage * imageProcessed; imageProcessed = cvCreateImage (cvSize (chiều rộng, chiều cao), IPL_DEPTH_8U, 1); . // Tạo các hình ảnh kích thước cố định // CV_INTER_CUBIC hoặc CV_INTER_LINEAR là tốt cho việc mở rộng, và // CV_INTER_AREA là tốt cho thu hẹp / decimation, nhưng xấu là sự tăng cường. cvResize (imageGrey, imageProcessed, CV_INTER_LINEAR); . // cho hình ảnh độ sáng và độ tương phản tiêu chuẩn cvEqualizeHist (imageProcessed, imageProcessed); ..... Sử dụng 'imageProcessed' cho Face Recognition .... if (imageGrey) cvReleaseImage (& imageGrey); if (imageProcessed) cvReleaseImage (& imageProcessed);
III.Làm thế nào để phát hiện một khuôn mặt bằng mặt Detector OpenCV:
Như đã đề cập ở trên, giai đoạn đầu tiên trong nhận diện khuôn mặt Face Detection là. Các thư viện OpenCV làm cho nó khá dễ dàng để phát hiện một khuôn mặt phía trước trong một hình ảnh bằng cách sử Haar Cascade Mặt Detector (còn gọi là phương pháp Viola-Jones). Chức năng "cvHaarDetectObjects" trong OpenCV thực hiện việc phát hiện khuôn mặt đích thực, nhưng chức năng là một chút tẻ nhạt để sử dụng trực tiếp, vì vậy nó là dễ nhất để sử dụng chức năng bao bọc này:
// Thực hiện nhận diện khuôn mặt trên hình ảnh đầu vào, sử dụng Haar Cascade nhất định. // Trả về một hình chữ nhật với các khu vực phát hiện trong hình ảnh nhất định. CvRect detectFaceInImage (IplImage * inputImg, CvHaarClassifierCascade * cascade) { // kích thước khuôn mặt nhỏ nhất. CvSize minFeatureSize = cvSize (20, 20); . // Chỉ tìm kiếm 1 khuôn mặt int cờ = CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_DO_ROUGH_SEARCH; . // Làm thế nào chi tiết nên việc tìm kiếm được nổi search_scale_factor = 1.1f; IplImage * detectImg; IplImage * greyImg = 0; CvMemStorage * lưu trữ; CvRect rc; tăng gấp đôi t; CvSeq * dễ phân biệt; kích thước CvSize; int i, ms, nFaces ; lưu trữ = cvCreateMemStorage (0); cvClearMemStorage (lưu trữ); // Nếu hình ảnh là màu sắc, sử dụng một bản sao màu xám của hình ảnh. DetectImg = (IplImage *) inputImg; if (inputImg-> nChannels> 1) { size = cvSize (inputImg-> chiều rộng, inputImg-> chiều cao); greyImg = cvCreateImage (kích thước, IPL_DEPTH_8U, 1); cvCvtColor (inputImg, greyImg, CV_BGR2GRAY); detectImg = greyImg; // Sử dụng hình ảnh thang độ xám. } // Phát hiện tất cả các khuôn mặt trong hình ảnh thang độ xám. t = (double) cvGetTickCount () ; rects = cvHaarDetectObjects (detectImg, thác, lưu trữ, search_scale_factor, 3, cờ, minFeatureSize); t = (double) cvGetTickCount () - t; ms = cvRound (t / ((gấp đôi) cvGetTickFrequency () * 1000.0)); nFaces = rects-> tổng; printf ( "Face Detection mất% d ms và tìm thấy% d đối tượng n", Ms, nFaces); // Lấy khuôn mặt được phát hiện đầu tiên (lớn nhất). If (nFaces> 0) rc = * (CvRect *) cvGetSeqElem (dễ phân biệt, 0); khác rc = cvRect (-1, -1, - 1, -1); // không thể tìm thấy những khuôn mặt. if (greyImg) cvReleaseImage (& greyImg); cvReleaseMemStorage (và lưu trữ); // cvReleaseHaarClassifierCascade (& thác); trở lại rc; // Trả lại khuôn mặt lớn nhất được tìm thấy, hoặc (- 1, -1, -1, -1). }
Bây giờ bạn chỉ có thể gọi là "detectFaceInImage" bất cứ khi nào bạn muốn tìm một khuôn mặt trong ảnh. Bạn cũng cần phải xác định phân loại mặt mà OpenCV nên sử dụng để phát hiện khuôn mặt.Ví dụ, OpenCV đi kèm với các phân loại khác nhau để phát hiện phía trước mặt, cũng như một số gương mặt cấu hình (xem bên), phát hiện mắt, phát hiện mũi, phát hiện miệng, toàn bộ cơ thể phát hiện, vv Bạn thực sự có thể sử dụng chức năng này với bất kỳ các dò khác nếu bạn muốn, hoặc thậm chí tạo máy dò tùy chỉnh riêng của bạn như cho xe hoặc phát hiện người , đối với trán nhận diện khuôn mặt, bạn có thể chọn một trong những Classifiers Haar Cascade mà đến với OpenCV (trong "data haarcascades " thư mục):
- "Haarcascade_frontalface_default.xml"
- "Haarcascade_frontalface_alt.xml"
- "Haarcascade_frontalface_alt2.xml"
- "Haarcascade_frontalface_alt_tree.xml"
Mỗi người sẽ cho kết quả hơi khác nhau tùy thuộc vào môi trường của bạn, do đó bạn thậm chí có thể sử dụng tất cả trong số họ và kết hợp các kết quả với nhau (nếu bạn muốn nhận diện nhất)
// Haar Cascade tập tin, sử dụng để nhận diện khuôn mặt. Char * faceCascadeFilename ="Haarcascade_frontalface_alt.xml"; // Nạp các phân HaarCascade để phát hiện khuôn mặt. CvHaarClassifierCascade * faceCascade; faceCascade = (CvHaarClassifierCascade *) cvLoad (faceCascadeFilename, 0, 0, 0); if (! FaceCascade) { printf ("Tải Couldnt Mặt dò '% s' n", FaceCascadeFilename); exit (1); } // Lấy frame kế tiếp từ máy ảnh. IplImage * inputImg = cvQueryFrame (camera); // Thực hiện nhận diện khuôn mặt trên hình ảnh đầu vào, bằng cách sử dụng phân loại Haar được CvRect faceRect = detectFaceInImage (inputImg , faceCascade); // Hãy chắc chắn rằng một khuôn mặt có giá trị đã được phát hiện. if (faceRect.awidth> 0) { printf ( "Đã phát hiện một khuôn mặt tại (% d,% d)! N", FaceRect.x, faceRect.y); } .... Sử dụng 'faceRect' và 'inputImg' .... // Miễn phí các nguồn tài nguyên mặt Detector khi chương trình kết thúc cvReleaseHaarClassifierCascade (& thác);