Tải bản đầy đủ (.docx) (56 trang)

ỨNG DỤNG XỬ LÝ ẢNH NHẬN DẠNG BIỂN SỐ XE SỬ DỤNG THUẬT TOÁN SVM

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.44 MB, 56 trang )

Mục lục

MỤC LỤC
DANH MỤC CÁC TỪ VIẾT TẮT
MỞ ĐẦU
CHƯƠNG 1 : LÀM QUEN VỚI THƯ VIỆN OPENCV
1.1 Giới thiệu chương
1.2 So sánh phiên bản OpenCV 1 và OpenCV 2
1.3 Hướng dẫn sử dụng thư viện Open CV trên Window
1.4 Kết luận chương
CHƯƠNG 2 : CÁC PHÉP XỬ LÝ ẢNH ĐƠN GIẢN TRONG OPENCV
2.1 Giới thiệu chương
2.2 Chương trình đầu tiên
2.3 Ảnh nhị phân, nhị phân hóa với ngưỡng động
2.4 Các phép toán hình thái học trong ảnh
2.4.1 Phép toán giãn nở (dialation)
2.4.2 Phép toán co (erosion)
2.4.3 Phép toán đóng và mở (closing & opening)
2.5 Kết luận chương
CHƯƠNG 3 : LẬP TRÌNH XỬ LÝ ẢNH VỚI GIAO DIỆN MFC
3.1 Giới thiệu chương
3.2 Khởi tạo project MFC
3.3 Là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
3.3.2 Lấy giá trị nhập vào từ một Edit Control
3.3.3 Hiển thị các test lên các control
3.3.4 Hiển thị ảnh lên một control
3.3.5 Enable, disnable một control
3.3.6 Lấy giá trị từ thanh trược (Slider control)
3.3.7 Lấy giá trị lựa chọn từ Combo Box
3.3.8 Dialog mở file và lưu file


3.3.9 Xử lý sự kiện khi click chuột vào button
1


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

3.3.10 Xử lý sự kiện khi thay đổi lựa chọn Combo box
3.3.11 Thêm menu vào chương trình, xử lý sự kiện khi click vào menu
3.4 Chuyển đổi các kiểu dữ liệu trong MFC
3.5 Chương trình tải ảnh và hiển thị ảnh trên giao diện MFC
3.6 Kết luận chương
CHƯƠNG 4: NHẬN DẠNG BIỂN SỐ XE BẰNG THUẬT TOÁN SVM
4.1 Giới thiệu chương
4.2 Phát hiện vùng chứa biển số xe và cách ly kí tự.
4.3 Nhận dạng kí tự
4.3.
4.3.2 Tính toán đặt trưng trong ảnh
4.4 Cài đặt chương trình nhận dạng biển số xe ô tô
4.4.1 Huấn luyện mô hình SVM
4.5 Phát hiện và nhận dạng biển số xe
4.6 Giao diện chương trình chính
4.7 Kết luận chương
KẾT LUẬN – HƯỚNG PHÁT TRIỂN
TÀI LIỆU THAM KHẢO
PHỤ LỤC

DANH MỤC CÁC TỪ VIẾT TẮT

2



Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

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

3


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

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.

4


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

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:

5


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

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:

6


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

// 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<Vec3f> 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ỉ />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

7


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

thường, để mặc định thư mục cài đặt là C:\ thư mục cài đặt xong sẽ có dạng
C:\opencv. Tiếp theo tiến hành tùy chỉnh để có thể làm việc với OpenCV qua hai
IDE thông dụng là Microsoft Visual Studio và Eclipse .
Trên Microsoft Visual Studio

Phiên bản Visual studio sử dụng ở đây là phiên bản Visual Studio 2010, các
phiên bản trước hoàn toàn có thể cấu hình một cách tương tự.
Tạo một project mới: New > Project, trong cửa sổ New Project chọn Visual C++,
Win32 Console Application. Đặt tên project là opencv.

Hình 1.1
Chọn OK, sau đó nhấn Next, hộp thoại tiếp theo xuất hiện, ở hộp thoại này chọn
Application type là Console application và Additional option là Empty project, nhấn
Finish để kết thúc quá trình khởi tạo.

8


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

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

click

chuột

Explorer

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

file thêm vào, giả sử




