ĐẠI HỌC QUỐC GIA HÀ NỘI

a

TRƯỜNG ĐẠI HỌC CÔNG NGHỆ

Trần Thị Hợp

HỆ ĐIỀU HÀNH ANDROID VÀ THỰC THI ỨNG DỤNG PHÁT HIỆN KHUÔN MẶT TRÊN ANDROID

KHOÁ LUẬN TỐT NGHIỆP ĐẠI HỌC HỆ CHÍNH QUY Ngành: Công Nghệ Điện Tử Viễn Thông

HÀ NỘI - 2011

ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ

Trần Thị Hợp

HỆ ĐIỀU HÀNH ANDROID VÀ THỰC THI ỨNG DỤNG PHÁT HIỆN KHUÔN MẶT TRÊN ANDROID

KHOÁ LUẬN TỐT NGHIỆP ĐẠI HỌC HỆ CHÍNH QUY Ngành: Công Nghệ Điện Tử Viễn Thông

Cán bộ hướng dẫn: TS. Nguyễn Linh Trung Cán bộ đồng hướng dẫn: TS. Nguyễn Thái Hà

HÀ NỘI - 2011

VIETNAM NATIONAL UNIVERSITY, HANOI UNIVERSITY OF ENGINEERING AND TECHNOLOGY

Tran Thi Hop

ANDROID OPERATING SYSTEM AND IMPLEMENTATION OF FACE DETECTION APPLICATION ON ANDROID

Major: Faculty of Electronics and Telecommunications

Supervisor: Ph.D Nguyen Linh Trung Co-Supervisor: Ph.D Nguyen Thai Ha

HÀ NỘI-2011

LỜI CẢM ƠN Để hoàn thành khóa luận này, em đã nhận được sự giúp đỡ nhiệt tình của TS. Nguyễn Linh Trung, TS. Nguyễn Thái Hà và các anh chị bên công ty Techburg, Hà Nội. Trước hết em xin bày tỏ lòng biết ơn sâu sắc tới TS. Nguyễn Linh Trung, Giảng viên khoa Điện Tử Viễn Thông, Trường Đại học Công Nghệ, ĐHQG Hà Nội, người đã hướng dẫn và chỉ bảo nhiệt tình cho em trong suốt quá trình học, nghiên cứu và hoàn thành khóa luận. Em xin trân trọng cảm ơn sự nhiệt tình hướng dẫn và giúp đỡ tận tình của TS. Nguyễn Thái Hà, Tổng giám đốc Công ty Techburg và các anh chị thuộc công ty đã nhiệt tình giúp đỡ và tạo điều kiện cho em học tập và hoàn thành khóa luận này. Cuối cùng, em xin gửi lời biết ơn tới gia đình và bạn bè đã giúp đỡ và động viên em rất nhiều để em có thể hoàn thành khóa luận này. Đặc biệt là gia đình, nơi đã sinh thành, nuôi dưỡng và động viên em rất nhiều trong thời gian qua. Hà Nội , ngày 20 tháng 5 năm 2011 Sinh viên: Trần Thị Hợp

TÓM TẮT Android là hệ điều hành cho thiết bị di động được phát triển bởi Google. Android dựa trên nhân Linux 2.6 và các ứng dụng Android được viết bằng ngôn ngữ lập trình Java. Khóa luận này tôi trình bày tổng quan về Android, kiến trúc Android, Android SDK, Android NDK, các thành phần tạo nên một ứng dụng Android và trình bày hai phương pháp phát hiện khuôn mặt sử dụng thư viện OpenCV và framework API của Android. Đồng thời khóa luận cũng trình bày sự khác nhau giữa máy ảo Java và máy ảo Dalvik. Dalvik là máy ảo thực thi các ứng dụng Android. Trong khóa luận này tôi trình bày quy trình xây dựng và thực thi một ứng dụng với Android NDK. Quy trình này sẽ được sử dụng để xây dựng ứng dụng phát hiện khuôn mặt sử dụng OpenCV. OpenCV là một thư viện hỗ trợ cho xử lý ảnh do Intel phát triển, bao gồm khoảng 500 hàm viết bằng các ngôn ngữ C và C++. Để sử dụng được thư viện này thì đầu tiên phải porting được thư viện OpenCV vào Android. Khóa luận cũng trình bày cách porting thư viện và trình bày thuật toán phát hiện khuôn mặt do Viola và Jones đưa ra. Để sử dụng thư viện OpenCV thì cần một giao diện để chương trình ứng dụng Android viết bằng Java có thể gọi được các hàm viết bằng C/C++ của OpenCV. Giao diện đó là JNI (Java Native Interface). Trong khóa luận tôi cũng đưa ra một demo với “Hello World” sử dụng Android NDK mà có hỗ trợ JNI. Từ đó đưa được giải pháp để phát triển ứng dụng phát hiện khuôn mặt sử dụng OpenCV. Phương pháp thứ hai để phát hiện khuôn mặt là sử dụng framework API của Android. API là giao diện lập trình ứng dụng (Application Programming Interface). Android cung cấp một framework API bao gồm các gói và các lớp giúp cho các nhà phát triển có thể sử dụng để phát triển nhiều ứng dụng hấp dẫn. Khóa luận trình bày về các gói và các lớp sử dụng framework API của Android để xây dựng ứng dụng phát hiện khuôn mặt trên Android và khóa luận đưa ra được kết quả khi tiến hành thực nghiệm. Với phương pháp này chỉ cần có kỹ năng lập trình Java tốt là có thể xây dựng được ứng dụng.

i

LỜI CAM ĐOAN Tôi xin cam đoan đề tài “Hệ điều hành Android và thực thi ứng dụng phát hiện khuôn mặt trên Android ” là kết quả tìm hiểu của riêng tôi với sự hướng dẫn của TS. Nguyễn Linh Trung và TS. Nguyễn Thái Hà. Trong khóa luận có sử dụng một số tài liệu và kết quả nghiên cứu như đã nêu trong phần tài liệu tham khảo. Các kết quả, số liệu sử dụng trong khóa luận là chính xác và trung thực. Khóa luận được hoàn thành trong thời gian tôi là sinh viên tại Bộ môn thông tin vô tuyến, Khoa điện tử viễn thông, Trường Đại học Công Nghệ, ĐHQG Hà Nội. Hà Nội, ngày 20 tháng 5 năm 2011 Sinh viên: Trần Thị Hợp

ii

MỤC LỤC
Trần Thị Hợp...................................................................................................................................1 Trần Thị Hợp...................................................................................................................................2 Tran Thi Hop....................................................................................................................................3 Danh sách hình vẽ...........................................................................................................................iv CHƯƠNG 1. HỆ ĐIỀU HÀNH ANDROID..................................................................................1 1.1.Android là gì?............................................................................................................................1 1.2.Máy ảo Dalvik...........................................................................................................................1 1.3.Kiến trúc Android......................................................................................................................3 1.4.Android emulator.......................................................................................................................5 1.5. Android SDK............................................................................................................................6 1.6.Android NDK............................................................................................................................8 1.7. Porting OpenCV vào Android................................................................................................10 1.8. Các thành phần tạo nên một ứng dụng Android....................................................................12 1.9. Phát triển ứng dụng Android và DVM...................................................................................19 1.10. Tạo và demo ứng dụng “Hello World” sử dụng Android NDK..........................................20 CHƯƠNG 2 .CÁC PHƯƠNG PHÁP PHÁT HIỆN KHUÔN MẶT TRÊN ANDROID............27 2.1. Thuật toán của Viola – Jones trong OpenCV........................................................................27 2.2. Phát hiện khuôn mặt sử dụng framework API của Android..................................................31 2.3. Xây dựng chương trình phát hiện khuôn mặt trên Android..................................................36 CHƯƠNG 3. KẾT QUẢ ĐẠT ĐƯỢC.........................................................................................48 3.1. Kết quả phát hiện khuôn mặt sử dụng framework API của Android..................................48 3.2. Khó khăn và hướng giải quyết...............................................................................................49 KẾT LUẬN....................................................................................................................................50 TÀI LIỆU THAM KHẢO.............................................................................................................50

iii

Danh sách hình vẽ
Hình 1. Qúa trình thực thi ứng dụng Java và ứng dụng Android [4].............................................2 Hình 2.Qúa trình biến đổi file mã Java thành file (.dex)................................................................2 Hình 3.Kiến trúc Android [9]..........................................................................................................3 Hình 4.Android Emulator................................................................................................................6 Hình 5.Các ứng dụng Android trong API Demos..........................................................................7

iv

Hình 6.Vai trò của JNI [7]...............................................................................................................9 Hình 7.Mô hình xây dựng và chạy code JNI [7]...........................................................................10 Hình 8.Mô hình porting OpenCV vào Android............................................................................11 Hình 9.Qúa trình porting OpenCV vào Android...........................................................................12 Hình 10.Ngăn xếp Activity............................................................................................................13 Hình 11.Chu kỳ sống của Activity [4]..........................................................................................14 Hình 12.Chu kỳ sống của Service [4]...........................................................................................17 Hình 13.Truyền thông giữa hai tiến trình......................................................................................17 Hình 14.Broadcast receiver...........................................................................................................17 Hình 15.Content Provider [4]........................................................................................................18 Hình 16.Ứng dụng Contacts sử dụng Contacts Provider để lấy dữ liệu......................................18 Hình 17.Intent [4]..........................................................................................................................19 Hình 18.Qúa trình tạo file APK.....................................................................................................20 Hình 19.Quá trình truy cập mã gốc qua JNI [4]............................................................................21 Hình 20.Demo ứng dụng Hello World dùng Android NDK........................................................26 Hình 21.Các đặc trưng Haar-like cơ bản [7].................................................................................27 Hình 22.Các đặc trưng Haar-like mở rộng [6]..............................................................................27 Hình 23.Cách tính Integral Image [8]............................................................................................28 Hình 24.Ví dụ cách tính nhanh các giá trị mức xám [7]...............................................................28 Hình 25.Mô hình cascade kết hợp với các bộ phân loại yếu [7]..................................................29 Hình 26.Kết hợp các bộ phân loại yếu thành bộ phân loại mạnh.................................................30 Hình 27. Hệ thống phát hiện khuôn mặt.......................................................................................30 Hình 28.Các gói Android cung cấp trong framework API...........................................................36 Hình 29.Mô hình phát hiện khuôn mặt trên Androi......................................................................36 Hình 30.Các góc Euler- hệ tọa độ xyz (cố định), hệ tọa độ XYZ (quay).....................................37 Hình 31.Các thành phần trong một Android Project....................................................................40 Hình 32. Các tệp trong thư mục bin của Android Project............................................................46 Hình 33.Hình ảnh gốc ban đầu......................................................................................................48 Hình 34.Kết quả phát hiện khuôn mặt trên Android.....................................................................48 v

vi

THUẬT NGỮ VIẾT TẮT SỬ DỤNG TRONG BÀI

ADB ADT AVD API BSD DVM GPS JNI JVM NDK OS OpenCV SDK UI VM

Android Debug Bridge Android Development Tools Android Virtual Devices Application Programming Interface Berkeley Software Distribution Dalvik Virtual Machine Global Positioning System Java Native Interface Java Virtual Machine Native Development Kit Operating System OpenSource Computer Vision Software Development Kit User Interface Virtual Machine

