File XML gồm các thẻ: - Titled:
Bằng 0 nếu sử dụng đặc trưng là hình chữ nhật đứng.
Bằng 1 nếu sử dụng đặc trưng là hình chữ nhật nghiêng 45. - Threshold:
Ngưỡng cho phép.
- Left_val:
Nếu ảnh đầu vào có đặc trưng Haar-like <= ngưỡng thì lấy giá trị này - Right_val:
Nếu ảnh đầu vào có đặc trưng Haar-like > ngưỡng thì lấy giá trị này - Feature: Mô tả đặc trưng Haarlike
Để truy xuất file XML và phục vụ cho việc boosting, OpenCV xây dựng các cấu trúc như sau:
35
#define CV_HAAR_FEATURE_MAX 3
/* một đặc trưng HaarLike gồm 2-3 hình chữ nhật với 1 trọng số weight*/
typedef struct CvHaarFeature {
int tilted; /* 0 đặc trưng là hình chữ nhật đứng, 1 đặc trưng là hình chữ nhật nghiêng 45 độ */
/* If rect[2].weight !=0, thì đặc trưng này chứa 3 hình chữ
nhật, ngược lại thì chứa 2 */
struct { CvRect r; float weight; } rect[CV_HAAR_FEATURE_MAX]; } CvHaarFeature;
/* cấu trúc cây phân lớp trả về giá trị phản hồi dựa trên đặc trưng HaarLike của vùng ảnh đang xét*/
typedef struct CvHaarClassifier {
int count; /* số lượng nodes của cây */
/* left[i] – lá trái của cây
right[i] – lá phải của cây
threshold[i] – Ngưỡng rẽ nhánh. Nếu đặc trưng HaarLike của vùng ảnh đang xét <= threshold thì thì lá trái được chọn. Ngược lại là lá phải
alpha[i] – giá trị trả về của lá */
CvHaarFeature* haar_feature; float* threshold; int* left; int* right; float* alpha; } CvHaarClassifier;
36
/* a boosted battery of classifiers(=stage classifier): the stage classifier returns 1
if the sum of the classifiers responses
is greater than \texttt{threshold} and 0 otherwise */
typedef struct CvHaarStageClassifier {
int count; /* số lượng các bộ phân lớp trong stage */ float threshold; /* threshold for the boosted classifier */ CvHaarClassifier* classifier; /* array of classifiers */
/* these fields are used for organizing trees of stage
classifiers,
rather than just stright cascades */
int next;
int child; int parent; }
CvHaarStageClassifier;
typedef struct CvHidHaarClassifierCascade CvHidHaarClassifierCascade;
/* Cấu trúc một cascade chứa các stage */
typedef struct CvHaarClassifierCascade {
int flags; /* chữ kí */
int count; /* số lượng stage */
CvSize orig_window_size; /* kích cỡ của các đối tượng được huấn luyện */
CvSize real_window_size; /* kích cỡ thực của đối tượng đang xét */
double scale; /* tỉ lệ của đối tượng */
CvHaarStageClassifier* stage_classifier; /* mảng các stage */ CvHidHaarClassifierCascade* hid_cascade; /* cascade ẩn được tạo thành bởi hàm cvSetImagesForHaarClassifierCascade */
}
37
Các hàm phục vụ cho boosting trong OpenCV:
CvHaarClassifierCascade* cvLoadHaarClassifierCascade(const char*directory, CvSize orig_window_size)
- directory: đường dẫn tới file huấn luyện
- orig_window_size: kích thước ban đầu của các đối tượng được huấn luyện
Hàm này có tác dụng load file huấn luyện
int cvRunHaarClassifierCascade (CvHaarClassifierCascade*cascade, CvPoint pt, int start_stage=0)
- pascase: Cascade được dùng
- pt: tọa độ góc trên bên trái của vùng ảnh đang xét
- start_stage: Vùng ảnh bắt đầu được xét từ stage này
Hàm có tác dụng đưa vùng ảnh đang xét qua các bộ phân lớp. Nếu vùng ảnh qua được tất cả các bộ phân lớp thì trả về giá trị dương, ngược lại thì trả về 0 hoặc giá trị âm
Void cvReleaseHaarClassifierCascade (CvHaarClassifierCascade**cascade)
- Cascade: Cascade đang được sử dụng
Hàm này có tác dụng giải phóng cascade đang dùng [7][3].
Các hàm, trên đều được sử dụng trong hàm detect_and_draw sẽ được trình bày ở phần sau.
3.1.2 Sử dụng Viola-Jones trong OpenCV:
Sau khi hoàn thành việc huấn luyện, ta sẽ sử dụng file huấn luyện cho việc phát hiện khuôn mặt. OpenCV đã hỗ trợ đầy đủ các câu lệnh trong việc truy xuất bộ phân lớp XML và kết xuất kết quả ra ảnh nên việc thực hiện khá đơn giản. Ở phần này, ta sẽ xây dựng hàm phục vụ cho việc phát hiện khuôn mặt dựa trên các câu lệnh của OpenCV và bộ phân lớp vừa huấn luyện.
Xây dựng hàm: void detect_and_draw( IplImage* img ) với img là ảnh đầu vào. Hàm này được viết như sau:
CvSeq *faces = cvHaarDetectObjects( img, cascade, storage, 1.1, 3, 0 /*CV_HAAR_DO_CANNY_PRUNNING*/, cvSize( 40, 40 ) );
Khai báo khuôn mặt của người được xác định trên ảnh . Khuôn mặt được xác định bằng hàm:
IntPtr cvHaarDetectObjects(IntPtr image,
IntPtr cascade,
IntPtr storage,
double scaleFactor,
38
int flags,
MCvSize minSize)
Trong đó:
img: Ảnh đầu vào.
cascade: Bộ huấn luyện.
storage: Bộ đệm.
scaleFactor: Hệ số tỉ lệ của cửa sổ kết quả.
minNeighbors: Số lượng hình chữ nhật kết quả nhỏ nhất của một nhóm. Nhóm
nào có số lượng hình chữ nhật nhỏ hơn tham số này sẽ bị loại bỏ.
minSize: Kích cỡ nhỏ nhất của hình chữ nhật quét qua ảnh để lấy các đặc trưng
Haarlike.
Hàm này hoạt động như sau: Scan toàn bộ ảnh bằng một vùng có kích thước cố định. Xét xem vùng đó có chứa khuôn mặt hay không bằng cách đưa qua máy phân lớp AdaBoost theo hàm cvRunHaarClassifierCascade. Trong đó, hàm cvRunHaarClassifierCascade sẽ kiểm tra xem vùng ảnh đó có đi qua hết các bộ phân lớp yếu hay không? Bộ phân lớp sẽ dựa trên tập huấn luyện XML để quyết định. Để đảm bảo phát hiện được tất cả các khuôn mặt với kích thước khác nhau, hàm sẽ quét ảnh trên nhiều độ phân giải. Kết quả xuất ra là tất cả các vùng ảnh đã qua được tất cả các bộ phân lớp yếu. Các vùng ảnh này được chồng lên nhau trên ảnh kết quả. Trong các vùng đó, sẽ có những vùng sai hoặc bị lệch đôi chút. Hàm sẽ tự động phân nhóm các vùng đó và cho ra kết quả cuối cùng là vùng trung bình của nhóm đó [3].
Tìm tất cả các gương mặt trong ảnh và xác định vị trí của khuôn mặt
/* với mỗi khuôn mặt tìm được, vẽ một hình chữ nhật */
for( i = 0 ; i < ( faces ? faces->total : 0 ) ; i++ ) { CvRect *r = ( CvRect* )cvGetSeqElem( faces, i ); cvRectangle( img,
cvPoint( r->x, r->y ),
cvPoint( r->x + r->width, r->y + r->height ), CV_RGB( 255, 0, 0 ), 1, 8, 0 );
}
/* hiển thị */
cvShowImage( "pic", img ); Trong hàm main:
CvHaarClassifierCascade *cascade; CvMemStorage *storage;
//Dẫn đường dẫn tới bộ huấn luyện có sẵn trong OpenCV
const char* cascade_name =
"D:/Soft/Programmer/Run/Library/OpenCV/opencv/data/haarcascades/haarcascade_fro ntalface_alt2.xml";
cascade = ( CvHaarClassifierCascade* )cvLoad( cascade_name, 0, 0, 0 );
39
/*dung lượng bộ nhớ đệm cho việc detect */
storage = cvCreateMemStorage( 0 );
IplImage *img = cvLoadImage("D:\\Code\\OpenCV\\HaarLike Pic\\Resource\\2.jpg"); detect_and_draw(img);
cvWaitKey();
cvReleaseImage(&img); cvDestroyWindow("result");