FirstApp.cpp.

9

cho


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

Hình 1.3
Bây giờ trong file này chúng ta có thể thêm vào các #include và gọi hàm main() để
chạy chương trình.
Để chương trình có thể chạy được với thư viện OpenCV thì cần tùy chỉnh
lại một số thuộc tính của project như sau : Vào Project -> Properties (hoặc nhấn tổ
hợp phím Alt + F7) để mở hộp thoại Properties. Hộp thoại opencv Property
Pages hiện ra, trong mục Configuration Properties chọn VC++ Directories,
tương ứng bên phải, tìm mục Include Directories và LibraryDirectories.
Chúng ta sẽ chỉ đường dẫn hai thư mục này đến các phần tương ứng của thư
việnOpenCV.
Mục Include Directories, ta tùy chỉnh ở ô bên phải tới C:\opencv\build\include
Mục Library Directories trỏ đến thư mục C:\opencv\build\x86\vc10\lib nếu
như sử dụng hệ điều hành 32bit hoặc C:\opencv\build\x64\vc10\lib cho hệ điều hành
64bit.
Tiếp theo, trong hộp thoại opencv Property Pages -> Configuration Properties
-> Linker chọn Input, tương ứng ở ô bên phải, thêm vào các giá trị cho mục
AdditionalDependencies
làopencv_core243d.lib,opencv_imgproc243d.lib,opencv_highgui243d.lib.

Hình 1.4


10


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

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 <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
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.

11


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

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 <iostream>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\core\core.hpp>
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

12


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

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



ả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:

13


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

Hình 2.1
2.3 Ảnh nhị phân, nhị phân hóa với ngưỡng động
Ảnh nhị phân là ảnh mà giá trị của các điểm ảnh chỉ được biểu diễn bằng hai
giá trị 0 hoặc 255 tương ứng với hai màu đen hoặc trắng. Nhị phân hóa một ảnh là

quá trình biếnmột ảnh xám thành ảnh nhị phân. Gọi f(x,y) là giá trị cường độ sáng
của một điểm ảnh ở vị trí (x,y),T là ngưỡng nhị nhị phân. Khi đó, ảnh xám f sẽ được
chuyển thành ảnh nhị phân dựa vào công thức f(x,y) = 0 nếu f(x,y) ≤ T và f(x,y)
=255 nếu f(x,y) > T
Hình sau mô tả một ảnh nhị phân với ngưỡng nhị phân T = 100

14


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

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.

15


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv


Hình 2.3
Để thu được một ảnh nhị phân tốt mà không cần phải quan tâm tới các điều kiện
ánh sáng khác nhau (không cần quan tâm tới ngưỡng T), người ta dùng một kĩ thuật
sao cho với mọi ngưỡng xám khác nhau ta luôn thu được một ảnh nhi phân tốt. Kĩ
thuật đó gọi là kĩ thuật nhị phân hóa với ngưỡng động (Dymamic threshold) hay nhị
phân thích nghi (Adaptive threshold).
Có nhiều phương pháp khác khác nhau để thực hiện việc này, tuy nhiên chúng
đều dựa trên ý tưởng chính là chia ảnh ra thành những vùng nhỏ, với mỗi vùng áp
dụng việc nhị phân cho vùng đó với những ngưỡng nhị phân khác nhau. Các
ngưỡng nhị phân ở các vùng được tính toán dựa trên độ lớn mức xám của chính các
pixel trên vùng đó. Giả sử ta tính toán ngưỡng cho một vùng nào đó dựa trên độ
trung bình của các pixel trong vùng đó (có thể xem một vùng là một cửa sổ). Ta xét
quá trình nhị phân với ngưỡng động trong một vùng cửa sổ 5x5:

16


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

Hình 2.4
Vùng ảnh nhị phân thu được ở trên là vùng ảnh được nhị phân với ngưỡng là trung
bình cộng của tất cả các ô trong cửa sổ T = (55 + 10 + 100 + …)/25 = 65.6.
Chương trình nhị phân hóa với ngưỡng động như sau:
// Adaptive Threshold
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
using namespace std;