vii

LỜI MỞ ĐẦU

Android là một hệ điều hành cho điện thoại di động do Google phát triển dựa trên nền tảng Linux 2.6. Android đang từng bước thống trị thị trường di động nhờ vào những ưu điểm vượt trội của nó. Không như iPhone của Apple người dùng dường như bị cột chặt với những gì hãng này cho phép thì Android được kế thừa tính mở từ Linux hay nói cụ thể hơn là Google và Android mang đến một thế giới hoàn toàn mở. Người dùng được tự do với những gì họ muốn và các nhà phát triển có được sự tự do hơn để tạo ra các ứng dụng. Ngoài ra với Android người tiêu dùng có thể có nhiều sự lựa chọn. Chẳng hạn như hãng LG tung ra trên thị trường 20 sản phẩm chạy nền Android năm 2010. Bên cạnh các tính năng đó thì Android sẽ từng bước thống trị thị trường di động nhờ vào ưu điểm hướng đến người dùng và với thương hiệu của Google đứng sau lưng nó. Đây là một thương hiệu đáng giá. Hiện nay Android không chỉ được dùng cho điện thoại di động mà còn được các nhà sản xuất điện tử trên thế giới sử dụng Android như là một nền tảng cho các sản phẩm nhúng, ví dụ như nhà thông minh, hệ thống thông tin giải trí ô tô, … Ngoài ra trong tương lai Google sẽ sớm tung ra một hệ điều hành cho tivi, đầu thu kỹ thuật số (set-top-box). Trong khóa luận này tôi sẽ trình bày tổng quan về hệ điều hành Android và trình bày hai hướng để phát triển ứng dụng phát hiện khuôn mặt trên Android đó là sử dụng OpenCV và framework API của Android. OpenCV là một thư viện hỗ trợ mạnh cho xử lý ảnh do Intel phát triển bao gồm các hàm được viết bằng ngôn ngữ C và C++ trong đó có hỗ trợ phát hiện khuôn mặt. Thuật toán phát hiện khuôn mặt của Viola – Jones được đưa vào OpenCV vì với tốc độ gấp 15 lần so với các thuật toán hiện tại [7]. Hướng thứ hai tôi sẽ trình bày trong khóa luận để xây dựng một ứng dụng phát hiện khuôn mặt với framework API của Android. API là giao diện lập trình ứng dụng, viết tắt của Application Programming Interface. Nền tảng Android cung cấp một framework API mà các ứng dụng có thể tương tác với hệ thống Android. Framework API bao gồm một lõi thiết lập các gói và các lớp. Trong ứng dụng phát hiện khuôn mặt tôi sử dụng lớp FaceDetector trong gói android.media của framework API do Android cung cấp để xây dựng ứng dụng. Với hướng thứ hai này chỉ cần kỹ năng lập trình Java tốt là có thể xây dựng được ứng dụng. Nội dung của khóa luận gồm 3 chương:

viii

Chương 1: Trình bày tổng quan về hệ điều hành Android, kiến trúc Android, Android SDK, Android NDK, porting OpenCV vào Android và quy trình xây dựng và thực thi một ứng dụng Android. Bản chất của việc Porting OpenCV vào Android là thêm một thư viện chia sẻ vào tầng thư viện của Android để từ đó có thể dùng thư viện này để phát triển nhiều ứng dụng khác không chỉ là phát hiện khuôn mặt. Chẳng hạn như dùng OpenCV có thể phát triển thêm các ứng dụng phân tích chuyển động, nhận dạng khuôn mặt. Chương này cũng đưa ra sự khác nhau giữa máy ảo Java và máy ảo Dalvik. Dalvik là máy ảo để thực thi các ứng dụng Android. Chương 2: Trình bày hai phương pháp phát hiện khuôn mặt trên Android sử dụng OpenCV và framework API của Android trong tầng applications framework của kiến trúc Android. Trong chương này tôi sẽ trình bày thuật toán của Viola – Jones sử dụng trong OpenCV và xây dựng chương trình phát hiện khuôn mặt với framework API của Android. Chương 3: Trình bày các kết quả đạt được và những khó khăn gặp phải từ đó đưa ra hướng giải quyết khó khăn.

ix

CHƯƠNG 1. HỆ ĐIỀU HÀNH ANDROID
1.1.Android là gì?
Android là một ngăn xếp phần mềm cho các thiết bị di động bao gồm một hệ điều hành, middleware và các ứng dụng khóa được phát triển bởi Google. Android được dựa trên nhân Linux 2.6 và các ứng dụng cho Android sử dụng ngôn ngữ lập trình Java. Android là một hệ điều hành mã nguồn mở, các nhà phát triển có thể tạo ra các ứng dụng cho Android và bất kỳ ai cũng có thể lấy và sửa đổi theo ý thích. Tuy nhiên các thiết bị Android cũng chứa một số phần mềm độc quyền mà các nhà phát triển không thể tiếp cận được những phần mềm này. Ví dụ: hệ thống định vị toàn cầu (GPS). Android cũng hỗ trợ nhiều tính năng như: Wi-fi, Bluetooth, các mạng 3G và 4G, …

1.2.Máy ảo Dalvik
Dalvik là máy ảo để thực thi các ứng dụng Android. Dalvik chạy các file ở định dạng (.dex). Từ góc nhìn của một nhà phát triển Dalvik giống như máy ảo Java nhưng thực tế thì hoàn toàn khác. Khi các nhà phát triển viết một ứng dụng Android thì đều phải thực hiện các đoạn mã trong Java. Sau đó các file mã Java sẽ được biên dịch sang mã bytecode. Sau đó để thực thi được các ứng dụng Android thì ta phải dùng một công cụ tên là dx để chuyển đổi mã bytecode của Java sang một file có định dạng dex (dex là viết tắt của Dalvik excutable), đóng vai trò như cơ chế ảo để thực thi các ứng dụng Android. Hình 1 mô tả sự khác nhau giữa giữa quá trình thực thi một ứng dụng Java và quá trình thực thi một ứng dụng Android:

1

Hình 1. Qúa trình thực thi ứng dụng Java và ứng dụng Android [4] Hình 1 thể hiện hai sự khác biệt giữa máy ảo Java (JVM: Java Virtual Machine) và máy ảo Dalvik (DVM: Dalvik Virtual Machine). Sự khác biệt đầu tiên là các mã bytecode mà JVM hoạt động là Java bytecode còn DVM hoạt động trên định dạng đặc biệt của nó (định dạng .dex). Sự khác biệt thứ hai là các lớp Java trong chương trình Java SE được biên dịch vào một hay nhiều file (.class) và nén vào file(.jar), sau đó JVM có được các file bytecode từ các file (.class) và file (.jar). Mặc dù các ứng dụng Android cũng được biên dịch trong ngôn ngữ lập trình Java nhưng sau khi các ứng dụng này được biên dịch thành các file (.class) thì một công cụ dx sẽ biến đổi tất cả các file (.class) thành file (.dex). Từ đó DVM đọc các chỉ dẫn và dữ liệu. Hình vẽ dưới đây thể hiện quá trình biến đổi đó:

Hình 2.Qúa trình biến đổi file mã Java thành file (.dex)

2

1.3.Kiến trúc Android

Hình 3.Kiến trúc Android [9] Android là một ngăn xếp phần mềm, bao gồm các tầng như trên hình 3. Trong đó các hàm thực thi các ứng dụng trong hai tầng Applications và Applications framework được viết bằng ngôn ngữ lập trình Java. Còn các hàm thực thi các ứng dụng ở các tầng dưới: Libraries, Android runtime, Linux kernel được viết bằng mã gốc hay native code được viết bằng ngôn ngữ C/C++. Khi cần xây dựng một ứng dụng Android mà cần phải sử dụng một đoạn mã viết bằng C/C++ ở các tầng bên dưới thì ta sẽ sử dụng JNI (Java Native Interface) để giúp ứng dụng Android viết bằng Java có thể truy cập được các hàm viết bằng C/C++. Ta sẽ nói rõ hơn về quá trình sử dụng JNI trong phần demo ứng dụng “Hello World” ở phần sau. Dưới đây ta sẽ tìm hiểu chức năng của từng tầng trong kiến trúc Android:

Tầng Applications

Android được tích hợp sẵn một số ứng dụng cần thiết cơ bản như: calendar, maps, contacts, brower, camera, phone, … Tất cả các ứng dụng này đều được viết bằng ngôn ngữ Java.  Tầng Applications framework

3

Bằng cách cung cấp một nền tảng phát triển mở Android cung cấp cho các nhà phát triển khả năng xây dựng các ứng dụng cực kỳ phong phú và sáng tạo. Nhà phát triển được tự do tận dụng các thiết bị phần cứng, thông tin địa điểm truy cập, các dịch vụ chạy nền, thiết lập hệ thống báo động, và cộng thêm các cảnh báo đến các thanh trạng thái, và nhiều hơn nữa. Nhà phát triển có thể truy cập vào các API cùng một framework được xây dựng bởi các ứng dụng lõi. Kiến trúc ứng dụng được thiết kế để đơn giản hóa việc sử dụng lại các thành phần; bất kỳ ứng dụng nào cũng có thể công bố khả năng của nó và bất kỳ ứng dụng nào khác cũng có thể sử dụng những khả năng này(có thể hạn chế bảo mật được thực thi bởi framework). Tất cả các ứng dụng cơ bản là một bộ dịch vụ và các hệ thống, bao gồm: • Một tập hợp phong phú và mở rộng các View có khả năng kế thừa lẫn nhau dùng để thiết kế phần giao diện ứng dụng như : gridview, tableview, linearlayout, …
• Trình cung cấp nội dung (Content Providers): Cho phép các ứng dụng có thể

truy xuất dữ liệu từ các ứng dụng khác (chẳng hạn như contacts) hoặc là chia sẻ dữ liệu giữa các ứng dụng đó. • Quản lý tài nguyên (Resource Manager): Cung cấp truy xuất tới các tài nguyên không phải là mã nguồn, chẳng hạn như graphics, và các file layout. • Quản lý thông báo (Notification Manager): Cho phép tất cả các ứng dụng hiển thị các cảnh báo trong thanh trạng thái. • Quản lý hoạt động (Activity Manager): Quản lý chu trình sống của ứng dụng và điều hướng các Activity.  Tầng Libraries

Android bao gồm một tập hợp các thư viện C/C++ được sử dụng bởi nhiều thành phần khác nhau trong hệ thống Android. Điều này được thể hiện thông qua nền tảng ứng dụng Android. Một số các thư viện cơ bản được liệt kê dưới đây:
• System C library – Thực hiện triển khai BSD của thư viện hệ thống C chuẩn

(libc) và chỉnh cho các thiết bị nhúng dựa trên Linux. BSD là giấy phép nguồn mở, cho phép mọi người sử dụng chương trình, mã nguồn của nó và các dẫn xuất.
• Media Libararies – Dựa trên PacketVideo’s OpenCORE; các thư viện hỗ trợ

phát và ghi âm với nhiều định dạng audio và video, cũng như đối với các file ảnh tĩnh bao gồm: MPEG4, H.264, MP3, AAC, ARM, JPG, và PNG.
4

