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.
103 trang |
Chia sẻ: phuongt97 | Lượt xem: 633 | Lượt tải: 0
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:
- va_ung_dung_xu_ly_anh_trong_thuc_the_voi_thu_vien_opencv_cc.pdf