Building some open source libraries with VS 2012

Today, after upgrading from VS 2010 to Visual Studio  2012 (with VS 2012 Update 4), I build some open source libraries (Boost 1.55, OpenCV 3.0.0-dev, FLANN 1.8.4, and Point Cloud Library 1.7.1-PCL) and here are some notes for ones who may find them useful.

0. Some thoughts on VS 2012: much bigger than VS 2010, without blend and other options, I just checked the MFC option but the memory required was more than 7 Gbs. The installation has less option as compared with VS 2010 (no option to exclude VB, Web support or C#, SQL Server … like in VS 2010). After update to Update 4, there is another option for MFC or Win32 project with targeting to v110-xp, this is due to the fact that VS 2012 compiled programs (before Update 4) could not run on XP. And the folder C:\ProgramData\Package Cache contains all the packages from VS 2012 installation (about 1.7 Gb, I wonders if this can be deleted). In my feelings, VS 2012 is not slower than VS 2010, it may be faster on stronger machine with 4 or 8 CPU cores. It’s a suprise that VS 2012 include the DirectX library in the C:\Program Files\Windows Kits\8.0 folder, so you can write DirectX based program without any further installation. One of the big improvement of VS 2012 is it is a true multicore compiler which can uses multicore for compiling a project, not a parallel compiler as VS 2010 (see more details from this address).

1. Hardware and software platform: Windows 7 SP1 32 bit on a laptop Core 2 Duo 2.4 Ghz with 3 Gb Ram, VS 2012 Update 4. Some required libraries are: Eigen 3.2 (for PCL), TBB 4.2 Update 2 (for OpenCV) and CMake 2.8.12.1, CUDA 5.5.2 32 bit. For details of building OpenCV with TBB, please read ref 1 or ref 2. The path to CMake’s bin directory is mandatory added to the PATH environment variable.

2. Building OpenCV 3.0.0-dev. I remove matlab, python and java building options from the file CMakeLists.txt of OpenCV and keep only the CUDA code version >=2.0 (in the file OpenCVDetectCUDA.cmake) to make the process faster. Then cmake-gui is used to generate the VS 2012’s solution and project files. On my machine, this ran for 4 hours and a folder of about 7 GBs was generated, but the install folder was only about 330 Mbs (other files and folders from the build folder can be delete after). The reason for the 4 hours duration may be caused by the /GL building option which was set for all the OpenCV projects.

3. Building Boost 1.55(which is also required by PCL): just run the bootstrap.bat from the command line and .\b2 command after but remember to add the VS 2012 path to the PATH environment variable.

4. Building FLANN 1.8.4: I used cmake-gui to create the solution file and build with VS 2012 without any problem (some python projects were not built, but I don’t need them).

5. Building PCL 1.7.1: Again, cmake-gui was used to generate the solution file, I had to set variables manually for boost and FLANN. Be careful with /GL building option because the whole optimization can caused failed build even your machine (64 bit) may have up to 16 GB of RAM, especially with pcl_feature project. This process took about 2 hours with 2.5 Gb build folder and no error was raised.

Một số hội thảo (conference) về công nghệ thông tin ở Việt Nam

Cập nhật cho năm 2015 (chi tiết về các hội thảo xem bên dưới):

1. Hội thảo SoICT năm 2015 sẽ được tổ chức từ 3-4 tháng 12 tại cố đô Huế, deadline là 26-07-2015.

2. Hội thảo KSE 2015 sẽ được tổ chức từ 8-10 tháng 10 tại đại học Công nghệ Thông tin, Đại học Quốc gia Tp Hồ Chí Minh, deadline là 01-05-2015.

3. Hội thảo FAIR 2015 sẽ được tổ chức tại Hà nội từ ngày 9-10 tháng 7 tại Hà nội, hạn nộp abstract là 10-05-2015, nộp full paper là 30-05-2015.

4. Hội thảo quốc gia về CNTT – Một số vấn đề chọn lọc của Công nghệ thông tin và Truyền thông sẽ được tổ chức tại Đại học Nguyễn Tất Thành, Tp Hồ Chí Minh, thời gian dự kiến vào tháng 10 năm 2015. Hiện chưa có thông báo chi tiết về hội thảo này.

5. Hội thảo NAFOSTED lần thứ hai về Khoa học Thông tin và Máy tính – The second NAFOSTED Conference on Information and Computer Science – NICS. Hội thảo được quĩ NAFOSTED tài trợ, và các bài báo tại hội thảo được đăng trên hệ thống cơ sở dữ liệu của IEEExplore Digital Library. Deadline là ngày 10 tháng 5 và hội thảo sẽ tổ chức vào 16-18 tháng 9, 2015 tại Học viện Bưu chính viễn thông tại Tp. Hồ Chí Minh.

 

1. Hội thảo chuyên đề quốc tế về Công nghệ Thông tin và Truyền thông – International Symposium on Information and Communication Technology (SoICT). Đến năm 2013, hội thảo này đã tổ chức được 4 lần, khá uy tín. Đúng như tên gọi, hội thảo này dành cho cả ngành Công nghệ thông tin và điện tử, viễn thông. Trong số các hội thảo về CNTT ở Việt Nam thì hội thảo này có qui trình tổ chức có thể nói là tốt, các chủ đề của hội nghị cũng được phân chia khá hợp lý (xem thêm ở web address), proceeding được đăng ở ACM ICPS.

2. Hội thảo quốc tế về công nghệ tri thức và hệ thống – International Conference on Knowledge and Systems Engineering (KSE). Hội thảo đã tổ chức được 5 lần, nội dung gồm khá nhiều lĩnh vực nghiên cứu của Công nghệ thông tin. Các bài báo của hội thảo theo chuẩn và được đăng ở Cơ sở dữ liệu của Springer-Verlag (12 trang). Một số bài sau hội thảo có thể được đăng trong special issue của tạp chí (cái này khá lợi).

3. Hội thảo quốc tế về công nghệ tính toán và truyền thông RIFV – RIFV International Conference on Computing and Communication Technologies. Hội nghị này ban đầu được khởi xướng bởi Viện tin học Pháp ngữ – IFI và Đại học Bách khoa Hà nội, đã tổ chức đến lần thứ 10. Kỷ yếu hội nghị được đăng ở Cơ sở dữ liệu của IEEE.

4. Hội thảo “Nghiên cứu cơ bản và ứng dụng Công nghệ thông tin” – Fundamental and Applied IT Research (FAIR). Đã tổ chức được 6 lần. Điểm hạn chế là kỷ yếu không nằm trong cơ sở dữ liệu quốc tế nào.

5. Hội thảo quốc gia về CNTT – Một số vấn đề chọn lọc của Công nghệ thông tin và Truyền thông. Đây là hội thảo cao tuổi nhất trong số các hội thảo về CNTT ở Việt Nam, năm nay là lần thứ 16, mỗi bài viết tham dự dài tối đa 8 trang (tiếng Anh hoặc Việt). Điểm hạn chế là kỷ yếu của hội thảo không nằm trong cơ sở dữ liệu quốc tế nào.

6. Hội thảo NAFOSTED lần thứ nhất về Khoa học Thông tin và Máy tính – The first NAFOSTED Conference on Information and Computer Science – NICS. Đây là hội nghị lần đầu tiên tổ chức và được quĩ NAFOSTED tài trợ, theo thông báo thì các bài chọn lọc có thể đăng trên tạp chí thuộc hệ thống cơ sở dữ liệu của Springer-Verlag.

7. International Conference on Advanced Technologies for Communications (ATC). Là một hội thảo chuyên về điện tử viễn thông, được tổ chức khá bài bản, đã được 6 lần, có một số ít ngành thuộc về công nghệ thông tin. Mỗi bài viết tham gia dài tối đa 6 trang. Kỷ yếu hội thảo được đăng trên cơ sở dữ liệu của IEEE.

8. Hội thảo khoa học Quốc gia về Điện tử – Truyền thông – REV 2013. Hội thảo này cũng được tổ chức lần đầu tiên, các lĩnh vực chủ yếu là điện tử viễn thông, tuy nhiên cũng có một số ít thuộc công nghệ thông tin. Kỷ yếu có  ISBN, một số bài chọn lọc đăng ở tạp chí  Journal on Electronics and Communications (JEC).

9. The International Conference on Communications and Electronics (ICCE). Cũng là một hội thảo chính về điện tử, viễn thông, tuy nhiên vẫn có vài chủ đề nhỏ thuộc về Công nghệ thông tin. Hội thảo được tổ chức 2 năm 1 lần, đã tổ chức được 4 lần. Kỷ yếu đăng trên cơ sở dữ liệu của IEEE.

Một vài vấn đề trong lập trình với OpenCV

Ngày 05/06/2015:

Ngày 04/06/2015, sau hơn 6 tháng kể từ bản beta, phiên bản chính thức OpenCV 3.0.0 đã được đưa ra với rất nhiều cải tiến. Bên cạnh đó bản TBB 4.3 update 5 cũng được MS cập nhật. Boost 1.5.8 cũng mới được cập nhật trong thời gian gần đây.

Ngày 13/11/2014:

Bản OpenCV 3.0-Beta đã được đưa ra sau nhiều cải tiến. Bên cạnh đó bản cập nhật IPP 8.2.1 và TBB 4.3.1 cũng được cập nhật. Microsoft cũng đã tung ra bản update 4 cho Visual Studio 2013 và bản Preview cho VS 2015. Boost 1.5.7 cũng mới được cập nhật trong thời gian gần đây. Qủa là một ngày với nhiều cập nhật.

Ngày 22/08/2014:

Với rất nhiều các tính năng mới và một giao diện (API) C++ gần như triệt để (các hàm hỗ trợ C với tiếp đầu ngữ cv, chẳng hạn như cvCopyImage, cvFillImage đã bị loại bỏ và số còn lại thì ngày càng ít đi), bản OpenCV 3.0 Alpha đã được đưa ra. Có thể xem thêm về các tính năng mới của bản alpha này ở đây và ở đây.  Link download.

Ngày 16/08/2014:

Bản OpenCV 3.0.0 dev-version mới nhất với các tính năng sau:

+ Hỗ trợ OpenCL mạnh hơn (nhiều hàm được cài đặt với OpenCL kernel hơn). Nền tảng OpenCL được mặc định sử dụng, nếu hệ thống không hỗ trợ, có thể có báo lỗi.

+ Nhanh hơn với thư viện IPP của Intel, hầu hếtcác thao tác đều nhanh hơn (xem chi tiết ở đây), chưa phát hiện hàm nào chậm hơn.

+ Module highgui được chia thành 2: videoio and highgui.

+ Sửa lỗi khi build module cudaoptflow.

+ Cập nhật với bản cmake 3.

+ Một số applications bị bỏ đi, chỉ còn một application là traincascade.

Ngày 21/07/2014:

Một địa chỉ với nhiều ví dụ theo kiểu “Learn by examples” về OpenCV: http://opencvexamples.blogspot.com/.

TBB 4.2 update 5.

Ngày 3/03/2014:

Forum cho các hỏi đáp về các vấn đề về lập trình với OpenCV (thực sự rất có ích): OpenCV Q&A forum.

Ngày 13/01/2014:

Update 3 of TBB 4.2: Hôm nay bản Update 3 của thư viện TBB 4.2 đã được tung ra. Đối với những ai muốn tối ưu tốc độ của thư viện OpenCV, thì TBB là một giải pháp khá tốt, bên cạnh các giải pháp khác như SSE2, WinThread hoặc C++11 thread. Có thể download bản TBB 4.2 update 3 ở địa chỉ này, xem các thay đổi từ bản Update 2 lên Update 3 ở đây.

Ngày 07/12/2013:

Một số nguồn, tài liệu có ích cho những người mới bắt đầu với OpenCV.

+ OpenCV 2.4.8 reference manual. Tài liệu về version mới nhất của OpenCV giúp tra cứu các hàm thư viện của OpenCV theo từng mục tương ứng với các file thư viện khác nhau như: core, imgproc, highgui, video …

+ OpenCV Tutorial 2.4.3: http://docs.opencv.org/opencv_tutorials.pdf. Hướng dẫn chi tiết về cấu hình với công cụ (VS, Eclipse), nền tảng (Windows, Linux, Adroid, iOS) và ngôn ngữ khác nhau (C++, Java). Thêm vào đó là khá nhiều ví dụ đơn giản, ngắn gọn.

http://opencv-srf.blogspot.fr/. Một Tutorial khác, cũng khá dễ hiểu.

Ngày 28/08/2013:

GUI application with OpenCV: để tạo một ứng dụng giao diện đồ họa sử dụng OpenCV có một số lựa chọn: dùng MFC, Qt, hoặc wxWidgets. Tuy nhiên Qt chiếm ưu thế hơn vì:

+ MFC đang bị MS đưa vào dạng cần loại bỏ

+ MFC chỉ chạy với Windows

+ wxWidgets không tiện và mạnh như Qt

+ Ứng dụng Qt có thể dễ dàng compile lại để chạy trên các hệ thống Windows hoặc Linux

Một số ví dụ cơ bản về tạo ứng dụng GUI sử dụng Qt với OpenCV:

link 1 – Hiển thị ảnh đơn giản

link 2 – Đa luồng và một số thao tác lọc ảnh

link 3 – Thao tác với webcam

Ngày 03/06/2013:

Xử lý ảnh xám (grayscale image processing). Theo mặc định khi hàm imread() hoặc cvLoadImage() đọc 1 ảnh (từ file hoặc một frame video), ảnh nhận được (Mat hoặc IplImage) sẽ có 3 channel cho ba màu Blue, Green, Red (theo đúng thứ tự). Tuy nhiên việc xử lý ảnh thường dựa trên ảnh xám (một channel, với giá trị điểm ảnh, hay cường độ sáng – intensity, dao động từ 0 tới 255) nên điều quan trọng đầu tiên là cần chuyển một ảnh đọc được về ảnh xám 1 channel, để thực hiện điều này ta làm như sau:

Mat im = imread(<file path>);
if(im.type()!=CV_8UC1)
	cvtColor(im, im, CV_BGR2GRAY);

Tiếp đến do các thao tác xử lý dựa trên điểm ảnh cần làm việc với các giá trị kiểu số thực nên ta cần chuyển tiếp các điểm ảnh về kiểu CV_32F hoặc CV_64F như sau:

im.convertTo(im,CV_32F);

Chú ý là thao tác này (chuyển thành ảnh xám 1 channel) là rất quan trọng vì nhiều hàm xử lý của OpenCV chỉ làm việc với dữ liệu ảnh (Mat) 1 channel, chẳng hạn như minMaxLoc(), compare().

Tất nhiên ta cũng có thể tách các channel của một ảnh hoặc hợp lại từ 3 channel bằng các hàm split() và merge(), ví dụ:

Mat im = imread(<file path>);
vector<Mat> rgb; 
split(in, rgb);

Mat color;

split(rgb, color);

Để truy cập vào một điểm ảnh ở hàng i cột j ta cùng cú pháp: im.at<float>(i,j) cho ảnh CV_32F và  im.at<double>(i,j) cho ảnh CV_64F.

Lấy giá trị mức xám lớn nhất (max) và nhỏ nhất (min) của một ảnh:

Mat im=imread(<file path>);

if(im.type()!=CV_8UC1)
	cvtColor(im, im, CV_BGR2GRAY);
double max_val, min_val; 
minMaxIdx(im, &min_val, &max_val, 0, 0); 
cout << "Max=" << max_val << ", Min=" << min_val << endl;

Ngày 30/05/2013:

1. Đọc/ghi file ảnh. Dữ liệu cho một chương trình xử lý ảnh là ảnh thu nhận từ các thiết bị ghi, thường được lưu dưới dạng file ảnh hoặc file video với các format khác nhau. Về cơ bản, OpenCV hỗ trợ đọc hầu hết các format ảnh phổ biến (.png, .jpg, .bmp, …), còn về format video thì trên hệ thống có codec nào, OpenCV có thể đọc được format đó, tuy nhiên phổ biến nhất là các file .avi. Hàm đọc file ảnh có 2 loại, một dành cho chương trình viết theo dạng C (sử dụng cấu trúc IplImage) và loại thứ hai dành cho các chương trình viết theo kiểu C++ (dùng lớp Mat), cụ thể như sau:

IplImage * img = cvLoadImage(<file path>);

Mat img = imread(<file path>);

Tương ứng là hai hàm dùng để ghi file ảnh:

cvSaveImage(<file path>, img ); // cho IplImage * img;

imwrite(<file path>, img); // cho Mat img;

Để đọc các frame của một file video hoặc từ một webcam có thể dùng cấu trúc CvCapture (khi đó ảnh đọc sẽ có kiểu là IplImage) hoặc VideoCapture (khi đó ảnh đọc sẽ là đối tượng của lớp Mat). Nói chung OpenCV không phân biệt ảnh được đọc từ file hay trực tiếp từ webcam (Bravo OpenCV!). Ban đầu là thao tác khởi tạo:

CvCapture* capture=0;
IplImage* frame=0;

capture = cvCaptureFromAVI(<file path>); // from file

capture = cvCaptureFromCAM(0); // from webcam

// đọc các frame tiếp theo

frame = cvQueryFrame( capture );

VideoCapture capture;

Mat frame;

capture.open(<file path>); // open file

capture.open(0); // open webcam device

// đọc các frame

capture >> frame;

Sau đây là một ví dụ đơn giản về đọc file .avi và hiển thị lên màn hình:

#include <opencv2\opencv.hpp>
#include <opencv2\core.hpp>
#include <opencv2\highgui.hpp>
#include <opencv2\imgproc.hpp>
using namespace cv;
int main(int argc, char** argv)
{
	CvCapture* capture=0;
	IplImage* frame=0;
	capture = cvCaptureFromAVI(argv[1]); // read AVI video
	if( !capture )
		throw "Error when reading steam_avi";

	cvNamedWindow( "w", 1);
	for(;;)
	{
		frame = cvQueryFrame( capture );
		if(!frame)
			break;
		cvShowImage("w", frame);

		cvWaitKey(10);
		if(cvWaitKey(30) >= 0)
			break;
	}
	cvReleaseImage(&frame);
	cvReleaseCapture( &capture );
	cvDestroyWindow("w");

	return 0;
}

Còn đây là một ví dụ với C++:

#include <opencv2\opencv.hpp>
#include <opencv2\core.hpp>
#include <opencv2\highgui.hpp>
#include <opencv2\highgui\highgui_c.h>
#include <opencv2\imgproc\imgproc_c.h>
//#include <iostream>
//using namespace std;
using namespace cv;
int main(int argc, char ** argv)
{
	VideoCapture capture;
	Mat frame;
	capture.open(argv[1]);
	if(!capture.isOpened())
		return 1;
	while(1)
	{
		capture >> frame;
		if(frame.empty())
			break;
		imshow("w", frame);
		cvWaitKey(10);
		if(cvWaitKey(30) >= 0)
			break;
	}
	return 0;
}

Xem thêm các ví dụ và chi tiết khác tại:

http://www.grandmaster.nu/blog/?page_id=49

http://docs.opencv.org/doc/tutorials/highgui/video-write/video-write.html

http://bsd-noobz.com/opencv-guide/40-4-display-video-from-file-camera

http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html

Ngày 23/05/2013:

1. Chuyển đổi kiểu giữa IplImage * (kết quả đọc ảnh bằng hàm cvLoadImage(), là một cấu trúc theo kiểu C) và Mat (một kiểu dữ liệu mới từ OpenCV 2, kết quả của hàm imread()) dùng hàm cvarrToMat():

IplImage * img = cvLoadImage(<file path>);

Mat mat = cvarrToMat(img);

cvShowImage(“Using IplImage”, img);

imshow(“Using Mat”, mat);

Kiểu dữ liệu Mat của OpenCV (thực chất là một class của C++) hay được dùng vì có nhiều thao tác dựa trên cấu trúc ma trận của nó. Để chuyển ngược lại thì đơn giản hơn:

Mat mat = imread(<file path>);

IplImage img = mat;

2. OpenCV và lập trình GPU

Để có thể lập trình GPU với thư viện OpenCV, ta cần hai file thư viện opencv_gpu (.lib và .dll). Do bản chính thức là 2.4.5 dành cho Windows không được dịch với GPU đầy đủ nên không chạy được các hàm GPU của OpenCV, khi đó cần build OpenCV from source để có thể dùng các hàm này. Xem hướng dẫn ở đây với bản OpenCV 2.4.9.

3. GpuMat và Mat

GpuMat là cấu trúc tương tự Mat nhưng được dùng để chạy trên GPU Device, ví dụ khi muốn đọc ảnh, chuyển dữ liệu ảnh lên GPU để thực hiện thao tác xử lý gì đó (lọc ảnh, trích chọn đặc trưng, DFT, FFT, Wavelets, convolution ..) ta dùng hàm upload, rồi gọi tới hàm xử lý, tiếp đến dùng hàm download để chuyển dữ liệu từ GPU device xuống Host Memory:

Mat img = imread(<file path>);

Mat result;

GpuMat d_img;

d_img.upload(img);

<gọi hàm trên GPU để xử lý ảnh>

d_img.download(result);

CVMLib 7.0-Đối thủ xứng tầm của Armadillo và Eigen

Sau một thời gian chờ đợi khá lâu từ phiên bản 6.1, ngày 6-1-2013 vừa qua CVMLIB 7.0, một thư viện rất mạnh hỗ trợ các thao tác trên ma trận được viết bởi tác giả Sergei Nikolaev, đã được tung ra. Phiên bản mới này hỗ trợ thư viện Intel MKL Intel 11.0 Update 1 cũng như các thư viện khác như ACML và lapack (bản 3.4.2). Người sử dụng có thể tự build từ source code trên máy của mình hoặc download bản precompiled về sử dụng. So với ArmadilloEigen, CVMLIB nhanh hơn (với đa số các thao tác trên ma trận). Sau đây là một ví dụ rất đơn giản cho các thao tác là nhân hai ma trận, SVD và EIG trên ma trận sử dụng CVMLIB:


// A simple example using CVM library

#include <cvm.h>
#include <ctime>
#include <iostream>

using namespace cvm;
using namespace std;

int main(int argc, char * argv[])
{
int n, m;
float *a, *b;
int i;
clock_t st, et;

if(argc==3)
{
n = atoi(argv[1]);
m = atoi(argv[2]);
}else
{
n = m = 1000;
}
a = new float[n*m];
b = new float[n*m];
srand(time(NULL));
for(i=0;i<n*m;i++)
{
a[i] = (float)rand()/INT_MAX;
b[i] = (float)rand()/INT_MAX;
}

basic_rmatrix ma(a, n, m);
basic_rmatrix mb(b, n, m);
basic_rmatrix mc(n, m);
basic_rmatrix asvd(a,n,m);
basic_srmatrix u(n);
basic_srsmatrix ms(n);
basic_srmatrix em(n);
basic_rvector ev(n);

st = clock();
mc = ma*mb;
et = clock();
cout << “Time for matrix multiplication is:” << (float)(et-st)/CLK_TCK;

st = clock();
ev = asvd.svd(u,em);
et = clock();
cout << “Time for SVD is:” << (float)(et-st)/CLK_TCK;

st = clock();
ev.eig(ms, em);
et = clock();
cout << “Time for EIG is:” << (float)(et-st)/CLK_TCK;

delete [] a;
delete [] b;
system(“pause”);
return 0;
}

Sách mới về OpenCV – Mastering OpenCV with Practical Computer Vision Projects

Update 14/01/2014: “Practical OpenCV” là một cuốn sách về OpenCV nữa mới được xuất bản dành cho cộng đồng những người lập trình với OpenCV. Cuốn sách được chia làm 2 phần, 11 chương với các nội dung như sau:

Part 1: Getting comfortable
Chapter 1: Introduction to Computer Vision and OpenCV
Chapter 2: Setting up OpenCV on your computer
Chapter 3: CV Bling – OpenCV inbuilt demos
Chapter 4: Basic operations on images and GUI windows

Part 2: Advanced computer vision problems and coding them in OpenCV
Chapter 5: Image filtering
Chapter 6: Shapes in images
Chapter 7: Image segmentation and histograms
Chapter 8: Basic machine learning and keypoint-based object detection
Chapter 9: Affine and Perspective transformations and their applications to image panoramas
Chapter 10: 3D geometry and stereo vision
Chapter 11: Embedded computer vision: Running OpenCV programs on the Raspberry Pi

Mã nguồn của cuốn sách có thể download về từ địa chỉ này.

Cùng với hai cuốn sách viết về OpenCV là Learning OpenCV: Computer Vision with the OpenCV Library và OpenCV 2 Computer Vision Application Programming Cookbook, PacktPub vừa cho xuất bản một cuốn sách mới về OpenCV có tên là “Mastering OpenCV with Practical Computer Vision Projects“. Cuốn sách được chia thành 8 chương với các chủ đề khác nhau, mỗi chủ đề được minh họa bằng một project có mã nguồn (source code) ( yêu cầu từ OpenCV v2.4.2 trở lên-phiên bản hiện tại là 2.4.3) và các giải thích, chỉ dẫn về thuật toán, chi tiết về lập trình với OpenCV tương ứng: lập trình OpenCV với Adroid, iOS (iPhone và iPad), nhận dạng biển số xe (Number Plate Recognition) với SVM và NN, Face tracking, Head Pose Estimation (AAM), nhận dạng mặt người – Face recognition với hai thuật toán cơ bản nhất là Eigenfaces-PCA and Fisherfaces-LDA, lập trình với nền tảng Kinect của Microsoft. Sách có một chương 4 là sample và toàn bộ source code (đã cập nhật file thiếu ở chương viết về head pose estimation) có thể download tại Github.

Nhận dạng mặt người (Face recognition) bằng PCA (eigenface) – Matlab code on ORL database

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.

Các thách thức đối với nhận dạng mặt: hiện nay các vấn đề sau được coi là thách thức lớn (chưa có phương pháp tốt) đối với nhận dạng mặt:

+ vấn đề hướng (pose variations), các kết quả với các ảnh có hướng thay đổi (>45 độ, không phải chính diện) còn khá khiêm tốn, có lẽ 3D là một hướng giải quyết.

+ vấn đề ảnh có độ phân giải thấp (low resolution): ảnh thu được từ các camera giám sát (surveillance camera) thường có kích thước và chất lượng rất rất thấp, các kết quả nghiên cứu về lĩnh vực này còn chưa nhiều.

+ làm việc với dữ liêu video (video based face recognition): với sự phát triển của các phương tiện multimedia, thông tin mặt người trong các dữ liệu video là vô cùng nhiều, tuy nhiên hầu hết các phương pháp nhận dạng vẫn làm việc với ảnh tĩnh trích xuất từ dữ liệu video, chưa có phương pháp tốt tận dụng hết ưu thế của dữ liệu video.

+ các hệ thống cực lớn (very large scale systems): các cơ sở dữ liệu (CSDL) ảnh mặt được test bởi các nhà nghiên cứu còn khá nhỏ (vài trăm tới vài chục nghìn ảnh mặt), tuy nhiên trên thực tế các CSDL có thể rất lớn, ví dụ CSDL ảnh mặt của cảnh sát của một nước có thể chứa từ hàng triệu tới hơn 1 tỉ ảnh …

+ aging condition: việc nhận dạng ảnh mặt thay đổi theo thời gian thực sự vẫn còn là một vấn đề lớn ngay cả đối với khả năng nhận dạng của con người.

+ illumination (ánh sáng): là một trong những biggest challenges của nhận dạng mặt, chưa có phương pháp tốt cho các ảnh chụp ở điều kiện out door unconstrained.

Nguồn gốc của các thách thức trên là do tập training thường chỉ có một ảnh cho mỗi đối tượng (lớp) với các điều kiện cố định, trong khi tập probe lại gồm các ảnh ở các điều kiện khác (như đã liệt kê ở trên), làm gia tăng sự khác biệt giữa ảnh training, gallery và probe.

Nghiên cứu về nhận dạng mặt: vì có nhiều bước và còn nhiều thách thức nên có thể lựa chọn một khía cạnh trong một bước để tiến hành, ví dụ như chỉ nghiên cứu về illumination normalization, hay chỉ làm với ảnh low resolution, nhận dạng cảm xúc của khuôn mặt, hoặc thậm chí cụ thể hơn nữa, chỉ làm về face image alignment … Tuy nhiên hầu hết các nhà nghiên cứu đều tập trung vào bước feature extraction, tức là tìm một cách thức trích chọn đặc điểm hiệu quả cho nhận dạng mặt.

CSDL cho nhận dạng mặt: điều đầu tiên cần thiết khi nghiên cứu về nhận dạng mặt là phải có các CSDL ảnh mặt và cách thức chuẩn (standard protocol) để thực hiện test trên các CSDL đó, vì còn phải so sánh với các kết quả đã có khác trên các CSDL đó. ORL là một CSDL nhỏ và cũ của AT&T nhưng khá thích hợp với người mới bắt đầu. Nó gồm 400 ảnh của 40 người, mỗi người có 10 ảnh với các biểu hiện (facial expression) và điều kiệu về hướng, ánh sáng khác nhau. Các CSDL khác nên test là: FERET, FRGC v2.0, SCFace, LFW, AR. Trong các CSDL này, ảnh mặt đã được chuẩn bị sẵn, tức là chúng ta không cần thực hiện bước face detection, chỉ cần dựa vào các thông tin được cung cấp để thực hiện cắt phần ảnh mặt cần thiết cho nhận dạng. Để download database ORL, các bạn có thể truy cập tới địa chỉ này. Lưu ý là CSDL này gồm các ảnh ở format .pgm, format này hơi lạ với các chương trình đọc ảnh của Windows, nhưng với Matlab thì không có vấn đề gì, các bạn có thể save lại thành định dạng .bmp hoặc .jpg để có thể nhận thấy rõ ràng hơn.

Trong bài viết này, tôi chỉ nói về PCA dành cho nhận dạng mặt theo phương pháp eigenface, sẽ không có các bước chuẩn hóa ánh sáng và trích chọn đặc điểm. CSDL được sử dụng minh họa là ORL, tập training trùng với tập reference và mỗi lớp (mỗi người) sẽ chọn n=1,2,3,4 hoặc 5 ảnh đưa vào tập training, số còn lại (10-n cho mỗi lớp) sẽ được dùng cho tập probe.

Phương pháp PCA cho nhận dạng mặt (eigenface): Mỗi ảnh có kích thước WxH (kích thước phổ biến là 128×128) sẽ được chuyển thành một vector cột có độ dài W*H (cho cả tập training và probe) (gọi là các vector Xi). Ở bước training, một vector trung bình của tất cả các ảnh training sẽ được tính (vector M), sau đó mỗi vector thuộc tập training sẽ bị mean-subtracted: Xi=Xi-M, ma trận hiệp phương sai được tính bằng C = A’*A, trong đó A’ là ma trận chuyển vị của A và A =[X1, X2, …Xk] là ma trận với các cột là các vetor Xi, k là số ảnh thuộc tập training (k=40*n với CSDL ORL). A sẽ có kích thước là (W*H)xk, còn ma trận C sẽ có kích thước là kxk, do k nhỏ hơn W*H rất nhiều nên việc tính k vector riêng (eigenvectors) và giá trị riêng tương ứng (eigenvalues) của C là dễ. Ta sẽ tìm được k giá trị riêng tương ứng với k vector riêng của C. Các vector riêng được sắp xếp theo thứ tự giảm dần của các giá trị riêng tương ứng, việc sử dụng tất cả các vector riêng là không cần thiết nên chỉ có N (N viết hoa nhé) giá trị riêng đầu tiên tương ứng với N vector riêng được sử dụng (chính về thế nên phương pháp này được gọi là phân tích thành phần chính-Principal Component Analysis). N vector riêng này sẽ tạo thành một ma trận có kích thước (W*H)xN là ma trận của không gian con nhận được (ta gọi ma trận này là Cp). Tiếp đến các ảnh thuộc tập training (ở đây cũng là tập reference) sẽ được chiếu vào không gian con bằng phép nhân: Ap = Cp’ * A, tương tự các ảnh của tập probe sẽ được chiếu vào không gian con bằng phép nhân: Bp = Cp’*B. Ap và Bp sẽ có kích thước tương ứng là NxNoTrain (NoTrain là số ảnh training, tức là bẳng k) và NxNoTest (NoTest là số ảnh của tập probe), nghĩa là mỗi ảnh tương ứng được biểu diễn bẳng một vector cột. Ở bước phân lớp, với mỗi ảnh thuộc tập probe, ta tìm ảnh thuộc tập training gần với nó nhất. Ở bước này các hàm khoảng cách: euclidean, mahalanobis, cosine angle distance đều có thể sử dụng.

Thực chất, ở nguyên bản của phương pháp PCA ma trận C = A*A’, và có kích thước là (W*H)x(W*H), tức là một ma trận rất, rất lớn nên Mathew A. Turk and Alex P. Pentland (tác giả của phương pháp eigenface) đã sử dụng một thủ thuật là tìm N vector riêng vi (i=1..N) và giá trị riêng của ma trận L=A’*A (dễ hơn do ma trận có kích thước nhỏ hơn) sau đó tính N vector riêng của C=A*A’ bằng công thức ui=A*vi.

Việc tìm các vector riêng của ma trận hiệp phương sai C (trên thực tế là với ma trận L) có hai cách: dùng phương pháp eigen decomposition (hàm eig của matlab) hoặc singular value decomposition-SVD (hàm svd của matlab), tuy nhiên svd có vẻ nhanh và cho kết quả tốt hơn so với eig.

Sau đây là bảng tỉ lệ kết quả nhận dạng (Rank-1 Recognition Rate-RR) với số ảnh huấn luyện cho mỗi đối tượng là từ 1->5:

Eigenfaces

Why matlab? Vì matlab nhanh và thích hợp cho việc nghiên cứu, thử nghiệm. Nên nhớ rằng PCA hay một phương pháp nào đó bạn nghĩ ra có thể chưa phải là tốt nhất, vì thế nên việc sử dụng C/C++/C# hay một ngôn ngữ lập trình ứng dụng nào đó để cài đặt là không thực sự cần thiết, bạn sẽ thấy tốc độ cũng không nhanh hơn (thường là chậm hơn, trừ khi bạn dùng GPU hoặc tối ưu mã nguồn), rất mất thời gian và chắc gì thuật toán của bạn đã có hiệu quả đủ tốt để đầu tư công sức cho việc lập trình, với lại một hệ thống nhận dạng mặt có thể chạy trên thực tế gồm rất nhiều bước khác nữa, ở đây bạn mới làm với các ảnh frontal của một database đã có sẵn, vì thế đừng có lăn tăn nhiều.

Cuối cùng, nếu bạn muốn trao đổi về nội dung bài viết hay lấy source code của PCA (eigenface), hãy để email lại qua mục comment của bài viết này, tôi sẽ gửi lại cho bạn qua email.

P/S (ngày 18/08/2014): sau một thời gian dài nhận được nhiều yêu cầu gửi code của nhiều bạn, tôi đã cố gắng nhanh nhất có thể gửi cho hầu hết các bạn với mục đích cung cấp một chút gì đó gọi là cơ sở và hy vọng có sự trao đổi với những ai cùng quan tâm. Nhưng sự trao đổi thì khá ít mà một số câu hỏi kiểu “chạy cái này thế nào?” hay “Sao không thấy gì?” thì phổ biến nên tôi mong muốn các bạn hãy đọc kỹ, xem kỹ trước khi yêu cầu và theo đuổi lĩnh vực này vì nhận dạng mặt và phương pháp eigenfaces không phải là những thứ dễ dàng (để hiểu và code) theo kiểu google search, download, click and get the results.

Update ngày 24/06/2015:

Face recognition with OpenCV tutorial.

Update ngày 17/06/2013:

More about eigenfaces

Java code

OpenCV based source code 1

OpenCV source code 2

C# based PCA source code 1

C# based PCA for shape matching

EmguCV C# tutorial

EgmuCV C# face detection

EgmuCV C# multiple faces detection and recognition

Eye tracking 1

Eye tracking 2

OpenCV based Eye tracking 3

OpenCV based face and eyes detection

Python 3.2 with Visual Studio 2010 – Why have to find another IDE?

In my previous post Python for Computer Vision, I showed some packages and Python 3.2 for Computer Vision. Python is a language that has many C/C++ properties and also Matlab (script language style), but a Python program is a real program, not a script like Matlab. So if we use Python (instead of Matlab) for implementation our algorithms, it is more convenient to make real program (or GUI program – with PyQt). The second step after install all needed packages for using Python is finding for a good IDE. There are many posts about “best IDE” for Python:
Post 1
Post 2
I just want to find an IDE that easy to use, like VS, QtCreator or DevCpp. And Python integration for Visual Studio 2010 is the best choice for me. It is very lightweight, just 2.5 Mb, and with its VS integration, I can exploit all features of VS, a familiar IDE for me.
After installing PTVS 1.5 Alpha, we can create new Python Project and write new Python program. Very impressive.