Mỗi ảnh trong một phân lớp sẽ được đặt ở một thư mục khác nhau và sẽ được gán một trọng số để tiến hành nhận dạng sau này
Chương trình tạo file CSV: Phụ lục 2
27
Hình 3. 5 Nội dung file CSV 3.4 Lưu đồ giải thuật tổng quát 3.4 Lưu đồ giải thuật tổng quát
Yêu cầu của đề tài là xây dựng một hệ thống chạy trên thời gian thực, hoạt động 24/24, có thể nhận dạng được một hoặc nhiều người cùng lúc.
Trong đề tài này sử dụng 2 cơ sở dữ liệu về đặc trưng gương mặt người được huấn luyện theo thuật toán AdaBoost được OpenCV cung cấp là:
Haarcascade_frontalface_alt2.xml: Đặc trưng gương mặt theo hướng nhiền chính diện.
Haarcascade_profileface.xml: Đặc trưng gương mặt theo hướng nhìn từ cạnh bên.
Để tăng độ chính xác của việc nhận diện gương mặt, ta có thể thu thập thêm các mẫu ảnh về gương mặt người ở các góc nhìn khác nhau. Sau đó huấn luyện các mẫu ảnh đó để được các tập tin dữ liệu *.xml của các đặc trưng gương mặt từ nhiều góc nhìn.
Việc tạo được đữ liệu chính xác cần số lượng mẫu huấn luyện phải nhiều và ở các điều kiện môi trường ngoại cảnh khác nhau. Và để huấn luyện được số lượng lớn mẫu đó thì cần một máy tính có cấu hình mạnh để việc huấn luyện có thể hồn thành nhanh chóng.
28 Chuẩn hóa khn mặt
Load file CSV
Huấn luyện đặc trưng khuôn mặt Load đặc trưng khn
mặt
Chuyển sang ảnh xám
Dị tìm đặc trưng khn mặt
Chuyển về kich thước khuôn mặt huấn luyện Nhận ảnh từ camera Phát hiện khn mặt Tính Eigenvalue và EigenVector Tính khoảng cách so với tập mẫu So sánh khoảng cách với ngưỡng Đóng khung và hiển thị tên Đóng khung và hiển thị “Unknow” N Y Nhỏ hơn Lớn hơn
29
3.5 Chương trình thực hiện
30
Chương 4
KẾT QUẢ THỰC HIỆN
Chương trình được ứng dụng chạy thử nghiệm trong nhiều điều kiện ánh sáng khác nhau, từ mơi trường có ánh sáng yếu cho đến môi trường đủ sáng ở các khoảng cách khác nhau, nhận dạng một hoặc nhiều người xuất hiện cùng lúc, và đạt được các kết quả như sau:
4.1 Kết quả nhận dạng một người
Trong môi trường ánh sáng phù hợp với môi trường ánh sáng khi lấy mẫu khn mặt thì chương trình có tỷ lệ nhận dạng chính xác cao. Khi thay đổi mơi trường sáng thì chỉ có phân lớp thứ 3 (ảnh lấy mẫu trực tiếp từ camera), cho tỷ lệ nhận dạng cao, còn phân lớp 1, 2 (ảnh lấy mẫu từ internet) khi thay đổi mơi trường sáng thì hầu như khơng nhận dạng được.
31
Hình 4. 2 Ảnh nhận dạng diễn viên Leonardo Decapiro - phân lớp thứ 2
32
4.2 Kết quả nhận dạng hai người
Trong môi trường ánh sáng phù hợp với môi trường ánh sáng tạo tập mẫu huấn luyện thì chương trình cho kết quả nhận dạng tốt. Khi có ánh sáng chói hoặc khơng đủ sáng thì chương trình chỉ cho kết quả nhận dạng đúng ở phân lớp 3.
Hình 4. 4 Nhận dạng khi xuất hiện mặt người ở phân lớp 1,3
33
4.3 Kết quả nhận dạng khi có người lạ xuất hiện
Trong mơi trường ánh sáng phù hợp với môi trường ánh sáng tạo tập mẫu huấn luyện thì chương trình cho kết quả nhận dạng tốt ở phân lớp 3. Ở phân lớp 1,2 chương trình cho kết quả nhận dạng thấp.
Hình 4. 6 Phân loại được khi có người lạ xuất hiện
34
35
Chương 5
KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN
5.1 Kết luận.
- Trên cơ sở nghiên cứu lý thuyết tổng quan về các phương pháp nhận dạng mặt người trong thời gian thực. Đặc biệt là thuật toán PCA, các đặc trưng Eigenfaces và Eigenvector kết hợp với kỹ thuật lập trình C++. Tơi đã áp dụng thành cơng thuật tốn nhận dạng phân tích thành phần chính PCA vào bài tốn nhận dạng mặt người trong thời gian thực. Xây dựng thành công phần mềm nhận dạng được một hoặc nhiều người xuất hiện trong khung ảnh. Đặc biệt chương trình xử lý ảnh động, lấy trực tiếp từ camera. Bên cạnh đó, trong q trình xây dựng chương trình ,tơi đã tìm hiểu về thư viện mã nguồn mở OpenCV, qua đó biết cách sử dụng các hàm trong thư viện OpenCV để xây dựng chương trình nhận dạng mặt người trên kit nhúng sau này.
- Về chương trình demo, chương trình được chạy thử nghiệm trên máy tính có bộ xử lý Core i7, thế hệ 4, tốc độ 2,4GHz; RAM 8GB. Tốc độ xử lý của chương trình khoảng 5 khung hình/s, khi ép xung lên 3,2Ghz thì có thể xử lý được khoảng 8 khung hình/s. Hiệu xuất của chương trình cịn tùy theo chất lượng của loại webcam được sử dụng, tập cơ sở dữ liệu lấy mẫu, và điều kiện ánh sáng khi lấy mẫu. Trong điều kiện ánh sáng phù hợp với môi trường ánh sáng khi lấy mẫu thì chương trình cho kết quả nhận dạng tốt, nhưng khi điều kiện ánh sáng thay đổi thì chương trình hay cho kết quả lẫn lộn giữa các phân lớp. Điều này cho thấy thuật toán PCA rất dễ bị ảnh hưởng của nhiễu do gương mặt bị nghiêng, hay mặt có râu, mặt cười, và đặc biệt là nhiễu do ánh sáng.
5.2 Hướng phát triển.
- Về cơ bản đã hoàn thành các yêu cầu mà ban đầu đề tài đề ra. Tuy nhiên, để ứng dụng vào thực tế thì thuật tốn PCA vẫn cịn nhiều điểm hạn chế, mà cụ thể đó là ảnh hưởng từ nhiễu. Do đó, hướng phát triển tiếp theo của đề tài sẽ tập trung vào phần xử lý nhiễu, hoặc kết hợp với các thuật toán nhận dạng khác để xây dựng một hệ thống nhận dạng chính xác hơn ở những mơi trường khác nhau, ở các góc nhìn gương mặt khác nhau...Từ đó áp dụng vào thực tế như hệ thống giám sát, kiểm tra an ninh, điểm danh học sinh tự động, kiểm tra một người có phải là cán bộ, giảng viên, cơng nhân viên của trường hay không….
- Kết nối với hệ thống Camera IP để có thể xây dựng 1 trung tâm giám sát an ninh cho công ty, chung cư…
36
- Tăng khả năng phát hiện của camera bằng cách sử dụng camera hồng ngoại hoặc sử dụng loại camera có độ phân giải cao
37
TÀI LIỆU THAM KHẢO
TIẾNG VIỆT
[1]. PGS.TS Nguyễn Quang Hoan, Xử Lý Ảnh, Học Viện Cơng Nghệ Bưu Chính
Viễn Thơng, 2006.
[2]. Trương Công Lợi, Nhận dạng khuôn mặt sử dung phương pháp biến đổi
Eigenfaces và mạng Nowrron, Đại học Đà Nẵng, 2013
[3]. Nguyễn Thành Thái, Nhận dạng mặt người dùng SVM và mạng nơron, Đại học CNTT Tp.HCM, 2006
[4]. Mạch Thị Kim Hạnh, Xác thực sinh trắc học khuôn mặt trên thiết bị di động, Đại học Lạc Hồng, 2013
[5]. PGS.TS. Nguyễn Thị Hồng Lan – Hệ thống an ninh thơng tin dựa trên sinh trắc học - PKI (Bio-PKI Based Information Security System), 2009
TIẾNG NƯỚC NGOÀI
[6]. M. A. Turk và A. P. Pentland - Face Recognition Using Eigenfaces, Proc. of IEEE Conf. on Computer Vision and Pattern Recognition, 1991.
[7]. Viola, P. and Jones, Rapid object detection using a boosted cascade of simple
features, Proc. IEEE Conf. on Computer Vision and Pattern Recognition, Dec. 2001.
[8]. Jolliffe, I.T. Principal Component Analysis, second edition (Springer), 2008. [9]. Timo Ahonen, Abdenour Hadid, and Matti Pietikăainen, Face Recognition with
Local Binary Patterns, 2004
[10]. Nefian, Hayes, Face detection and recognition using hidden Markov models,
1998
[11]. Douc, R. and Cappe, O. and Moulines, E., "Comparison of Resampling Schemes
for Particle Filtering", Image and Signal Processing and Analysis, 2005.
[12]. Michael Isard and Andrew Blake, “Conditional Density Propagation for Visual
Tracking”, 1997.
[13]. Shai Avidan, MobilEye Vision Technologies, 24 Mishol Hadkalim, Jerusalem, Israel, “Support Vector Tracking”, 2008
[14]. Michael Isard, Andrew Blake, “Condensation – conditional density
PHỤ LỤC
1. Đoạn chương trình lấy mẫu khn mặt
import sys, math, Image def Distance(p1,p2): dx = p2[0] - p1[0] dy = p2[1] - p1[1]
return math.sqrt(dx*dx+dy*dy)
def ScaleRotateTranslate(image, angle, center = None, new_center = None, scale = None, resample=Image.BICUBIC): if (scale is None) and (center is None):
return image.rotate(angle=angle, resample=resample) nx,ny = x,y = center
sx=sy=1.0
if new_center:
(nx,ny) = new_center if scale:
(sx,sy) = (scale, scale) cosine = math.cos(angle) sine = math.sin(angle) a = cosine/sx b = sine/sx c = x-nx*a-ny*b d = -sine/sy e = cosine/sy f = y-nx*d-ny*e
return image.transform(image.size, Image.AFFINE, (a,b,c,d,e,f), resample=resample)
def CropFace(image, eye_left=(0,0), eye_right=(0,0), offset_pct=(0.2,0.2), dest_sz = (70,70)):
# calculate offsets in original image
offset_h = math.floor(float(offset_pct[0])*dest_sz[0]) offset_v = math.floor(float(offset_pct[1])*dest_sz[1]) # get the direction
eye_direction = (eye_right[0] - eye_left[0], eye_right[1] - eye_left[1])
# calc rotation angle in radians rotation = -
math.atan2(float(eye_direction[1]),float(eye_direction[0])) # distance between them
dist = Distance(eye_left, eye_right) # calculate the reference eye-width reference = dest_sz[0] - 2.0*offset_h # scale factor
scale = float(dist)/float(reference) # rotate original around the left eye
image = ScaleRotateTranslate(image, center=eye_left, angle=rotation)
# crop the rotated image
crop_xy = (eye_left[0] - scale*offset_h, eye_left[1] - scale*offset_v)
crop_size = (dest_sz[0]*scale, dest_sz[1]*scale)
image = image.crop((int(crop_xy[0]), int(crop_xy[1]),
int(crop_xy[0]+crop_size[0]), int(crop_xy[1]+crop_size[1]))) # resize it
image = image.resize(dest_sz, Image.ANTIALIAS) return image
if __name__ == "__main__":
image = Image.open("tin8.png")
#CropFace(image, eye_left=(311,283), eye_right=(416,282), offset_pct=(0.1,0.1),
dest_sz=(200,200)).save("phat1_10_10_200_200.jpg")
CropFace(image, eye_left=(334,100), eye_right=(375,99), offset_pct=(0.2,0.2),
dest_sz=(200,200)).save("tin8_20_20_200_200.jpg")
#CropFace(image, eye_left=(311,283), eye_right=(416,282), offset_pct=(0.3,0.3),
dest_sz=(200,200)).save("phat1_30_30_200_200.jpg")
#CropFace(image, eye_left=(311,283), eye_right=(416,282), offset_pct=(0.2,0.2)
2. Đoạn chương trình tạo file CSV
if __name__ == "__main__": if len(sys.argv) != 2:
print "usage: create_csv <base_path>" sys.exit(1)
BASE_PATH=sys.argv[1] SEPARATOR=";"
label = 0
for dirname, dirnames, filenames in os.walk(BASE_PATH): for subdirname in dirnames:
subject_path = os.path.join(dirname, subdirname) for filename in os.listdir(subject_path):
abs_path = "%s/%s" % (subject_path, filename) print "%s%s%d" % (abs_path, SEPARATOR, label) label = label + 1
3. Đoạn chương trình phát hiện và nhận dạng khuôn mặt
#include "opencv2/core/core.hpp" #include "opencv2/contrib/contrib.hpp" #include "opencv2/highgui/highgui.hpp" #include <iostream> #include <fstream> #include <sstream> using namespace cv;
using namespace std;
static Mat norm_0_255(InputArray _src) { Mat src = _src.getMat(); Mat dst; switch(src.channels()) { case 1: cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1); break; case 3: cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3); break; default: src.copyTo(dst); break; } return dst; }
static 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, please check the given filename.";
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())); }
} }
int main(int argc, const char *argv[]) { if (argc < 2) {
cout << "usage: " << argv[0] << " <csv.ext> <output_folder> " << endl; exit(1); } string output_folder = "."; if (argc == 3) { output_folder = string(argv[2]); }
string fn_csv = string(argv[1]); vector<Mat> images;
vector<int> labels; try {
read_csv(fn_csv, images, labels); } catch (cv::Exception& e) {
cerr << "Error opening file \"" << fn_csv << "\". Reason: " << e.msg << endl;
exit(1); }
if(images.size() <= 1) {
string error_message = "Chuong trinh can it nhat 2 anh de chay, vui long them anh vao tap du lieu!";
CV_Error(CV_StsError, error_message); }
int height = images[0].rows;
Mat testSample = images[images.size() - 1]; int testLabel = labels[labels.size() - 1]; images.pop_back();
labels.pop_back();
Ptr<FaceRecognizer> model = createEigenFaceRecognizer(); model->train(images, labels);
int predictedLabel = model->predict(testSample);
string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
cout << result_message << endl;
Mat eigenvalues = model->getMat("eigenvalues"); Mat W = model->getMat("eigenvectors");
Mat mean = model->getMat("mean"); if(argc == 2) { imshow("mean", norm_0_255(mean.reshape(1, images[0].rows))); } else { imwrite(format("%s/mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, images[0].rows))); }
for (int i = 0; i < min(10, W.cols); i++) {
string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
cout << msg << endl;
Mat ev = W.col(i).clone();
Mat grayscale = norm_0_255(ev.reshape(1, height)); Mat cgrayscale;
applyColorMap(grayscale, cgrayscale, COLORMAP_JET); if(argc == 2) {
imshow(format("eigenface_%d", i), cgrayscale); } else {
imwrite(format("%s/eigenface_%d.png", output_folder.c_str(), i), norm_0_255(cgrayscale)); }
}
for(int num_components = min(W.cols, 10); num_components < min(W.cols, 300); num_components+=15) {
Mat evs = Mat(W, Range::all(), Range(0, num_components));
Mat projection = subspaceProject(evs, mean, images[0].reshape(1,1));
Mat reconstruction = subspaceReconstruct(evs, mean, projection); reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows)); if(argc == 2) { imshow(format("eigenface_reconstruction_%d", num_components), reconstruction); } else { imwrite(format("%s/eigenface_reconstruction_%d.png", output_folder.c_str(), num_components), reconstruction); } } if(argc == 2) { waitKey(0); } return 0; }