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; }