• Surface Manager- Quản lý truy cập vào hệ thống hiển thị. • LibWebCore- Một công cụ trình duyệt web hiện đại. • SGL – Công cụ đồ họa 2D cơ sở. • 3D libraries – Sự thực hiện dựa trên OpenGL ES 1.0 APIs. • Free Type- Biểu diễn font véc-tơ và bitmap. • QLite –Cơ sở dữ liệu. • Webkit – Thư viện cho việc biểu diễn HTML

Tầng Android runtime

Tầng này bao gồm các thư viện lõi và máy ảo Dalvik. Các thư viện lõi bao gồm các thư viện lớp cơ bản nhất như: cấu trúc dữ liệu, mạng, các tiện ích, hệ thống file. DVM được thiết kế để đạt được các chức năng quản lý chu kỳ sống của đối tượng, quản lý ngăn xếp, quản lý luồng, bảo mật, …DVM là lý tưởng để sử dụng với yêu cầu về không gian bộ nhớ và CPU thấp so với các máy ảo chạy trên các máy tính để bàn và hệ thống máy chủ. Theo tính toán của Google thì cần 64M RAM cho phép hệ thống hoạt động tốt, 24M RAM được sử dụng để khởi tạo và bắt đầu hệ thống cơ bản, và 20M RAM được sử dụng cho các dịch vụ cấp cao.  Linux kernel

Android được xây dựng trên nhân Linux, nhưng Android không phải là Linux. Android dựa trên Linux phiên bản 2.6 cho các hệ thống dịch vụ cốt lõi như an ninh, quản lý bộ nhớ, quản lý quá trình, ngăn xếp mạng, và mô hình điều khiển. Hạt nhân cũng hoạt động như một lớp trừu tượng giữa phần cứng và phần còn lại của ngăn xếp phần mềm. Linux kernel hỗ trợ các thư viện chia sẻ (shared libraries) và nó còn là một mã nguồn mở.

1.4.Android emulator
Android SDK và Plugin Eclipse được gọi là Android Development Tools (ADT). Trình giả lập Android ( Android Emulator) được tích hợp với Eclipse, sử dụng ADT plug-in cho Eclipse IDE. Trình giả lập điện thoại Android hay còn gọi là AVD (Android Virtual Device) trên đó các ứng dụng có thể chạy và được thử nghiệm. Một khi AVD được khởi chạy, có thể triển khai một số lượng ứng dụng bất kỳ trong khi nó vẫn còn đang chạy và thậm chí có thể sử dụng nó để gỡ rối ứng dụng. Hình dưới đây mô tả một trình giả lập Android:
5

Hình 4.Android Emulator Các trình giả lập Android là một công cụ tiện lợi nhưng nó có một số hạn chế đó là: các trình giả lập không phải là một thiết bị nói chung nó mô phỏng hành vi của chiếc điện thoại, không hỗ trợ các chức năng nghe nhạc, quay phim, chụp ảnh, USB, Bluetooth, …

1.5. Android SDK
Android SDK cung cấp nhiều tập tin và các công cụ đặc biệt nhằm mục đích giúp cho việc thiết kế và phát triển các ứng dụng chạy trên nền tảng Android. Android SDK cũng chứa các thư viện để buộc các ứng dụng vào trong các đặc tính lõi của Android, chẳng hạn như những thư viện này được kết hợp với các chức năng của điện thoại di động (thực hiện và nhận cuộc gọi), các chức năng GPS, và nhắn tin văn bản. Những thư viện này tạo nên lõi của SDK và sẽ được sử dụng thường xuyên nhất. Phần lớn Android SDK bao gồm các tập tin, tài liệu, với lập trình API, các công cụ, và các ví dụ. Trong Android SDK có một vài tập tin trong thư mục gốc giống như android.jar (một ứng dụng Java được biên dịch có chứa các thư viện lõi SDK và API), một số ghi chú, phần còn lại của Android SDK được chia thành ba thư mục chính: • Docs: Chứa tất cả các tài liệu đi kèm với Android. • Samples: Bao gồm các ví dụ, có thể được biên dịch và kiểm tra bên trong của Eclipse.

6

• Tools: Chứa tất cả các công cụ gỡ lỗi, biên dịch, và phát triển mà ta cần trong

suốt quá trình phát triển một ứng dụng Android. Trong mục Samples của Android SDK có chứa 6 ví dụ mẫu cho ứng dụng Android. Những ví dụ này cung cấp bởi Google để cung cấp cho ta một ý tưởng nhanh chóng về làm cách nào để phát triển một ứng dụng Android. Mỗi ứng dụng mẫu thể hiện mỗi phần khác nhau về chức năng của Android. Chúng ta có thể mở và chạy các ứng dụng này từ bên trong của Eclipse. Ứng dụng API Demos là một ứng dụng chủ (host application) mô tả nhiều hàm API trong một Activity đơn lẻ. Một Activity là một ứng dụng Android. Ứng dụng API Demos như chỉ ra hình dưới bao gồm nhiều ví dụ khác nhau về chức năng của Android:

Hình 5.Các ứng dụng Android trong API Demos Giao diện lập trình ứng dụng API (Application Programming Interface) là phần lõi của Android SDK. API là tập hợp các hàm, phương thức, đặc tính, lớp và các thư viện được sử dụng bởi các nhà phát triển ứng dụng để tạo ra các chương trình làm việc trên nền tảng cụ thể. Các Android API chứa tất cả các thông tin cụ thể mà ta cần để tạo ra ứng dụng có thể làm việc và tương tác với một ứng dụng trên nền Android. Android SDK cũng chứa hai bộ APIs bổ sung là Google APIs và Optional APIs: • Google APIs

7

Nằm trong tập tin android.jar, các API của Google được chứa trong gói com.google.*. Có một vài gói đi kèm với các API của Google. Một số gói được vận chuyển trong các API của Google bao gồm các gói cho đồ họa, tính khả chuyển, địa chỉ liên hệ và các tiện ích về lịch. Chẳng hạn như với gói cho Google Maps. Sử dụng gói com.google.android.maps. Trong gói này có chứa các thông tin cho bản đồ Google (Google Maps) ta có thể tạo các ứng dụng tương tác liên tục với giao diện quen thuộc của Google Maps. • Optional APIs Các Optional APIs bao gồm các tùy chọn chương trình khi cố gắng sử dụng các tính năng này trong các ứng dụng Android. Một trong những tính năng tùy chọn là một điện thoại di động dựa trên GPS. Android LBS (Location-Based Services) API giải quyết việc tiếp nhận và sử dụng thông tin từ GPS của điện thoại. (Kết hợp thông tin trong LBS Android API với GPS trong Google Maps API có thể tạo ra một ứng dụng rất hữu ích có thể tự động hiển thị một bản đồ định vị trí ). Một số Optional APIs khác bao gồm các tùy chọn cho việc sử dụng Bluetooth, Wi-Fi, chơi nhạc MP3 và truy cập phần cứng 3-D-OpenGL.

1.6.Android NDK
Như tôi đã đề cập trong phần kiến trúc của Android. Khi ta viết một ứng dụng cho Android sử dụng ngôn ngữ lập trình Java mà cần phải sử dụng một đoạn mã nào đó ở các tầng bên dưới (chẳng hạn tầng Libraries) viết bằng các ngôn ngữ C/C++. Để Java có thể truy cập được các hàm C/C++ thì ta cần một giao diện để chúng có thể tương tác với nhau. Giao diện đó là JNI (Java Native Interface). Android NDK là một công cụ đồng hành với Android SDK cho phép xây dựng các phần quan trọng thực hiện các ứng dụng trong mã gốc (native code). Nó cung cấp các headers và các thư viện cho phép xây dựng các activities khi lập trình bằng C hoặc C++. Nếu ta viết mã máy, các ứng dụng vẫn được đóng gói vào một file .apk và chúng vẫn chạy bên trong máy ảo trên thiết bị. Sử dụng mã gốc không dẫn đến tăng hiệu suất tự động, nhưng luôn luôn tăng độ phức tạp ứng dụng. Android NDK là một bộ công cụ cho phép nhúng các thành phần sử dụng mã gốc trong các ứng dụng Android. Các ứng dụng Android chạy trong máy ảo Dalvik. NDK (Native Development Kit) cho phép thực hiện các phần của ứng dụng sử dụng mã gốc chẳng hạn như C và C++. Android NDK cung cấp một chuỗi các công cụ và các file xây dựng để tạo các thư viện mã gốc từ các nguồn C và C++; Android NDK
8

là một cách để gói các thư viện vào trong file APK (file APK là file sẽ được phát hành trên Android cho việc thực thi ứng dụng); Android NDK bao gồm một chuỗi các header của hệ thống được hỗ trợ trong các phiên bản của nền tảng Android (ví dụ: libc, JNI headers, C++ headers, OpenGL, …); Android NDK bao gồm một số tài liệu, mã đơn giản và một số các ví dụ. Android NDK hỗ trợ JNI giúp các nhà phát triển ứng dụng xây dựng các ứng dụng có sử dụng các đoạn mã gốc của tầng bên dưới. Điều này là quan trọng vì trong một hệ thống nhúng bao gồm các tầng tạo nên một ngăn xếp phần mềm. Khi ta cần xây dựng một ứng dụng thuộc tầng trên cần kế thừa một số hàm viết bằng mã gốc thuộc tầng bên dưới (có thể là tầng lõi liên quan đến phần cứng) thì JNI đóng vai trò quan trọng. JNI là một tính năng mạnh của nền tảng Java cho phép các nhà lập trình tận dụng được sức mạnh của nền tảng Java (một chương trình viết bằng ngôn ngữ Java có thể chạy được trên nhiều hệ điều hành “viết một lần chạy mọi nơi”). JNI là một giao diện hai chiều cho phép các ứng dụng Java gọi mã gốc và ngược lại. Hình dưới đây mô tả vai trò của JNI:

Hình 6.Vai trò của JNI [7] Ta có thể sử dụng JNI để viết các phương thức gốc (native methods) cho phép các ứng dụng Java gọi các hàm được thực thi trong các thư viện gốc. Các ứng dụng Java gọi các phương thức gốc trong cùng một cách. Dưới đây là mô hình xây dựng và chạy code JNI:

9

Hình 7.Mô hình xây dựng và chạy code JNI [7] Hoạt động của mô hình trên như sau: Đầu tiên ta viết mã nguồn Java (Java Source) sau đó sử dụng trình biên dịch javac để biên dịch các file mã nguồn này thành file ở định dạng (.class). Trong file mã nguồn Java ta sẽ thực hiện các công việc là viết lệnh gọi thư viện động mà ta sẽ tạo ở phần sau (Dynamic Library) và định nghĩa hay khai báo các phương thức thực hiện các hàm native code mà ta sẽ viết ở sau, và mã nguồn Java này cũng là nơi để khởi tạo các phương thức. Tiếp theo ta sẽ tạo ra các header file bằng cách dùng lệnh với javah –jni. Sau khi tạo ra các header file thì ta sẽ viết mã C thực thi các hàm và các phương thức mà được khai báo trong mã nguồn Java. Tiếp theo để tạo ra thư viện động ta cần phải biên dịch mã C vừa viết ở trên. Để link được thư viện này tới mã nguồn Java thì trong mã nguồn Java ta viết lệnh gọi thư viện này. Sau tất cả các bước trên thì chương trình được thực thi trên máy ảo Java.

