ĐỒ ÁN TỐT NGHIỆP ĐIỆN TỬ ỨNG DỤNG XỬ LÝ ẢNH BẰNG THUẬT TOÁN SVM
1. Đặt vấn đề
Xử lý ảnh và thị giác máy là lĩnh vực mà ngày nay được phát triển và ứng dụng rất rộng rãi trong nhiều lĩnh vực khác nhau nhờ vào sự phát triển ngày càng mạnh mẽ của các hệ thống máy tính, các thuật toán và công trình nghiên cứu khác nhau của nhiều nhà khoa học trên thế giới.
Ở Việt Nam, các ứng dụng về xử ảnh đã bước đầu được triển khai trên một số lĩnh vực như lắp đặt hệ thống nhận dạng biển biển số xe ở các bãi đổ xe, hệ thống nhận dạng mặt người… Tuy nhiên nhìn một cách khách quan thì số lượng các ứng dụng được triển khai trên thực tế là ít ỏi, lĩnh vực này sẽ còn phát triển mạnh mẽ trong tương lai nếu như được quan tâm một cách nghiêm túc.
Vì vậy bài toán nhận dạng biển số xe có nhiều ý nghĩa trong thực tế, nó giúp việc giám sát, quản lý, thống kê các phương tiện một cách dễ dàng, tiện lợi và nhanh chóng. Một số ứng dụng điển hình đã được triển khai trong thực tế như ứng dụng trong quản lý bãi đỗ xe thông minh, ứng dụng thu phí ở các trạm thu phí, ứng dụng phát hiện lỗi vi phạm giao thông một cách tự động …
- Nội dung và phương pháp nghiên cứu
Trong đề tài “ỨNG DỤNG XỬ LÝ ẢNH BẰNG THUẬT TOÁN SVM” với nhiệm vụ nghiên cứu về mặt kĩ thuật của bài toán nhận dạng biển số xe, viết chương trình mô phỏng bằng ngôn ngữ C++ với sự giúp đỡ của thư viện OpenCV, một thư viện mã nguồn mở được đánh giá là mạnh mẽ về tốc độ xử lý đáp ứng được các ứng dụng trong thời gian thực, sau đó sử dụng thuật toán máy học SVM (Surport Vector Machine) để nhận dạng ký tự biển số xe.
2.1Giới thiệu
Trong phần này ta nghiên cứu về mặt kĩ thuật của một bài toán nhận dạng biển số xe, viết chương trình demo và các bước cần thiết để đưa bài toán vào ứng dụng thực tế.
Có nhiều cách khác nhau để thực hiện bài toán nhận dạng này, ở các phần mềm thương mại hoàn chỉnh, nó là sự kết hợp và tối ưu của khá nhiều thuật toán phức tạp, trong bài này, ta đi theo hướng tiếp cận chia bài toán thành hai bài toán nhỏ: phát hiện biển số xe, cách ly kí tự và nhận dạng các kí tự.
Hình 1
2.2 Phát hiện vùng chứa biển số xe và cách ly kí tự.
Vì biển số xe có những đặc trưng cơ bản được quy định bởi các cơ quan chức năng nên chúng ta có thể dựa vào đặc trưng này để phân biệt với các đối tượng khác. Dựa vào các đặc trưng hình học này để trích chọn ra vùng chứa biển số xe, các bước thực hiện như sau:
Bước 1: Load ảnh, tiền xử lý ảnh (khử nhiễu, làm mịn …)
Bước 2: Chuyển ảnh ban đầu thành ảnh xám rồi nhị phân hóa ảnh đó.
Bước 3: Tìm các đường bao quanh đối tượng. Sau khi nhị phân ảnh, các đối tượng sẽ là các khối hình đen trên nền trắng, với mỗi đối tượng ta luôn vẽ được một đường biên bao quanh đối tượng đó. Để tránh tình trạng các đối tượng không tạo ra được các đường biên khép kín do các vết rạn nứt hoặc nhiễu gây ra, trước khi tìm biên ta nên làm mịn đường biên bằng các phép giãn nở (hoặc phép co).
Bước 4: Xác định hình chữ nhật bao quanh các đường bao quanh đã tìm được từ bước 3. Đường bao quanh đã tìm được ở bước 3 là một chuỗi các điểm biên nối liền của đối tượng, dựa vào tọa độ của các điểm biên này ta sẽ xác định được hình chữ nhật ngoại tiếp bao quanh đối tượng.
Bước 5: Tìm ra các hình chữ nhật có khả năng là vùng chứa biển số, nếu hình chữ nhật thu được ở bước 4 là vùng chứa biển số thì nó phải thỏa mãn ít nhất được một số điều kiện sau:
+ Tỉ lệ chiều dài/ rộng phải xấp xĩ 4.3.
+ Số đối tượng thỏa mãn là một kí tự biển số trong vùng hình chữ nhật phải là một số lớn hơn một ngưỡng nào đó. Với biển số xe 4 chữ số, số kí tự này là 7, với biển số xe mới với 5 kí tự số, số kí tự này là 8…
Sau khi đã xác định được vùng có khả năng là biển số, ta sẽ cắt vùng hình đó, đồng thời lấy ra các kí tự trong vùng đó lưu vào một mảng để thực hiện việc nhận dạng.
2.3 Nhận dạng kí tự
Các kí tự sau khi được cách ly là những kí tự đơn lẽ trong một khung hình chữ nhật có kích thước nhất định. Để nhận dạng được kí tự này chúng ta có thể sử dụng rất nhiều phương pháp khác nhau, từ đơn giản như phương pháp sử dụng độ tương quan chéo (cross correlation) cho đến những phương pháp sử dụng các mô hình máy học (machine learning) như mạng Neuron nhân tạo, SVM …
Đối với các phương pháp sử dụng máy học, ta cần sưu tầm một lượng mẫu các kí tự nhất định, từ vài trăm cho tới hàng nghìn mẫu rồi đưa vào các bộ huấn luyện, kết quả huấn luyện này sẽ được dùng để nhận dạng các mẫu mới. Độ chính xác của kết quả nhận dạng nói chung của phương pháp này tùy thuộc vào độ phức tạp của mô hình, khối lượng mẫu huấn luyện, thời gian tính toán.
2.4 Phương pháp SVM
Trước hết cần phải nhận thấy rằng SVM là một bộ máy phân loại dữ liệu, muốn sử dụng được nó cần phải có dữ liệu, dữ liệu đối với các kí tự mà ta cần nhận dạng ở đây chính là các đặc trưng trong ảnh của kí tự đó. Giả sử ta cần phân loại 30 lớp dữ liệu (tương ứng với 30 kí tự trong biển số xe), với mỗi lớp dữ liệu, ta tính toán được 10 vector đặc trưng (10 mẫu), và mỗi vector đặc trưng tưng ứng với các đặc trưng trong một ảnh. Khi đó ta sẽ đưa vào bộ huấn luyện SVM toàn bộ dữ liệu này, sau đó với một ảnh bất kì, ta sẽ tính toán một vector đặc trưng của ảnh đó, mô hình SVM sẽ xem xét xem dữ liệu này (tức vector đặc trưng này) thuộc vào lớp nào trong số những lớp mà nó đã được huấn luyện.
Sơ đồ tổng quát quá trình nhận dạng
Hình 2
3. Kết quả thực nghiệm
Hình sau mô tả kết quả chạy chương trình:
Hình 3
Nhận xét : Theo kết quả mô phỏng đã thử nghiệm trên 10 mẫu thử thì tỷ lệ nhận dạng là 100%. Tuy nhiên nếu thử nghiệm trên nhiều mẫu thử hơn thì tỷ lệ nhận dạng là sẽ không hoàn toàn như ý muốn mà có thể thấp hơn do có nhiều yếu tố bất lợi.
4. Kết luận và hướng phát triển đề tài
Đề tài đã trình bày một cách hệ thống về bài toán nhận dạng biển số xe và các hướng giải quyết trên cơ sở các bài toán cơ bản: Phát hiện vùng chứa biển số xe và bài toán nhận dạng chữ và số trong vùng được phát hiện.
Bài toán nhận dạng biển số xe này xây dựng một mô hình chung tổng quát, để ứng dụng trong thực tế cần giới hạn bớt lại một số điều kiện giúp cho việc tìm kiếm biển số được chính xác hơn, thêm vào đó các mẫu huấn luyện kí tự cần phải được sưu tập nhiều hơn, các vector đặc trưng cũng phải được tính toán tỉ mỉ hơn để giúp cho kết quả nhận dạng có độ chính xác cao hơn nữa.
TÀI LIỆU THAM KHẢO
[1]Hoàng Kiếm, Nguyễn Ngọc Kỷ và các tác giả, “Nhận dạng các phương pháp và ứng dụng”, NXB thống kê năm 1992.
[2]Lương Mạnh Bá, Nguyễn Thanh Thủy, “Nhập môn xử lý ảnh số”, NXB KH&KT năm 2003.
[3] Nguyễn Quốc Trung, “Xử lý tín hiệu và lọc số, tập 1”, NXB KH&KT, 2006.
[4] Đỗ Năng Toàn, “Một thuật toán phát hiện vùng và ứng dụng của nó trong quá trình vectơ hóa tự động”, Tạp chí Tin học và Điều khiển, Tập 16 số 1 năm 2000.
[5] Đỗ Năng Toàn, “Biên ảnh và một số tính chất”, Tạp chí KH&CN, Tập 40 số ĐB năm 2002.
MỤC LỤC
DANH MỤC CÁC TỪ VIẾT TẮT.. 3
MỞ ĐẦU.. 4
CHƯƠNG 1 : LÀM QUEN VỚI THƯ VIỆN OPENCV.. 5
1.1 Giới thiệu chương. 5
1.2 So sánh phiên bản OpenCV 1 và OpenCV 2. 5
1.3 Hướng dẫn sử dụng thư viện Open CV trên Window.. 7
1.4 Kết luận chương. 11
CHƯƠNG 2 : CÁC PHÉP XỬ LÝ ẢNH ĐƠN GIẢN TRONG OPENCV.. 12
2.1 Giới thiệu chương. 12
2.2 Chương trình đầu tiên. 12
2.3 Ảnh nhị phân, nhị phân hóa với ngưỡng động. 14
2.4 Các phép toán hình thái học trong ảnh. 19
2.4.1 Phép toán giãn nở (dialation). 19
2.4.2 Phép toán co (erosion). 20
2.4.3 Phép toán đóng và mở (closing & opening). 21
2.5 Kết luận chương. 25
CHƯƠNG 3 : LẬP TRÌNH XỬ LÝ ẢNH VỚI GIAO DIỆN MFC.. 26
3.1 Giới thiệu chương. 26
3.2 Khởi tạo project MFC.. 26
3.3 Làm việc với các điều khiển (Control) của MFC.. 28
3.3.1 Đặt tên biến cho các control28
3.3.2 Lấy giá trị nhập vào từ một Edit Control29
3.3.3 Hiển thị các test lên các control30
3.3.4 Hiển thị ảnh lên một control30
3.3.5 Enable, disnable một control30
3.3.6 Lấy giá trị từ thanh trược (Slider control). 30
3.3.7 Lấy giá trị lựa chọn từ Combo Box. 30
3.3.8 Dialog mở file và lưu file. 31
3.3.9 Xử lý sự kiện khi click chuột vào button. 32
3.3.10 Xử lý sự kiện khi thay đổi lựa chọn Combo box. 32
3.3.11 Thêm menu vào chương trình, xử lý sự kiện khi click vào menu. 33
3.4 Chuyển đổi các kiểu dữ liệu trong MFC.. 35
3.5 Chương trình tải ảnh và hiển thị ảnh trên giao diện MFC.. 36
3.6 Kết luận chương. 37
CHƯƠNG 4: NHẬN DẠNG BIỂN SỐ XE BẰNG THUẬT TOÁN SVM... 38
4.1 Giới thiệu chương. 38
4.2 Phát hiện vùng chứa biển số xe và cách ly kí tự.39
4.3 Nhận dạng kí tự. 40
4.3.1 Phương pháp SVM41
4.3.2 Tính toán đặt trưng trong ảnh. 43
4.4 Cài đặt chương trình nhận dạng biển số xe ô tô. 44
4.4.1 Huấn luyện mô hình SVM... 44
4.5 Phát hiện và nhận dạng biển số xe. 45
4.6 Giao diện chương trình chính. 46
4.7 Kết luận chương. 47
KẾT LUẬN – HƯỚNG PHÁT TRIỂN.. 48
TÀI LIỆU THAM KHẢO.. 49
PHỤ LỤC.. 50
DANH MỤC CÁC TỪ VIẾT TẮT
API Application Programming Interface
BSD Berkeley Software Distribution
IDE Integrated Development Environment
IEEE Institute of Electrical and Electronics Engineers
LPR License Plate Recognition
MFC Microsoft Foundation Classes
OpenCV Open Source Computer Vision
RFID Radio Frequency Identification
SVM Surport Vector Machine
MỞ ĐẦU
Xử lý ảnh và thị giác máy là lĩnh vực mà ngày nay được phát triển và ứng dụng rất rộng rãi trong nhiều lĩnh vực khác nhau nhờ vào sự phát triển ngày càng mạnh mẽ của các hệ thống máy tính, các thuật toán và công trình nghiên cứu khác nhau của nhiều nhà khoa học trên thế giới.
Ở Việt Nam, các ứng dụng về xử ảnh đã bước đầu được triển khai trên một số lĩnh vực như lắp đặt hệ thống nhận dạng biển biển số xe ở các bãi đổ xe, hệ thống nhận dạng mặt người…Tuy nhiên nhìn một cách khách quan thì số lượng các ứng dụng được triển khai trên thực tế là quá ít ỏi, lĩnh vực này sẽ còn phát triển mạnh mẽ trong tương lai nếu như được quan tâm một cách nghiêm túc.
Trong đề tài “ỨNG DỤNG XỬ LÝ ẢNH BẰNG THUẬT TOÁN SVM” với nhiệm vụ nghiên cứu về mặt kĩ thuật của bài toán nhận dạng biển số xe, viết chương trình mô phỏng bằng ngôn ngữ C++ với sự giúp đỡ của thư viện OpenCV, một thư viện mã nguồn mở được đánh giá là mạnh mẽ về tốc độ xử lý đáp ứng được các ứng dụng trong thời gian thực, sau đó sử dụng thuật toán máy học SVM (Surport Vector Machine) để nhận dạng ký tự biển số xe.
Nội dung đồ án bao gồm:
Chương 1 : Làm quen với thư viện OpenCV
Chương 2 : Các phép xử lý ảnh đơn giản trong OpenCV
Chương 3 : Lập trình xử lý ảnh với giao diện MFC
Chương 4 : Nhận dạng biển số xe bằng thuật toán SVM
Tuy em đã cố gắng tìm tòi và nỗ lực hết sức để thực hiện đồ án nhưng hẳn sẽ có không ít sai sót, vì vậy kính mong các thầy cô góp ý và chỉ bảo thêm, giúp em nắm vững hơn vốn kiến thức của mình.
Em xin chân thành cảm ơn.
CHƯƠNG 1 : LÀM QUEN VỚI THƯ VIỆN OPENCV
1.1 Giới thiệu chương
Chương này giới thiệu về OpenCV (Open Source Computer Vision), một thư viện mã nguồn mở về thị giác máy với hơn 500 hàm và hơn 2500 các thuật toán đã được tối ưu về xử lý ảnh, và các vấn đề liên quan tới thị giác máy. OpenCV được thiết kế một cách tối ưu, sử dụng tối đa sức mạnh của các dòng chip đa lõi… để thực hiện các phép tính toán trong thời gian thực, nghĩa là tốc độ đáp ứng của nó có thể đủ nhanh cho các ứng dụng thông thường.
OpenCV là thư viện được thiết kế để chạy trên nhiều nền tảng khác nhau (cross-patform), nghĩa là nó có thể chạy trên hệ điều hành Window, Linux, Mac, iOS …Việc sử dụng thư viện OpenCV tuân theo các quy định về sử dụng phần mềm mã nguồn mở BSD do đó có thể sử dụng thư viện này một cách miễn phí cho cả mục đích phi thương mại lẫn thương mại. Dự án về OpenCV được khởi động từ những năm 1999, đến năm 2000 nó được giới thiệu trong một hội nghị của IEEE về các vấn đề trong thị giác máy và nhận dạng, tuy nhiên bản OpenCV 1.0 mãi tới tận năm 2006 mới chính thức được công bố và năm 2008 bản 1.1 (pre-release) mới được ra đời. Tháng 10 năm 2009, bản OpenCV thế hệ thứ hai ra đời (thường gọi là phiên bản 2.x), phiên bản này có giao diện của C++ (khác với phiên bản trước có giao diện của C) và có khá nhiều điểm khác biệt so với phiên bản thứ nhất.
Thư viện OpenCV ban đầu được sự hỗ trợ từ Intel, sau đó được hỗ trợ bở Willow Garage, một phòng thí nghiệm chuyên nghiên cứu về công nghệ robot. Cho đến nay, OpenCV vẫn là thư viện mở, được phát triển bởi nguồn quỹ không lợi nhuận (none -profit foundation) và được sự hưởng ứng rất lớn của cộng đồng.
1.2 So sánh phiên bản OpenCV 1 và OpenCV 2
Cho tới nay, trải qua hơn 6 năm từ lúc phiên bản OpenCV đầu tiên được công bố, đã có lần lượt nhiều phiên bản OpenCV ra đời, tuy nhiên có thể chia thư viện này thành hai bản chính dựa trên những đặc điểm khác biệt lớn nhất của chúng:
phiên bản OpenCV thế hệ thứ nhất (hay còn gọi là phiên bản OpenCV 1.x) và phiên bản OpenCV thứ hai (hay còn gọi là phiên bản OpenCV 2.x). Sau đây là một số điểm khác biệt cơ bản giữa hai phiên bản này.
OpenCV 1.x (bao gồm bản 1.0 và bản pre-release 1.1) dựa trên giao diện C, cấu trúc của một ảnh số dựa trên cấu trúc của IplImage, trong khi thư OpenCV 2.x dựa trên giao diện C++, cấu trúc của ảnh số, ma trận dựa trên cấu trúc của cv::Mat.
Trong OpenCV 1.x, người sử dụng phải hoàn toàn quản lý bộ nhớ của các đối tượng, nghĩa là khi một đối tượng mới được tạo ra, chúng ta phải luôn chú ý để giải phóng nó khi không còn sử dụng nữa (trong nhiều trường hợp có thể sẽ bị tràn bộ nhớ nếu không chú ý đều này), trong khi thư viện OpenCV 2.x việc quản lý bộ nhớ trở nên dễ dàng hơn nhờ các hàm hủy các các lớp đối tượng trong OpenCV 2.x đã thực hiện điều này khi một đối tượng không còn được sử dụng nữa.
Việc viết các dòng lệnh để thực hiện cùng một chức năng trong OpenCV 2.x là dễ dàng hơn nhiều so với OpenCV 1.x, một phần là là giao diện C++ có phần dễ hiểu hơn so với C, một phần là các hàm trong OpenCV 2.x đã được tối ưu hóa nhiều bước trung gian không cần thiết về mặt giao diện người sử dụng. Chẳng hạn khi xét ví dụ về việc phát hiện đường tròn trong ảnh màu dựa vào thuật toán Hough, các bước để thực hiện là load một ảnh màu, chuyển sang ảnh nhị phân, tìm biên dựa trên bộ lọc canny và phát hiện đường tròn dựa trên thuật toán Hough. OpenCV 1.x thực hiện như sau:
// Phát hiện đường tròn trong ảnh OpenCV 1.x
IplImage* src = cvLoadImage(“image.jpg”);
IplImage* gray = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
cvCvtColor(src, gray, CV_BGR2GRAY);
cvCanny(gray, gray, 10, 30, 3);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq*circles=cvHoughCircles(gray,storage,CV_HOUGH_GRADIENT, 1,50,100,50);
Trong khi đó, OpenCV 2.x thực hiện như sau:
// Phát hiện đường tròn trong ảnh OpenCV 2.x
Mat src = imread(“image.jpg”);
Mat gray;
CvtColor(src, gray, CV_BGR2GRAY);
Canny(gray, gray, 10, 30, 3);
Vector
HoughCircles(gray, circles, CV_HOUGH_GRADIENT, 1, 50, 100, 50);
Nhận thấy đối tượng ảnh gray trong OpenCV 2.x không cần phải khởi tạo, đối tượng storage (đối tượng trung gian, không có ý nghĩa về mặt sử dụng) cũng không cần phải khởi tạo (và do đó không cần giải phóng).
Thư viện OpenCV 1.x tuy chứa một lượng lớn hàm xử lý và thuật toán, tuy nhiên nó vẫn ở dạng sơ khai. Thư viện OpenCV 2.x đã được bổ xung khá nhiều hàm, thuật toán và được tối ưu khá nhiều đặc biệt trong các khía cạnh về phát hiện đối tượng (detection), nhận dạng đối tượng (partten regconition) và theo dõi đối tượng (tracking). Hơn thế nữa, tuy có giao diện là C++ nhưng OpenCV 2.x vẫn dữ một phần giao diện C để tương thích với các phiên bản của OpenCV 1.x.
Từ một số đặc điểm trên có thể thấy rằng thư viện OpenCV phiên bản 2.x là có nhiều điểm nổi trội hơn so với phiên bản 1.x, tuy nhiên trong một số trường hợp như ở các hệ thống nhúng khi mà trình dịch chỉ đơn thuần chấp nhận ngôn ngữ C thì phiển bản 1.x vẫn còn giá trị. Trong đồ án này, các nội dung cài đặt, thuật toán, ứng dụng … chỉ dành cho OpenCV phiên bản 2.x trên nền tảng hệ điều hành Window.
1.3 Hướng dẫn sử dụng thư viện Open CV trên Window
Trước hết chúng ta download thư viện OpenCV về máy tính, tốt hơn là luôn download bản mới nhất tại địa chỉ http://sourceforge.net/projects/opencvlibrary/.
Chọn bản đã build sẵn phù hợp với hệ điều hành đang dùng, bản OpenCV được sử dụng trong đề tài này là bản 2.4.3. Sau khi download về máy, tiến hành cài đặt bình
thường, để mặc định thư mục cài đặt là C:\ thư mục cài đặt xong sẽ có dạng C:\opencv. Tiếp theo tiến hành tùy chỉnh để có thể làm việc với OpenCV qua hai IDE thông dụng là Microsoft Visual Studio và Eclipse .
Trên Microsoft Visual Studio
Phiên bản Visual studio sử dụng ở đây là phiên bản Visual Studio 2010, các phiên bản trước hoàn toàn có thể cấu hình một cách tương tự.
Tạo một project mới: New > Project, trong cửa sổ New Project chọn Visual C++, Win32 Console Application. Đặt tên project là opencv.
Hình 1.1
Chọn OK, sau đó nhấn Next, hộp thoại tiếp theo xuất hiện, ở hộp thoại này chọn Application type là Console application và Additional option là Empty project, nhấn Finish để kết thúc quá trình khởi tạo.
Hình 1.2
Project mới được tạo ra là project hoàn toàn trống, chúng ta phải thêm vào đó ít nhất một file nguồn để chương trình
có thể chạy được, trong Solution Explorer click chuột phải vào Source Files, chọn Add -> New Item… Hộp thoại Add New Item hiện ra, ta chọn kiểu cần thêm vào là C++ File(.cpp) đồng thời trong ô Name ta đặt tên cho file thêm vào, giả sử là FirstApp.cpp.
Hình 1.3
Bây giờ trong file này chúng ta có thể thêm vào các #include và gọi hàm main() để chạy chương trình.
Để chương trình có thể chạy được với thư viện OpenCV thì cần tùy chỉnh lại một số thuộc tính của project như sau : Vào Project -> Properties (hoặc nhấn tổ hợp phím Alt + F7) để mở hộp thoại Properties. Hộp thoại opencv Property Pages hiện ra, trong mục Configuration Properties chọn VC++ Directories, tương ứng bên phải, tìm mục Include Directories và LibraryDirectories. Chúng ta sẽ chỉ đường dẫn hai thư mục này đến các phần tương ứng của thư việnOpenCV.
Mục Include Directories, ta tùy chỉnh ở ô bên phải tới C:\opencv\build\include
Mục Library Directories trỏ đến thư mục C:\opencv\build\x86\vc10\lib nếu như sử dụng hệ điều hành 32bit hoặc C:\opencv\build\x64\vc10\lib cho hệ điều hành 64bit.
Tiếp theo, trong hộp thoại opencv Property Pages -> Configuration Properties -> Linker chọn Input, tương ứng ở ô bên phải, thêm vào các giá trị cho mục AdditionalDependencies làopencv_core243d.lib,opencv_imgproc243d.lib,opencv_highgui243d.lib.
Hình 1.4
Chữ d đứng cuối các file trên thể hiện là đang hoạt động ở chế độ debug, ta có thể thêm các lib không có chữ “d” ở cuối như opencv_core243.lib…trong chế độ
release. Cuối cùng, khi dịch xong một chương trình, để nó có thể chạy được ta cần chú ý tới cácfile *.dll. Cách đơn giản là chúng ta copy các file *.dll tương ứng (như opencv_core243d.dll, opencv_imgproc243d.dll) vào thư mục chứa file chạy của chươngtrình (file *.exe). Các file *.dll này nằm trong mục C:\opencv\build\x86\bin với win 32 bit hoặc C:\opencv\build\x64\bin với win 64 bit. Với các phiên bản OpenCV cũ hơn, ta cần copy luôn file tbb_debug.dll (trong chế độ debug) hoặc tbb.dll (trong chế độ release) vào thư mục chứa file *.exe. tbb.dll (Thread building block) là file khá quan trọng, thiếu nó chương trình sẽ báo lỗi.
Sau khi đã hoàn tất việc chỉ dẫn thư mục chứa header, library và link tới các library tương ứng, ta có thể include các header của opencv vào chương trình và có thể gọi các hàm làmviệc của OpenCV.
#include
#include
#include
#include
using namespace std;
using namespace cv;
void main()
{
...
}
1.4 Kết luận chương
Nội dung chương 1 đã nêu rõ về thư viện OpenCV cũng như cách cài đặt chương trình và các phiên bản ra đời của OpenCV. Qua đó giúp hỗ trợ cho việc xử lý ảnh thuận tiện hơn.
CHƯƠNG 2 : CÁC PHÉP XỬ LÝ ẢNH ĐƠN GIẢN TRONG OPENCV
2.1 Giới thiệu chương
Chương 2 sẽ giới thiệu các chương trình đơn giản để xử lý một bức ảnh. Trong chương này em giới thiệu 3 chương trình chính đó là: chương trình để load và hiển thị một ảnh, chương trình nhị phân hóa với ngững động, chương trình về các phép toán hình thái học về việc giản nỡ và nối liền biên ảnh để tìm biển số xe ô tô.
2.2 Chương trình đầu tiên
Trong ví dụ này, em sẽ viết một chương trình Hello world để load và hiển thị một ảnh.
Chương trình như sau :
#include "stdafx.h"
#include
#include
#include
using namespace std;
using namespace cv;
int main()
{
cout<<"Chuong trinh dau tien"<
Mat img = imread("vietnam.jpg", CV_LOAD_IMAGE_COLOR);
namedWindow("Viet Nam", CV_WINDOW_AUTOSIZE);
imshow("Viet Nam", img);
waitKey(0);
return 0;
}
Như đã nói ở trên, trong Opencv với giao diện C++, tất cả các kiểu dữ liệu ảnh, ma trận điều được lưu ở dạng cv::Mat. Hàm imread sẽ đọc ảnh đầu vào và lưu vào biến img. Nguyên mẫu của hàm này như sau: cv::Mat imread(const std::string &filename, int flags) trong đó, filename là đường dẫn tới file ảnh, nếu file ảnh không nằm trong thư mục làm việc hiện hành thì chúng ta phải chỉ ra đường dẫn có dạng như D:\Anh\vietnam.jpg hoặc D://Anh//Vietnam.jpg. Flags là tham số loại ảnh mà chúng ta muốn load vào, cụ thể nếu muốn load ảnh màu thì chúng ta để CV_LOAD_IMAGE_COLOR, còn nếu muốn là ảnh xám thì để CV_LOAD_IMAGE_GRAYSCALE…Sau khi đã load ảnh thành công, muốn hiển thị ảnh lên màn hình cần tạo ra một cửa sổ, hàm namedWindow(const std::string &winname, int flags) sẽ tạo ra cửa sổ với tiêu đề cửa sổ là một chuỗi string winname. Tham số flags sẽ chỉ ra kiểu cửa sổ muốn tạo: nếu tham số CV_WINDOW_AUTOSIZE được sử dụng thì kích cỡ cửa sổ tạo ra sẽ được hiển thị một cách tự động tùy thuộc vào kích thước của ảnh, nếu là tham số CV_WINDOW_AUTOSIZE_FULLSCREEN kích thước cửa sổ sẽ khít với màn hình máy tính …Cuối cùng, hàm imshow(const std::string &winname, cv::InputArray Mat) sẽ hiển thị ảnh ra cửa sổ đã được tạo ra trước đó.
Hàm waitKey(int delay) sẽ đợi cho đến khi có một phím được bấm vào trong khoảng thời gian là delay. Chú ý là nếu không có hàm này thì chương trình sau khi chạy sẽ không dừng lại màn hình và kết thúc luôn, ta dùng hàm này mục đích là để dừng màn hình lại trong một khoảng thời gian bằng tham số delay (tính theo đơn vị millisecond). Nếu muốn dừng màn hình lại mãi mãi ta đặt tham số delay bằng 0.
Và sau đây là kết quả của chương trình chạy:
Hình 2.1
2.3 Ảnh nhị phân, nhị phân hóa với ngưỡng động
Ảnh nhị phân là ảnh mà giá trị của các điểm ảnh chỉ được biểu diễn bằng hai giá trị 0 hoặc 255 tương ứng với hai màu đen hoặc trắng. Nhị phân hóa một ảnh là quá trình biếnmột ảnh xám thành ảnh nhị phân. Gọi f(x,y) là giá trị cường độ sáng của một điểm ảnh ở vị trí (x,y),T là ngưỡng nhị nhị phân. Khi đó, ảnh xám f sẽ được chuyển thành ảnh nhị phân dựa vào công thức f(x,y) = 0 nếu f(x,y) ≤ T và f(x,y) =255 nếu f(x,y) > T
Hình sau mô tả một ảnh nhị phân với ngưỡng nhị phân T = 100
Hình 2.2
Hàm để chuyển nhị phân hóa ảnh trong OpenCV là hàm threshold(). Nguyên mẫu hàm như sau:
threshold(cv::InputArray src, cv::OutputArray dst, double thresh, int maxval, int type)
Trong đó, src là ảnh đầu vào một kênh màu (ảnh xám …), dst là ảnh sau khi được nhị phân hóa, thresh là ngưỡng nhị phân, maxval là giá trị lớn nhất trong ảnh (maxval = 255 đối với ảnh xám), type là kiểu nhị phân có thể là CV_THRESH_BINARY,CV_THRESH_BINARY_INV, CV_THRESH_OTSU… lần lượt là nhị phân hóa thông thường, nhị phân hóa ngược và nhị phân hóa theo thuật toán Otsu …
Kết quả của việc nhị phân hóa một ảnh phụ thuộc vào ngưỡng T, có nghĩa là với mỗi ngưỡng T khác nhau thì ta có những ảnh nhị phân khác nhau. Hình sau mô tả 3 ảnh nhị phân tương ứng với ngưỡng T = 50, T = 100 và T = 150.
........
Hình 3.3
Đến đây ta đã khởi tạo xong một project MFC có dựa trên nền Dialog, Dialog hiện ra mặc định có một button OK, button Cancel và một label, ta có thể để sử dụng hoặc xóa đi và thiết kế theo ý riêng của mình.
3.3Làm việc với các điều khiển (Control) của MFC
3.3.1 Đặt tên biến cho các control
Khi muốn sử dụng một Control nào, ta kéo control đó từ Toolbox và cho vào dialog. Để làm việc với các control một cách dễ dàng, chúng ta nên đặt tên biến cho các control.
Hình 3.4 |
Để đặt tên biến cho một control, ta click chuột phải vào control, sau đó chọn AddVariable.Một hộp thoại Add Member Variable Wizard hiện ra và trong mục variable name ta đặt tên cho control đó. Chú ý là đối với các
control mà ID của nó có dạng IDC_STATIC (như StaticText) thì ta chỉ có thể đặt tên biến được khi đổi ID của nó, chẳng hạn như đổi thành IDC_STATIC, IDC_LABEL…
Hình 3.5
3.3.2 Lấy giá trị nhập vào từ một Edit Control
Để lấy giá trị nhập vào từ một Edit Control, ta sử dụng hàm GetWindowText(). Giả sử như Edit Control được đặt tên là text_box, khi đó ta có thể lấy giá trị text trong ô Edit Control như sau:
CString text;
text_box.GetWindowTextW(text);
Giá trị lấy được sẽ được lưu trong một chuỗi CString text. Một điểm cần chú ý về sau là các hàm trong MFC khi được build ở chế độ Unicode và chế độ Multi-byte thì các gọi các hàm, cách sử dụng các hàm cũng có những điểm khác nhau nho nhỏ, chẳng hạn như cũng là lấy giá trị trong một ô Edit Control nhưng nếu ở chế độ Multi-byte ta sẽ dùnglệnh sau:
CString text;
text_box.GetWindowTextA(text);
Ta có thể tùy chỉnh để trình dịch build theo chế độ Unicode hoặc Multi-byte bằng cáchvào Project -> Properties (hoặc nhấn Alt + F7), hộp thoại
Propertieshiện ra, chọnConfiguration Properties -> General và tùy chỉnh ở mục CharacterSet.
3.3.3 Hiển thị text lên các control
Để hiểnthị text lên các control (Button, Edit control, Static Text ..), ta dùng hàmSetWindowText(CString text)
text_box.SetWindowTextW(_T("text")); // Unicode
text_box.SetWindowTextA("text"); // Multi-byte
3.3.4 Hiển thị ảnh lên một control
Để hiển thị ảnh lên một control, ta dùng hàm SetBitmap(). Đoạn code sau load một ảnh bitmap từ ổ D và hiển thị lên một button có tên là btn:
HBITMAP image = (HBITMAP)LoadImageA(0, "D:/test.bmp", IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE);
btn.SetBitmap(image);
3.3.5 Enable, disable một control
Ta sử dụng hàm EnableWindow để cho phép control có được phép sử dụng hay không
text_box.EnableWindow(flase); // Vo hieu hoa edit control
text_box.EnableWindow(true); // Cho phep edit control hoat dong
3.3.6 Lấy giá trị từ thanh trượt (Slider Control)
Giả sử thanh trượt được đặt tên là slider, khi đó ta có thể lấy giá trị hiện tại của thanh trượt bằng hàm GetPos() : int value = slider.GetPos();
Ta cũng có thể dùng hàm SetRange để đặt giá trị lớn nhất và bé nhất cho thanh trượt, và dùng hàm SetPos để đặt vị trí cho thanh trượt:
slider.SetRange(0, 100); slider.SetPos(50);
3.3.7Lấy giá trị lựa chọn từ Combo Box
Combo box cho phép ta lựa chọn, chuyển đổi giữa các lựa chọn một cách nhanh chóng. Để thêm các lựa chọn vào Combo Box ta có thể điển trực tiếp vào mục Data trong properties của nó, (giả sử ta có các lựa chọn về tỉnh thành ở Việt Nam
như HaNoi, ThanhHoa, DaNang…ta sẽ click chuột phải vào Combo box, chọn properties, trong bảng properties ở mục Data chúng ta điền vào HaNoi; ThanhHoa; DaNang… các lựa chọn được phân cách bởi dấu ";" ). Để xem lựa chọn nào đang được chọn, ta dùng hàm GetCurSel().
int choice = combo_box.GetCurSel(); Giá trị trả về là thứ tự các dữ liệu trong mục Data của Combo box.
3.3.8 Dialog mở file và lưu file
Mục đích của loại dialog này là tạo ra một hộp thoại cho phép người dùng chọn đến đường dẫn để mở file và lưu file. Kết quả cuối cùng mà ta quan tâm nhất là lấy được đường dẫn mà người dùng lựa chọn.
CString Filter=_T("image files (*.bmp; *.jpg) |*.bmp;*.jpg|All Files
(*.*)|*.*||");
CFileDialog dlg(TRUE, _T("*.jpg"), NULL,
OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY,Filter, NULL);// Mo file
CFileDialog dlg(FALSE, _T("*.jpg"), NULL,
OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY,Filter,NULL);// Luu file
Filter sẽ lọc và chỉ hiển thị những file tương ứng mà ta cần quan tâm, trong trường hợp trên ta đang xét mở hoặc lưu một file ảnh do đó ta để file mở rộng là bmp hoặc jpg. Nếu muốn hiển thị tất cả các loại file chỉ việc để filter là *.*, hộp thoại mở file và lưu file chỉ khác nhau ở thông số đầu tiên khi tạo đối tượng dlg, nếu là mở file ta đặt là TRUE, lưu file ta đặt là FALSE.
Hiển thị hộp thoại này và lấy đường dẫn người dùng chọn như sau:
if(dlg.DoModal() == IDOK)
{
CString file_name = dlg.GetPathName();// lay duong dan day du
}
3.3.9 Xử lý sự kiện khi click chuột vào button
Hầu hết các control trong MFC đều có một hoặc nhiều sự kiện khi người dùng tương tác với nó, chẳng hạn sự kiện click chuột vào button, sự kiện kéo thanh trượt của slidercontrol …
Hình 3.6
Để xử lý các sự kiện cho các control, trong mục properties của control tương ứng ta chọn vào icon sự kiện sau đó chọn các sự kiện cần xử lý. Chẳng hạn đối với button, ta chọn BN_CLICKED rồi chọn OnBnClickedButton1, khi đó ta sẽ có một hàm được tự động sinh ra và ta có thể xử lý các vấn đề liên quan tới sự kiện click chuột. Hàm sau sẽ sinh ra một Message Box khi click vào button1
void CxyzDlg::OnBnClickedButton1()
{
MessageBoxA(NULL, "Button1 duoc
click", "Thong bao", 0);
}
3.3.10Xử lý sự kiện khi thay đổi lựa chọn Combo Box
Sự kiện thay đổi lựa chọn của Combo Box là CBN_SELENDOK. Đoạn code sau mô tả sự thay đổi lựa chọn của người dùng trên Combo Box, với mỗi lựa chọn ta sinh ra một Message Box tương ứng.
void CxyzDlg::OnCbnSelendokCombo1()
{
int index = combo_box.GetCurSel();
switch(index)
{
case 0:
MessageBoxA(NULL, "Ban chon HaNoi", "Thong bao", 0);
break;
case 1:
MessageBoxA(NULL, "Ban chon ThanhHoa", "Thong bao", 0);
break;
case 2:
MessageBoxA(NULL, "Ban chon DaNang", "Thong bao", 0);
break;
default:
MessageBoxA(NULL, "Khong chon?", "Thong bao", 0);
break;
}
}
3.3.11 Thêm menu vào chương trình, xử lý sự kiện khi click vào menu
Menu trong MFC được xem là resource của chương trình. Việc thêm menu vào dialog đòi hỏi chúng ta phải thêm nó vào resource của chương trình. Trước hết chúng ta hiển thị cửa sổ xem cácresource của chương trình bằng cách từ menu của Visual Studio chọn View -> Resource View (hoặc nhận tổ hợp phìm Ctrl + Shift + E). Cửa sổ Resource View hiện ra, ta clickchuột phải vào đó, chọn Add->Resource… Cửa sổ Add Resource hiện ra, ta chọn Menu và click vào button New. Ngay sau đó ta sẽ có một resource chứa menu chống, ta tiến hành điền tên các
menu mà ta muốn chương trình thực hiện. Hình bên ta điền 3 menu chức năng nhỏ là Open, Save và Exit.
Khi đã tạo xong menu, nó vẫn chỉ nằm ở trong resource của chương trình, muốn menu này được gắn vào dialog khi chạy, ta vào properties của dialog, trong mục Menu chọn IDR_MENU1, với IDR_MENU1 chính là ID của menu ta vừa tạo ra.
Để xử lý sự kiện click chuột của menu nào, click chuột phải vào menu ấy và chọn Add Event Handler…
Hình 3.8
Ở hộp thoại Event Handler Wizard chọn lớp mà chúng ta muốn thêm menu vào sau đó click vào button Add and Edit để đi tới hàm xử lý sự kiện khi click vào menu, ví dụ sau là gọi hàm OnCancel() để thoát khỏi chương trình
void CxyzDlg::OnUpdateFileExit(CCmdUI *pCmdUI)
{
OnCancel();
}
Ngoài một số điều khiển thông dụng đã nhắc tới ở trên, MFC còn cung cấp rất nhiều các điều khiển khác giúp cho việc tạo ra giao diện một cách dễ dàng và đẹp mắt hơn.
3.4 Chuyển đổi các kiểu dữ liệu trong MFC
Các kiểu dữ liệu của MFC về cơ bản là giống với các kiểu dữ liệu trong C, tuy nhiên có một số trường hợp ta phải chuyển đổi qua lại giữa các kiểu dữ liệu để phù hợp với đầu vào, đầu ra của một việc nào đó, chẳng hạn khi ta dùng CFileDialog để mở một đường dẫn sau đó đọc ảnh từ đường dẫn này, kết quả trả về đường dẫn của CFileDialog là một chuỗi CString tuy nhiên hàm cv::imread lại đọc ảnh từ một chuỗi string, do đó ta phải chuyển đổi từ CString sang string. Một số chuyển đổi sau đây là hữu ích cho việc hiển thịgiao diện, và lấy dữ liệu từ giao diện người dùng.
Với chế độ biên dịch không sử dụng Unicode, chúng ta có thể chuyển đổi hai kiểu dữ liệu này dễ dàng:
Chuyển từ string sang CString:
std::string str = "chuoi string";
CString cstr = str.c_str();
Chuyển từ CString sang string
CString cstr = "chuoi cstring";
std::string str = std::string(cstr);
với chế độ biên dịch có sử dụng Unicode:
Chuyển từ string sang CString:
std::string str = "chuoi string";
CStringW cstr = (CStringW)(str.c_str());
Chuyển từ CString sang string
CString cstr = _T("chuoi cstring");
std::wstring wstr = (std::wstring)cstr;
std::string str;
str.assign(wstr.begin(), wstr.end());
Chuyển đổi số sang CString và ngược lại
Cách chuyển đổi này giúp ta lấy số liệu dưới dạng số của các ô Edit Control hoặc hiển thị số lên các control.
Chuyển đổi CString sang số
CString cstr1 = "123";
int num1 = atoi(cstr1); // Chuyen sang so nguyen khong su dung Unicode
int num1 = _wtoi(cstr1); // Chuyen sang so nguyen su dung Unicode
CString cstr2 = "10.5";
float num2 = atof(cstr2) // Chuyen sang so thuc khong su dung Unicode
float num2 = _wtof(cstr2) // Chuyen sang so thuc su dung Unicode
Chuyển số sang CString
char s1[20];
int num = 10;
sprintf(s1, "%d", num);
CString cstr1 = s1;// chuyen so nguyen sang cstring - khong unicode
CString cstr2;
cstr2.Format(_T("%d"), num);// chuyen so nguyen sang cstring unicode
Tương tự với số thực ta có thể chuyển đổi tương tự và thay "%d" bằng "%f".
3.5 Tải ảnh và hiển thị ảnh trên giao diện MFC
Chúng ta tạo mới một project, đặt tên project là HienThiThongTinAnh và thiết kế giao diện như hình sau:
Hình 3.9
Trong đó, các Labels hiển thị thông tin của ảnh chính là Static Text, ID IDC_STATIC của chúng được đổi và chúng được đặt tên biến là l_width, l_height, l_channels, l_path (đối với các static text dùng để hiển thị kết quả). ID của Picture Control được đổi thành IDC_STATIC_PICTURE.
3.7 Kết luận chương
Tóm lại trong chương này giới thiệu về giao diện MFC và cách thực hiện để tạo giao diện, giúp người xem quan sát cụ thể và thông qua đó có thể biết được các tiêu chí để xử lý biển số xe.
CHƯƠNG 4 : NHẬN DẠNG BIỂN SỐ XE BẰNG THUẬT TOÁN
SVM DÙNG THƯ VIỆN OPENCV
4.1Giới thiệu chương
Bài toán nhận dạng biển số xe có nhiều ý nghĩa trong thực tế, nó giúp việc giám sát, quản lý, thống kê … các phương tiện một cách dễ dàng, tiện lợi và nhanh chóng. Một số ứng dụng điển hình đã được triển khai trong thực tế như ứng dụng trong quản lý bãi đỗ xe thông minh, ứng dụng thu phí ở các trạm thu phí, ứng dụng phát hiện lỗi vi phạm giao thông một cách tự động … Trong phần này ta nghiên cứu về mặt kĩ thuật của một bài toán nhận dạng biển số xe, viết chương trình demo và các bước cần thiết để đưa bài toán vào ứng dụng thực tế.
Giả sử ta đang xây dựng bài toán nhận dạng biển số xe ô tô, với đầu vào là một ảnh chứa biển số xe và đầu ra là một chuỗi kí tự của biển số đã được nhận dạng. Nếu quan sát bằng mắt người ta có thể dễ dàng nhận biết được một biển số, tuy nhiên với máy tính, đó là một điều không dễ dàng gì, nó rất dễ bị nhiễu, bị nhầm bởi các hình khối xung quanh tương tự, bởi các điều kiện thời tiết, góc độ… Để hạn chế bớt được những khó khăn này, nhiều hệ thống nhận dạng trong thực tế thường giới hạn các điều kiện chẳng hạn như camera thu ảnh được cố định ở một vị trí, xe được đi vào một khe hẹp nhất định…
Có nhiều cách khác nhau để thực hiện bài toán nhận dạng này, ở các phần mềm thương mại hoàn chỉnh, nó là sự kết hợp và tối ưu của khá nhiều thuật toán phức tạp, trong bài này, ta đi theo hướng tiếp cận chia bài toán thành hai bài toán nhỏ: phát hiện biển số xe, cách ly kí tự và nhận dạng các kí tự.
Hình 4.1
4.2 Phát hiện vùng chứa biển số xe và cách ly kí tự.
Vì biển số xe có những đặc trưng cơ bản được quy định bởi các cơ quan chức năng nên tacó thể dựa vào đặc trưng này để phân biệt với các đối tượng khác. Theo quy định của bộ công an, biển số xe đằng trước của các loại xe dân dụng là một hình chữ nhật, có kích thước 470x110 (mm), phông nền màu trắng và các kí tự chữ cái in hoa màu đen. Các kí tựchữ số bao gồm từ 0 tới 9 và các kí tự chữ số bao gồm A, B, C, D, E, F, G, H, K, L ,M ,N, P, S, T, U, V, X, Y, Z (20 kí tự). Ta sẽ dựa vào các đặc trưng hình học này để tríchchọn ra vùng chứa biển số xe, các bước thực hiện như sau:
Bước 1: Load ảnh, tiền xử lý ảnh (khử nhiễu, làm mịn …)
Bước 2: Chuyển ảnh ban đầu thành ảnh xám rồi nhị phân hóa ảnh đó. Để ảnh nhị phân thu được kết quả tốt và không bị phụ thuộc vào các điều kiện ánh sáng khác nhau, ta sử dụng phương pháp nhị phân hóa với ngưỡng động (adaptive threshold) Bước 3: Tìm các đường bao quanh đối tượng. Sau khi nhị phân ảnh, các đối tượng sẽ là các khối hình đen trên nền trắng, với mỗi đối tượng ta luôn vẽ được một đường biên bao quanh đối tượng đó. Để tránh tình trạng các đối tượng không tạo ra được các đường biên khép kín do các vết rạn nứt hoặc nhiễu gây ra, trước khi tìm biên ta nên làm mịn đường biên bằng các phép giãn nở (hoặc phép co).
Bước 4: Xác định hình chữ nhật bao quanh các đường bao quanh đã tìm được từ bước 3. Đường bao quanh đã tìm được ở bước 3 là một chuỗi các điểm biên nối liền của đối tượng, dựa vào tọa độ của các điểm biên này ta sẽ xác định được hình chữ nhật ngoại tiếp bao quanh đối tượng.
Bước 5: Tìm ra các hình chữ nhật có khả năng là vùng chứa biển số, nếu hình chữ nhật thu được ở bước 4 là vùng chứa biển số thì nó phải thỏa mãn ít nhất được một số điều kiện sau:
+ Tỉ lệ chiều dài/ rộng phải xấp xĩ 4.3. Trong cài đặt thực tế ta có thể cho tỉ lệ này dao động trong khoảng [4.0, 4.5].
+ Số đối tượng thỏa mãn là một kí tự biển số trong vùng hình chữ nhật phải là một số lớn hơn một ngưỡng nào đó. Với biển số xe 4 chữ số, số kí tự này là 7, với biển số xe mới với 5 kí tự số, số kí tự này là 8, cũng có một số biển số xe có nhiều hơn 8 kí tự do có 2 kí tự chữ cái … Để xác định một đối tượng là kí tự hay không, ta cũng sẽ dựa vào đặc điểm hình học của kí tự đó như tỉ lệ chiều dài/rộng đối tượng, tỉ lệ chiều cao, dài của đối tượng so với tỉ lệ chiều cao, dài của hình chữ nhật đang được xem xét là biển số, tỉ lệ pixel đen/trắng của dối tượng … Nếu xác định đó là một kí tự của biển số xe ta cũng sẽ đồng thời lưu nó lại, đó chính là cách ta cách ly đối tượng trong biển số.
+ Ngoài ra, tùy thuộc vào điều kiện của bài toán ta có thể cố định thêm một số đặc tính để chắc chắn hơn vùng chứa biển số, chẳng hạn như kích thước của hình chữ nhật không được vượt quá một nửa kích thước của ảnh đầu vào, tỉ lệ pixel đen/trắng trong hình chữ nhật phải nằm trong một ngưỡng nào đó…
Sau khi đã xác định được vùng có khả năng là biển số, ta sẽ cắt vùng hình đó, đồng thời lấy ra các kí tự trong vùng đó lưu vào một mảng để thực hiện việc nhận dạng.
4.3 Nhận dạng kí tự
Các kí tự sau khi được cách ly là những kí tự đơn lẽ trong một khung hình chữ nhật có kích thước nhất định. Để nhận dạng được kí tự này có thể sử dụng rất nhiều phương pháp khác nhau, từ đơn giản như phương pháp sử dụng độ tương
quan chéo (crosscorrelation) cho đến những phương pháp sử dụng các mô hình máy học (machinelearning) như mạng Neuron nhân tạo, SVM …
Đối với các phương pháp sử dụng máy học, chúng ta cần sưu tầm một lượng mẫu các kí tự nhất định, từ vài trăm cho tới hàng nghìn mẫu rồi đưa vào các bộ huấn luyện, kết quả huấn luyện này sẽ được dùng để nhận dạng các mẫu mới. Độ chính xác của kết quả nhận dạng nói chung của phương pháp này tùy thuộc vào độ phức tạp của mô hình, khối lượng mẫu huấn luyện, thời gian tính toán. Trong đề tài này, em sử dụng phương pháp SVM để nhận dạng kí tự.
4.3.1 Phương pháp SVM
Hình 4.2
SVM (Surport Vector Machine) là một mô hình máy học giám sát được dùng trongviệc phân tích, phân lớp dữ liệu dựa vào các siêu phẳng. Giả sử có một tập dữ liệu hai chiều như hình bên, khi đó chúng ta có thể phân lớp dữ liệu này thành hai phần nhờ một siêu. Siêu phẳng trong mặt phẳng là một đường thằng, trong không gian3 chiều là một mặt phẳng và tổng quát trong không gian n chiều là một không gian n-1chiều. Trong trường hợp dữ dữ liệu là không tuyến tính, chúng ta cần ánh xạ tập dữ liệu đó lên một không gian có số chiều lớn hơn để thuận tiện cho việc phân loại dữ liệu, nhiệm vụ là cần phải tìm siêu phẳng sao cho khoảng cách tới các biên của dữ liệu là lớn nhất. Hiểu đơn giản về phương pháp này như sau: cho một tập các mẫu huấn luyện,với mỗi mẫu được gắn vào một nhãn, quá trình
huấn luyện SVM sẽ xây dựng một mô hình cho phép dự đoán một tập dữ diệu khác thuộc về nhãn nào, tức phân loại tập dữ liệu đó thuộc vào lớp nào.
Sơ đồ tổng quát quá trình nhận dạng :
Hình 4.3
Cần phải nhận thấy rằng SVM là một bộ máy phân loại dữ liệu, muốn sử dụng được nó cần phải có dữ liệu, dữ liệu đối với các kí tự mà chúng ta cần nhận dạng ở đây chính là các đặc trưng trong ảnh của kí tự đó. Giả sử cần phân loại 30 lớp dữ liệu (tương ứng với 30 kí tự trong biển số xe), với mỗi lớp dữ liệu, ta tính toán được 10 vector đặc trưng (10 mẫu), và mỗi vector đặc trưng tưng ứng với các đặc trưng trong một ảnh. Khi đó sẽ đưa vào bộ huấn luyện SVM toàn bộ dữ liệu này, sau đó với một ảnh bất kì, ta sẽ tính toán một vector đặc trưng của ảnh đó, mô hình SVM sẽ xem xét xem dữ liệu này (tứcvector đặc trưng này) thuộc vào lớp nào trong số những lớp mà nó đã được huấn luyện.
4.3.2 Tính toán đặc trưng trong ảnh
Đặc trưng trong ảnh là những đặc điểm riêng biệt giúp phân biệt ảnh này với ảnh khác.Việc xem xét như thế nào là các đặc trưng trong ảnh là một việc không có quy ước trước, nó phụ thuộc vào cách nghiên cứu, cài đặt của từng trường hợp cụ thể và vẫn đang đượcnghiên cứu để đưa ra những phương pháp tốt nhất.
Giả sử có hai kí tự như hình bên, nhìn bằng mắt thường thì có thể dễ dàng phân biệt được hai kí tự 0 và 4, tuy nhiên làm sao để máy tính phân biệt được hai kí tự này? Bây giờ chúng ta sẽ đưa hai kí tự này về cũng một kích thước, chia nhỏ các kí tự thành 16 ô nhỏ khác nhau.
Hình 4.4
Nhận thấy rằng nếu tính tổng các pixel đen trong các ô của hai bức ảnh thì số 0 và số 4 có thể phân biệt dựa vào các ô (1,1), (1, 4), (2, 2), (3,3) … tại những ô đó, tổng số các điểm ảnh đen là khác nhau hoàn toàn. Tính toán số điểm ảnh đen của 16 ô vuông này ta có thể thu được 16 đặc trưng của một ảnh, 16 đặc trưng này đủ để phân biệt kí tự 0 và 4.Tuy nhiên, với 30 kí tự ta cần phải tính toán nhiều hơn các đặc trưng, các đặc trưng không nhất thiết phải là 0 (tức không có điểm ảnh đen nào) hoặc 1(tức là toàn số điểm ảnh đen trong ô) mà có thể là một tỉ lệ tương đối nào đó. Từ 16 đặc trưng cơ bản trên, ta kết hợp chúng lại để tạo ra những đặc trưng khác, chẳng hạn như lấy tổng các đặc trưng trên đường chéo (1,1) + (2,2) + (3,3) + (4,4)
hoặc tổng các đặc trưng xung quanh đường biên của ảnh … số đặc trưng càng lớn thì việc phân loại các lớp càng ít bị sai, có nghĩa là xác suất nhận dạng càng lớn.
4.4 Cài đặt chương trình nhận dạng biển số xe ô tô
Chúng ta tạo một chương trình dựa trên Dialog của MFC, đặt tên project là LPR (License Plate Recognition). Về cơ bản có thể chia chương trình thành 3 phần chính như sau: phần chứa giao diện chính của chương trình (được định nghĩa trong file LPRDlg.h và LPRDlg.cpp), phần chứa các hàm chính cho việc phát hiện, nhận dạng biển số xe và không liên quan tới giao diện (được định nghĩa trong file LprCore.h và LprCore.cpp) và phần chứa một công cụ giúp cho ta có thể huấn luyện được mô hình SVM một cách tùy ý (được định nghĩa trong file TrainSVM.h vàTrainSVM.cpp). Ngoài ra còn có một số phần nhỏ giúp cho việc lập trình được dễ dàng hơn như phần chuyển đổi các biến dữ liệu trong MFC chẳng hạn(unity_conversion.h).
4.4.1 Huấn luyện mô hình SVM
Để tạo được mô hình SVM phục vụ cho việc nhận dạng kí tự sau này, chúng ta cần huấn luyện và lưu mô hình sau khi huấn luyện.
Chuẩn bị cơ sở dữ liệu :
Chúng ta cần chuẩn bị cơ sở dữ liệu là tập hợp của các kí tự trong biển số xe. Có 30 kí tự thường gặp trong biển số xe, do đó ta cần phân loại 30 lớp này, trong trường hợp ở đây giả sử với mỗi lớp, tức là mỗi kí tự ta có 10 ảnh, chúng ta sẽ lưu các ảnh này vào các folder, tên các folder được đặt tên theo các kí tự, chẳng hạn như folder 0 chứa 10ảnh của kí tự 0, folder 1 chứa 10 ảnh của kí tự 1, … folder 30 chứa 10 ảnh của kí tự Z. Ta cần đánh tên folder theo số tứ tự, vì số thứ tự cũng chính là nhãn tương ứng đưa vào việc nhận dạng. Chúng ta sẽ tính toán đặc trưng của từng kí tự và lưu tất cả các đặc trưng này vàomột ma trận để phục vụ cho việc huấn luyện. Hàm tính toán đặc trưng trong một ảnh sẽ dựa trên ý tưởng tổng các điểm đen trong một khung hình, tuy nhiên nó được chuẩn hóa bằng cách chia cho tổng tất cả các điểm ảnh đen của kí tự.
4.5 Phát hiện và nhận dạng biển số xe
Cài đặt một lớp nhận phát hiện và nhận dạng biển số xe theo như các bước đã nói ở trên, và đặt tên cho lớp này LprCore. Chúng ta sẽ cài đặt lớp này với giao diện sao cho việc sử dụng nó là dễ dàng nhất, giao diện (interface) của lớp này được định nghĩa như sau:
// lprcore.h header
#pragma once
#include
#include
using namespace std;
using namespace cv;
class LprCore
{
public:
LprCore(void);
~LprCore(void);
void set_image(Mat);
void set_svm_model(string);
void do_process();
vector
vector
vector
vector
vector
void clear();
private:
bool done;
bool ready;
SVM svm;
Mat image;
vector
vector
vector
vector
vector
char character_regconition(Mat);
bool plate_detection();
bool plate_recognition();
};
4.6 Giao diện chương trình chính
Giao diện chương trình chính bao gồm các picture control để hiển thị ảnh, các button, menu cho việc điểu khiển và các label để hiển thị kết quả như sau:
Hình 4.5
Ngoài ra, chương trình còn có một số menu khác nhằm giúp chúng ta lưu kết quả ảnh biển số hoặc kết quả nhận dạng được dưới dạng một chuỗi text, menu hiển thị dialog cho việc huấn luyện mô hình SVM
Hình sau mô tả kết quả chạy chương trình:
Hình 4.6
Nhận xét: Tùy vào độ phân giải và góc độ của camera so với biển số xe thì kết quả chính xác sẽ khác nhau. Nên dùng loại camera MTC-WDL713EF-R.
4.7 Kết luận chương
Theo kết quả mô phỏng đã thử nghiệm trên 10 mẫu thử thì tỷ lệ nhận dạng là 100%. Tuy nhiên nếu thử nghiệm trên nhiều mẫu thử thì tỷ lệ nhận dạng là sẽ không hoàn toàn như ý muốn mà có thể thấp hơn do có nhiều yếu tố bất lợi.
KẾT LUẬN – HƯỚNG PHÁT TRIỂN
Sự phát triển của công nghệ thông tin đã có tác động đến nhiều mặt của đời sông xã hội trong đó phải kể đến lĩnh vực giám sát tự động. Trong giám sát tự động, việc giám sát đối với các phương tiện giao thông là một vấn đề nổi trội. Nhiều chính phủ, thành phố trên thế giới đã xây dựng hệ thống giám sát tự động đối với các phương tiện giao thông của mình.
Đề tài nhằm mục đích tìm hiểu bài toán giám sát, quản lý các phương tiện giao thông một cách tự động thông qua việc “Phát hiện và nhận dạng chữ, số trong biển số xe”.
Đề tài đã trình bày một cách hệ thống về bài toán nhận dạng biển số xe và các hướng giải quyết trên cơ sở các bài toán cơ bản: Phát hiện vùng chứa biển số xe và bài toán nhận dạng chữ và số trong vùng được phát hiện.
Bài toán nhận dạng biển số xe này xây dựng một mô hình chung tổng quát, để ứng dụng trong thực tế cần giới hạn bớt lại một số điều kiện giúp cho việc tìm kiếm biển số được chính xác hơn, thêm vào đó các mẫu huấn luyện kí tự cần phải được sưu tập nhiều hơn, các vector đặc trưng cũng phải được tính toán tỉ mỉ hơn để giúp cho kết quả nhận dạng có độ chính xác cao hơn nữa. Ngoài ra, còn nhiều khía cạnh khác liên quan đến bài toán ứng dụng này trong thực tế như cần phải xây dựng hệ cơ sở dữ liệu để lưu trữ kết quả, so sánh kết quả, xây dựng hệ thống phần cứng, điều khiển phần cứng để điều khiển hệ thống như các hệ thống thẻ từ RFID, hệ camera, hệ động cơ cho các điều khiển cơ học …
Một lần nữa em xin chân thành cảm ơn các thầy, các cô đã truyền đạt kiến thức để em có thể hoàn thành đồ án có kết quả như mong đợi.
TÀI LIỆU THAM KHẢO
[1]Hoàng Kiếm, Nguyễn Ngọc Kỷ và các tác giả, “Nhận dạng các phương pháp và ứng dụng”, NXB thống kê năm 1992.
[2]Lương Mạnh Bá, Nguyễn Thanh Thủy, “Nhập môn xử lý ảnh số”, NXB KH&KT năm 2003.
[3] Nguyễn Quốc Trung, “Xử lý tín hiệu và lọc số, tập 1”, NXB KH&KT, 2006.
[4] Đỗ Năng Toàn, “Một thuật toán phát hiện vùng và ứng dụng của nó trong quá trình vectơ hóa tự động”, Tạp chí Tin học và Điều khiển, Tập 16 số 1 năm 2000.
[5] Đỗ Năng Toàn, “Biên ảnh và một số tính chất”, Tạp chí KH&CN, Tập 40 số ĐB năm 2002.
PHỤ LỤC
1. Chương trình tải ảnh và hiển thị ảnh trên giao diện MFC
void CHienThiThongTinAnhDlg::OnBnClickedButton1()
{
// Load anh va hien thi anh
static CString Filter=_T("image files (*.bmp; *.jpg) |*.bmp;*.jpg|All
Files(*.*)|*.*||");
CFileDialog Load(TRUE, _T("*.jpg"), NULL,
OFN_FILEMUSTEXIST|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY,Filter, NULL);
Load.m_ofn.lpstrTitle= _T("Load Image");
if (Load.DoModal() == IDOK)
{
path = Load.GetPathName();
std::string filename(path);
src = cv::imread(filename,1);
cv::namedWindow("Hien thi anh", 1);
HWND hWnd = (HWND) cvGetWindowHandle("Hien thi anh");
HWND hParent = ::GetParent(hWnd);
::SetParent(hWnd, GetDlgItem(IDC_STATIC_PICTURE)->m_hWnd);
::ShowWindow(hParent, SW_HIDE);
// resize va hien thi anh
cv::Mat dst;
cv::resize(src, dst, cv::Size(320, 240), 0, 0, 1);
cv::imshow("Hien thi anh", dst);