using namespace cv;
int main()
{
cout<<"Nhi phan anh voi nguong dong"<Mat src = imread("Thap_But.jpg", CV_LOAD_IMAGE_GRAYSCALE);
Mat dst;
adaptiveThreshold(src, dst, 255, CV_ADAPTIVE_THRESH_MEAN_C,
CV_THRESH_BINARY, 35, 5);
imshow("Anh xam goc", src);
imshow("Anh nhi phan voi nguong dong", dst);
waitKey(0);

17


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

return 1;
}
Trong chương trình trên, hàm thực hiện việc nhị phân hóa với ảnh động
là hàm adaptiveThreshold. Nguyên mẫu của hàm như xau:
cv::adaptiveThreshold(cv::InputArray src,OutputArray dst, double maxValue,
int adaptiveMethod, int thresholdType, int blockSize, double C)
Trong đó, src là ảnh xám cần nhị phân, dst là ảnh kết quả thu được, maxValue
là giá trị lớn nhất trong ảnh xám (thông thường là 255), adaptiveMethod là cách
thức nhị phân với ngưỡng động, nó chính là cách tính giá trị ngưỡng nhị phân trong
từng vùng cần nhị phân, thresholdType như đã nói ở trên, blockSize là kích thước
của sổ áp dụng cho việc tính toán ngưỡng động, và C là một thông số để bù trừ
trong trường hợp ảnh có độ tương phản quá lớn.
Kết quả khi chạy chương trình như sau:


Hình 2.5

18


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

2.4 Các phép toán hình thái học trong ảnh
Các phép toán hình thái học là những phép toán liên quan tới cấu trúc hình học
(hay topo) của các đối tượng trong ảnh. Các phép toán hình thái học tiêu biểu bao
gồm phép giãn nở (dialation), phép co (erosion), phép mở (opening) và phép đóng
(closing).
2.4.1 Phép toán giãn nở (dialation)
Phép toán giãn nở được định nghĩa A B = với x trong đó, A là đối tượng trong
ảnh, B là một cấu trúc phần tử ảnh. Phép toán này có tác dụng làm cho đối tượng
ban đầu trong ảnh tăng lên về kích thước (giãn nở ra).
Cấu trúc phần tử ảnh (image structuring element) là một hình khối được định
nghĩa sẵn nhằm tương tác với ảnh xem nó có thỏa mãn một số tính chất nào đó
không, một số cấu trúc phần tử hay gặp là cấu trúc theo khối hình vuông và hình
chữ thập.

Hình 2.6
Xét một ảnh với đối tượng trong ảnh được biểu diễn bằng màu nền nâu, sau đó
dùng cấu trúc phần tử hình vuông (màu đỏ) để làm giãn nở ảnh, kết quả là ảnh được
giãn nở ra, chúng ta đánh dấu là dấu x.

19



Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

Hình 2.7
Ứng dụng của phép giãn nở là làm cho đối tượng trong ảnh được tăng lên về
kích thước, các lỗ nhỏ trong ảnh được lấp đầy, nối liền đường biên ảnh đối với
những đoạn rời nhỏ…
2.4.2 Phép toán co (erosion)
Phép toán co được định nghĩa A = {x |} trong đó A là đối tượng trong ảnh, B là
cấu trúc phần tử ảnh. Ta cũng sẽ xét một ví dụ như trên với phép co trong ảnh. Đối
tượng trong ảnh được biểu diễn bởi màu xám, cấu trúc phần tử ảnh là khối có viền
màu đỏ, x là điểm sau phép thỏa mãn phép co ảnh, 0 là điểm không thỏa mãn.

Hình 2.8

20


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

Nhận thấy rằng sau phép toán này đối tượng trong ảnh bị co lại, chính vì vậy
mà nó được ứng dụng trong việc giảm kích thước của đối tượng, tách rời các đối
tượng gần nhau và làm mảnh, tìm xương đối tượng.
2.4.3 Phép toán đóng và mở ảnh (closing & opening)
Phép toán mở (opening) và đóng (closing) là sự kết hợp của phép co (erosion)
và phép giãn nở (dialation), chúng được định nghĩa như sau :
+ Phép toán mở : Opening(I) = D(E(I))
+ Phép toán đóng : Close(I) = E(D(I))
Phép toán mở được ứng dụng trong việc loại bỏ các phần lồi lõm và làm cho
đường bao quanh đối tượng trong ảnh trở nên mượt mà hơn.
Phép toán đóng được ứng dụng trong việc làm trơn đường bao quanh đối tượng,