1.7. Porting OpenCV vào Android
Để phát triển ứng dụng Android với OpenCV thì đầu tiên ta cần porting được thư viện này vào trong kiến trúc của Android. OpenCV (Open Computer Vision library) do Intel phát triển. Thư viện OpenCV gồm khoảng 500 hàm được viết bằng ngôn ngữ lập trình C và C++. OpenCV là công cụ mã nguồn mở thích hợp cho nghiên cứu và phát triển. Để porting OpenCV vào Android ta sử dụng Android NDK. Dưới đây là mô hình porting OpenCV:

10

Hình 8.Mô hình porting OpenCV vào Android Tổ chức thư viện OpenCV bao gồm 4 module chính và 2 module mở rộng. Các module CV và CVAUX hỗ trợ các chức năng cấp cao (nhận dạng khuôn mặt, hiệu chỉnh camera), xử lý ảnh, phân tích chuyển động. Module CxCore tổ chức dữ liệu cơ sở, thực hiện các thuật toán (phép tính ma trận, tính toán). Module HighGuid giúp tạo nhanh giao diện và hỗ trợ truy xuất ảnh/phim từ file hoặc thiết bị ngoại vi. Để porting thì đầu tiên ta tải thư viện OpenCV về và giải nén. Sau đó dùng Android NDK để porting. Trong eclipse ta sẽ tạo một project cho việc thực thi porting. Sau đó tạo một file tên là jni trong project. File jni này sẽ chứa hai file là Application.mk và Android.mk. File Android.mk bao gồm các module là các thư viện của OpenCV cần porting vào trong Android với đường dẫn đúng. Sau đó dùng lệnh ndk-build trên Ubuntu để biên dịch thư viện OpenCV cho kiến trúc Arm của Android. Chú ý để sử dụng được lệnh ndk-build ta cần phải tải android NDK về và link đến đúng thư mục chứa android NDK đã được giải nén. Sau khi porting thì ta sẽ được một thư viện chia sẻ tên là libOpenCV.so và nằm trong thư mục libs/armeabi. Thư viện chia sẻ này sẽ nằm trong tầng Libraries trong kiến trúc Android. Hình dưới đây mô tả quá trình porting OpenCV cho kiến trúc Arm của Android.

11

Hình 9.Qúa trình porting OpenCV vào Android

1.8. Các thành phần tạo nên một ứng dụng Android
Các ứng dụng Android sẽ được xây dựng từ các thành phần cơ bản đó là: Activity, Service, Broadcast receiver, Content Provider và Intent.  Activity

Activity là một thành phần ứng dụng cung cấp một màn hình mà người dùng có thể tương tác để làm một cái gì đó. Chẳng hạn như: quay số điện thoại, chụp ảnh, gửi email hoặc xem một bản đồ. Một Activity có thể bắt đầu từ các Activity khác. Bên trong hệ thống các Activity được quản lý như một ngăn xếp. Khi một Activity mới được bắt đầu thì nó được đặt ở đỉnh của ngăn xếp và trở trành Activity đang chạy. Activity trước sẽ ở bên dưới Activity mới và sẽ không thấy trong suốt quá trình Activity mới tồn tại. Nếu người dùng nhấn nút Back thì Activity kế tiếp của ngăn xếp sẽ di chuyển lên và trở thành active. Hình dưới đây mô tả một ngăn xếp các Activity:

12

Hình 10.Ngăn xếp Activity Mỗi tiến trình chạy ứng dụng trên nền tảng Android được đặt trên một ngăn xếp. Khi sử dụng một Activity trên foreground thì tiến trình hệ thống sẽ đưa Activity đó lên trên cùng của ngăn xếp và tiến trình trước đó sẽ được chuyển xuống mức dưới. Tất cả các Activity đều có khả năng bị dừng lại hoặc bị phá hủy bất cứ lúc nào bởi vì người sử dụng có thể thay đổi các Activity tùy theo ý thích của họ. Chẳng hạn như: họ đang dùng Activity là một cuộc gọi và sau đó họ dừng cuộc gọi và chuyển sang Activity khác là chụp ảnh, gửi email hay nhắn tin SMS. Nếu tiến trình Activity bị thoát ra khỏi foreground thì nó sẽ bị hủy. Hình dưới đây mô tả chu kỳ sống của Activity:

13

Hình 11.Chu kỳ sống của Activity [4]

• Trạng thái Starting:

Khi một Activity không tồn tại trong bộ nhớ thì nó ở trạng thái starting. Trong khi Activity đang khởi động thì Activity sẽ đi qua một chuỗi các phương thức callback. Và cuối cùng Activity sẽ ở trạng thái running. Lưu ý rằng quá trình chuyển đổi từ trạng thái starting sang trạng thái running là một trong những các hoạt động tốn kém nhất về thời gian tính toán, và nó cũng ảnh hưởng trực tiếp đến tuổi thọ của pin. Đó là lý do tại sao ta không thể tự động hủy các Activity mà chúng không còn được hiển thị. • Trạng thái Running: Activity ở trong trạng thái running (đang hoạt động) nghĩa là Activity đó được hiển thị trên màn hình và tương tác với người dùng. Người dùng có thể tương tác như gõ phím, chạm vào màn hình và nhấn các nút. Tất cả các thao tác này được xử lý bởi Activity này. Như vậy tại một thời điểm nào đó thì chỉ có một Activity. • Trạng thái Paused: Khi một Activity không được focus( chẳng hạn như nó không được tương tác với người sử dụng ) nhưng nó vẫn có thể được nhìn thấy ở trên màn hình. Trong trường hợp này ta nói Activity đang ở trạng thái tạm dừng (paused).

14

• Trạng thái Stopped: Khi một Activity không hiển thị nhưng vẫn còn ở trong bộ nhớ thì ta nói rằng nó đang ở trạng thái dừng (Stopped). Các Activity ở trạng thái dừng này có thể được đưa trở lại để trở thành một Activity đang chạy (running) hoặc nó cũng có thể bị phá hủy và loại bỏ khỏi bộ nhớ. Hệ thống vẫn giữ lại các Activity xung quanh trạng thái stopped bởi vì có thể người dùng vẫn sẽ muốn quay trở lại các Activity trước đó và muốn khởi động lại các Activity ở trạng thái dừng, do đó sẽ tiết kiệm được thời gian khởi động vì ta sẽ không phải khởi động một Activity lại từ đầu. Các Activity ở trạng thái stopped có thể bị loại khỏi bộ nhớ bất cứ lúc nào. • Trạng thái Destroyed: Một Activity bị phá hủy thì nó không còn ở trong bộ nhớ. Trình quản lý Activity quyết định Activity này không còn cần thiết và do đó sẽ loại bỏ Activity đó. Trước khi Activity bị phá hủy thì nó có thể thực hiện các hành động nhất định, ví dụ như bất kỳ một thông tin nào chưa được lưu thì nó sẽ lưu lại các thông tin đó. Tuy nhiên trước khi bị phá hủy thì Activity sẽ được ngừng lại (stopped). Trong suốt chu kỳ sống của Activity thì mỗi Activity của một chương trình Android sẽ tồn tại ở vài trạng thái khác nhau. Lập trình viên không phải điều khiển các trạng thái trong chương trình. Tất cả hoạt động đó đều được xử lý bằng cách gọi phương thức theo cấu trúc on_ten_trang_thai(), ví dụ như onStart(), onPause(). Lập trình viên sẽ phải ghi đè các phương thức này trong lớp Activity, và Android sẽ gọi chúng ở thời điểm thích hợp:

onCreate(Bundle): phương thức này được gọi khi Activity khởi chạy lần đầu tiên. Ta có thể sử dụng nó để thực thi việc khởi tạo các thành phần khác như tạo giao diện người dùng, kết nối dữ liệu đến danh sách. Phương thức này có một tham số, nó có thể là null hoặc là thông tin trạng thái trước đó được lưu bởi phương thức onSaveInstanceState().

onStart: Phương thức này được gọi trước khi một Activity ẩn với người dùng.

onResume(): Được gọi khi Activity bắt đầu tương tác với người dùng. Tại thời điểm này thì Activity ở trên đỉnh của ngăn xếp Activity.

15

onPause(): Nó được gọi khi chuyển sang chế độ chạy nền, thường là khi có một Activity khác được chạy trên nó. Tại đây ta có thể lưu lại trạng thái cố định của chương trình cũng như ghi lại thay đổi trong cơ sở dữ liệu.

onStop(): Gọi khi Activity không còn xuất hiện với người dùng và nó sẽ không cần tới nữa. Nếu bộ nhớ không đủ, phương thức này sẽ không bao giờ được gọi.

onRestart(): Nếu phương thức này được gọi, thì Activity sẽ được hiển thị lại từ trạng thái stop.

onDestroy(): Phương thức này phải được gọi trước khi hủy một Activity. Nếu bộ nhớ không đủ, phương thức này sẽ không bao giờ được gọi.

onSaveIntanceState(Bundle): Android sẽ gọi phương thức này để cho phép Activity lưu lại trạng thái của nó. Thường ta sẽ không cần ghi đè nó bởi vì quá trình thực hiện để lưu lại trạng thái cho tất cả các giao diện người dùng được điều khiển một cách tự động.

onRestoreInstanceStat(Bundle): Sẽ được gọi khi Activity được khởi tạo lại từ trạng thái được lưu trước đó, được thực hiện bởi phương thức:onSaveInstanceState(): Các Activity không chạy ở trên cùng có thể bị dừng lại hoặc hệ thống sẽ hủy tiến trình Linux chứa Activity đó để tạo không gian cho các Activity mới.

Service

Một Service là một thành phần ứng dụng có thể thực hiện các hoạt động lâu dài trong nền (background) mà không có bất kỳ các thành phần giao diện người dùng nào. Chú ý là không được nhầm lẫn các dịch vụ của Android (một thành phần của ứng dụng) với các thành phần cấp dưới của hệ điều hành như các dịch vụ Linux nguồn (native Linux), các server. Chu kỳ sống của Service đơn giản hơn rất nhiều so với chu kỳ sống của Activity. Hình 11 mô tả chu kỳ sống của một Service:

16

Hình 12.Chu kỳ sống của Service [4] Khi một Service sử dụng IPC, AIDL (Android Interface Definnition Language) được sử dụng để tạo ra mã cho phép truyền thông giữa hai tiến trình qua IPC. Hình dưới mô tả quá trình truyền thông giữa hai tiến trình:

Hình 13.Truyền thông giữa hai tiến trình  Broadcast receiver

Broadcast receiver là một thành phần thu nhận các Intent bên ngoài gửi tới. Ví dụ: ta cần viết một chương trình thay thế cho phần gọi điện mặc định của Android khi đó ta cần một broadcast receiver để nhận biết các Intent là các cuộc gọi tới.

Hình 14.Broadcast receiver

17

Content Provider

