Vă Ứng dụng xử lý ảnh trong thực thế với thư viện OpenCV C/C++

n Long

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 vân

tay chấm công ở các công sở môn học xử lý ảnh ở các trường đại học được xem là

môn học bắt buộc ở một số ngành như công nghệ thông tin, điện tử viễn thông 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.

pdf103 trang | Chia sẻ: phuongt97 | Lượt xem: 633 | Lượt tải: 0download
Bạn đang xem trước 20 trang nội dung tài liệu Vă Ứng dụng xử lý ảnh trong thực thế với thư viện OpenCV C/C++, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
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: o 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]. o 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ố. o 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. 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 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 Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 76 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 phần này ta sử dụng phương pháp SVM để nhận dạng kí tự. Phương pháp SVM. (Chi tiết về phương pháp này bạn đọc có thể tham khảo trong các tài liệu chuyên ngành khác). SVM (Surport Vector Machine) là một mô hình máy học giám sát được dùng trong việc phân tích, phân lớp dữ liệu dựa vào các siêu phẳng. Giả sử ta có một tập dữ liệu hai chiều như hình bên, khi đó 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 gian 3 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-1 chiều. Trong trường hợp dữ dữ liệu là không tuyến tính, 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 một cách đơ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. Quay lại bài toán nhận dạng kí tự biển số xe ta đang xét, làm sao để nhận dạng được các kí tự này dựa trên mô hình 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ó ta 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. 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 được nghiên cứu để đưa ra những phương pháp tốt nhất. Trong phần này ta sẽ tính toán các vector đặc trưng dựa trên ý tưởng của phương pháp Haar, chú ý rằng bạn đọc có áp dụng phương pháp tính toán đặc trưng trong ảnh hay hơn, hiệu quả hơn. Giả sử ta có hai kí tự như hình bên, nhìn bằng mắt thường ta 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ờ Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 77 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 như sau Ta 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) hặ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. Cài đặt chương trình Nhận dạng biển số xe ô tô 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). 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, ta cần huấn luyện và lưu mô hình sau khi huấn luyện. Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 78 Chuẩn bị cơ sở dữ liệu. 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 tự tự ta có 10 ảnh, 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. 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ào mộ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ự. vector calculate_feature(Mat src) { Mat img; if(src.channels() == 3) cvtColor(src, img, CV_BGR2GRAY); threshold(img, img, 100, 255, CV_THRESH_BINARY); vector r; resize(img, img, Size(40, 40)); int h = img.rows/4; int w = img.cols/4; int S = count_pixel(img); int T = img.cols * img.rows; for(int i = 0; i < img.rows; i += h) { for(int j = 0; j < img.cols; j += w) { Mat cell = img(Rect(i,j, h , w)); int s = count_pixel(cell); float f = (float)s/S; r.push_back(f); } } for(int i = 0; i < 16; i+= 4) { float f = r[i] + r[i+1] + r[i+2] + r[i+3]; r.push_back(f); } for(int i = 0; i < 4; ++i) { float f = r[i] + r[i+4] + r[i+8] + r[i+ 12]; r.push_back(f); } r.push_back(r[0] + r[5] + r[10] + r[15]); Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 79 r.push_back(r[3] + r[6] + r[9] + r[12]); ... return r; //32 dac trung } Trong đó hàm count_pixel là hàm tính toán số pixel đen trong một ảnh int count_pixel(Mat img, bool black_pixel = true) { int black = 0; int white = 0; for(int i = 0; i < img.rows; ++i) for(int j = 0; j < img.cols; ++j) { if(img.at(i,j) == 0) black++; else white++; } if(black_pixel) return black; else return white; } Đoạn code sau sẽ huấn luyên một mô hình svm, với đầu vào là một folder chứa dữ liệu huấn luyện như đã nói ở trên (folder này chứa 30 folder con, mỗi folder con chứa 10 kí kí tự mẫu) const int number_of_class = 30; const int number_of_sample = 10; const int number_of_feature = 32; CvSVMParams params; params.svm_type = CvSVM::C_SVC; params.kernel_type = CvSVM::RBF; params.gamma = 0.5; params.C = 16; params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6); SVM svm; Mat data = Mat(number_of_sample * number_of_class, number_of_feature, CV_32FC1); Mat label = Mat(number_of_sample * number_of_class, 1, CV_32FC1); int index = 0; vector folders = list_folder("D:/Data"); for(size_t i = 0; i < folders.size(); ++i) { cout<<i<<"..."<<endl; vector files = list_file(folders.at(i)); Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 80 string folder_path = folders.at(i); string label_folder = folder_path.substr(folder_path.length() - 1); for(size_t j = 0; j < files.size(); ++j) { src = imread(files.at(j)); if(src.empty()) continue; vector feature = calculate_feature(src); if(feature.size() < number_of_feature) { cout<<"error " <<endl; continue; } for(size_t t = 0; t < feature.size(); ++t) data.at(index, t) = feature.at(t); label.at(index, 0) = i; index++; } } svm.train_auto(data, label, Mat(), Mat(), params); svm.save("E:/svm.txt"); Trong đoan chương trình trên, ta lần lượt đọc qua tất cả các folder con trong thư mục D:/Data bằng hàm list_folder (hàm này ta viết dựa trên header dirent.h, với mục đích liệt kê danh sách các folder trong một thư mục), sau đó ta tính toán tất cả các đặc trưng của các ảnh trong các folder này và lưu vào ma trận data. Ma trận label chứa nhãn của các lớp cần nhận dạng, nó cũng chính là tên của các folder tương ứng đã được đánh số thứ tự tăng dần. Hàm train_auto sẽ thực hiện việc huấn luyện một cách tự động và tối ưu các thông số của mô hình. Ở đây các thông số params ta sử dụng chỉ là một trong số nhiều mô cách mà ta có thể đặt thông số. Công cụ cài đặt trong chương trình là một lớp TrainSVM kế thừa từ lớp CDialog tạo ra nhiều tùy chỉnh giúp cho việc đưa các thông số đầu vào, đầu ra một cách dễ dàng hơn. Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 81 Phát hiện và nhận dạng biển số xe Ta 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. 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(); Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 82 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(); }; ở các lớp khác khi sử dụng giao diện này, chỉ việc đưa ảnh đầu vào, đưa mô hình hình svm đã được huấn luyện, gọi hàm do_process và sau đó có thể lấy ra các kết quả như biển số nhận dạng được, kết quả nhận dạng được, thời gian của các quá trình Bản chất của hàm do_process sẽ gọi hàm plate_detection và hàm plate_recognition. Nếu gọi hai hàm này thành công, có nghĩa là quá trình thực hiện đã thành công và ta gán cho biến trạng thái là true void LprCore::do_process() { if(this->plate_detection() && this->plate_recognition()) done = true; } Các hàm lấy kết quả sẽ trả về kết quả tương ứng như biển số, chuỗi kí tự nhận dạng được vector LprCore::get_text_recognition() { if(done) return this->text_recognition; } vector LprCore::get_plate_detection() { if(done) return this->plates; } Ta sẽ xét hai hàm cài đặt hàm chính của lớp đó là hàm bool plate_detection() và hàm char character_recognition(Mat). Hàm bool plate_recognition() thực chất là việc là việc gọi hàm char character_recognition(Mat) cho một chuỗi các ảnh kí tự trong biển số. Hàm bool plate_detection(),trả về kết quả true nếu phát hiện được biển số đồng thời lưu các biển số phát hiện được vào vector vector plates: Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 83 Trước hết,ta thực hiện các phép biến đổi thông thường để thu được một ảnh nhị phân có kết quả tốt, sau đó thực hiện phép tìm đường bao quanh (contour), với mỗi đường bao, ta vẽ hình chữ nhật bao quanh và xem xét các điều kiện của hình chữ nhật đó: cvtColor(image, gray, CV_BGR2GRAY); adaptiveThreshold(gray, binary, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 55, 5); findContours(binary, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) ); if(contours.size() <= 0) return false; for(size_t i = 0; i < contours.size(); ++i) { Rect r = boundingRect(contours.at(i)); if(r.width > image.cols/2 || r.height > image.cols/2 || r.width < 120 || r.height 4.5 || (double)r.width/r.height < 3.5) continue; ... } Nếu các hình chữ nhật bao quanh không thỏa mãn được điều kiện là biển số ta sẽ bỏ qua không xét tiếp nữa mà chuyển tới các đường bao khac. Trong trường hợp thỏa mãn, ta tiếp tục vòng lặp bằng cách tìm các hình bao quanh đối tượng trong hình chữ nhật đó thỏa mãn điều kiện của một kí tự trong biển số xe Mat sub_image = image(r); vector r_characters; for(size_t j = 0; j < sub_contours.size(); ++j) { Rect sub_r = boundingRect(sub_contours.at(j)); if(sub_r.height > r.height/2 && sub_r.width < r.width/8 && sub_r.width > 5 && r.width > 15 && sub_r.x > 5) { Mat cj = _plate(sub_r); double ratio = (double)count_pixel(cj)/(cj.cols*cj.rows); if(ratio > 0.2 && ratio < 0.7) { r_characters.push_back(sub_r); rectangle(sub_image, sub_r, Scalar(0,0,255), 2, 8, 0); } } } Trong đoạn code trên, để thỏa mãn các đường bao quanh đối tượng là một kí tự biển số, ngoài so sách tỉ lệ tương quan dài, rộng của đối tượng so với biển số ta còn so sánh tỉ lệ pixel đen trên tổng số pixel của đối tượng và ta giả sử rằng nếu là một kí tự của biển số thì Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 84 nó nằm trong khoảng 0,2 đến 0,7. Sau bước này, nếu số lượng r_characters lớn một ngưỡng nào đó (thường là > 7) thì ta sẽ công nhận nó r là một vùng chứa biển số, các kí tự cắt ra được sau đó cần phải sắp xếp lại theo thứ tự từ trái sang phải để cho nó tương ứng với thứ tự các chữ cái trong biển số trước khi áp dụng cho việc nhận dạng. Hàm char character_regconition(Mat img_character) trả về kết quả là một kí tự kiểu char với một ảnh đầu vào tương ứng. Để thực hiện việc nhận dạng, đầu tiên ta cần tính toán các đặc trưng của ảnh đầu vào img_character. Việc tính toán các đặc trưng sẽ cho ta một vector chứa các đặc trưng của ảnh đó, ta sẽ dùng hàm predict của dối tượng svm để xem xem vector đó thuộc về lớp nào. Kết quả trả về của hàm predict là một số thực tương ứng với nhãn mà ta đã huấn luyện, có 30 nhãn tương ứng với các số từ 0 – 9 và từ A – Z. Chú ý là không phải tất cả các chữ cái đều được sử dụng, do vậy sau kết quả thu được từ hàm predict cần phải được chuyển đổi sang các kí tự tương ứng. Chú ý là trước khi sử dụng hàm predict để dự đoán ta cần phải load mô hình SVM được huấn luyện từ bước trên. void LprCore::set_svm_model(string file_name) { this->svm.load(file_name.c_str()); ready = true; } Hàm cài đặt cho nhận dạng kí tự như sau: char LprCore::character_recognition(Mat img_character) { char c = '*'; // truong hop khong cho ket qua tra ve * if(img_character.empty()) return c; // neu anh rong if(!ready) return c; // neu chua load mo hinh svm vector feature = calculate_feature(img_character); Mat m = Mat(number_of_feature, 1, CV_32FC1); for(size_t i = 0; i < feature.size(); ++i) m.at(i, 0) = feature[i]; float r = this->svm.predict(m); // du doan mau moi int ri = (int)r; if(ri >= 0 && ri <= 9) c = (char)(ri + 48); //ma ascii 0 = 48 if(ri >= 10 && ri < 18) c = (char)(ri + 55); //ma accii A = 65, --> tu A-H if(ri >= 18 && ri < 22) c = (char)(ri + 55 + 2); //K-N, bo I,J if(ri == 22) c = 'P'; if(ri == 23) c = 'S'; if(ri >= 24 && ri < 27) c = (char)(ri + 60); //T-V, if(ri >= 27 && ri < 30) c = (char)(ri + 61); //X-Z Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 85 return c; } Và cuối cùng, toàn bộ kí tự trong biển số được nhận dạng qua hàm bool plate_recognition() bool LprCore::plate_recognition() { if(plates.size() <= 0 ) return false; double t = (double)cvGetTickCount(); for(size_t i = 0; i < characters.size(); ++i) { string result; for(size_t j = 0; j < characters.at(i).size(); ++j) { char cs = character_recognition(characters.at(i).at(j)); result.push_back(cs); } this->text_recognition.push_back(result); } t = (double)cvGetTickCount() - t; t = (double)t/(cvGetTickFrequency()*1000.); //convert to second process_time.push_back(t); return true; } Giao diện chương trình chính Ta thiết kế 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: Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 86 Các button, label được khai báo trong trong header LPRDlg.h và các hàm xử lý sự kiện được cài đặt trong file LPRDlg.cpp // LPRDlg.h : header file #pragma once #include #include "LprCore.h" #include "afxwin.h" // CLPRDlg dialog class CLPRDlg : public CDialogEx { public: CLPRDlg(CWnd* pParent = NULL); enum { IDD = IDD_LPR_DIALOG }; ... private: cv::Mat src; cv::Mat plate; cv::Mat character; LprCore lpr; string file_name; string text_recognition; // Implementation protected: ... DECLARE_MESSAGE_MAP() public: Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 87 afx_msg void OnUpdateFileOpenimage(CCmdUI *pCmdUI); afx_msg void OnBnClickedButton1(); afx_msg void OnBnClickedButton2(); CStatic text_result; ... }; Menu Open image hoặc button Load Image có chức năng tạo ra các dilog để mở file, file được mở sẽ được đọc, lư vào biến src và sẽ là ảnh đầu vào cho chương trình. // CLPRDlg.cpp void CLPRDlg::OnUpdateFileOpenimage(CCmdUI *pCmdUI) { // Open Image ... CFileDialog dlg(TRUE, _T("*.bitmap"), NULL, ...) if(dlg.DoModal() == IDOK) { file_name = to_string(dlg.GetPathName()); src = imread(file_name); if(src.empty()) return; ... } } Button Show Result sẽ thực hiện các hàm xử lý và hiển thị kết quả khi nó được nhấn vào. // CLPRDlg.cpp void CLPRDlg::OnBnClickedButton2() { // Show results if(src.empty()) return; Mat disp_plate, disp_character; lpr.set_image(src); lpr.do_process(); vector plates = lpr.get_plate_detection(); vector characters = lpr.get_character_isolation(); vector t = lpr.get_process_time(); vector text = lpr.get_text_recognition(); if(plates.size() > 0) { plate = plates[0]; resize(plate, disp_plate, Size(280,50)); imshow("plate", disp_plate); character = characters[0]; resize(character, disp_character, Size(280,50)); imshow("character", disp_character); text_recognition = text[0]; Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 88 text_result.SetWindowTextW(to_wstring(text_recognition)); num_plate.SetWindowTextW(to_wstring((int)plates.size())); time_detection.SetWindowTextW(to_wstring(t[0]) + " ms"); ... } else { ... } } Trong đoạn code trên, ta sẽ kiểm kiểm tra xem ảnh đầu vào có rỗng không trước khi đặt nó vào đối tượng lpr để thực hiện các phép xử lý. Sau khi thực hiện các phép xử lý, ta sẽ kiểm tra xem nếu như kết quả đầu ra mà lớn hơn một biển số (plates.size() > 0) thì ta sẽ hiển thị các kết quả lên. Lưu ý là hiện tại ta mới chỉ hiển thị kết quả đầu tiên, trong trong ảnh có nhiều hơn một biển số ta có thể lần lượt hiển thị các kết quả đó một cách dễ dàng. Ngoài ra, chương trình còn có một số menu khác nhằm giúp 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: Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 89 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ế ta 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 quanh đế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 Ng uy ễn V ăn L on g Ứng dụng xử lý ảnh trong thực tế với thư viện OpenCV Tác giả: Nguyễn Văn Long – long.06clc@gmail.com Page 90 3. MyCam, một số hiệu ứng ảnh với video. Trong phần này, ta sẽ tạo một chương trình có thể thu nhận ảnh từ webcam và bằng các hàm xử lý ảnh đơn giản như trong các ví dụ trên để tạo ra những hiệu ứng video đẹp mắt, chương trình có một số chức năng chính như: thu nhận video từ webcam, các chức năng xử lý video dựa trên các hàm xử lý ảnh (làm mờ, làm méo, chuyển đổi không gian màu ) chức năng chụp hình, ghi hình, điều chỉnh một số thông số Nhưng trước hết chúng ta hãy tìm hiểu cấu trúc của một video, cách xử lý trên video và sự hỗ trợ của thư viện OpenCV để làm việc với video như thế nào. Cấu trúc của một file video. Ta thường xem một bài clip ca nhạc, một bộ phim trên máy tính, trên Youtube Chúng được gọi chung là một video. Một file video có thể có nhiều định dạng khác nhau như avi, mp4, mov , xét về cầu trúc, một file video được tạo nên từ nhiều thành phần khác nhau gọi là các track, chẳng hạn như track về video, track về audio, track về phụ đề Ta cần phải phân biệt về định dạng một file video (file extention) và bộ giải mã video (video codec). Định dạng file, chẳng hạn như avi, mp4, mov, flv

Các file đính kèm theo tài liệu này:

  • pdfva_ung_dung_xu_ly_anh_trong_thuc_the_voi_thu_vien_opencv_cc.pdf