lấp đầy các khoảng trống trên biên và loại bỏ những hố nhỏ (một số pixel đứng
thành cụm độc lập)
Trong OpenCV, các phép toán hình thái học trong ảnh được cài đặt trong hàm
cv::morphologyEx, riêng phép giãn nở và phép co có thể gọi trực tiếp từ hàm
cv::dilate và cv::erode: morphologyEx(const Mat& src, Mat& dst, int op, const
Mat& element, Point anchor, int iterations, int borderType, const Scalar&
borderValue)
Trong đó src, dst là ảnh đầu vào và ảnh sau phép xử lý hình thái học. op là kiểu
lựa chọn phép hình thái học, chẳng hạn như phép giãn nở là MORPH_DILATE,
phép đóng là MORPH_OPEN… element là cấu trúc phần tử ảnh, có ba cấu trúc cơ
bản là theo khối hình vuông, hình chữ thập và hình elip. Để tạo ra các cấu trúc này
ta có thể tự định nghĩa một ma trận với các hình khối tương ứng hoặc sử dụng hàm
getStructuringElement, hàm này có cấu trúc như sau: getStructuringElement(int
shape, Size ksize, Point anchor), với shape là kiểu hình khối (một trong 3 hình khối
trên), ksize là kích thước của hình khối và là kích thước của hai số nguyên lẻ,
anchor là điểm neo và thông thường nhận giá trị là((ksize.width – 1)/2, (ksize.height
– 1)/2). Thông số tiếp theo anchor cũng có ý nghĩa tương tự. iterations là số lần lặp

21


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

lại của phép toán hình thái và hai thông số cuối cùng là về giới hạn biên của những
điểm ảnh nằm ngoài kích thước ảnh trong quá trình tính toán.
Phép toán về giản nở và co có thể được gọi từ hàm cv::morphologyEx thông
qua hai đối số op là MORPH_DILATE và MORPH_ERODE hoặc chúng có thể
được gọi trực tiếp từ hàm cv::dilate và cv::erode, Cấu trúc của hai hàm này là
tương tự nhau và các tham số hoàn toàn giống với tham số trong hàm
morphologyEx:

dilate(const Mat& src, Mat& dst, const Mat& element, Point anchor=Point(-1, -1),
int iterations, int borderType, const Scalar& borderValue)
Một điều cần chú ý là trái với cách diễn đạt về các phép hình thái như trên,
OpenCV có cách cài đặt ngược lại giữa đối tượng và nền ảnh, nghĩa là trong phép
giản nở (dilate), phần được giản nở là nền của ảnh (background) chứ không phải các
đối tượng vật thể trong ảnh, điều đó cũng có nghĩa rằng phép giản nở sẽ làm co lại
các đối tượng vật thể trong ảnh và phép co (erode) sẽ làm co nền của ảnh đồng thời
giản nở các đối tượng vật thể trong ảnh.
Sau đây chúng ta sẽ xét một ví dụ về việc sử dụng các phép toán hình thái trong
ảnh trong việc phát hiện biển số xe ô tô và cách ly các kí tự trong biển số. Giả sử ta
có một ảnh chứa biển số, vì biển số có nền trắng và kí tự màu đen, nên trước tiên ta
nhị phân ảnh đó, sau đó tìm đường bao của các đối tượng (contour) để từ đó xác
định được xem những đường bao nào có khả năng là biển số xe nhất dựa trên tỉ lệ
các cạnh chiều dài, rộng của hình chữ nhật bao quanh đường bao đó (đây là một
cách tiếp cận rất đơn giản). Tuy nhiên, chỉ xác định được đường bao quanh đối
tượng khi tập các điểm nằm trên biên của nó tạo thành một vùng kín. Trong nhiều
trường hợp của biển số, việc bị mất một vài điểm ảnh trong quá trình nhị phân trên
biên là chuyện thường xuyên xảy ra và do đó sẽ khó xác định được một đường bao
quanh biển số. Để khắc phục tình trạng này, ta sẽ làm giãn nở đường biên (điều đó
sẽ tương đương với việc gọi hàm erode để làm co lại nền ảnh) để các điểm ảnh trên
biên trở nên liền hơn.