Content Provider lưu trữ và lấy dữ liệu và nó có thể truy cập vào tất cả các ứng dụng. Đây là cách duy nhất để chia sẻ dữ liệu giữa các ứng dụng. Android với một số Content Provider cho các loại dữ liệu( như video, âm thanh, hình ảnh, thông tin liên lạc cá nhân, …). Các loại dữ liệu này được liệt kê trong gói android.provider. Hình dưới mô tả chức năng của một Content Provider. Ứng dụng có thể truy xuất và chia sẻ dữ liệu với Database qua Content Provider với các phương thức insert(), update(), delete() và query().

Hình 15.Content Provider [4] Hệ thống Android luôn luôn sử dụng cơ chế này. Ví dụ, trình liên hệ (Contacts Provider) là một trình cung cấp nội dung (Conten Provider). Contacts Provider cho thấy tất cả các dữ liệu liên hệ (contact data) người dùng đến nhiều ứng dụng. Lưu trữ truyền thông (Media Store) sẽ chịu trách nhiệm lưu trữ và chia sẻ các phương tiện truyền thông khác nhau, ví dụ như hình ảnh và âm nhạc trên các ứng dụng khác nhau. Hình 14 minh họa cách sử dụng các ứng dụng liên hệ (Contacts app) sử dụng Contacts Provider. Một ứng dụng là hoàn toàn riêng biệt để lấy dữ liệu về các liên hệ của người dùng .

Hình 16.Ứng dụng Contacts sử dụng Contacts Provider để lấy dữ liệu

18

Intent

Intent là thông điệp của hệ thống chạy xung quanh ở bên trong thiết bị, thông báo cho các ứng dụng của các sự kiện khác nhau từ việc thay đổi trạng thái phần cứng đến việc dữ liệu đến (như một tin nhắn SMS đến) hay các sự kiện ứng dụng (như hoạt động được đưa ra từ menu chính của thiết bị). Hay nói cách khác Inten là một miêu tả về hoạt động cần được thực hiện, là một cơ cấu cho phép truyền thông điệp giữa các thành phần của một ứng dụng và giữa các ứng dụng với nhau. Một ứng dụng Android thường bao gồm nhiều Activity, mỗi Activity hoạt động độc lập với nhau và thực hiện những công việc khác nhau. Intent chính là cầu nối giữa các Activity, là người đưa thư giúp ta triệu gọi và truyền các dữ liệu cần thiết để thực hiện một Activity từ một Activity khác. Hình 15 cho thấy Intent có thể được sử dụng để “nhảy” giữa các Activity khác nhau ở trong cùng một ứng dụng hoặc trong các ứng dụng khác nhau.

Hình 17.Intent [4]

1.9. Phát triển ứng dụng Android và DVM
Như tôi đã đề cập ở trên thì file APK là file sẽ được phát hành trên Android cho việc thực thi các ứng dụng Android. DVM hay Dalvik Virtual Machine là máy ảo để thực thi các ứng dụng. Hình dưới đây mô tả quá trình tạo ra một file APK:

19

Hình 18.Qúa trình tạo file APK Hình trên mô tả quá trình tạo file APK. Đầu tiên các file mã nguồn Java sẽ được biên dịch bởi trình biên dịch Java thành các file class sau đó các file class này được biên dịch thành một file dex bởi công cụ dx. Tiếp đó công cụ đóng gói Android (aapt) sẽ nén tất cả các file dex, file AndroidManifest.xml và các file resource thành một file APK. File APK này sẽ được phát hành trên Android cho việc thực thi ứng dụng. File AndroidManifest.xml là file tự động sinh ra khi ta xây dựng bất kỳ một ứng dụng Android nào. File này định nghĩa các thông tin về hệ thống. Qúa trình này cũng giải thích được tại sao người ta sử dụng máy ảo Dalvik thay vì sử dụng máy ảo Java để chạy các ứng dụng. Một ứng dụng định nghĩa nhiều lớp, sau khi biên dịch thì rất nhiều file class được tạo ra trong đó có chứa rất nhiều những thông tin dư thừa. Các file ở định dạng .dex có thể tích hợp tất cả các file class vào một file duy nhất để giảm bớt kích thước của file và các hoạt động I/O. Từ đó đẩy nhanh tốc độ tìm kiếm.

1.10. Tạo và demo ứng dụng “Hello World” sử dụng Android NDK
Android NDK (Native Development Kit) đơn giản hóa làm việc với mã nguồn gốc. Nó bao gồm toàn bộ chuỗi công cụ cần thiết để xây dựng trên kiến trúc ARM. Nó được thiết kế để tạo ra một thư viện chia sẻ (shared library). Lưu ý rằng mã nguồn (native code) có thể truy cập thông qua JNI vẫn chạy bên trong máy ảo Dalvik. Hình dưới đây mô tả tất cả các bước khi phát triển một ứng dụng Android cần phải sử dụng đoạn mã viết bằng C/C++:

20

Hình 19.Quá trình truy cập mã gốc qua JNI [4] Tạo lớp Java biểu thị cho mã nguồn Mã nguồn Java nằm bên trong thư mục src trong Eclipse project. Nó như là một loại keo liên kết đến mã nguồn của ứng dụng Android ta sẽ viết ở sau. Trong file mã nguồn Java nà ta sẽ khai báo các phương thức gốc mà sẽ được thực hiện ở trong file mã C viết ở sau và đồng thời trong file này ta cũng viết lệnh để load thư viện chia sẻ được dùng trong ứng dụng. // Code chương trình: /src/com.hop/NativeLib.java Package com.hop; publicclass NativeLib { static { System.loadLibrary("ndk_demo"); } /** * Trả về chuỗi Hello World*/ public native String hello(); }

21

Tạo các file header mã nguồn Trong thư mục bin của project. Ta chạy lệnh javah để tạo ra file header JNI. Tiếp theo ta tạo một thư mục tên là jni trong thư mục project. Sau đó sao chép header JNI từ thư mục bin vừa tạo ra ở trên đến thư mục jni. **/ Code chuong trinh*/ NDKDemo/bin$ javah com_hop_NativeLib.h ../jni/ -jni com.hop.NativeLibNDKDemo/bin$ mv

Sau đó viết code C. Trong folder jni tạo file ndk_demo.c. Trong hàm C này ta sẽ viết code thực hiện mã nguồn (native code). Để bắt đầu, ta sao chép các signatures của các hàm từ file header và viết code thực hiện cho các hàm này. Trong ví dụ này file header mà ta tạo ra dùng lệnh javah ở trên có dạng như sau: **/code của file header JNI tao ra voi lenh javah*/ <EclipseWorkspace>/NDKDemo/jni/com_hop_NativeLib.h /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h>/* Header for class com_hop_NativeLib */ #ifndef _Included_com_hop_NativeLib #define_Included_com_hop_NativeLib #ifdef__cplusplusextern "C" { #endif /* *Class:com_hop_NativeLib *Method: hello *Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_hop_NativeLib_hello (JNIEnv *, jobject); #ifdef __cplusplus

22

} #endif #endif

Thực thi mã nguồn bằng cách viết code C Ta sẽ viết code thực hiện trong hàm C như sau: <EclipseWorkspace>/NDKDemo/jni/ndk_demo.c #include "com_hop_NativeLib.h"JNIEXPORTjstring JNICALL Java_com_hop_NativeLib_hello (JNIEnv * env, jobjectobj) { return (*env)->NewStringUTF(env, "Hello World!");} Biên dịch tất cả và xây dựng thư viện chia sẻ Để xây dựng thư viện, đầu tiên ta cần tạo một makefile cho việc biên dịch code c: <EclipseWorkspace>/NDKDemo/jni/Android.mk // code: LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := ndk_demo LOCAL_SRC_FILES := ndk_demo.cinclude $(BUILD_SHARED_LIBRARY) Tập tin Android.mk là một bản xây dựng nhỏ để mô tả nguồn cho NDK xây dựng hệ thống. Cú pháp của nó được mô tả chi tiết trong file docs/Android-MK.html. NDK nhóm các nguồn thành các module, mỗi module có thể là một thư viện tĩnh hoặc một thư viện chia sẻ. Ta cũng có thể định nghĩa một số module trong một file Android.mk hoặc có thể viết một số file Android.mk, mỗi file sẽ định nghĩa một module. Chú ý rằng: một file Android.mk có thể được phân tích nhiều lần bởi hệ thống xây dựng. Theo mặc định thì NDK sẽ xem xét cho bản xây dựng với dạng sau: $PROJECT/jni/Android.mk

23

Nếu ta muốn định nghĩa các file Android.mk trong các thư mục con thì ta nên sử dụng cấu trúc: include $(call all-subdir-makefiles). Cấu trúc này sẽ bao gồm tất cả các file Android.mk trong các thư mục con của đường dẫn file xây dựng hiện tại. Bước tiếp theo là cần phải nói cho NDK biết cách để xây dựng thư viện chia sẻ và đưa nó vào nơi đúng ở bên trong Eclipse project. Để làm điều này cần tạo một folder <NDKHOME>/apps/ndk_demo/ và ở bên trong folder này tạo file Application.mk. Dưới đây là mã: <NDKHOME>/apps/ndk_demo/Application.mk APP_PROJECT_PATH := $(call my-dir)/project APP_MODULES := ndk_demo

Trong khi file Android.mk miêu tả các module cho hệ thống xây dựng, thì file Application.mk mô tả bản thân ứng dụng. Tập tin Application.mk bao gồm chính xác các modul theo yêu cầu của ứng dụng và các kiến trúc CPU để tạo ra mã máy, chi tiết xem trong file docs/APPLICATION-MK.html. Chú ý là để xem được các file này cần tải Android NDK tại http://developer.android.com/sdk/ndk/index.html , sau đó giải nén trong một thư mục nào đó. Bước tiếp theo ta tạo một liên kết mềm <NDKHOME>/apps/ndk_demo/ project đến Eclipseproject. Dùng lệnh trên command line của Ubuntu. [username] $lns~/Workspace/Android/NDKDemo<NDKHOME>/apps/ndk_demo/project Sau khi làm xong các bước trên, vào trong thư mục NDK và chạy lệnh : make APP=ndk_demo Kết quả khi chạy lệnh trên như sau : android-ndk-1.5_r1$ make APP=ndk_demoAndroid NDK: Building for application 'ndk_demo' Compilethumb : ndk_demo<= sources/ndk_demo/ndk_demo.cSharedLibrary : libndk_demo.soInstall : libndk_demo.so => apps/ndk_demo/project/libs/armeabi

24

