Thông báo

Tất cả đồ án đều đã qua kiểm duyệt kỹ của chính Thầy/ Cô chuyên ngành kỹ thuật để xứng đáng là một trong những website đồ án thuộc khối ngành kỹ thuật uy tín & chất lượng.

Đảm bảo hoàn tiền 100% và huỷ đồ án khỏi hệ thống với những đồ án kém chất lượng.

ĐỒ ÁN TỐT NGHIỆP ĐIỆN TỬ ỨNG DỤNG XỬ LÝ ẢNH BẰNG THUẬT TOÁN SVM

mã tài liệu 301000100146
nguồn huongdandoan.com
đánh giá 5.0
mô tả 110 MB Bao gồm tất cả file thuyết minh, code, chương trình mô phỏng bằng ngôn ngữ C++.... ,nhiều tài liệu liên quan kèm theo ĐỒ ÁN TỐT NGHIỆP ĐIỆN TỬ ỨNG DỤNG XỬ LÝ ẢNH BẰNG THUẬT TOÁN SVM
giá 989,000 VNĐ
download đồ án

NỘI DUNG ĐỒ ÁN

ĐỒ Á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 …

  1. 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   circles;

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 typeConsole applicationAdditional optionEmpty 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 AdditionalDependenciesopencv_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) ≤ Tf(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.hLPRDlg.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.hLprCore.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.hTrainSVM.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 get_text_recognition();

vector get_plate_detection();

vector get_character_isolation();

vector> get_character();

vector get_process_time();

void clear();

private:

bool done;


bool ready;

SVM svm;

Mat image;

vector plates;

vector draw_character;

vector> characters;

vector text_recognition;

vector process_time;

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

Close