22


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

#include "stdafx.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
void main()
{
Mat src1 = imread("BienSo.jpg", CV_LOAD_IMAGE_COLOR);
Mat src2 = src1.clone(); // copy anh
Mat gray, binary;
cvtColor(src1, gray, CV_BGR2GRAY);
threshold(gray, binary, 100, 255, CV_THRESH_BINARY);
imshow("Anh nhi phan goc", binary);
Mat morpho;
Mat element = getStructuringElement(MORPH_CROSS, Size(3,3),
Point(1,1));
erode(binary, morpho, element, Point(-1,-1), 3);
imshow("Anh sau khi thuc hien phep gian no", morpho);
vectorfindContours(binary, contours1, CV_RETR_LIST, CV_CHAIN_APPROX_NONE );
for(size_t i = 0; i < contours1.size(); i++)
{
Rect r = boundingRect(contours1[i]);
if(r.width/(double)r.height > 3.5f && r.width/(double)r.height <4.5f)
rectangle(src1, r, Scalar(0, 0, 255), 2, 8, 0);
else
rectangle(src1, r, Scalar(0, 255, 0), 1, 8, 0);

23


Chương 2: Các phép xử lý ảnh đơn giản trong Opencv


}
imshow("Ket qua phat hien truoc phep gian no", src1);
vectorfindContours(morpho, contours2, CV_RETR_LIST, CV_CHAIN_APPROX_NONE );
for(size_t i = 0; i < contours2.size(); i++)
{
Rect r = boundingRect(contours2[i]);
if(r.width/(double)r.height > 3.5f && r.width/(double)r.height <4.5f)
rectangle(src2, r, Scalar(0, 0, 255), 2, 8, 0);
else
rectangle(src2, r, Scalar(0, 255, 0), 1, 8, 0);
}
imshow("Ket qua phat hien sau khi phep gian no", src2);
waitKey(0);
}
Trong chương trình trên, chúng ta lần lượt thực hiện tìm biên với hai ảnh nhị
phân, một ảnh nhị phân thông thường và một ảnh nhị phân đã được làm giản nở
thông qua hàm erode. HàmfindContours sẽ tìm đường bao quanh của các đối tượng
đã được nhị nhâp hóa và lưu đường bao này vào một vector là các điểm nằm trên
đường bao đó, hàm boundingRect sẽ tìm ra một hình chữ nhật bao một tập điểm của
một đường bao được tìm ra từ hàm findContours. Dựa vào tỉ lệ kích thước chiều
dài/rộng của hình chữ nhật này ta có thể xem xét liệu đường bao mà ta tìm được có
phải là một vùng của biển số hay không, nếu phải ta sẽ vẽ hình chữ nhật này thông
qua hàm rectangle với một màu khác (Scalar(0, 0, 255) :màu đỏ) và nét đậm hơn.
Kết quả chạy chương trình như sau:

24



Chương 2: Các phép xử lý ảnh đơn giản trong Opencv

Hình 2.9
Nhận thấy rằng, điểm đứt trong ảnh được nối liền nhờ sự giãn nở của biển cạnh
biển số (sự co lại của nền ảnh) nên ta tìm được một hình bao khép kín quanh biển
số, tuy nhiên ta cũng nhận thấy rằng khi các đối tượng vật thể trong ảnh giãn nở ra,
các kí tự sẽ có xu hướng dính vào nhau và việc tách các kí tự ra là khó khăn, chẳng
hạn trên hình do có đinh vít ở giữa mà số 2 và số 9 gần như nối liền. Đây là lúc cần
phải thực hiện việc co lại của các đối tượng (sự giãn nở của nền ảnh), và do đó
chúng ta hoàn toàn có thể cài đặt để tách ra các kí tự này.
2.5 Kết luận chương
Đây là công đoạn đầu tiên mang tính quyết định đối với quá trình xử lý ảnh.
Ảnh đầu vào sẽ được thu nhận qua các thiết bị camera, máy scanner…và sau đó tín
hiệu này sẽ được số hóa và qua các công đoạn xử lý như trên với mục đích nâng cao
chất lượng ảnh để chuẩn bị cho các bước xử lý phức tạp hơn về sau.

25


×