Thư viện chia sẻ được tạo ra sẽ ở dạng có tiền tố lib đằng trước và đuôi là .so. Như ví dụ trên thì thư viện chia sẻ được tạo ra là libndk_demo.so. Để chương trình ứng dụng Android có thể sử dụng và link được đến thư viện này thì thư viện này phải nằm trong thư mục libs/armeabi của project. Điều đó cho thấy ta đã porting được thư viện này vào trong Android trên kiến trúc Arm. Sử dụng mã nguồn bên trong các Activity của Android Ta đã có thư viện native c được thực thi, biên dịch và được đặt trong một nơi đúng. Bây giờ ta có thể gọi nó từ Activity bằng cách khởi tạo các lớp NativeLib và nó chỉ là một đối tượng Java bình thường. Package com.hop; importandroid.app.Activity; importandroid.os.Bundle; public class NDKDemo extends Activity { NativeLibnativeLib; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Cuối cùng chạy chương trình ta sẽ nhìn thấy dòng chữ Hello World.

25

Hình 20.Demo ứng dụng Hello World dùng Android NDK

26

CHƯƠNG 2 .CÁC PHƯƠNG PHÁP PHÁT HIỆN KHUÔN MẶT TRÊN ANDROID
2.1. Thuật toán của Viola – Jones trong OpenCV
Ý tưởng của thuật toán phát hiện khuôn mặt của Vola – Jones là biểu diễn ảnh theo Integral Image và sử dụng thuật toán Adaboost kết hợp với các đặc trưng Haarlike. 2.1.1. Đặc trưng Haar-like Có 4 đặc trưng cơ bản để xác định khuôn mặt người. Mỗi đặc trưng Haar-like là sự kết hợp của hai hoặc ba hình chữ nhật đen trắng. Hình dưới đây mô tả 4 đặc trưng Haar-like cơ bản:

Hình 21.Các đặc trưng Haar-like cơ bản [7] Để phát hiện khuôn mặt thì các đặc trưng Haar-like cơ bản trên được mở rộng thành các đặc trưng cạnh, đặc trưng đường và đặc trưng trung tâm.

Hình 22.Các đặc trưng Haar-like mở rộng [6] Giá trị của các đặc trưng Haar-like là sự chênh lệch giữa tổng các điểm ảnh của các vùng đen và các vùng trắng. Để có thể tính nhanh các giá trị đặc trưng này Viola – Jones đưa ra khái niệm Integral Image. Integral Image là một mảng hai chiều với kích thước bằng kích thước của ảnh cần tính giá trị đặc trưng Haar-like. Hình dưới đây mô tả cách tính Integral Image:

27

Hình 23.Cách tính Integral Image [8] Sau khi đã tính được Integral Image thì việc tính tổng các giá trị mức xám của một vùng bất kỳ nào đó trên ảnh thực hiện rất đơn giản theo cách sau: Giả sử ta cần tính tổng các giá trị mức xám của vùng D như trong hình dưới đây. Ta có thể tính như sau:

D = A + B + C + D – (A+B) – (A+C) + A Với A + B + C + D
Với A+B+C+D là giá trị tại điểm P4 trên Integral Image. Tương tự như vậy A+B là giá trị tại điểm P2, A+C là giá trị tại điểm P3, A là giá trị tại điểm P1. Vậy D được tính như sau:

Hình 24.Ví dụ cách tính nhanh các giá trị mức xám [7]

Tiếp theo để chọn các đặc trưng Haar-like dùng cho việc thiết lập ngưỡng, Viola và Jones sử dụng một phương pháp máy học được gọi là AdaBoost. AdaBoost được kết hợp với các bộ phân loại yếu để tạo thành một bộ phân loại mạnh. Với bộ phân loại mạnh có thể đưa ra câu trả lời chính xác trên 60%. 2.1.2. AdaBoost AdaBoost là một bộ phân loại mạnh phi tuyến phức dựa trên hướng tiếp cận boosting được Freund và Schapire đưa ra vào năm 1995. AdaBoost cũng hoạt động trên nguyên tắc kết hợp tuyến tính các bộ phân loại yếu để tạo nên một bộ phân loại
28

mạnh. AdaBoost là một cải tiến của tiếp cận boosting. AdaBoost sử dụng thêm khái niệm trọng số để đánh dấu các mẫu khó nhận dạng. Trong quá trình tập huấn cứ mỗi bộ phân loại yếu được xây dựng thì thuật toán sẽ tiến hành cập nhật lại trọng số để chuẩn bị cho việc xây dựng bộ phân loại yếu tiếp theo. Cập nhật bằng cách tăng trọng số của các mẫu bị nhận dạng sai và giảm trọng số của các mẫu được nhận dạng đúng bởi bộ phân loại yếu vừa xây dựng. Bằng cách này thì bộ phân loại yếu sau có thể tập trung vào các mẫu mà bộ phân loại yếu trước nó làm chưa tốt. Cuối cùng là các bộ phân loại yếu sẽ được kết hợp lại tùy theo mức độ tốt của chúng để tạo nên một bộ phân loại mạnh AdaBoost. Viola – Jones dùng AdaBoost kết hợp với các bộ phân loại yếu sử dụng các đặc trưng Haar-like theo mô hình cascade sau:

Hình 25.Mô hình cascade kết hợp với các bộ phân loại yếu [7] Trong đó hk là các bộ phân loại yếu được biểu diễn như sau:

x là cửa sổ con cần xét, θ k là ngưỡng, fk là giá trị đặc trưng Haar-like và pk là hệ số quyết định chiều của phương trình. Hình dưới đây mô tả quá trình kết hợp các bộ phân loại yếu thành bộ phân loại mạnh.

29

Hình 26.Kết hợp các bộ phân loại yếu thành bộ phân loại mạnh 2.1.3. Mô hình phát hiện khuôn mặt Hình dưới đây là mô hình phát hiện khuôn mặt của thuật toán do Viola và Jones đưa ra.

Hình 27. Hệ thống phát hiện khuôn mặt Từ ảnh gốc ban đầu ta sẽ tính được Integral Image là mảng hai chiều với phần tử (x, y) sẽ được tính bằng tổng của các phần tử (x’, y’) với x’<x và y’<y. Mục đích là để tính nhanh tổng của các giá trị mức xám của một vùng hình chữ nhật bất kỳ trên ảnh gốc. Các vùng ảnh con này sẽ được đưa qua các hàm Haar cơ bản để ước lượng đặc trưng. Kết quả ước lượng sẽ được đưa qua bộ điều chỉnh AdaBoost để loại bỏ nhanh các đặc trưng không có khả năng là đặc trưng của khuôn mặt người. Chỉ có một tập nhỏ các đặc trưng mà bộ điều chỉnh AdaBoost cho là có khả năng là đặc
30

trưng của khuôn mặt. Tập các đặc trưng này sẽ được chuyển sang cho bộ quyết định kết quả. Bộ quyết định kết quả là tập các bộ phân loại yếu . Bộ này sẽ tổng hợp kết quả là khuôn mặt người nếu kết quả của các bộ phân loại yếu trả về là khuôn mặt. Mỗi bộ phân loại yếu sẽ quyết định kết quả cho một đặc trưng Haar-like, được xác định ngưỡng đủ nhỏ sao cho có thể vượt được tất cả các bộ dữ liệu mẫu trong tập dữ liệu tập huấn. Trong quá trình xác định khuôn mặt người, mỗi vùng ảnh con sẽ được kiểm tra với các đặc trưng trong chuỗi các đặc trưng Haar-like. Nếu có một đặc trưng Haar-like nào cho ra kết quả là khuôn mặt người thì các đặc trưng khác không cần xét nữa.

2.2. Phát hiện khuôn mặt sử dụng framework API của Android
2.2.1.Gói android.graphics Gói này cung cấp các công cụ đồ họa cấp thấp như canvas, các bộ lọc màu sắc, điểm, và hình chữ nhật, cho phép ta xử lý và vẽ ra màn hình trực tiếp. Trong gói này có các lớp con như:
• •

Bitmap.

BitmapFactory– tạo các đối tượng Bitmap từ nhiều nguồn khác nhau, bao gồm các tập tin, các dòng (stream), và các mảng byte. Trong lớp này có lớp con BitmapFactory.Options. BitmapRegionDecoder– được sử dụng để giải mã vùng hình chữ nhật từ một hình ảnh.
• • •

BitmapShader– được sử dụng để vẽ ảnh bitmap như một kiến trúc (texture).

Camera – một camera có thể được sử dụng để tính toán biến đổi 3D và tạo ra một ma trận có thể được áp dụng, ví dụ như trên Canvas.
• •

Canvas- lớp Canvas giữ yêu cầu vẽ.

Color- lớp color xác định các phương thức cho việc tạo và chuyển đổi số nguyên về màu sắc. ImageFormat- cung cấp các định dạng màu như JPEG (định dạng được mã hóa), NV16 (định dạng YCbCr được sử dụng cho video), NV21 (định dạng YCrCb được sử dụng cho ảnh, sử dụng định dạng mã hóa NV21), RGB-565(định dạng RGB được sử dụng cho ảnh mã hóa như RGB-565), UNKNOWN( giá trị không đổi là 0),

31

YUY2 (định dạng YCbCr được sử dụng cho ảnh, sử dụng định dạng mã hóa YUY2), và cuối cùng là định dạng YV12(định dạng YUV android: định dạng này được tiếp xúc với bộ giải mã phần mềm và ứng dụng).
• •

Matrix- lớp Matrix giữ một ma trận cỡ 3x3 cho việc chuyển đổi tọa độ.

Paint-lớp Paint nắm giữ thông tin về màu sắc về việc làm thế nào để vẽ hình, văn bản và các ảnh bitmap. PixelFormat-bao gồm các định dạng A_8, JPEG, LA_88, L_8, RGB-322, RGB-565,….
• •

Rect-có chức năng nắm giữ tọa độ 4 số nguyên cho hình chữ nhật.

và còn nhiều các lớp và các hàm con khác. Trong ứng dụng phát hiện khuôn mặt ta sẽ sử dụng một số lớp trong gói android.graphics bằng cách viết lệnh trong mã nguồn Java: import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PoinF; 2.2.2.Gói android.app Gói này chứa các lớp cấp cao đóng gói mô hình ứng dụng android.Một ứng dụng Android được xác định bằng cách sử dụng một hoặc nhiều hơn 4 thành phần ứng dụng lõi của Android. Trong gói này có hai thành phần ứng dụng được định nghĩa là: hoạt động (Activity) và dịch vụ (Service). Trong gói android.content có hai thành phần khác là BroadcastReceiver và Contentprovider. Gói android.app cung cấp một số lớp với các chức năng nhất định. Dưới đây là một số lớp: ActionBar- đây là giao diện công cộng cho các ActionBar. Các hoạt động của ActionBar như là một thay thế cho các thanh tiêu đề trong các Activity. Nó cung cấp cơ sở cho việc tạo ra các hành động cũng như các phương thức điều hướng trên một ứng dụng.

32

Activity- một hoạt động là đơn lẻ, những gì người dùng có thể làm được tập trung. Hầu như tất cả các hoạt động đều tương tác với người sử dụng, vì vậy lớp Activity sẽ tạo ra một cửa sổ mà có thể đặt giao diện người dùng với setContenView (View). Trong khi các hoạt động thường được trình bày cho người sử dụng như là cửa sổ toàn màn hình, chúng cũng có thể được trình bày theo những cách khác như : cửa sổ nổi hoặc nhúng bên trong một hoạt động (sử dụng ActivityGroup).
• • • • •

AcivityGroup- là một màn hình có chứa và chạy nhiều các hoạt động nhúng. ActivityManager- Tương tác với các hoạt động chạy trong hệ thống. ActivityManager.MemoryInfo- Ta có thể có được thông tin về bộ nhớ sẵn có.

ActivityManager.ProcessErrorSateInfo- thông tin có thể lấy được về bất kỳ quá trình nào có lỗi xảy ra. ActivityManager.RecentTaskInfo- thông có thể lấy được về nhiệm vụ mà người dùng gần đây nhất bắt đầu hoặc truy cập.

ActivityManager.RunningAppProcessInfo- thông tin có thể lấy được về quá trình chạy chương trình.

ActivityManager.RunningServiceInfo- thông tin có thể lấy được về một dịch vụ cụ thể mà hiện đang chạy trong hệ thống.

ActivityManager.RunningTaskInfo-thông tin có thể lấy được về một nhiệm vụ cụ thể mà hiện tại đang chạy trong hệ thống.
• •

AlarmManager- Lớp này cung cấp truy cập đến các dịch vụ báo động hệ

thống. AlertDialog- đây là một lớp con của hộp thoại (Dialog) có thể hiển thị một, hai hoặc ba nút (button).

Application-đây là lớp cơ sở cho những ai cần phải duy trì trạng thái ứng dụng toàn cầu.

FragmentTransaction- giao diện để tương tác với các đối tượng Fragment bên trong một Activity.
• • •

Instrumentation-đây là lớp cơ sở cho việc thực thi mã ứng dụng.

Instrumentation.ActivityResult- mô tả kết quả thực thi của một Activity để trả về cho activity ban đầu.

33

LauncherActivity-hiển thị một danh sách tất cả các hoạt động có thể được thực hiện cho một mục đích nhất định.

LauncherActivity.IconResizer- tiện ích để thay đổi kích thước các biểu tượng (icon) để phù hợp với kích thước biểu tượng mặc định.

ListActivity- một Activity có thể hiển thị một danh sách các mục bằng cách liên kết với một nguồn dữ liệu như một một mảng và đưa ra xử lý sự kiện khi người dùng chọn một mục.

Và còn có một số lớp khác như NativeActivity, Notification,…Trong ứng dụng phát hiện khuôn mặt ta sử dụng lớp Activity bằng cách viết trong mã nguồn Java : import android.app.Activity; 2.2.3.Gói android.content Chứa các lớp cho việc truy cập và xuất bản dữ liệu trên thiết bị. Nó bao gồm ba loại chính của APIs: Thứ nhất là chia sẻ nội dung: đối với nội dung chia sẻ (sharing content) giữa các thành phần ứng dụng thì các lớp quan trọng nhất là: ContentProvider và ContentResolver cho việc quản lý và xuất bản dữ liệu kết hợp với ứng dụng.

Intent và IntentFilter, để cung cấp các tin nhắn cấu trúc giữa các thành phần ứng dụng khác nhau cho phép các thành phần khởi tạo các thành phần khác và trả về kết quả.

Thứ hai là quản lý gói (android.content.pm) : Để truy cập thông tin về một gói Android (.apk), bao gồm thông tin về các hoạt động, quyền (permission), dịch vụ, giao diện, bộ cung cấp (provider). Các lớp quan trọng nhất để truy cập thông tin này là PackageManager. Thứ ba là quản lý tài nguyên (android.content.res): Để lấy dữ liệu tài nguyên kết hợp với một ứng dụng, chẳng hạn như chuỗi, drawables, truyền thông và chi tiết về cấu hình thiết bị. Các lớp quan trọng nhất để truy cập dữ liệu này là Resources- lớp này để truy cập tài nguyên của ứng dụng. Hệ thống tài nguyên Android theo dõi tất cả assets phi mã (non-code) kết hợp với một ứng dụng. Assets là một thư mục trong Android project. Ta có thể có được thể hiện của Resources liên quan đến ứng dụng với getResources().

34

Các công cụ Android SDK biên dịch các tài nguyên ứng dụng vào các ứng dụng nhị phân ở thời gian xây dựng. Để sử dụng một resource thì cần phải cài đặt một cách chính xác trong cây mã nguồn (nằm bên trong thư mục res của project) và xây dựng các ứng dụng. Như một phần của quá trình xây dựng, các công cụ SDK tạo ra các biểu tượng cho mỗi tài nguyên mà có thể được sử dụng trong mã ứng dụng để truy cập vào tài nguyên. Sử dụng tài nguyên ứng dụng giúp cho việc cập nhật các đặc điểm khác nhau của các ứng dụng mà không cần thay đổi mã, và bằng cách cung cấp bộ tài nguyên thay thế, cho phép tối ưu hóa ứng dụng đối với một loạt các cấu hình thiết bị (chẳng hạn như cho các ngôn ngữ khác nhau và kích cỡ màn hình). Đây là một khía cạnh quan trọng để phát triển ứng dụng Android được tương thích trên các loại thiết bị khác nhau. Trong gói android.content có chứa một số lớp con trong đó có lớp context – đây là một lớp trừu tượng trong đó sự thực thi được cung cấp bởi hệ thống Android. Nó cho phép truy cập vào tài nguyên ứng dụng cụ thể và các lớp, … Trong ứng dụng phát hiện khuôn mặt ta sử dụng lớp Context bằng cách viết trong mã nguồn Java: import android.content.Context; 2.2.4.Gói android.media Gói này cung cấp các lớp quản lý các giao diện truyền thông khác nhau trong audio và video.Các giao diện lập trình ứng dụng viết tắt là API (Appication Programming Interface) Media trong một số trường hợp để chơi (play) và ghi lại (record) các tập tin media – bao gồm âm thanh (ví dụ như chơi nhạc MP3 hoặc các file nhạc khác, nhạc chuông, hiệu ứng âm thanh trò chơi) và video (ví dụ như bật một đoạn video xem trực tiếp qua web). Các lớp đặc biệt khác trong gói cung cấp khả năng phát hiện khuôn mặt người trong ảnh Bitmap (FaceDetector), điều khiển âm thanh định tuyến (với điện thoại hoặc tai nghe) và điều khiển cảnh báo như nhạc chuông và tiếng rung của điện thoại ( lớp AudioManager). Trong ứng dụng ta sử dụng các lớp trong gói này bằng cách viết trong mã nguồn Java: import android.media.FaceDetector; import android.media.FaceDetector.Face; Các lớp FaceDetector và FaceDetector.Face sẽ trình bày ở phần sau
35

2.3. Xây dựng chương trình phát hiện khuôn mặt trên Android
Android cung cấp một lớp android.media.FaceDetector để xác định khuôn mặt người trong ảnh Bitmap. Các lớp FaceDetector và FaceDetector.Face do android SDK cung cấp [11]. Các lớp này có mặt trong android.media. Ta có thể vào trang phát triển của Google để tìm hiểu về các gói và các lớp Android hỗ trợ. Hình dưới đây mô tả các gói Android hỗ trợ trong trang phát triển của Google:

Hình 28.Các gói Android cung cấp trong framework API 2.3.1.Mô hình phát hiện khuôn mặt trên Android sử dụng framework API

Hình 29.Mô hình phát hiện khuôn mặt trên Androi  Khối Image input:

Ảnh đầu vào là ảnh bitmap với định dạng RGB-565 và kích thước ảnh là 320x480 .

36

Khối FaceDetector:

Khối này thực hiện chức năng phát hiện khuôn mặt trong đối tượng ảnh bitmap. Lớp FaceDetector trong khối này nhận các thông số của ảnh đầu vào là chiều rộng , chiều cao của ảnh để phân tích và số lượng tối đa khuôn mặt có thể phát hiện được. Khi một đối tượng được xây dựng thì những thông số này không thể thay đổi được. Lớp FaceDetector nằm trong gói android.media.  Khối findFaces:

Khối này có chức năng tìm tất cả các khuôn mặt trong một bức ảnh. Hàm thực hiện chức năng này là: Public int findFaces (Bitmap bitmap, Face[]faces) Hàm này trả về số lượng khuôn mặt. Ở hàm trên với thông số faces là một mảng chứa tất cả các thông tin để xác định vị trí của một khuôn mặt trong ảnh bitmap. Các thông tin này được lưu trong lớp FaceDetector.Face. Một khuôn mặt với các tư thế chụp ảnh khác nhau. Phát hiện khuôn mặt dựa trên các góc Euler của khuôn mặt , khoảng cách giữa hai mắt và vị trí của điểm giữa hai mắt. Góc Euler đại diện cho sự định hướng không gian của bất kỳ hệ quy chiếu nào như một thành phần của phép quay từ một hệ quy chiếu. Trong hệ tọa độ cố định được kí hiệu là (x, y, z) và trong hệ quay được kí hiệu bằng chữ in hoa (X, Y, Z). Với một hệ quy chiếu có các hướng cần mô tả, đầu tiên xác định đường thẳng đi qua nút N như hình vẽ dưới đây:

Hình 30.Các góc Euler- hệ tọa độ xyz (cố định), hệ tọa độ XYZ (quay) Với N là giao điểm của các mặt phẳng tọa độ xy và XY. Đường thẳng đi qua nút N được thể hiện bằng màu xanh lá cây với:   α là góc giữa trục x và đường thẳng qua nút. β là góc giữa trục z và trục Z.
37

γ là góc giữa đường thẳng của các nút và trục X.

Trong lớp FaceDetector.Face ta sử dụng một hàm Pose (int euler). Hàm này sẽ trả về tư thế của khuôn mặt hay góc Euler của khuôn mặt đối với trục tọa độ cho trước. Đó là phép quay quanh hoặc là theo trục X, hoặc là theo trục Y, hoặc là theo trục Z (Các vị trí trong không gian Euclide 3- chiều). Với thông số euler là tọa độ Euler để lấy một góc từ (EULER_X hoặc EULER_Y hoặc EULER_Z). Trong đó EULER_X là trục X góc Euler của khuôn mặt với giá trị không đổi : 0(0x00000000); EULER_Y là trục Y góc Euler của khuôn mặt với giá trị không đổi: 1(0x00000001); EULER_Z là trục Z góc Euler của khuôn mặt với giá trị không đổi là: 2(0x00000002). // mã thực thi hàm pose (int euler)

Để cho kết quả phát hiện khuôn mặt được tốt nhất thì thông số hệ số tin cậy trên 0.3 thường là đủ tốt. Ta sử dụng hàm confidence() , trả về hệ số an toàn giữa 0 và 1. Dưới đây là mã nguồn thực thi các hàm:

38

Khối drawRect

Sau khi qua khối findFaces phát hiện ra tất cả các khuôn mặt thì khối drawRect sẽ thực hiện chức năng vẽ khung hình chữ nhật lên khuôn mặt phát hiện được sử dụng đồ họa canvas trong gói android.graphics.

39

2.3.2.Viết chương trình ứng dụng phát hiện khuôn mặt trên Android Phần này tôi trình bày về các thành phần trong một ứng dụng Android cụ thể với ứng dụng phát hiện khuôn mặt trên Android sử dụng APIs của Android trong tầng Applications framework.

Hình 31.Các thành phần trong một Android Project  Thư mục src

Thư mục này chứa tất cả các lớp do người dùng xác định, bao gồm lớp hoạt động mặc định. Trong thư mục này là code cho mã nguồn Java. Dưới đây là mã nguồn Java cho ứng dụng phát hiện khuôn mặt. Ta sử dụng các phương thức gọi các hàm trên trong chương trình Java:

40

package hop.android; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas;// sử dụng canvas để vẽ. import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.media.FaceDetector; import android.media.FaceDetector.Face; import android.os.Bundle; import android.view.View; public class AndroidFaceDetector extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //setContentView(R.layout.main); setContentView(new myView(this)); } private class myView extends View{ private int imageWidth, imageHeight; private int numberOfFace = 5;// số khuôn mặt cần detect. private FaceDetector myFaceDetect; private FaceDetector.Face[] myFace;
41

float myEyesDistance; int numberOfFaceDetected; Bitmap myBitmap; public myView(Context context) { super(context); BitmapFactory.Options BitmapFactoryOptionsbfo = new BitmapFactory.Options(); BitmapFactoryOptionsbfo.inPreferredConfig = Bitmap.Config.RGB_565; myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.face5, BitmapFactoryOptionsbfo); imageWidth = myBitmap.getWidth(); imageHeight = myBitmap.getHeight(); myFace = new FaceDetector.Face[numberOfFace]; myFaceDetect = new FaceDetector(imageWidth, imageHeight, numberOfFace); numberOfFaceDetected = myFaceDetect.findFaces(myBitmap, myFace); } @Override protected void onDraw(Canvas canvas) { canvas.drawBitmap(myBitmap, 0, 0, null); Paint myPaint = new Paint();

42

myPaint.setColor(Color.GREEN); myPaint.setStyle(Paint.Style.STROKE); myPaint.setStrokeWidth(3); /** thuật toán lấy điểm giữa và khoảng cách hai mắt ** với biến i chạy từ 0 đến số lượng khuôn mặt cần phát hiện*/ for(int i=0; i < numberOfFaceDetected; i++) { Face face = myFace[i]; PointF myMidPoint = new PointF(); face.getMidPoint(myMidPoint); myEyesDistance = face.eyesDistance(); /** vẽ hình chữ nhật với canvas*/ canvas.drawRect( (int)(myMidPoint.x - myEyesDistance), (int)(myMidPoint.y - myEyesDistance), (int)(myMidPoint.x + myEyesDistance), (int)(myMidPoint.y + myEyesDistance), myPaint); } } } }

43

Thư mục gen

Chứa các tệp do ADT tạo tự động. Tệp R.java bên trong thư mục này chứa các tham chiếu tĩnh tới tất cả các tài nguyên hiện có trong thư mục res để cho chúng có thể tham khảo dễ dàng và động từ mã Java. Tệp này được tự động sinh ra khi xây dựng ứng dụng. package hop.android; public final class R { public static final class attr { } public static final class drawable { public static final int face3=0x7f020000; public static final int face4=0x7f020001; public static final int face5=0x7f020002; public static final int icon=0x7f020003; } public static final class layout { public static final int main=0x7f030000; } public static final class string { public static final int app_name=0x7f040001; public static final int hello=0x7f040000; } }

44

Thư mục res

Chứa tất cả các tài nguyên cho project: Các biểu tượng, các hình ảnh, các chuỗi ký tự và các bố trí. Thư mục res bao gồm:  Các thư mục drawable : Dành cho tất cả các tệp hình ảnh.  Thư mục layout: Dành cho các bố trí quy định các màn hình giao diện người dùng cho các hoạt động dưới dạng mã XML. Tệp Main.xml được tự động tạo ra. Thư mục này gắn liền với cách bố trí thẳng đứng mặc định. Tệp Main.xml có một biểu diễn giao diện người dùng, có thể kéo thả các bố trí khác nhau và các khung nhìn trên một màn hình trống để xây dựng các thành phần giao diện người dùng cho hoạt động này. Dưới đây là nội dung của tệp Main.xml:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout>

45

Thư mục bin

Chứa các tệp class được biên dịch và một số tệp sau:

Hình 32. Các tệp trong thư mục bin của Android Project.  Tệp class.dex: Tệp có thể thực thi được tạo ra từ các lớp biên dịch.

 Tệp Tran_Thi_Hop_FaceDetect.apk: Tệp lưu trữ nén sẽ được chuyển đến thiết bị Android. Ứng dụng này có thể được cài đặt trên thiết bị Android bất kỳ thông qua tệp lưu trữ này.   Tệp resources.ap_: Tệp các tài nguyên ứng dụng nén. AndroidManifest.xml

Mỗi ứng dụng phải có một file AndroidManifest.xml nằm trong thư mục gốc của nó. File này định nghĩa các thông tin cần thiết về ứng dụng cho hệ thống Android, thông tin hệ thống phải có trước khi nó có thể chạy bất kỳ code của ứng dụng. Đây là một phần rất quan trọng của ứng dụng Android. Khi ta tạo một ứng dụng Android sử dụng Eclipse thì sẽ sinh ra file AndroidManifest.xml. File này được tự động sinh ra bởi Eclipse. Vì vậy, ta không bận tâm đến việc tạo ra nó mà hãy quan tâm đến nội dung bên trong file này. Dưới đây là nội dung của một file AndroidManifest.xml tự động được sinh ra khi tạo ứng dụng phát hiện khuôn mặt:

46

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="hop.android" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".AndroidFaceDetector" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>

Thẻ <application>, bên trong thẻ này chứa các thuộc tính được định nghĩa cho ứng dụng Android như : android:icon = “drawable resource”  ở đây đặt đường dẫn đến file icon của ứng dụng khi cài đặt. Ví dụ: android:icon = “@drawable/icon”.

Thẻ <activity>, bên trong thẻ này có các thuộc tính: android:name = “string”  tên của lớp thực hiện Activity hay nó là một lớp con của Activity. Trong ứng dụng này là : AndroidFaceDetector.

android:label – nhãn cho Activity, được hiển thị trên màn hình khi Activity được chạy. Nó thường được hiển thị cùng với biểu tượng của hoạt động. Trong file manifest trên thì nhãn tên là Tran_Thi_Hop_FaceDetection.

Ngoài ra còn có nhiều thuộc tính khác, chi tiết xem tại : http://developer.android.com/guide/topics/manifest/manifestintro.html#filestruct

47

CHƯƠNG 3. KẾT QUẢ ĐẠT ĐƯỢC
3.1. Kết quả phát hiện khuôn mặt sử dụng framework API của Android

Hình 33.Hình ảnh gốc ban đầu

Hình 34.Kết quả phát hiện khuôn mặt trên Android

48

3.2. Khó khăn và hướng giải quyết
Như tôi đã đề cập trong phần kiến trúc Android. Khi viết chương trình ứng dụng cho Android ta phải sử dụng ngôn ngữ Java. Trong bài toán phát hiện khuôn mặt sử dụng thuật toán của Viola – Jones trong OpenCV thì vấn đề khó khăn là để Java có thể gọi được các thư viện của OpenCV viết bằng ngôn ngữ C và C++ thì cần phải thành thạo ngôn ngữ lập trình JNI. Do thời gian hạn chế nên khóa luận này tôi chỉ đưa ra hướng giải quyết sử dụng JNI để viết chương trình phát hiện khuôn mặt sử dụng OpenCV trên Android. Quy trình xây dựng và thực thi ứng dụng sẽ giống với quy trình tạo và demo ứng dụng “Hello World” dùng Android NDK mà tôi đã trình bày ở phần trên. Chúng ta đã porting được OpenCV vào Android rồi, vấn đề chỉ là tìm hiểu về lập trình JNI để tiếp tục phát triển ứng dụng. Đây cũng là hướng phát triển đề tài trong tương lai.

49

KẾT LUẬN
Khóa luận này đưa ra được tổng quan về hệ điều hành Android. Đây là nền tảng để cho những ai mới bắt đầu lập trình với Android. Khóa luận đã đạt được những mục tiêu cần tìm hiểu để xây dựng chương trình ứng dụng Android. Trong khóa luận tôi đã trình bày về kiến trúc Android trong đó có demo một chương trình ứng dụng phát hiện khuôn mặt sử dụng framework API của Android trong tầng Applications framework. Từ đó giúp phát triển thêm các ứng dụng khác sử dụng framework API để xây dựng. Trước khi xây dựng chương trình ứng dụng thì tôi trình bày về các thành phần tạo nên một ứng dụng cho Android ;quá trình một ứng dụng được thực thi như thế nào; các thành phần trong một dự án Android ; sự khác biệt giữa máy ảo Java và máy ảo Dalvik và trình bày về cách porting thư viện OpenCV và thuật toán phát hiện khuôn mặt của Viola – Jones được sử dụng trong OpenCV. Môi trường cần để xây dựng và thực thi các ứng dụng cho Android đó là các ngôn ngữ lập trình Java, JNI, C/C++. Ngoài ra Android dựa trên nền tảng Linux nên môi trường tốt để viết các ứng dụng là Linux hoặc Ubuntu. Tuy nhiên cũng có thể viết trên Windows nhưng phải dùng đến swing để dùng các lệnh của Linux. Dùng Ubuntu sẽ ít gặp rắc rối về lỗi và virus. Khóa luận cũng đã trình bày về Android SDK, Android NDK là các công cụ hỗ trợ mạnh cho phát triển các ứng dụng Android. Tôi cũng đưa ra được các quy trình làm một dự án phần mềm với các công cụ này. Một ví dụ đơn giản để từ đó hiểu được quy trình làm một dự án và chương trình được thực thi như thế nào trên Android. Từ đó sau này có thể phát triển thêm nhiều ứng dụng hấp dẫn khác cho Android. Tóm lại để có thể xây dựng và phát triển các ứng dụng Android thì cần phải có kiến thức về Android được trình bày trong khóa luận và biết lập trình Java, JNI, C/C+ + và nắm chắc kiến thức về Linux với lập trình shell và các tập lệnh của Linux.

TÀI LIỆU THAM KHẢO
50

TÀI LIỆU TIẾNG ANH:

[1] AndroidTM A Programmer’s Guide, J.F. DiMarzio, Pulisher: McGraw-Hill Proesional, 2008. [2] Harvey M. Deitel, Paul J.Deitel, Java How to Program (4th Edition), Publisher: Prentice Hall PRT Upper Saddle River, NJ, USA, 2001. [3] James Steele Nelson To, The Android Developer’s Cookbook Building Applications with the Android SDK, Publisher: Add ison-Wes ley, 2010. [4] Marko Gargenta, Learning Android, Publisher: O’Reilly Media, 1 edition, 2010. [5] Robin Hewitt, Seeing with OpenCV, Servo magazine, January 2007, Inc. [6] Rainer Lienhart and Jochen Maydt, “An extended set of Haar- like features for Rapid Object Detection”, Intel Labs, Intel Corporation, Santa Clara, CA 95052, USA. [7] Sheng Liang, The JavaTM Native Interface, Programmer’s Guide and Specification, Publisher: Prentice Hall PRT, 1st edition, 1999. [8] Viola–Jones, “Rapid Object Detection using a Boosted Cascade of Simple Features”, Accepted conference on Computer Vision and pattern recognition 2001. [9] Viola–Jones, “Robust Real-time Object Detection”, Second international workshop on statistical and computational theories of vision – modeling, learning, computing, and sampling, Vancouver, Canada, July 13, 2001. [10] W. Frank Ableson, Charilie Collins, Robi Sen, Unlocking Android, Publisher: Manning Publications, 2009. [11] http://developer.android.com

51

Sign up to vote on this title
UsefulNot useful