SlideShare ist ein Scribd-Unternehmen logo
1 von 103
Downloaden Sie, um offline zu lesen
NguyễnVănLong
Ứ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 1
Ứng dụng xử lý ảnh trong thực thế với thư
viện OpenCV C/C++
Nguyễn Văn Long
long.06clc@gmail.com
NguyễnVănLong
Ứ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 2
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 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.
Xuất phát từ thực tế rằng môn học xử lý ảnh ở các trường đại học là một môn học mang
nặng tính học thuật, khô khan, các vấn đề được mô tả dưới dạng toán học, sinh viên nắm
bắt môn học một cách chung chung mà không đi vào bản chất vấn đề, ứng dụng thực tiễn
của môn học, thêm vào đó số lượng tài liệu về chuyên ngành này bằng tiếng Việt là không
nhiều, bằng quá trình nghiên cứu nghiêm túc, kinh nghiệm thực tế tác giả đã cố gắng cho
ra đời cuốn sách Ứng dụng xử lý ảnh trong thưc tế với thư viện OpenCV.
Cuốn đề cập tới một số phần của lĩnh vực xử lý ảnh và thị giác máy, thông qua sự diễn
giải trực quan, không xa vào những công thức toán học trừu tượng, phức tạp nhưng vẫn
làm nổi bật nên được vấn đề, giúp người đọc có được cái nhìn tổng quát, hiểu được khái
niệm và hơn nữa biết được những vấn đề đó ứng dụng vào thực tế như thế nào. Các chủ
đề trong cuôn sách này đều đi kèm với một chương trình mô phỏng được viết bằng ngôn
ngữ C++ với sự giúp đỡ của thư viện OpenCV, một thư viện mã nguông 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.
Cuốn sách được chia thành bốn phần, phần đầu giới thiệu về thư viện OpenCV, phần thứ
hai nói về một số vấn đề chọn lọc thường gặp trong xử lý ảnh như không gian màu, các
bộ lọc, cách phát hiện đường thẳng đường tròn trong ảnh …, phần thứ ba nói về một số
thủ thuật để lập trình với thư viện MFC và phần cuối cùng nói về một số ứng dụng thực tế
như bài toán nhận dạng biển số xe …
Cuốn sách không chỉ là tài liệu tham khảo bổ ích trong quá trình học tập của các bạn sinh
viên, quá trình làm luận văn, đồ án … mà còn là công cụ tốt hỗ trợ cho việc triển khai các
ứng dụng thương mại của các kĩ sư, doanh nghiệp và những người quan tâm tới lĩnh vực.
Cuối cùng dù đã dành nhiều tâm huyết để hoàn thành cuốn sách nhưng chắc chắn cuốn
sách vẫn còn nhiều sai xót, tác giả mong được sự góp ý của bạn đọc. Xin gửi lời chúc tốt
tốt đẹp và lời cảm ơn sâu sắc tới độc giả
NguyễnVănLong
Ứ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 3
Hướng dẫn sử dụng sách
Cuốn sách được viết dựa trên những nghiên cứu và quá trình làm việc thực tế của tác giả,
với mỗi vấn đề nêu trong sách bạn đọc có thể đọc qua để nắm bắt được ý tưởng chính, sau
đó có thể tìm thêm tài liệu để nâng cao hơn vấn đề và có thể thực hành dựa vào mẫu
chương trình, source code đi kèm.
Thư viện OpenCV được viết trong sách là bản OpenCV 2.4.3, đối với các bản OpenCV
khác thì bạn đọc có thể tùy chỉnh lại một chút tuy nhiên về bản chất của vấn đề là tương
đối giống nhau. Ngôn ngữ lập trình cho các ví dụ là C/C++, IDE sử dụng là Visual Studio
2010. Tuy nhiên đa số chương trình trong cuốn sách này đều được tách biệt phần xử lý
chính ra vào một file *.cpp nào đó nên ta có thể lấy nó để áp dụng vào các trình dịch
khác.
Có 10 chủ đề chính bao quát một số khía cạnh của lĩnh vực xử lý ảnh được viết khá chi
tiết và giải thích đầy đủ, 3 project được tác giả mô tả chung chung hơn. Do đó bạn đọc
nếu chưa thực sự quen với thư viện OpenCV nên đọc theo thứ tự từ đầu tới cuối
Trong cuốn sách có nhiều vấn đề liên quan tới kĩ thuật lập trình nhưng do phạm vi giới
hạn, tác giả chỉ có thể nói qua được một số khía cạnh, trên thực tế có nhiều cách khác
nhau để giải quyết cùng một công việc, với những vấn đề lập trình bạn đọc chưa rõ có thể
tham khảo thêm tài ở các nguồn khác nhau hoặc giải quyết theo hướng mà bạn đọc cảm
thấy là thỏa đáng nhất
NguyễnVănLong
Ứ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 4
Mục Lục
Chương I. Làm quen với thư viện OpenCV
1. Giới thiệu về thư viện OpenCV 5
2. Phiên bản OpenCV 1 hay OpenCV 2 5
3. Hướng dẫn sử dụng OpenCV trên Window 6
Chương II. Các phép xử lý đơn giản trong OpenCV
1. Chương trình đầu tiên 12
2. Không gian màu, chuyển đổi không gian màu 13
3. Điều chỉnh độ sang, độ tương phản 17
4. Ảnh nhị phân, nhị phân hóa với ngưỡng động 19
5. Histogram, cân bằng histogram 23
6. Phóng to, thu nhỏ, xoay ảnh 27
7. Lọc số trong ảnh 30
8. Các phép toán hình thái học trong ảnh 37
9. Tìm biên ảnh với bộ lọc Canny 43
10.Chuyển đổi Hough, Phát hiện đường thẳng, đường tròn trong ảnh 46
Chương III. Lập trình xử lý ảnh với giao diện MFC
1. Giới thiệu về MFC 51
2. Khởi tạo project MFC 51
3. Làm việc với các điều khiển (Control) 54
4. Chuyển đổi các kiểu dữ liệu trong MFC 59
5. Chương trình tải ảnh và hiển thị ảnh lên giao diện MFC 61
Chương IV. Một số ứng dụng trong thực tế
1. My Photo Editor, phần mềm chỉnh sửa ảnh đơn giản 64
2. Nhận dạng biển số xe 73
3. MyCam, một số hiệu ứng ảnh trong video 90
NguyễnVănLong
Ứ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 5
Chương I. Làm quen với thư viện OpenCV
1. Giới thiệu về thư viện OpenCV
OpenCV (Open Source Computer Vision) là 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 đó bạn 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.
2. Phiên bản OpenCV 1 hay 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 ta sẽ chỉ ra 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, 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.
NguyễnVănLong
Ứ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 6
- 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 ta hãy
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 1.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);
Ta thấy rằng đố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 ta 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 cuốn sách 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.
3. Hướng dẫn sử dụng thư viện OpenCV trên Window
NguyễnVănLong
Ứ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 7
Trước hết ta cần 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 cuốn sách này là
bản 2.4.3 với lần update cuối cùng là vào ngày 25 tháng 12 năm 2012. Sau khi download
về máy, tiến hành cài đặt bình thường, ta để 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 ta sẽ 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 CDT
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 ta 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
Chọn OK, sau đó nhấn Next, hộp thoại tiếp theo xuất hiện, ở hộp thoại này ta 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
NguyễnVănLong
Ứ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 8
Project mới được tạo ra là project hoàn toàn trố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 ta
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.
Bây giở trong file này 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 ta 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, ta tìm mục Include Directories và Library
Directories. Ta sẽ chỉ đường dẫn hai thư mục này đến các phần tương ứng của thư viện
OpenCV.
Mục Include Directories, ta tùy chỉnh ở ô bên phải tới C:opencvbuildinclude
Mục Library Directories trỏ đến thư mục C:opencvbuildx86vc10lib nếu như ta sử
dụng hệ điều hành 32bit hoặc C:opencvbuildx64vc10lib cho hệ điều hành 64bit.
NguyễnVănLong
Ứ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 9
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 Additional
Dependencies là opencv_core243d.lib, opencv_imgproc243d.lib, opencv_highgui243d.lib.
Chú ý là
các lib thêm vào sẽ tương ứng với các
header ta khai báo trong chương trình, và
tùy thuộc vào mục đích sử dụng mà ta có
thể thêm vào các lib các nhau, giả sử ta cần
sử dụng tới các hàm về video, khi đó ta
thêm header #include
<opencv2/video/video.hpp> thì trong phần
Additional Dependencies ta phải khai báo
thêm opencv_video243d.lib. Chữ d đứng
cuối các file trên thể hiện ta đ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. Tuy nhiên khi đang còn học tập và cần nhiều chỉnh sửa ta nên để ở chế độ debug.
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ác
file *.dll. Cách đơn giản nhất là 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ương
trình (file *.exe). Các file *.dll này nằm trong mục C:opencvbuildx86bin với win 32 bit
hoặc C:opencvbuildx64bin 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àm
việ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()
{
...
}
NguyễnVănLong
Ứ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 10
Với Eclipse CDT
Khởi động Eclipse, Từ cửa sổ Eclipse chọn New -> C++ Project , hộp thoại C++ Project
xuất hiện, trong hộp thoại ta chọn Project name là opencv, Project type là Hello World
C++ Project (Có thể chọn là Empty
Project), Toolchains là MinGW GCC,
Chọn Finish và ta có một Project mới.
Bây giờ tùy chỉnh cho project này hoạt
động được với OpenCV.
Trong cửa sổ của Eclipse chọn Project -
>Properties, cửa sổ Properties hiện ra.
Tron cửa sổ Properties chọn C/C++
Build->Settings. Trong tab Tool Settings.
Ở phần GCC C++ Compiller chọn
Include rồi dẫn đường dẫn tới mục
Include của OpenCV
là C:opencvbuildinclude. Trong phần
MinGW C++ Linker chọn Library và
chọn các mục như sau: click vào dấu
cộng ở Library search path (-L) và dẫn
tới thư mục
lib: C:opencvbuildx86mingwlib đối
với Windows 32 bit hoặc
C:opencvbuildx64mingwlib đối với
Windows 64 bit. Tiếp đó click vào dấu "cộng" để thêm Library(-I) vào, các library cần
thêm lần lượt là: opencv_core243, opencv_highgui243, opencv_imgproc243 ... nói chung
là tùy vào nhu cầu sử dụng có thể thêm một hoặc nhiều lib vào.
NguyễnVănLong
Ứ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 11
Ta cũng cần phải copy các *.dll tương ứng vào thư mục chứa file chạy *.execủa chương
trình để chương trình có thể chạy thành công.
NguyễnVănLong
Ứ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 12
Chương II. Các phép xử lý ảnh và ứng dụng cơ bản
1. Chương trình đầu tiên
Trong bài này ta sẽ tìm hiểu một ví dụ đầu tiên như 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 <opencv2highguihighgui.hpp>
#include <opencv2corecore.hpp>
using namespace std;
using namespace cv;
int main()
{
cout<<"Chuong trinh dau tien"<<endl;
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ì ta phải chỉ ra đường dẫn tương đối dạng như D:Anhvietnam.jpg hoặc
D://Anh//Vietnam.jpg. Flags là tham số loại ảnh mà ta muốn load vào, cụ thể nếu nếu
muốn load ảnh mầu thì ta để CV_LOAD_IMAGE_COLOR, nếu là ảnh xám thì ta để
CV_LOAD_IMAGE_GRAYSCALE…
Sau khi đã load ảnh thành công, muốn hiển thị ảnh lên màn hình ta phải 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 dung hàm này mục đích là để dừng màn hình lại
NguyễnVănLong
Ứ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 13
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ả chương trình chay:
2. Không gian màu, chuyển đổi giữa các không gian màu
Khôn gian màu là một mô hình toán học dùng để mô tả các màu sắc trong thực tế được
biểu diễn dưới dạng số học. Trên thực tế có rất nhiều không gian màu khác nhau được mô
hình để sử dụng vào những mục đích khác nhau. Trong bài này ta sẽ tìm hiểu qua về ba
không gian màu cơ bản hay được nhắc tới và ứng dụng nhiều, đó là hệ không gian màu
RGB, HSV và CMYK.
Không gian màu RGB
RGB là không gian màu rất phổ biến được dùng trong đồ họa máy tính và nhiều thiết bị kĩ
thuật số khác. Ý tưởng chính của không gian màu này là sự kết hợp của 3 màu sắc cơ bản
: màu đỏ (R, Red), xanh lục (G, Green) và xanh lơ (B, Blue) để mô tả tất cả các màu sắc
khác.
Nếu như một ảnh số được mã hóa bằng 24bit, nghĩa là 8bit cho kênh R, 8bit cho kênh G,
8bit cho kênh B, thì mỗ kênh này màu này sẽ nhận giá trị từ 0-255. Với mỗi giá trị khác
nhau của các kênh màu kết hợp với nhau ta sẽ được một màu khác nhau, như vậy ta sẽ có
tổng cộng 255x255x255 = 1.66 triệu màu sắc.
NguyễnVănLong
Ứ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 14
Ví dụ: màu đen là sự kết hợp của các kênh màu (R, G, B)
với giá trị tương ứng (0, 0, 0) màu trắng có giá trị (255,
255, 255), màu vàng có giá trị (255, 255, 0), màu tím đậm
có giá trị (64, 0, 128) ...Nếu ta dùng 16bit để mã hóa một
kênh màu (48bit cho toàn bộ 3 kênh màu) thì dãi màu sẽ
trãi rộng lên tới 3*2^16 = ... Một con số rất lớn.
Không gian màu CMYK.
CMYK là không gian màu được sử dụng phổ biến trong
ngành công nghiệp in ấn.Ý tưởng cơ bản của hệ không
gian này là dùng 4 màu sắc cơ bản để phục vụ cho việc pha trộn mực in. Trên thực tế,
người ta dùng 3 màu là C=Cyan: xanh lơ, M=Magenta: hồng xẫm, và Y=Yellow: vàng để
biểu diễn các màu sắc khác nhau. Nếu lấy màu hồng xẫm cộng với vàng sẽ ra màu đỏ,
màu xẫm kết hợp với xanh lơ sẽ cho xanh lam ... Sự kết hợp của 3 màu trên sẽ cho ra màu
đen, tuy nhiên màu đen ở đây khôn phải là đen tuyệt đối và thường có độ tương phản lớn,
nên trong ngành in, để tiết kiệm mực in người ta thêm vào màu đen để in những chi tiết
có màu đen thay vì phải kết hợp 3 màu sắc trên. Và như vậy ta có hệ màu CMYK. chữ K
ở đây là để kí hiệu màu đen (Black), có nhẽ chữ B đã được dùng để biểu diễn màu Blue
nên người ta lấy chữ cái cuối K để biểu diễn màu đen?
Nguyên lý làm việc của hệ màu này như sau : Trên một
nền giấy trắng, khi mỗi màu này được in lên sẽ loại bỏ dần
đi thành phần màu trắng. 3 màu C, M, Y khác nhau in theo
những tỉ lệ khác nhau sẽ loại bỏ đi thành phần đó một cách
khác nhau và cuối cùng cho ta màu sắc cần in. Khi cần in
màu đen, thay vì phải in cả 3 màu người ta dùng màu đen
để in lên. Nguyên lý này khác với nguyên lý làm việc của
hệ RGB ở chỗ hệ RGB là sự kết hợp của các thành phần
màu, còn hệ CMYK là sự loại bỏ lẫn nhau của các thành
phần màu.
Không gian màu HSV.
HSV và cũng gần tương tự như HSL là không gian màu được dùng nhiều trong việc ch ỉnh
sữa ảnh, phân tích ảnh và một phần của lĩnh vực thị giác máy tính. Hệ không gian này dựa
vào 3 thông số sau để mô tả màu sắc
H = Hue: màu sắc, S = Saturation: độ đậm đặc, sự bảo hòa, V = value: giá trị cường độ
sáng.
Không gian màu này thường được biểu diễn dưới dạng hình trụ hoặc hình nón . Theo đó,
Ứ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 14
Ví dụ: màu đen là sự kết hợp của các kênh màu (R, G, B)
với giá trị tương ứng (0, 0, 0) màu trắng có giá trị (255,
255, 255), màu vàng có giá trị (255, 255, 0), màu tím đậm
có giá trị (64, 0, 128) ...Nếu ta dùng 16bit để mã hóa một
kênh màu (48bit cho toàn bộ 3 kênh màu) thì dãi màu sẽ
trãi rộng lên tới 3*2^16 = ... Một con số rất lớn.
Không gian màu CMYK.
CMYK là không gian màu được sử dụng phổ biến trong
ngành công nghiệp in ấn.Ý tưởng cơ bản của hệ không
gian này là dùng 4 màu sắc cơ bản để phục vụ cho việc pha trộn mực in. Trên thực tế,
người ta dùng 3 màu là C=Cyan: xanh lơ, M=Magenta: hồng xẫm, và Y=Yellow: vàng để
biểu diễn các màu sắc khác nhau. Nếu lấy màu hồng xẫm cộng với vàng sẽ ra màu đỏ,
màu xẫm kết hợp với xanh lơ sẽ cho xanh lam ... Sự kết hợp của 3 màu trên sẽ cho ra màu
đen, tuy nhiên màu đen ở đây khôn phải là đen tuyệt đối và thường có độ tương phản lớn,
nên trong ngành in, để tiết kiệm mực in người ta thêm vào màu đen để in những chi tiết
có màu đen thay vì phải kết hợp 3 màu sắc trên. Và như vậy ta có hệ màu CMYK. chữ K
ở đây là để kí hiệu màu đen (Black), có nhẽ chữ B đã được dùng để biểu diễn màu Blue
nên người ta lấy chữ cái cuối K để biểu diễn màu đen?
Nguyên lý làm việc của hệ màu này như sau : Trên một
nền giấy trắng, khi mỗi màu này được in lên sẽ loại bỏ dần
đi thành phần màu trắng. 3 màu C, M, Y khác nhau in theo
những tỉ lệ khác nhau sẽ loại bỏ đi thành phần đó một cách
khác nhau và cuối cùng cho ta màu sắc cần in. Khi cần in
màu đen, thay vì phải in cả 3 màu người ta dùng màu đen
để in lên. Nguyên lý này khác với nguyên lý làm việc của
hệ RGB ở chỗ hệ RGB là sự kết hợp của các thành phần
màu, còn hệ CMYK là sự loại bỏ lẫn nhau của các thành
phần màu.
Không gian màu HSV.
HSV và cũng gần tương tự như HSL là không gian màu được dùng nhiều trong việc ch ỉnh
sữa ảnh, phân tích ảnh và một phần của lĩnh vực thị giác máy tính. Hệ không gian này dựa
vào 3 thông số sau để mô tả màu sắc
H = Hue: màu sắc, S = Saturation: độ đậm đặc, sự bảo hòa, V = value: giá trị cường độ
sáng.
Không gian màu này thường được biểu diễn dưới dạng hình trụ hoặc hình nón . Theo đó,
Ứ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 14
Ví dụ: màu đen là sự kết hợp của các kênh màu (R, G, B)
với giá trị tương ứng (0, 0, 0) màu trắng có giá trị (255,
255, 255), màu vàng có giá trị (255, 255, 0), màu tím đậm
có giá trị (64, 0, 128) ...Nếu ta dùng 16bit để mã hóa một
kênh màu (48bit cho toàn bộ 3 kênh màu) thì dãi màu sẽ
trãi rộng lên tới 3*2^16 = ... Một con số rất lớn.
Không gian màu CMYK.
CMYK là không gian màu được sử dụng phổ biến trong
ngành công nghiệp in ấn.Ý tưởng cơ bản của hệ không
gian này là dùng 4 màu sắc cơ bản để phục vụ cho việc pha trộn mực in. Trên thực tế,
người ta dùng 3 màu là C=Cyan: xanh lơ, M=Magenta: hồng xẫm, và Y=Yellow: vàng để
biểu diễn các màu sắc khác nhau. Nếu lấy màu hồng xẫm cộng với vàng sẽ ra màu đỏ,
màu xẫm kết hợp với xanh lơ sẽ cho xanh lam ... Sự kết hợp của 3 màu trên sẽ cho ra màu
đen, tuy nhiên màu đen ở đây khôn phải là đen tuyệt đối và thường có độ tương phản lớn,
nên trong ngành in, để tiết kiệm mực in người ta thêm vào màu đen để in những chi tiết
có màu đen thay vì phải kết hợp 3 màu sắc trên. Và như vậy ta có hệ màu CMYK. chữ K
ở đây là để kí hiệu màu đen (Black), có nhẽ chữ B đã được dùng để biểu diễn màu Blue
nên người ta lấy chữ cái cuối K để biểu diễn màu đen?
Nguyên lý làm việc của hệ màu này như sau : Trên một
nền giấy trắng, khi mỗi màu này được in lên sẽ loại bỏ dần
đi thành phần màu trắng. 3 màu C, M, Y khác nhau in theo
những tỉ lệ khác nhau sẽ loại bỏ đi thành phần đó một cách
khác nhau và cuối cùng cho ta màu sắc cần in. Khi cần in
màu đen, thay vì phải in cả 3 màu người ta dùng màu đen
để in lên. Nguyên lý này khác với nguyên lý làm việc của
hệ RGB ở chỗ hệ RGB là sự kết hợp của các thành phần
màu, còn hệ CMYK là sự loại bỏ lẫn nhau của các thành
phần màu.
Không gian màu HSV.
HSV và cũng gần tương tự như HSL là không gian màu được dùng nhiều trong việc ch ỉnh
sữa ảnh, phân tích ảnh và một phần của lĩnh vực thị giác máy tính. Hệ không gian này dựa
vào 3 thông số sau để mô tả màu sắc
H = Hue: màu sắc, S = Saturation: độ đậm đặc, sự bảo hòa, V = value: giá trị cường độ
sáng.
Không gian màu này thường được biểu diễn dưới dạng hình trụ hoặc hình nón . Theo đó,
NguyễnVănLong
Ứ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 15
đi theo vòng tròn từ 0 -360 độ là trường biểu diễn màu sắc(Hue). Trường này bắt đầu từ
màu đỏ đầu tiên (red primary) tới màu xanh lục đầu tiên (green primary) nằm trong
khoảng 0-120 độ, từ 120 - 240 độ là màu xanh lục tới xanh lơ (green primary - blue
primary). Từ 240 - 360 là từ màu đen tới lại màu đỏ.
Không gian màu HSV Hình tròn biểu diễn màu sắc (HUE)
Chuyển đổi giữa các không gian màu.
Chuyển đổi RGB sang CMYK và ngược lại.
Như đã nói ở trên, thành phần K là thành phần phụ dùng để in cho những điểm màu có
màu đen trong hệ CYMK, do vậy để chuyển không gian màu từ RGB sang CMYK trước
hết ta chuyển RGB sang CMY sau đó tìm thành phần K còn lại. Cô ng thức chuyển từ
RGB sang CMY:
(C', M', Y') = ((255 - R), (255 - G), (255 - B)).
Việc tính giá trị của K lại là một vấn đề khác vì nó liên quan tới nhà sản xuất công nghệ
in, tuy nhiên về mặt lý thuyết có thể chấp nhận rằng K = min {C'/2,55, M'/2,55, Y'/2,55} ,
như vậy 0<= K <=100.
Nếu K = 100, thì C = M = Y =0 (trương hợp in màu đen)
Nếu 0< K < 100: C = (C'/2.55 - K) * 100 /(100 - K), M = (M'/2.55 - K) * 100 /(100 - K),
Y = (Y'/2.55 - K) *100 /(100 - K) và K = K. Trong đó, C, M, Y, K được làm tròn tới để
lấy chỉ số nguyên.
Chuyển đổi RGB sang HSV và ngược lại
Giả sử ta có một điểm màu có giá trị trong hệ RGB là (R, G, B). ta chuyển sang không
gian HSV như sau:
Đặt M = Max(R, G, B), m = Min(R, G, B) và C = M - m.
Nếu M = R, H' = (G - B)/C mod 6. Nếu M = G, H' = (B - R)/C + 2. Nếu M = B, H' = (R -
G)/C + 4. Và H = H'x60. Trong trường hợp C = 0, H = 00
V = M.
Ứ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 15
đi theo vòng tròn từ 0 -360 độ là trường biểu diễn màu sắc(Hue). Trường này bắt đầu từ
màu đỏ đầu tiên (red primary) tới màu xanh lục đầu tiên (green primary) nằm trong
khoảng 0-120 độ, từ 120 - 240 độ là màu xanh lục tới xanh lơ (green primary - blue
primary). Từ 240 - 360 là từ màu đen tới lại màu đỏ.
Không gian màu HSV Hình tròn biểu diễn màu sắc (HUE)
Chuyển đổi giữa các không gian màu.
Chuyển đổi RGB sang CMYK và ngược lại.
Như đã nói ở trên, thành phần K là thành phần phụ dùng để in cho những điểm màu có
màu đen trong hệ CYMK, do vậy để chuyển không gian màu từ RGB sang CMYK trước
hết ta chuyển RGB sang CMY sau đó tìm thành phần K còn lại. Cô ng thức chuyển từ
RGB sang CMY:
(C', M', Y') = ((255 - R), (255 - G), (255 - B)).
Việc tính giá trị của K lại là một vấn đề khác vì nó liên quan tới nhà sản xuất công nghệ
in, tuy nhiên về mặt lý thuyết có thể chấp nhận rằng K = min {C'/2,55, M'/2,55, Y'/2,55} ,
như vậy 0<= K <=100.
Nếu K = 100, thì C = M = Y =0 (trương hợp in màu đen)
Nếu 0< K < 100: C = (C'/2.55 - K) * 100 /(100 - K), M = (M'/2.55 - K) * 100 /(100 - K),
Y = (Y'/2.55 - K) *100 /(100 - K) và K = K. Trong đó, C, M, Y, K được làm tròn tới để
lấy chỉ số nguyên.
Chuyển đổi RGB sang HSV và ngược lại
Giả sử ta có một điểm màu có giá trị trong hệ RGB là (R, G, B). ta chuyển sang không
gian HSV như sau:
Đặt M = Max(R, G, B), m = Min(R, G, B) và C = M - m.
Nếu M = R, H' = (G - B)/C mod 6. Nếu M = G, H' = (B - R)/C + 2. Nếu M = B, H' = (R -
G)/C + 4. Và H = H'x60. Trong trường hợp C = 0, H = 00
V = M.
Ứ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 15
đi theo vòng tròn từ 0 -360 độ là trường biểu diễn màu sắc(Hue). Trường này bắt đầu từ
màu đỏ đầu tiên (red primary) tới màu xanh lục đầu tiên (green primary) nằm trong
khoảng 0-120 độ, từ 120 - 240 độ là màu xanh lục tới xanh lơ (green primary - blue
primary). Từ 240 - 360 là từ màu đen tới lại màu đỏ.
Không gian màu HSV Hình tròn biểu diễn màu sắc (HUE)
Chuyển đổi giữa các không gian màu.
Chuyển đổi RGB sang CMYK và ngược lại.
Như đã nói ở trên, thành phần K là thành phần phụ dùng để in cho những điểm màu có
màu đen trong hệ CYMK, do vậy để chuyển không gian màu từ RGB sang CMYK trước
hết ta chuyển RGB sang CMY sau đó tìm thành phần K còn lại. Cô ng thức chuyển từ
RGB sang CMY:
(C', M', Y') = ((255 - R), (255 - G), (255 - B)).
Việc tính giá trị của K lại là một vấn đề khác vì nó liên quan tới nhà sản xuất công nghệ
in, tuy nhiên về mặt lý thuyết có thể chấp nhận rằng K = min {C'/2,55, M'/2,55, Y'/2,55} ,
như vậy 0<= K <=100.
Nếu K = 100, thì C = M = Y =0 (trương hợp in màu đen)
Nếu 0< K < 100: C = (C'/2.55 - K) * 100 /(100 - K), M = (M'/2.55 - K) * 100 /(100 - K),
Y = (Y'/2.55 - K) *100 /(100 - K) và K = K. Trong đó, C, M, Y, K được làm tròn tới để
lấy chỉ số nguyên.
Chuyển đổi RGB sang HSV và ngược lại
Giả sử ta có một điểm màu có giá trị trong hệ RGB là (R, G, B). ta chuyển sang không
gian HSV như sau:
Đặt M = Max(R, G, B), m = Min(R, G, B) và C = M - m.
Nếu M = R, H' = (G - B)/C mod 6. Nếu M = G, H' = (B - R)/C + 2. Nếu M = B, H' = (R -
G)/C + 4. Và H = H'x60. Trong trường hợp C = 0, H = 00
V = M.
NguyễnVănLong
Ứ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 16
S = C/V. Trong trường hợp V hoặc C bằng 0, S = 0.
Để chuyển từ HSV sang RGB ta làm như sau:
Giả sử ta có không gian màu HSV với H = [0, 360], S = [0, 1], V = [0, 1]. Khi đó, ta tính
C = VxS. H' = H/60.
X = C(1 - |H' mod2 -1|). Ta biểu diễn hệ (R1, G1, B1) như sau:
( 1, 1, 1) =
⎩
⎪
⎪
⎨
⎪
⎪
⎧
(0, 0, 0) ế ℎư đượ á đị ℎ
( , , 0) ế 0 ≤ < 1
( , , 0) ế 1 ≤ < 2
(0, , ) ế 2 ≤ < 3
(0, , ) ế 3 ≤ < 4
( , 0, ) ế 4 ≤ < 5
, 0, ) ế 5 ≤ < 6
Chương trình chuyển đổi các không gian màu
Trong OpenCV, các không gian màu được được chuyển đổi qua lại nhờ hàm cvtColor
(convert color), nguyên mẫu hàm này như sau:
cv::cvtColor(cv::InputArray src, cv::OutputArray dst, int code)
Trong đó, src, dst là ảnh gốc và ảnh thu được sau khi chuyển đổi không gian màu. code
mà mã chuyển đổi không gian màu. OpenCV định nghĩa khá nhiều chuyển đổi giữa các
không gian màu chẳng hạn như code = CV_BGR2GRAY sẽ chuyển ảnh ở không gian màu
RGB sang ảnh xám, code = CV_HSV2BGR sẽ chuyển ảnh ở không gian màu HSV sang
không gian màu RGB …
#include "stdafx.h"
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
void main()
{
Mat src = imread("LucBinh.jpg", CV_LOAD_IMAGE_COLOR);
Mat gray, hsv, ycrcb;
cvtColor(src, gray, CV_BGR2GRAY);
cvtColor(src, hsv, CV_BGR2HSV);
cvtColor(src, ycrcb, CV_BGR2YCrCb);
imshow("src", src);
imshow("gray", gray);
imshow("hsv", hsv);
imshow("ycrcb", ycrcb);
waitKey(0);
NguyễnVănLong
Ứ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 17
}
Sau đây là hình ảnh khi chuyển đổi các không gian màu trên
3. Điều chỉnh độ sang và độ tương phản trong ảnh
Trong bài này ta sẽ tìm hiểu về cấu trúc của một bức ảnh, cách tiếp cận và điều chỉnh tới
từng điểm ảnh.
Một ảnh số được lưu trữ trên máy tính là một ma trận các điểm ảnh (hay pixel). Trong
OpenCV nó được biểu diễn dưới dạng cv::Mat. Ta xét một kiểu ảnh thông thường nhất,
đó là ảnh RGB. Với ảnh này, mỗi pixel ảnh quan sát được là sự kết hợp của các thành
phần màu R (Red), Green (Green) và Blue (Blue). Sự kết hợp này theo những tỉ lệ R, G,
B khác nhau sẽ tạo ra vô số các màu sắc khác nhau. Giả sử ảnh được mã hóa bằng 8 bit
với từng kênh màu, khi đó mỗi giá trị của R, G, B sẽ nằm trong khoảng [0, 255]. Như vậy
ta có thể biểu diễn tới 255*255*255 ~ 1.6 triệu màu sắc từ ba màu cơ bản trên. Ta có thể
xem cách biểu diễn ảnh trong OpenCV ở định dạng cv::Mat qua hình ảnh sau:
NguyễnVănLong
Ứ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 18
Cột 0 Cột 1 Cột m
Hàng 0 0, 0 0, 0 0, 0 0, 1 0, 1 0, 1 0, m 0, m 0, m
Hàng 1 1, 0 1, 0 1, 0 1, 1 1, 1 1, 1 1, m 1, m 1, m
Hàng 2 2, 0 2, 0 2, 0 2, 1 2, 1 2, 1 2, m 2, m 2, m
Hàng n n, 0 n, 0 n, 0 N, 1 n, 1 n, 1 n, m n, m n, m
Như vậy, mỗi ảnh sẽ có n hàng và m cột, m gọi là chiều dài của ảnh (width) và n gọi là
chiều cao của ảnh (heigh). Mỗi pixel ở vị trí (i,j) trong ảnh sẽ tương ứng với 3 kênh màu
kết hợp trong nó. Để truy xuất tới từng pixel ảnh với những kênh màu riêng rẽ ta sử dụng
mẫu sau:
img.at<cv::Vec3b>(i,j)[k]
Trong đó, i ,j là pixel ở hàng thứ i và cột thứ j, img là ảnh mà ta cần truy xuất tới các pixel
của nó. cv::Vec3b là kiểu vector uchar 3 thành phần, dung để biểu thị 3 kênh màu tương
ứng. k là kênh màu thứ k, k = 0, 1, 2 tương ứng với kênh màu B, G, R. Chú ý là trong
OpenCV, hệ màu RGB được biểu diễn theo thứ tự chữ cái là BGR.
Sau đây ta sẽ áp dụng kiến thức trên để làm tăng, giảm độ sang và tương phản của một
ảnh màu, việc làm này cũng hoàn toàn tương tự đối với ảnh xám, chỉ khác biệt là ảnh ta
dung một kênh duy nhất để biểu diễn ảnh xám.
Chương trình tăng, giảm độ sáng và độ tương phản của một ảnh
Giả sử f là một hàm biểu diễn cho một ảnh nào đó, f(x,y) là giá trị của pixel trong ảnh ở vị
trí (x,y). Đặt g(x,y) = αf(x,y) + β. Khi đó, nếu α ≠ 1, thì ta nói ảnh g(x,y) có độ tương phản
gấp α lần so với ảnh f(x,y). Nếu β ≠ 0ta nói độ sáng của ảnh g(x,y) đã thay đổi một lượng
là β. Dựa vào công thức trên ta có chương trình thay đổi độ sáng và tương phản của ảnh
như sau:
#include "stdafx.h"
#include <iostream>
#include <opencv2corecore.hpp>
#include <opencv2highguihighgui.hpp>
using namespace std;
using namespace cv;
int main()
{
cout<<"Chuong trinh dieu chinh do sang va tuong phan"<<endl;
Mat src = imread("hoa_huong_duong.jpg", 1);
Mat dst = src.clone();
double alpha = 2.0;
int beta = 30;
for(int i = 0; i < src.rows; i++)
for(int j = 0; j < src.cols; j++)
for(int k = 0; k < 3; k++)
NguyễnVănLong
Ứ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 19
dst.at<Vec3b>(i,j)[k] = saturate_cast<uchar>(
alpha*(src.at<Vec3b>(i,j)[k] ) + beta);
imshow("anh goc", src);
imshow("anh co sau khi chinh do tuong phan va do sang", dst);
waitKey(0);
return 0;
}
Trong chương trình trên, hàm clone() sẽ sao chép một ảnh giống hệt như ảnd gốc cho vào
ảnh đích (dst = src.clone()). Giá trị của các pixel ảnh f(x,y) và g(x,y) ở đây phải nằm trong
khoảng [0, 255], trong khi phép biến đổi g(x,y) = αf(x,y) + β có thể khiến cho giá trị của
g(x,y) vượt qua ngưỡng đó. Để tránh tình trạng tràn số hoặc kiểu dữ liệu không tương
thích, ta dùng thêm hàm saturate_cast<uchar>(type). Hàm này sẽ biến kiểu dữ liệu
type nếu không phải là uchar thành kiểu dữ liệu uchar
Sau đây là kết quả chương trình với giá trị α = 2.0 và β = 30
4. Ả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ến
mộ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
NguyễnVănLong
Ứ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 20
Ảnh xám Ảnh nhị phân
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.
T = 50 T = 100 T = 150
Để 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ĩ
NguyễnVănLong
Ứ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 21
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 đó
(ta 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:
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 <opencv2corecore.hpp>
#include <opencv2highguihighgui.hpp>
#include <opencv2imgprocimgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
cout<<"Nhi phan anh voi nguong dong"<<endl;
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);
Ứ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 21
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 đó
(ta 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:
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 <opencv2corecore.hpp>
#include <opencv2highguihighgui.hpp>
#include <opencv2imgprocimgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
cout<<"Nhi phan anh voi nguong dong"<<endl;
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);
Ứ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 21
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 đó
(ta 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:
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 <opencv2corecore.hpp>
#include <opencv2highguihighgui.hpp>
#include <opencv2imgprocimgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
cout<<"Nhi phan anh voi nguong dong"<<endl;
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);
NguyễnVănLong
Ứ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 22
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:
Ảnh xám Ảnh nhị phân
NguyễnVănLong
Ứ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 23
5. Histogram, cân bằng histogram trong ảnh
Histogram của một ảnh là một biểu đồ nói lên
mối quan hệ giữa các giá trị của pixel ảnh (điểm
ảnh) và tần suất xuất hiện của chúng. Nhìn vào
biểu đồ histogram ta có thể đoán được một ảnh
sáng tối như thế nào.
Nếu một ảnh có histogram lệch về phía phải
biểu đồ, ta nói ảnh đó thừa sáng. Nếu lệch về
phía trái thì ảnh đó thiếu sáng. Hình bên mô tả
histogram của một ảnh xám, ảnh này có
histogram lệch về phía trái của biểu đồ và do đó
ảnh này là khá tối. Đối với ảnh màu, ta có thể
tính toán histogram cho từng kênh màu một.
Sau đây là chương trình tính và vẽ biểu đồ
histogram của một ảnh màu.
#include <iostream>
#include <opencv2highguihighgui.hpp>
#include <opencv2imgprocimgproc.hpp>
using namespace std;
using namespace cv;
int main()
{
std::cout<<"Tim histogram anh mau"<<std::endl;
Mat src = imread("buoi.jpg");
vector<Mat> img_rgb;
Mat img_r, img_g, img_b;
int w = 400, h = 400;
int size_hist = 255;
float range[] = {0, 255};
const float* hist_range = {range};
split(src, img_rgb);
calcHist(&img_rgb[0], 1, 0, Mat(), img_b, 1, &size_hist, &hist_range, true, false);
calcHist(&img_rgb[1], 1, 0, Mat(), img_g, 1, &size_hist, &hist_range, true, false);
calcHist(&img_rgb[2], 1, 0, Mat(), img_r, 1, &size_hist, &hist_range, true, false);
int bin = cvRound((double)w/size_hist);
Mat disp_r(w, h, CV_8UC3, Scalar( 255,255,255) );
Mat disp_g = disp_r.clone();
Mat disp_b = disp_r.clone();
normalize(img_b, img_r, 0, disp_b.rows, NORM_MINMAX, -1, Mat() );
normalize(img_g, img_g, 0, disp_g.rows, NORM_MINMAX, -1, Mat() );
normalize(img_r, img_b, 0, disp_r.rows, NORM_MINMAX, -1, Mat() );
NguyễnVănLong
Ứ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 24
for( int i = 1; i < 255; i++ )
{
line(disp_r, Point(bin*(i), h), Point(bin*(i), h - cvRound(img_r.at<float>(i))),
Scalar(0, 0, 255), 2, 8, 0 );
line(disp_g, Point(bin*(i), h), Point(bin*(i), h - cvRound(img_g.at<float>(i))),
Scalar( 0, 255, 0), 2, 8, 0 );
line(disp_b, Point( bin*(i), h), Point(bin*(i), h - cvRound(img_b.at<float>(i))),
Scalar(255, 0, 0), 2, 8, 0 );
}
namedWindow("src", 0);
imshow("src", src);
imshow("Histogram of Blue chennel", disp_b);
imshow("Histogram of Green chennel", disp_g);
imshow("Histogram of Red chennel", disp_r);
cv::waitKey(0);
return 1;
}
Trong chương trình trên, đầu tiên ảnh được đưa vào là một ảnh mầu, để tính histogram
của từng kênh mầu một ta sẽ phân tách ảnh này thành 3 kênh mầu riêng rẽ theo thứ tự là
Blue, Green và Red. Hàm cv::split(const cv::Mat src, cv::Mat *mvbegin) sẽ tách thành
src thành các kênh màu tương ứng lưu trong mvbegin.
Hàm cv:: calcHist(const cv::Mat *images, int nimages, const int *channels,
cv::InputArray mask, cv::OutputArray hist, int dims, const int histSize, const float
**ranges, bool uniform = true, bool accumulate = false) sẽ tính histogram của ảnh đầu
vào images và lưu kết quả tính toán vào mảng hist. Các thông số khác bao gồm: nimages
là số lượng ảnh đầu vào, channels là danh sách chiều các kênh dung để tính histogram,
mask là một mặt nạ tùy chỉnh, nếu không dung gì thì để là cv::Mat(). dims là chiều của
histogram, bản OpenCV hiện tại hỗ trợ tính toán histogram với số chiều lên tới 32.
histSize là kích thước dãy histogram mỗi chiều, hai tham số cuối có thể để mặc định,
Sau đây là kết quả chương trình
NguyễnVănLong
Ứ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 25
Đối với ảnh xám, ta có thể xem như nó là một kênh màu, do vậy để tính histogram của
ảnh xám ta cũng có thể làm hoàn toàn tương tự bằng cách gọi hàm caclHist()
Cân bằng histogram
Cân bằng histogram (histogram equalization) là
phương pháp làm cho biểu đồ histogram của ảnh được
phân bố một cách đồng đều. Đây là một biến đổi khá
quan trọng giúp nâng cao chất lượng ảnh, thông
thường đây là bước tiền xử lý của một ảnh đầu vào
cho các bước tiếp theo.
Để cân bằng histogram, ta dung hàm
equalizeHist(cv::InputArray src, cv::OuputArray dst)
trong đó, src là ảnh đầu vào một kênh màu (ảnh xám
chẳn hạn), dst là ảnh sau khi cân bằng. Ví dụ:
Mat src = imread("src.jpeg", CV_LOAD_IMAGE_GRAYSCALE); // Load anh xam
imshow("Anh xam goc", src);
Mat dst;
equalizeHist(src, dst);
imshow("anh xam sau khi can bang histogram", dst);
Ta có kết quả sau:
NguyễnVănLong
Ứ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 26
Để cân bằng histogram của một ảnh màu, trước hết ta chuyển ảnh màu ở dạng RGB sang
HSV, sau đó cân bằng thành phần kênh màu V (Value tức độ sáng) và biến đổi ngược lại.
Chương trình sau cân bằng histogram của ảnh màu
// Can bang histogram
#include <opencv2corecore.hpp>
#include <opencv2highguihighgui.hpp>
#include <opencv2imgprocimgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
cout<<"Chuong trinh can bang histogram"<<endl;
Mat src = imread("Cho_Ben_Thanh.jpg", CV_LOAD_IMAGE_COLOR);
Mat hsv, disp;
cvtColor(src, hsv, CV_BGR2HSV);
vector<Mat> hsv_channels;
// Tach hsv thanh 3 kenh mau
split(hsv, hsv_channels);
// Can bang histogram kenh mau v (value)
equalizeHist(hsv_channels[2], hsv_channels[2]);
// Tron anh
merge(hsv_channels, hsv);
// Chuyen doi hsv sang rgb de hien thi
cvtColor(hsv, disp, CV_HSV2BGR);
imshow("anh mau goc", src);
imshow("anh mau sau khi can bang histogram", disp);
waitKey(0);
}
Sau đây là kết quả của chương trình trên
NguyễnVănLong
Ứ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 27
6. Phóng to, thu nhỏ và xoay ảnh
Như đã nói ở trên, ảnh số thực chất là một ma trận các điểm ảnh, do đó để có thể phóng
to, thu nhỏ hay xoay một tấm ảnh ta có thể sử dụng các thuật toán tương ứng trên ma trận.
Ta sẽ sử dụng biển đổi affine để quay và thay đổi tỉ lệ to, nhỏ của một ma trận.
Biến đổi affine:
Giả sử ta có vector = [ , ] và ma trận M 2x2. Phép biển đổi affine trong không gian
hai chiều có thể được định nghĩa p’ = Mp trong đó = [ , ] . Viết một cách tường
minh ta có:
′
′
=
Hay x’ = αx + δy, y’ = γx + βy .
Xét ma trận = . Nếu δ = γ = 0, khi đó x’ = αx và y’ = βy, phép biến đổi này làm
thay đổi tỉ lệ của ma trận. Nếu là trong ảnh nó sẽ phóng to hoặc thu nhỏ ảnh. Hình sau mô
tả phép biến đổi với tỉ lệ α = β = 2
NguyễnVănLong
Ứ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 28
Nếu ta định nghĩa ma trận =
cos ( ) −sin ( )
sin ( ) cos ( )
thì phép biến sẽ quay p thành p’ với
góc quay là θ.
Nếu ma trận M được định nghĩa thành =
α. cos (θ) −sin ( )
sin ( ) . cos ( )
thì phép biến đổi sẽ
vừa là phép biến đổi theo tỉ lệ và quay.
Bây giờ ta sẽ xét chương trình phóng to, thu nhỏ và quay ảnh.
// Chuong trinh phong to, thu nho va quay anh
#include <opencv2corecore.hpp>
#include <opencv2highguihighgui.hpp>
#include <opencv2imgprocimgproc.hpp>
using namespace cv;
int main()
{
Mat src = imread("HoaSen.jpg");
Mat dst = src.clone();
double angle = 45.0;
NguyễnVănLong
Ứ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 29
double scale = 1.5;
Point2f center(src.cols/2, src.rows/2);
Mat mat_rot = getRotationMatrix2D(center, angle, scale);
warpAffine(src, dst, mat_rot, src.size());
imshow("Anh goc", src);
imshow("Anh sau phep bien doi", dst);
waitKey(0);
return 1;
}
Trong chương trình trên, hàm cv::getRotationMatrix2D(cv::Point center, double
angle, double scale) sẽ tạo ra ma trận với tâm quay center, góc quay angle và tỉ lệ
scale. Ma trận này được tính toán trong Opencv là ma trận như sau:
=
(1 − ). . − . .
− . . − (1 − ). .
Với = . cos ( ) và = . sin ( )
Ta thấy rằng ma trận này là hoàn hoàn tương đương với ma trận của phép biến đổi affine
đã nói ở trên, ngoại trừ thành phần thứ 3 là thành phần giúp dịch chuyển tâm quay vào
chính giữa của bức ảnh. Chú ý là có sự khác biệt một chút về chiều của hệ tọa độ trong
ảnh, hệ tọa độ trong ảnh lấy góc trên bên trái làm gốc tọa độ (0,0) còn hệ tọa độ thông
thường ta hay lấy điểm dưới bên trái làm gốc, do đó có sự ngược chiều.
Kết quả của chương trình trên với tỉ lệ scale = 1.5 và góc quay = 450
như hình sau
Ngoài hai phép biến đổi là tỉ lệ và quay như trên, ta có thể thực hiện các biến đổi khác của
phép biến đổi affine như phép trượt (shearing), hoặc phép phản chiếu (reflection) bằng
NguyễnVănLong
Ứ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 30
việc định nghĩa lại ma trận M. Ta thử định nghĩa lại ma trận M để được một ảnh trượt của
ảnh gốc. Quay lại ma trận M như trên, nếu ta định nghĩa α = β = 1 còn δ nh ận một giá trị
bất kì, khi đó ta sẽ có:
= +
=
ta sẽ định nghĩa ma
trận =
1 0.5 0
0 1 0
để trượt ảnh
ban đầu thành ảnh mới với hệ số trượt
δ = 0.5, chú ý là thành phần thứ ba
0
0
định nghĩa ma trận trong Opencv sẽ
thể hiện dộ dịch chuyển, giống như trong ví dụ trên ta chuyển tâm quay về tâm của bức
ảnh chẳng hạn. Ta sẽ làm giống hệt ví dụ trên, chỉ thay ma trận M là ma trận ta tự định
nghĩa
double I[2][3] = {1,0.5,0, 0,1,0}; // cac phan tu cua ma tran
Mat mat_rot(2,3,CV_64F, I); // khoi tao ma tran
warpAffine(src, dst, mat_rot, src.size());
và ta có kết quả:
7. Lọc số trong ảnh
Lọc số trong ảnh có ý nghĩa quan trọng trong việc tạo ra các hiệu ứng trong ảnh, một số
hiệu ứng nhờ sử dụng các bộ lọc như làm mờ ảnh(Blur), làm trơn ảnh(Smooth) …
Nguyên tắc chung của phương pháp lọc ảnh là cho ảnh nhân chập với một ma trận lọc,
Idst = M*Isrc
NguyễnVănLong
Ứ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 31
Isrc, Idst là ảnh gốc và ảnh sau khi thực hiện phép lọc ảnh bằng cách nhân với ma trận lọc
M. Ma trận M đôi khi còn gọi là mặt nạ (mask), nhân (kernel). Với mỗi phép lọc ta có
những ma trận lọc M khác nhau, không có quy định cụ thể nào cho việc xác định M, tuy
nhiên ma trận này có một số đặc điểm như sau:
- Kích thước của ma trận thường là một số lẻ chẳng hạn 3x3, 5x5 … Khi đó, tâm của
ma trận sẽ nằm ở giao của hai đường chéo và là điểm áp đặt lên ảnh mà ta cần tính
nhân chập.
- Tổng các phần tử trong ma trận thông thường bằng 1. Nếu tổng này lớn hơn 1, ảnh
qua phép lọc sẽ có độ sáng lớn hơn ảnh ban đầu. Ngược lại ảnh thu được sẽ tối hơn
ảnh ban đầu.
Ví dụ về ma trận lọc (ma trận lọc Sobel theo hướng x, y và ma trận Gausian Blur)
−1 0 +1
−2 0 +2
−1 0 +1
−1 −2 −1
0 0 0
+1 +2 +1
⎣
⎢
⎢
⎢
⎡
1 4 7 4 1
4 16 26 16 4
7 26 41 26 7
4 16 26 16 4
1 4 7 4 1⎦
⎥
⎥
⎥
⎤
Công thức cụ thể cho việc lọc ảnh như sau:
( , ) = ( , ) ∗ ( , ) = ( − , − ) × ( , )
Trong đó, ta đang tính phép nhân chập cho điểm ảnh có tọa độ (x,y) và vì ta lấy tâm của
ma trận lọc là điểm gốc nên u chạy từ -n (điểm bên trái) và v chạy từ -n (điểm phía trên)
đến n, với n = (kích thước mặt nạ - 1)/2. Để dễ hiểu hơn ta xét một ví dụ về việc làm trơn
nhờ sử dụng một ma trận lọc như sau:
1/9 1/9 1/9
1/9 1/9 1/9
1/9 1/9 1/9
100 100 100 100 100
100 200 205 203 100
100 195 200 200 100
100 200 205 195 100
100 100 100 100 100
100 100 100 100 100
100 144 205 203 100
100 195 200 200 100
100 200 205 195 100
100 100 100 100 100
* =
nhân chập
pixel (2,2)
NguyễnVănLong
Ứ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 32
1/9 1/9 1/9
1/9 1/9 1/9
1/9 1/9 1/9
……
Và kết quả cuối cùng ta có:
1/9 1/9 1/9
1/9 1/9 1/9
1/9 1/9 1/9
Ta thấy rằng, ảnh ban đầu với là ảnh có độ tương phản khá lớn (các giá trị độ lớn pixel
chênh lệch lớn: 100, 200, …), sau phép lọc ảnh có độ tương phản giản đi hay bị làm mờ
đi(lúc này độ chênh lệch giá trị giữa các pixel giảm đi: 100, 144, 167 …). Sau đây ta sẽ
xem xét một số bộ lọc trong OpenCV.
Lọc Blur:
100 100 100 100 100
100 200 205 203 100
100 195 200 200 100
100 200 205 195 100
100 100 100 100 100
100 100 100 100 100
100 144 167 203 100
100 195 200 200 100
100 200 205 195 100
100 100 100 100 100
100 100 100 100 100
100 200 205 203 100
100 195 200 200 100
100 200 205 195 100
100 100 100 100 100
100 100 100 100 100
100 144 167 145 100
100 167 200 168 100
100 144 166 144 100
100 100 100 100 100
* =
nhân chập
pixel (2,3)
* =
nhân chập
NguyễnVănLong
Ứ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 33
Ma trận lọc của phương pháp này có dạng : =
∗
⎣
⎢
⎢
⎢
⎡
1 1 . . 1
1 1 . . 1
. . . . .
. . . . .
1 1 . . 1⎦
⎥
⎥
⎥
⎤
Bộ lọc này có tác dụng làm trơn ảnh, khử nhiễu hạt.
Hàm cài đặt trong OpenCV có dạng:
cv::blur(const Mat& src, const Mat& dst, Size ksize, Point anchor, int borderType)
trog đó, src và dst là ảnh gốc và ảnh sau phép lọc. ksize là kích thước ma trận lọc,
ksize = Size(rows, cols), anchor là điểm neo của ma trận lọc, nếu để mặc định là (-
1,-1) thì điểm này chính là tâm của ma trận. borderType là phương pháp để ước
lượng và căn chỉnh các điểm ảnh nếu qua phép lọc chúng bị vượt ra khỏi giới hạn
của ảnh. Thông thường giá trị mặc định của nó là 4.
Ảnh qua phép lọc blur
Lọc Sobel:
Lọc sobel chính là cách tính xấp xỉ đạo hàm bậc nhất theo hướng x và y, nó cũng
chính là cách tính gradient trong ảnh. Bộ lọc này thông thường được áp dụng cho
mục đích tìm biên trong ảnh. Ma trận lọc theo các hướng x, y lần lượt như sau:
−1 0 +1
−2 0 +2
−1 0 +1
−1 −2 −1
0 0 0
+1 +2 +1
Trong OpeCV, hàm cài đặt phép lọc này như sau:
cv::Sobel(const Mat& src, Mat& dst, int ddepth, int xorder, int yorder, int ksize,
double scale, double delta, int borderType)
Trong đó, src và dst là ảnh gốc và ảnh qua phép lọc. ddepth là độ sâu của ảnh sau
phép lọc, có thể là CV_32F, CV_64F … . xoder và yoder là các đạo hàm theo
NguyễnVănLong
Ứ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 34
hướng x và y, để tính đạo hàm theo hướng nào ta đặt giá trị đó lên 1, ngược lại nếu
giá trị bằng 0, hàm cài đặt sẽ bỏ qua không tính theo hướng đó. Scale và delta là
hai thông số tùy chọn cho việc tính giá trị đạo hàm lưa giá trị vi sai vào ảnh sau
phép lọc, chúng có giá trị mặc định là 1 và 0. borderType là tham số như trên.
Ảnh qua phép lọc Sobel:
Lọc Laplace:
Lọc Laplace là cách tính xấp xỉ đạo hàm bậc hai trong ảnh, nó có ý nghĩa quan
trọng trong việc tìm biên ảnh và phân tích, ước lượng chuyển động của vật thể.
= ∆ = +
Ma trận lọc có dạng như sau:
0 1 0
1 −4 1
0 1 0
Trong OpenCV, bộ lọc này được cài đặt qua hàm:
cv::Laplacian(const Mat& src, Mat& dst, int ddepth, int ksize=1, double scale=1,
double delta=0, int borderType)
Các thông số này có ý nghĩa giống như các thông số trong bộ lọc Sobel, chỉ khác ở
chỗ ksize là một giá trị int mặc định bằng 1 và khi đó ma trận lọc laplace trên được
áp dụng.
Ảnh qua phép lọc Laplace:
NguyễnVănLong
Ứ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 35
Ngoài 3 bộ lọc trên, OpenCV còn cài đặt khá nhiều bộ lọc khác như lọc trung vị
(medianBlur), lọc Gause (gaussianBlur), pyrDown, pyrUp … Tuy nhiên, ta hoàn toàn có
thể cài đặt bộ lọc cho riêng mình thông qua hàm cv::filter2D. Nguyên mẫu hàm này như
sau:
filter2D(const Mat& src, Mat& dst, int ddepth, const Mat& kernel, Point anchor, double
delta, int borderType).
Trong đó, src và dst là ảnh gốc và ảnh thu được qua phép lọc, kernel là ma trân lọc.
Thông số anchor để chỉ ra tâm của ma trận, delta điều chỉnh độ sáng của ảnh sau phép lọc
(ảnh sau phép lọc được cộng với delta và borderType là kiểu xác định những pixel nằm
ngoài vùng ảnh.
Hàm cv::filter2D thực chất là hàm tính toán nhân chập giữa ảnh gốc và ma trận lọc để cho
ra ảnh cuối sau phép lọc. Như vậy qua trên ta thấy rằng để tiến hành việc lọc ảnh ta chỉ
cần định nghĩa một ma trận lọc kernel. Có rất nhiều nghiên cứu về toán học đã định nghĩa
các ma trận này, do đó việc áp dụng vào lọc ảnh sẽ là khá đơn giản.
Chương trình demo phương pháp lọc ảnh.
Chương trình sau sẽ thực hiện một số bộ lọc ảnh do chính ta định nghĩa, chẳng hạn ta có
ma trận lọc =
−1 −1 0
−1 0 1
0 1 1
, ma trận này là ma trận sẽ làm nổi bật ảnh giống như
ảnh khắc 3D, ta sẽ áp dụng ma trận này để lọc một ảnh.
#include "stdafx.h"
#include <opencv2corecore.hpp>
#include <opencv2imgprocimgproc.hpp>
#include <opencv2highguihighgui.hpp>
NguyễnVănLong
Ứ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 36
using namespace cv;
void main()
{
Mat src = imread("HoaDao.jpg", CV_LOAD_IMAGE_COLOR);
Mat dst;
double m[3][3] = { -1, -1, 0,
-1, 0, 1,
0, 1, 1
};
Mat M = cv::Mat(3,3,CV_64F, m, Point(-1,-1), 128.0);
cv::filter2D(src, dst, src.depth(), M);
imshow("Anh goc", src);
imshow("Anh qua phep loc", dst);
cv::waitKey(0);
}
Kết quả của chương trình như sau:
Một số bộ lọc sau có thể hữu ích cho việc tạo ra các hiệu ứng ảnh đẹp mắt:
=
1 1 1
1 −7 1
1 1 1
, = 0
NguyễnVănLong
Ứ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 37
=
−1 −1 −1
−1 8 −1
−1 −1 −1
, = 0
=
−1 −1 −1
−1 8 −1
−1 −1 −1
, = 0
8. 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).
Phép toán giãn nở (dilation)
Phép toán giãn nở được định nghĩa ⊕ = ⋃ ớ ⊂ 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)
NguyễnVănLong
Ứ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 38
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
Ta hãy 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 và phần giản nở ra ta đánh dấu là dấu x.
x x x
x
x
Ứ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ỏ …
Phép toán co (erosion)
Phép toán co trong ảnh được định nghĩa ⊖ = { |( ) ⊆ } 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.
NguyễnVănLong
Ứ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 39
0
x
Ta 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.
Phép toán mở (opening) và đóng (closing) là sự kết hợ của phép co (erosion) và giản
(dialation) như trên, chúng được định nghĩa như sau:
Phép toán mở : ∘ = ( ⊖ ) ⊕
Phép toán đóng: ∙ = ( ⊕ ) ⊖
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
đối tượng trong ảnh trở lên mượt mà hơn.
Phép toán đóng được ứng dụng trong việc làm trơn đường bao đố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)
NguyễnVănLong
Ứ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 40
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à khí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 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,
nó có ý nghĩa như các ví dụ trong bài trước.
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 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 đó (dĩ nhiên đây là một cách
tiếp cận rất đơn giản!). Tuy nhiên, ta 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
NguyễnVănLong
Ứ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 41
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ở lên liền lơn.
#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);
vector<vector<Point> > contours1;
findContours(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);
}
imshow("Ket qua phat hien truoc phep gian no", src1);
vector<vector<Point> > contours2;
findContours(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);
}
NguyễnVănLong
Ứ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 42
imshow("Ket qua phat hien sau khi phep gian no", src2);
waitKey(0);
}
Trong chương trình trên, 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àm
findContours 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
Ta 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
vit ở giữ mà số 2 và số 9 gần như nối liền. Đây là lúc ta cần 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 đó bạn đọc hoàn toàn có thể cài đặt để tách ra
các kí tự này.
NguyễnVănLong
Ứ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 43
9. Tìm biên ảnh dựa trên bộ lọc Canny
Bộ lọc Canny là sự kết hợp của nhiều bước khác nhau để tìm và tối ưu đường biên, kết
quả là cho ra một đường biên khá mảnh và chính xác. Quá trình tìm biên sử dụng phương
pháp canny có thể được thực hiện qua 4 bước sau:
Bước 1: Loại bớt nhiễu trong ảnh.
Người ta loại nhiễu trong ảnh, làm cho ảnh mờ đi bằng cách nhân chập ảnh với một bộ
lọc Gause, chẳng hạn bộ lọc Gaus 5x5 với hệ số σ = 1.4:
=
1
159
⎣
⎢
⎢
⎢
⎡
2 4 5 4 2
4 9 12 9 4
5 12 15 12 5
4 9 12 9 4
2 4 5 4 2⎦
⎥
⎥
⎥
⎤
Bước 2: Tính toán giá trị gradient trong ảnh
Vì đường biên trong ảnh là nơi phân cách giữa các đối tượng khác nhau, nên tại đó
gradient của nó sẽ biến đổi mạnh mẽ nhất. Để tính toán gradient trong ảnh, ta có thể sử
dụng bộ lọc Sobel, hoặc trực tiếp nhâp chập ma trận ảnh với các mặ nạ theo hướng x và y
chẳng hạn =
−1 0 +1
−2 0 +2
−1 0 +1
, =
−1 −2 −1
0 0 0
+1 +2 +1
Sau đó tính độ lớn gradient trong ảnh :
= + và =
Trong đó, Gx, Gy chính là đạo hàm theo hướng X, Y của điểm ảnh ta đang xét. Góc θ sẽ
được làm tròn theo các hướng thẳng đứng, nằm ngang và hướng chéo, nghĩa là nó sẽ được
làm tròn để nhận các giá trị 0, 45, 90 và 135 độ.
Bước 3: Loại bỏ các giá trị không phải là cực đại
Bước này sẽ tìm ra những điểm ảnh có khả năng là biên ảnh nhất bằng cách loại bỏ đi
những giá trị không phải là cực đại trong bước tìm gradient ảnh ở trên. Ta thấy rằng, với
giá trị của góc θ ở trên thì biên của đối tượng có thể tuân theo bốn hướng, và ta có bốn
khả năng sau:
NguyễnVănLong
Ứ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 44
4. Nếu θ = 00
, khi đó, điểm A sẽ được xem là
một điểm trên biên nếu độ lớn gradient tại A
lớn hơn độ lớn gradient của các điểm tại A3,
A7.
5. Nếu θ = 450
, khi đó, điểm A sẽ được xem là
một điểm trên biên nếu độ lớn gradient tại A
lớn hơn độ lớn gradient của các điểm tại A4,
A8
6. Nếu θ = 900
, khi đó, điểm A sẽ được xem là
một điểm trên biên nếu độ lớn gradient tại A
lớn hơn độ lớn gradient của các điểm tại A1,
A5.
7. Nếu θ = 1350
, khi đó, điểm A sẽ được xem là một điểm trên biên nếu độ lớn
gradient tại A lớn hơn độ lớn gradient của các điểm tại A2, A6
Bước 4: Chọn ra biên của đối tượng trong ảnh
Sau bước trên, ta thu được tập các điểm tương ứng trên đường biên khá mỏng. Vì những
điểm có giá trị gradient lớn bao giờ cũng có xác suất là biên thật sự hơn những điểm có
giá trị gradient bé, đo đó để xác định chính xác hơn nữa biên của các đối tượng, ta sử
dụng các ngưỡng. Theo đó, bộ lọc canny sẽ sử dụng một ngưỡng trên (upper threshold) và
một ngưỡng dưới (lower threshold), nếu gradient tại một điểm trong ảnh có giá trị lớn hơn
ngưỡng trên thì ta xác nhận đó là một điểm biên trong ảnh, nếu giá trị này bé hơn ngưỡng
dưới thì đó không phải điểm biên. Trong trường hợp giá trị gradient nằm giữa ngưỡng
trên và ngưỡng dưới thì nó chỉ được tính là điểm trên biên khi các điểm liên kết bên cạnh
của nó có giá trị gradient lớn hơn ngưỡng trên.
Tìm biên ảnh bằng bộ lọc canny trong OpenCV:
OpenCV cung cấp một hàm cho ta xác định biên trong ảnh của các đối tượng. Nguyên
mẫu của hàm này như sau :
canny(Mat src, Mat dst, int lower_threshold, int upper_threshold, int kernel_size)
Trong đó, src là ảnh cần phát hiện biên (là ảnh xám), dst là ảnh chứa biên được phát hiện,
lower_threshold, upper_threshold là ngưỡng dưới, ngưỡng trên như đã nói bên trên,
kernel_size là kích thước của mặt nạ dùng cho bước thứ hai để tính toán gradient của các
điểm trong ảnh.
Chương trình demo tìm biên trong ảnh dựa trên bộ lọc canny:
NguyễnVănLong
Ứ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 45
#include "stdafx.h"
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
void main()
{
Mat gray = cv::imread("TuoiTho.jpg", CV_LOAD_IMAGE_GRAYSCALE);
Mat dst1, dst2;
imshow("Anh xam", gray);
GaussianBlur(gray, gray, Size(9,9), 2);
double t1 = 30, t2 = 200;
Canny(gray, dst1, t1, t2, 3, false);
t1 = 100; t2 = 120;
Canny(gray, dst2, t1, t2, 3, false);
imshow("Bien trong anh voi nguong 1", dst1);
imshow("Bien trong anh voi nguong 2", dst2);
waitKey(0);
}
Trong chương trình trên, trước khi tìm biên bằng phương pháp canny ta đã làm trơn một
ảnh xám bằng bộ lọc GaussianBlur (việc làm này có ý rất lớn trong việc giảm thiểu các
tiểu tiết không mong muốn trong đường biên sau này). Về nguyên tắc, bộ lọc
GaussianBlur cũng là một bộ lọc số như đã giới thiệu ở bài trước về lọc số trong ảnh, cấu
trúc của hàm GaussianBlur như sau:
cv::GaussianBlur(cv::InputArray src, cv::OutputArray dst, cv::Size ksize, double sigmaX,
double sigmaY = 0, int borderType = 4), trong đó src và dst sẽ là các mảng dữ liệu đầu
vào và kết quả. Một ảnh cũng có thể coi là một mảng dữ liệu, đo đó src và dst chính là
ảnh đầu và ảnh thu được sau khi biến đổi, ksize là kích thước của ma trận lọc, sigmaX,
sigmaY là độ lệch chuẩn theo hướng x và y. Nếu sigmaY = 0, độ lệch chuẩn theo hướng y
sẽ được lấy theo sigmaX. BorderType là cách nội suy biên đối với những điểm ảnh tràn ra
ngoài kích thước của ảnh.
Kết quả thu được sau các ngưỡng t1, t2 khác nhau, ta được những biên có độ chi tiết khác
nhau như hình sau.
NguyễnVănLong
Ứ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 46
10.Chuyển đổi Hough, Phát hiện đường thẳng, đường tròn trong ảnh
Chuyển đổi Hough (Hough transformation) là một phương pháp được dùng nhiều trong
phân tích và xử lý ảnh, mục đích chính của phương pháp này là tìm ra những hình dáng
đặc trưng trong ảnh bằng cách chuyển đổi không gian ảnh ban đầu sang một không gian
của các tham số nhằm đơn giản quá trình tính toán, trong bài này ta xét chuyển đổi Hough
cho đường thẳng và đường tròn.
NguyễnVănLong
Ứ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 47
Chuyển đổi Hough cho đường thẳng.
Ta đã biết rằng, một đường thẳng trong không gian hai chiều có thể được biểu diễn dưới
dạng y = kx + m và cặp hệ số góc k, giá trị m có thể được chọn để làm đặc trưng cho một
đường thẳng. Tuy nhiên, cách biểu diễn theo cặp (k, m) khó thỏa mãn với những đường
thẳng thẳng đứng khi mà hệ số góc là một số vô cùng. Để tránh trường hợp này, ta sẽ biểu
diễn đường thẳng trong hệ tọa độ cực.
Phương trình đường thẳng trong hệ tọa độ cực
có dạng như sau:
= ( ) + ( )
Trong đó, r là khoảng cách từ gốc tọa độ O tới
đường thẳng, θ là góc cực.
Như vậy, với mỗi điểm (x0, y0) ta có một họ
các đường thẳng đi qua thõa mãn phương trình
= ( ) + ( )
Phương trình này biểu diễn một đường cong, như vậy trong một tấm ảnh có n điểm (n
pixel) ta sẽ có n các đường cong. Nếu đường cong của các điểm khác nhau giao nhau, thì
các điểm này cùng thuộc về một đường thẳng.
Bằng cách tính các giao điểm này, ta sẽ xác định
được đường thẳng, đó là nội dung ý tưởng của
thuật toán Hough cho đường thẳng.
Chuyển đổi Hough cho đường tròn
Chuyển đổi Hough cho đường tròn cũng tương
tự như với đường thẳng, phương trình đường
tròn được xác định bởi:
= +
= +
Trong đó, (u,v) là tâm đường tròn, R là bán kính đường tròn, θ là góc có giá trị từ 0 tới
360 độ. Một đường tròn sẽ hoàn toàn được xác định nếu ta biết được bộ ba thông số
(u,v,R). Từ phương trình trên ta có thể chuyển đổi tương đương
= −
= −
NguyễnVănLong
Ứ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 48
Ta xét với trường hợp đã biết trước giá trị của R. Khi đó, với mỗi điểm ảnh (x,y) ta sẽ xác
định được một giá trị (u,v) và lưu nó vào một mảng. Tâm của đường tròn sẽ là giá trị xuất
hiện trong mảng với tần suất lớn nhất. Trong trường hợp R chưa biết, ta tăng giá trị của R
từ một ngưỡng min tới ngưỡng max nào đó và tiến hành như với trường hợp đã biết trước
giá trị R
Tìm đường thẳng, đường tròn trong ảnh.
Để tìm đường thẳng trong ảnh, thư viện OpenCV có hỗ trợ hàm cv::HoughLines và
cv::HoughLinesP, hai hàm này về cơ bản đều thực hiện một thuật toán, nhưng đưa ra kết
quả ở hai dạng khác nhau.
Dạng 1: đưa ra kết quả của đường thẳng là một cặp giá trị (r, θ)
cv::HoughLines(src, lines, rho, theta, threshold, param)
Trong đó, src là ảnh nhị phân chứa biên của các đối tượng cần được phát hiện đường
thẳng (trong thực tế ta có thể sử dụng là một ảnh xám), lines là vector chứa kết quả đầu ra
của (r, θ) đã được phát hiện, rho là độ phân giải của r (tính theo pixel, thực chất đó là
bước tăng nhỏ nhất của r để tính toán), theta là độ phân giải của góc θ (có giá trị từ 0 tới
360 độ), threshold là giá trị nhỏ nhất của tổng các giao điểm của các đường cong để xác
định đường thẳng, param là một thông số mặc định của OpenCV chưa sử dụng đến (nó có
giá trị bằng 0)
Dạng 2: đưa ra kết quả là tọa độ điểm đầu và điểm cuối của đường thẳng
cv::HoughLinesP(src, lines, rho, theta, threshold, minLenght, maxGap)
Trong đó, các thông số src, rho, theta, threshold giống như dạng 1, lines là vector chứa
tọa độ điểm đầu và tọa độ điểm cuối của đường thẳng phát hiện được (x1, y1, x2, y2),
minLength là độ dài nhỏ nhất để có thể xem nó là một đường thẳng (tính theo đơn vị
pixel), maxGap là khoảng cách lớn nhất của hai điểm cạnh nhau để xác định chúng có
thuộc về một đường thẳng hay không (tính theo đơn vị pixel)
Đối với đường tròn, ta cũng áp dụng hàm tương tự: cv::HougCircles(), nguyên mẫu của
hàm như sau:
cv::HougCircles(src, circles, method, dp, min_dist, param1, param2, min_radius,
max_radius)
Trong đó, src có thể là một ảnh nhị phân chứa biên của đối tượng hoặc ảnh xám (chương
trình sẽ tự động dò biên bằng phương pháp canny), circles là vector chứa kết quả phát
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv

Weitere ähnliche Inhalte

Was ist angesagt?

Nhận diện khuôn mặt và phát hiện khuôn mặt
Nhận diện khuôn mặt và phát hiện khuôn mặtNhận diện khuôn mặt và phát hiện khuôn mặt
Nhận diện khuôn mặt và phát hiện khuôn mặtThường Nguyễn
 
ứNg dụng phép biến đổi wavelet trong xử lý ảnh
ứNg dụng phép biến đổi wavelet trong xử lý ảnhứNg dụng phép biến đổi wavelet trong xử lý ảnh
ứNg dụng phép biến đổi wavelet trong xử lý ảnhThanh Hoa
 
Xử lý ảnh PTIT
Xử lý ảnh PTITXử lý ảnh PTIT
Xử lý ảnh PTITTran Tien
 
49899816 giao-trinh-xu-ly-anh
49899816 giao-trinh-xu-ly-anh49899816 giao-trinh-xu-ly-anh
49899816 giao-trinh-xu-ly-anhphaothu0304
 
Vien tham - 7 he thong xu ly anh vien tham
Vien tham - 7 he thong xu ly anh vien thamVien tham - 7 he thong xu ly anh vien tham
Vien tham - 7 he thong xu ly anh vien thamttungbmt
 
GIÁO TRÌNH XỬ LÝ ẢNH Biên soạn PGS.TS NGUYỄN QUANG HOAN_10223112052019
GIÁO TRÌNH XỬ LÝ ẢNH Biên soạn  PGS.TS NGUYỄN QUANG HOAN_10223112052019GIÁO TRÌNH XỬ LÝ ẢNH Biên soạn  PGS.TS NGUYỄN QUANG HOAN_10223112052019
GIÁO TRÌNH XỬ LÝ ẢNH Biên soạn PGS.TS NGUYỄN QUANG HOAN_10223112052019PinkHandmade
 
Tiểu luận cơ sở ngành kỹ thuật phần mềm. phần mềm mô phỏng các thuật toán s...
Tiểu luận  cơ sở ngành kỹ thuật phần mềm. phần mềm  mô phỏng các thuật toán s...Tiểu luận  cơ sở ngành kỹ thuật phần mềm. phần mềm  mô phỏng các thuật toán s...
Tiểu luận cơ sở ngành kỹ thuật phần mềm. phần mềm mô phỏng các thuật toán s...jackjohn45
 
xử lý hình thái học và ứng dụng
xử lý hình thái học và ứng dụngxử lý hình thái học và ứng dụng
xử lý hình thái học và ứng dụngPham Ngoc Long
 
Kĩ thuật lọc ảnh và ứng dụng trong lọc nhiễu làm trơn
Kĩ thuật lọc ảnh và ứng dụng trong lọc nhiễu làm trơnKĩ thuật lọc ảnh và ứng dụng trong lọc nhiễu làm trơn
Kĩ thuật lọc ảnh và ứng dụng trong lọc nhiễu làm trơnNguyen Thieu
 
Huongdansudungphanmemenvi[bookbooming.com]
Huongdansudungphanmemenvi[bookbooming.com]Huongdansudungphanmemenvi[bookbooming.com]
Huongdansudungphanmemenvi[bookbooming.com]bookbooming1
 
Nhận dạng mặt người bằng thuật toán PCA trên Matlab
Nhận dạng mặt người bằng thuật toán PCA trên MatlabNhận dạng mặt người bằng thuật toán PCA trên Matlab
Nhận dạng mặt người bằng thuật toán PCA trên Matlabhieu anh
 
Bao cao tot nghiep complate
Bao cao tot nghiep complateBao cao tot nghiep complate
Bao cao tot nghiep complateMr[L]ink
 
BÀI GIẢNG LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
BÀI GIẢNG LẬP TRÌNH HƯỚNG ĐỐI TƯỢNGBÀI GIẢNG LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
BÀI GIẢNG LẬP TRÌNH HƯỚNG ĐỐI TƯỢNGTrường Phạm
 

Was ist angesagt? (18)

Luận văn: Kỹ thuật đối sánh hình dạng sử dụng đặc trưng, HOT
Luận văn: Kỹ thuật đối sánh hình dạng sử dụng đặc trưng, HOTLuận văn: Kỹ thuật đối sánh hình dạng sử dụng đặc trưng, HOT
Luận văn: Kỹ thuật đối sánh hình dạng sử dụng đặc trưng, HOT
 
Nhận diện khuôn mặt và phát hiện khuôn mặt
Nhận diện khuôn mặt và phát hiện khuôn mặtNhận diện khuôn mặt và phát hiện khuôn mặt
Nhận diện khuôn mặt và phát hiện khuôn mặt
 
ứNg dụng phép biến đổi wavelet trong xử lý ảnh
ứNg dụng phép biến đổi wavelet trong xử lý ảnhứNg dụng phép biến đổi wavelet trong xử lý ảnh
ứNg dụng phép biến đổi wavelet trong xử lý ảnh
 
Xu ly-anh
Xu ly-anhXu ly-anh
Xu ly-anh
 
Xử lý ảnh PTIT
Xử lý ảnh PTITXử lý ảnh PTIT
Xử lý ảnh PTIT
 
49899816 giao-trinh-xu-ly-anh
49899816 giao-trinh-xu-ly-anh49899816 giao-trinh-xu-ly-anh
49899816 giao-trinh-xu-ly-anh
 
Vien tham - 7 he thong xu ly anh vien tham
Vien tham - 7 he thong xu ly anh vien thamVien tham - 7 he thong xu ly anh vien tham
Vien tham - 7 he thong xu ly anh vien tham
 
Luận văn: Kiểm tra lỗi in trên Rearcase sử dụng mạng nơron
Luận văn: Kiểm tra lỗi in trên Rearcase sử dụng mạng nơronLuận văn: Kiểm tra lỗi in trên Rearcase sử dụng mạng nơron
Luận văn: Kiểm tra lỗi in trên Rearcase sử dụng mạng nơron
 
GIÁO TRÌNH XỬ LÝ ẢNH Biên soạn PGS.TS NGUYỄN QUANG HOAN_10223112052019
GIÁO TRÌNH XỬ LÝ ẢNH Biên soạn  PGS.TS NGUYỄN QUANG HOAN_10223112052019GIÁO TRÌNH XỬ LÝ ẢNH Biên soạn  PGS.TS NGUYỄN QUANG HOAN_10223112052019
GIÁO TRÌNH XỬ LÝ ẢNH Biên soạn PGS.TS NGUYỄN QUANG HOAN_10223112052019
 
Tiểu luận cơ sở ngành kỹ thuật phần mềm. phần mềm mô phỏng các thuật toán s...
Tiểu luận  cơ sở ngành kỹ thuật phần mềm. phần mềm  mô phỏng các thuật toán s...Tiểu luận  cơ sở ngành kỹ thuật phần mềm. phần mềm  mô phỏng các thuật toán s...
Tiểu luận cơ sở ngành kỹ thuật phần mềm. phần mềm mô phỏng các thuật toán s...
 
xử lý hình thái học và ứng dụng
xử lý hình thái học và ứng dụngxử lý hình thái học và ứng dụng
xử lý hình thái học và ứng dụng
 
Luận văn: Bài toán phát hiện xương nhờ phép toán hình thái, HOT
Luận văn: Bài toán phát hiện xương nhờ phép toán hình thái, HOTLuận văn: Bài toán phát hiện xương nhờ phép toán hình thái, HOT
Luận văn: Bài toán phát hiện xương nhờ phép toán hình thái, HOT
 
Kĩ thuật lọc ảnh và ứng dụng trong lọc nhiễu làm trơn
Kĩ thuật lọc ảnh và ứng dụng trong lọc nhiễu làm trơnKĩ thuật lọc ảnh và ứng dụng trong lọc nhiễu làm trơn
Kĩ thuật lọc ảnh và ứng dụng trong lọc nhiễu làm trơn
 
Huongdansudungphanmemenvi[bookbooming.com]
Huongdansudungphanmemenvi[bookbooming.com]Huongdansudungphanmemenvi[bookbooming.com]
Huongdansudungphanmemenvi[bookbooming.com]
 
Nhận dạng mặt người bằng thuật toán PCA trên Matlab
Nhận dạng mặt người bằng thuật toán PCA trên MatlabNhận dạng mặt người bằng thuật toán PCA trên Matlab
Nhận dạng mặt người bằng thuật toán PCA trên Matlab
 
Bao cao tot nghiep complate
Bao cao tot nghiep complateBao cao tot nghiep complate
Bao cao tot nghiep complate
 
BÀI GIẢNG LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
BÀI GIẢNG LẬP TRÌNH HƯỚNG ĐỐI TƯỢNGBÀI GIẢNG LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
BÀI GIẢNG LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG
 
Đề tài: Bài toán phát hiện trạng thái mắt của mặt người trong ảnh
Đề tài: Bài toán phát hiện trạng thái mắt của mặt người trong ảnhĐề tài: Bài toán phát hiện trạng thái mắt của mặt người trong ảnh
Đề tài: Bài toán phát hiện trạng thái mắt của mặt người trong ảnh
 

Ähnlich wie Ung dung xu ly anh trong thuc te voi thu vien open cv

Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cvUng dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cvNguyen An
 
lap-trinh-huong-doi-tuong_nguyen-manh-son_lthdt_ptit - [cuuduongthancong.com]...
lap-trinh-huong-doi-tuong_nguyen-manh-son_lthdt_ptit - [cuuduongthancong.com]...lap-trinh-huong-doi-tuong_nguyen-manh-son_lthdt_ptit - [cuuduongthancong.com]...
lap-trinh-huong-doi-tuong_nguyen-manh-son_lthdt_ptit - [cuuduongthancong.com]...tPhan78
 
Ky thuat-lap-trinh 13754342619
Ky thuat-lap-trinh 13754342619Ky thuat-lap-trinh 13754342619
Ky thuat-lap-trinh 13754342619Ky Nguyen Ad
 
Visualbasic6lythuyet 121025092821-phpapp01
Visualbasic6lythuyet 121025092821-phpapp01Visualbasic6lythuyet 121025092821-phpapp01
Visualbasic6lythuyet 121025092821-phpapp01hatrungkhien
 
Lập trình với microsoft visual basic 6.0
Lập trình với microsoft visual basic 6.0Lập trình với microsoft visual basic 6.0
Lập trình với microsoft visual basic 6.0Học Huỳnh Bá
 
[Bao cao]tim hieu ve mo hinh lap trinh
[Bao cao]tim hieu ve mo hinh lap trinh[Bao cao]tim hieu ve mo hinh lap trinh
[Bao cao]tim hieu ve mo hinh lap trinhThùy Linh
 
[Pascal] sang tao1[v5.10]
[Pascal] sang tao1[v5.10][Pascal] sang tao1[v5.10]
[Pascal] sang tao1[v5.10]MasterCode.vn
 
1 chương trình đào tạo của hướng nghề thiết kế đồ họa quảng cáo bài rút gọn
1 chương trình đào tạo của hướng nghề thiết kế đồ họa quảng cáo   bài rút gọn1 chương trình đào tạo của hướng nghề thiết kế đồ họa quảng cáo   bài rút gọn
1 chương trình đào tạo của hướng nghề thiết kế đồ họa quảng cáo bài rút gọnMun Mum Mim
 
Bg ngonngulaptrinh c++
Bg ngonngulaptrinh c++Bg ngonngulaptrinh c++
Bg ngonngulaptrinh c++Cu Chuần
 
Hướng dẫn bộ kĩ sư robot chuyên sâu Lego Education
Hướng dẫn bộ kĩ sư robot chuyên sâu Lego EducationHướng dẫn bộ kĩ sư robot chuyên sâu Lego Education
Hướng dẫn bộ kĩ sư robot chuyên sâu Lego EducationCat Van Khoi
 
Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++Da To
 
Baigiangkythuatlaptrinh hvbcvt
Baigiangkythuatlaptrinh hvbcvtBaigiangkythuatlaptrinh hvbcvt
Baigiangkythuatlaptrinh hvbcvtAricent Bug
 
Cac giai phap_lap_trinh_c___final_
Cac giai phap_lap_trinh_c___final_Cac giai phap_lap_trinh_c___final_
Cac giai phap_lap_trinh_c___final_Hồ Lợi
 

Ähnlich wie Ung dung xu ly anh trong thuc te voi thu vien open cv (20)

Ung dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cvUng dung xu ly anh trong thuc te voi thu vien open cv
Ung dung xu ly anh trong thuc te voi thu vien open cv
 
Báo cáo
Báo cáoBáo cáo
Báo cáo
 
lap-trinh-huong-doi-tuong_nguyen-manh-son_lthdt_ptit - [cuuduongthancong.com]...
lap-trinh-huong-doi-tuong_nguyen-manh-son_lthdt_ptit - [cuuduongthancong.com]...lap-trinh-huong-doi-tuong_nguyen-manh-son_lthdt_ptit - [cuuduongthancong.com]...
lap-trinh-huong-doi-tuong_nguyen-manh-son_lthdt_ptit - [cuuduongthancong.com]...
 
Ky thuat-lap-trinh 13754342619
Ky thuat-lap-trinh 13754342619Ky thuat-lap-trinh 13754342619
Ky thuat-lap-trinh 13754342619
 
Ky thuat lap trinh
Ky thuat lap trinhKy thuat lap trinh
Ky thuat lap trinh
 
Ktlt
KtltKtlt
Ktlt
 
Visualbasic6lythuyet 121025092821-phpapp01
Visualbasic6lythuyet 121025092821-phpapp01Visualbasic6lythuyet 121025092821-phpapp01
Visualbasic6lythuyet 121025092821-phpapp01
 
Lập trình với microsoft visual basic 6.0
Lập trình với microsoft visual basic 6.0Lập trình với microsoft visual basic 6.0
Lập trình với microsoft visual basic 6.0
 
[Bao cao]tim hieu ve mo hinh lap trinh
[Bao cao]tim hieu ve mo hinh lap trinh[Bao cao]tim hieu ve mo hinh lap trinh
[Bao cao]tim hieu ve mo hinh lap trinh
 
Đề tài: Đồ án Xử lý ảnh Nhận dạng mặt người trên matlab, HAY
Đề tài: Đồ án Xử lý ảnh Nhận dạng mặt người trên matlab, HAYĐề tài: Đồ án Xử lý ảnh Nhận dạng mặt người trên matlab, HAY
Đề tài: Đồ án Xử lý ảnh Nhận dạng mặt người trên matlab, HAY
 
[Pascal] sang tao1[v5.10]
[Pascal] sang tao1[v5.10][Pascal] sang tao1[v5.10]
[Pascal] sang tao1[v5.10]
 
1 chương trình đào tạo của hướng nghề thiết kế đồ họa quảng cáo bài rút gọn
1 chương trình đào tạo của hướng nghề thiết kế đồ họa quảng cáo   bài rút gọn1 chương trình đào tạo của hướng nghề thiết kế đồ họa quảng cáo   bài rút gọn
1 chương trình đào tạo của hướng nghề thiết kế đồ họa quảng cáo bài rút gọn
 
Phạm văn ất
Phạm văn ấtPhạm văn ất
Phạm văn ất
 
Bg ngonngulaptrinh c++
Bg ngonngulaptrinh c++Bg ngonngulaptrinh c++
Bg ngonngulaptrinh c++
 
Hướng dẫn bộ kĩ sư robot chuyên sâu Lego Education
Hướng dẫn bộ kĩ sư robot chuyên sâu Lego EducationHướng dẫn bộ kĩ sư robot chuyên sâu Lego Education
Hướng dẫn bộ kĩ sư robot chuyên sâu Lego Education
 
Ctdlgt
CtdlgtCtdlgt
Ctdlgt
 
Ctdlgt
CtdlgtCtdlgt
Ctdlgt
 
Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++Ngon ngu lap_trinh_c++
Ngon ngu lap_trinh_c++
 
Baigiangkythuatlaptrinh hvbcvt
Baigiangkythuatlaptrinh hvbcvtBaigiangkythuatlaptrinh hvbcvt
Baigiangkythuatlaptrinh hvbcvt
 
Cac giai phap_lap_trinh_c___final_
Cac giai phap_lap_trinh_c___final_Cac giai phap_lap_trinh_c___final_
Cac giai phap_lap_trinh_c___final_
 

Ung dung xu ly anh trong thuc te voi thu vien open cv

  • 1. NguyễnVănLong Ứ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 1 Ứng dụng xử lý ảnh trong thực thế với thư viện OpenCV C/C++ Nguyễn Văn Long long.06clc@gmail.com
  • 2. NguyễnVănLong Ứ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 2 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 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. Xuất phát từ thực tế rằng môn học xử lý ảnh ở các trường đại học là một môn học mang nặng tính học thuật, khô khan, các vấn đề được mô tả dưới dạng toán học, sinh viên nắm bắt môn học một cách chung chung mà không đi vào bản chất vấn đề, ứng dụng thực tiễn của môn học, thêm vào đó số lượng tài liệu về chuyên ngành này bằng tiếng Việt là không nhiều, bằng quá trình nghiên cứu nghiêm túc, kinh nghiệm thực tế tác giả đã cố gắng cho ra đời cuốn sách Ứng dụng xử lý ảnh trong thưc tế với thư viện OpenCV. Cuốn đề cập tới một số phần của lĩnh vực xử lý ảnh và thị giác máy, thông qua sự diễn giải trực quan, không xa vào những công thức toán học trừu tượng, phức tạp nhưng vẫn làm nổi bật nên được vấn đề, giúp người đọc có được cái nhìn tổng quát, hiểu được khái niệm và hơn nữa biết được những vấn đề đó ứng dụng vào thực tế như thế nào. Các chủ đề trong cuôn sách này đều đi kèm với một chương trình mô phỏng được viết bằng ngôn ngữ C++ với sự giúp đỡ của thư viện OpenCV, một thư viện mã nguông 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. Cuốn sách được chia thành bốn phần, phần đầu giới thiệu về thư viện OpenCV, phần thứ hai nói về một số vấn đề chọn lọc thường gặp trong xử lý ảnh như không gian màu, các bộ lọc, cách phát hiện đường thẳng đường tròn trong ảnh …, phần thứ ba nói về một số thủ thuật để lập trình với thư viện MFC và phần cuối cùng nói về một số ứng dụng thực tế như bài toán nhận dạng biển số xe … Cuốn sách không chỉ là tài liệu tham khảo bổ ích trong quá trình học tập của các bạn sinh viên, quá trình làm luận văn, đồ án … mà còn là công cụ tốt hỗ trợ cho việc triển khai các ứng dụng thương mại của các kĩ sư, doanh nghiệp và những người quan tâm tới lĩnh vực. Cuối cùng dù đã dành nhiều tâm huyết để hoàn thành cuốn sách nhưng chắc chắn cuốn sách vẫn còn nhiều sai xót, tác giả mong được sự góp ý của bạn đọc. Xin gửi lời chúc tốt tốt đẹp và lời cảm ơn sâu sắc tới độc giả
  • 3. NguyễnVănLong Ứ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 3 Hướng dẫn sử dụng sách Cuốn sách được viết dựa trên những nghiên cứu và quá trình làm việc thực tế của tác giả, với mỗi vấn đề nêu trong sách bạn đọc có thể đọc qua để nắm bắt được ý tưởng chính, sau đó có thể tìm thêm tài liệu để nâng cao hơn vấn đề và có thể thực hành dựa vào mẫu chương trình, source code đi kèm. Thư viện OpenCV được viết trong sách là bản OpenCV 2.4.3, đối với các bản OpenCV khác thì bạn đọc có thể tùy chỉnh lại một chút tuy nhiên về bản chất của vấn đề là tương đối giống nhau. Ngôn ngữ lập trình cho các ví dụ là C/C++, IDE sử dụng là Visual Studio 2010. Tuy nhiên đa số chương trình trong cuốn sách này đều được tách biệt phần xử lý chính ra vào một file *.cpp nào đó nên ta có thể lấy nó để áp dụng vào các trình dịch khác. Có 10 chủ đề chính bao quát một số khía cạnh của lĩnh vực xử lý ảnh được viết khá chi tiết và giải thích đầy đủ, 3 project được tác giả mô tả chung chung hơn. Do đó bạn đọc nếu chưa thực sự quen với thư viện OpenCV nên đọc theo thứ tự từ đầu tới cuối Trong cuốn sách có nhiều vấn đề liên quan tới kĩ thuật lập trình nhưng do phạm vi giới hạn, tác giả chỉ có thể nói qua được một số khía cạnh, trên thực tế có nhiều cách khác nhau để giải quyết cùng một công việc, với những vấn đề lập trình bạn đọc chưa rõ có thể tham khảo thêm tài ở các nguồn khác nhau hoặc giải quyết theo hướng mà bạn đọc cảm thấy là thỏa đáng nhất
  • 4. NguyễnVănLong Ứ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 4 Mục Lục Chương I. Làm quen với thư viện OpenCV 1. Giới thiệu về thư viện OpenCV 5 2. Phiên bản OpenCV 1 hay OpenCV 2 5 3. Hướng dẫn sử dụng OpenCV trên Window 6 Chương II. Các phép xử lý đơn giản trong OpenCV 1. Chương trình đầu tiên 12 2. Không gian màu, chuyển đổi không gian màu 13 3. Điều chỉnh độ sang, độ tương phản 17 4. Ảnh nhị phân, nhị phân hóa với ngưỡng động 19 5. Histogram, cân bằng histogram 23 6. Phóng to, thu nhỏ, xoay ảnh 27 7. Lọc số trong ảnh 30 8. Các phép toán hình thái học trong ảnh 37 9. Tìm biên ảnh với bộ lọc Canny 43 10.Chuyển đổi Hough, Phát hiện đường thẳng, đường tròn trong ảnh 46 Chương III. Lập trình xử lý ảnh với giao diện MFC 1. Giới thiệu về MFC 51 2. Khởi tạo project MFC 51 3. Làm việc với các điều khiển (Control) 54 4. Chuyển đổi các kiểu dữ liệu trong MFC 59 5. Chương trình tải ảnh và hiển thị ảnh lên giao diện MFC 61 Chương IV. Một số ứng dụng trong thực tế 1. My Photo Editor, phần mềm chỉnh sửa ảnh đơn giản 64 2. Nhận dạng biển số xe 73 3. MyCam, một số hiệu ứng ảnh trong video 90
  • 5. NguyễnVănLong Ứ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 5 Chương I. Làm quen với thư viện OpenCV 1. Giới thiệu về thư viện OpenCV OpenCV (Open Source Computer Vision) là 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 đó bạn 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. 2. Phiên bản OpenCV 1 hay 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 ta sẽ chỉ ra 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, 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.
  • 6. NguyễnVănLong Ứ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 6 - 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 ta hãy 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 1.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); Ta thấy rằng đố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 ta 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 cuốn sách 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. 3. Hướng dẫn sử dụng thư viện OpenCV trên Window
  • 7. NguyễnVănLong Ứ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 7 Trước hết ta cần 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 cuốn sách này là bản 2.4.3 với lần update cuối cùng là vào ngày 25 tháng 12 năm 2012. Sau khi download về máy, tiến hành cài đặt bình thường, ta để 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 ta sẽ 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 CDT 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 ta 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 Chọn OK, sau đó nhấn Next, hộp thoại tiếp theo xuất hiện, ở hộp thoại này ta 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. NguyễnVănLong Ứ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 8 Project mới được tạo ra là project hoàn toàn trố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 ta 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. Bây giở trong file này 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 ta 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, ta tìm mục Include Directories và Library Directories. Ta sẽ chỉ đường dẫn hai thư mục này đến các phần tương ứng của thư viện OpenCV. Mục Include Directories, ta tùy chỉnh ở ô bên phải tới C:opencvbuildinclude Mục Library Directories trỏ đến thư mục C:opencvbuildx86vc10lib nếu như ta sử dụng hệ điều hành 32bit hoặc C:opencvbuildx64vc10lib cho hệ điều hành 64bit.
  • 9. NguyễnVănLong Ứ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 9 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 Additional Dependencies là opencv_core243d.lib, opencv_imgproc243d.lib, opencv_highgui243d.lib. Chú ý là các lib thêm vào sẽ tương ứng với các header ta khai báo trong chương trình, và tùy thuộc vào mục đích sử dụng mà ta có thể thêm vào các lib các nhau, giả sử ta cần sử dụng tới các hàm về video, khi đó ta thêm header #include <opencv2/video/video.hpp> thì trong phần Additional Dependencies ta phải khai báo thêm opencv_video243d.lib. Chữ d đứng cuối các file trên thể hiện ta đ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. Tuy nhiên khi đang còn học tập và cần nhiều chỉnh sửa ta nên để ở chế độ debug. 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ác file *.dll. Cách đơn giản nhất là 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ương trình (file *.exe). Các file *.dll này nằm trong mục C:opencvbuildx86bin với win 32 bit hoặc C:opencvbuildx64bin 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àm việ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() { ... }
  • 10. NguyễnVănLong Ứ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 10 Với Eclipse CDT Khởi động Eclipse, Từ cửa sổ Eclipse chọn New -> C++ Project , hộp thoại C++ Project xuất hiện, trong hộp thoại ta chọn Project name là opencv, Project type là Hello World C++ Project (Có thể chọn là Empty Project), Toolchains là MinGW GCC, Chọn Finish và ta có một Project mới. Bây giờ tùy chỉnh cho project này hoạt động được với OpenCV. Trong cửa sổ của Eclipse chọn Project - >Properties, cửa sổ Properties hiện ra. Tron cửa sổ Properties chọn C/C++ Build->Settings. Trong tab Tool Settings. Ở phần GCC C++ Compiller chọn Include rồi dẫn đường dẫn tới mục Include của OpenCV là C:opencvbuildinclude. Trong phần MinGW C++ Linker chọn Library và chọn các mục như sau: click vào dấu cộng ở Library search path (-L) và dẫn tới thư mục lib: C:opencvbuildx86mingwlib đối với Windows 32 bit hoặc C:opencvbuildx64mingwlib đối với Windows 64 bit. Tiếp đó click vào dấu "cộng" để thêm Library(-I) vào, các library cần thêm lần lượt là: opencv_core243, opencv_highgui243, opencv_imgproc243 ... nói chung là tùy vào nhu cầu sử dụng có thể thêm một hoặc nhiều lib vào.
  • 11. NguyễnVănLong Ứ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 11 Ta cũng cần phải copy các *.dll tương ứng vào thư mục chứa file chạy *.execủa chương trình để chương trình có thể chạy thành công.
  • 12. NguyễnVănLong Ứ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 12 Chương II. Các phép xử lý ảnh và ứng dụng cơ bản 1. Chương trình đầu tiên Trong bài này ta sẽ tìm hiểu một ví dụ đầu tiên như 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 <opencv2highguihighgui.hpp> #include <opencv2corecore.hpp> using namespace std; using namespace cv; int main() { cout<<"Chuong trinh dau tien"<<endl; 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ì ta phải chỉ ra đường dẫn tương đối dạng như D:Anhvietnam.jpg hoặc D://Anh//Vietnam.jpg. Flags là tham số loại ảnh mà ta muốn load vào, cụ thể nếu nếu muốn load ảnh mầu thì ta để CV_LOAD_IMAGE_COLOR, nếu là ảnh xám thì ta để CV_LOAD_IMAGE_GRAYSCALE… Sau khi đã load ảnh thành công, muốn hiển thị ảnh lên màn hình ta phải 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 dung hàm này mục đích là để dừng màn hình lại
  • 13. NguyễnVănLong Ứ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 13 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ả chương trình chay: 2. Không gian màu, chuyển đổi giữa các không gian màu Khôn gian màu là một mô hình toán học dùng để mô tả các màu sắc trong thực tế được biểu diễn dưới dạng số học. Trên thực tế có rất nhiều không gian màu khác nhau được mô hình để sử dụng vào những mục đích khác nhau. Trong bài này ta sẽ tìm hiểu qua về ba không gian màu cơ bản hay được nhắc tới và ứng dụng nhiều, đó là hệ không gian màu RGB, HSV và CMYK. Không gian màu RGB RGB là không gian màu rất phổ biến được dùng trong đồ họa máy tính và nhiều thiết bị kĩ thuật số khác. Ý tưởng chính của không gian màu này là sự kết hợp của 3 màu sắc cơ bản : màu đỏ (R, Red), xanh lục (G, Green) và xanh lơ (B, Blue) để mô tả tất cả các màu sắc khác. Nếu như một ảnh số được mã hóa bằng 24bit, nghĩa là 8bit cho kênh R, 8bit cho kênh G, 8bit cho kênh B, thì mỗ kênh này màu này sẽ nhận giá trị từ 0-255. Với mỗi giá trị khác nhau của các kênh màu kết hợp với nhau ta sẽ được một màu khác nhau, như vậy ta sẽ có tổng cộng 255x255x255 = 1.66 triệu màu sắc.
  • 14. NguyễnVănLong Ứ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 14 Ví dụ: màu đen là sự kết hợp của các kênh màu (R, G, B) với giá trị tương ứng (0, 0, 0) màu trắng có giá trị (255, 255, 255), màu vàng có giá trị (255, 255, 0), màu tím đậm có giá trị (64, 0, 128) ...Nếu ta dùng 16bit để mã hóa một kênh màu (48bit cho toàn bộ 3 kênh màu) thì dãi màu sẽ trãi rộng lên tới 3*2^16 = ... Một con số rất lớn. Không gian màu CMYK. CMYK là không gian màu được sử dụng phổ biến trong ngành công nghiệp in ấn.Ý tưởng cơ bản của hệ không gian này là dùng 4 màu sắc cơ bản để phục vụ cho việc pha trộn mực in. Trên thực tế, người ta dùng 3 màu là C=Cyan: xanh lơ, M=Magenta: hồng xẫm, và Y=Yellow: vàng để biểu diễn các màu sắc khác nhau. Nếu lấy màu hồng xẫm cộng với vàng sẽ ra màu đỏ, màu xẫm kết hợp với xanh lơ sẽ cho xanh lam ... Sự kết hợp của 3 màu trên sẽ cho ra màu đen, tuy nhiên màu đen ở đây khôn phải là đen tuyệt đối và thường có độ tương phản lớn, nên trong ngành in, để tiết kiệm mực in người ta thêm vào màu đen để in những chi tiết có màu đen thay vì phải kết hợp 3 màu sắc trên. Và như vậy ta có hệ màu CMYK. chữ K ở đây là để kí hiệu màu đen (Black), có nhẽ chữ B đã được dùng để biểu diễn màu Blue nên người ta lấy chữ cái cuối K để biểu diễn màu đen? Nguyên lý làm việc của hệ màu này như sau : Trên một nền giấy trắng, khi mỗi màu này được in lên sẽ loại bỏ dần đi thành phần màu trắng. 3 màu C, M, Y khác nhau in theo những tỉ lệ khác nhau sẽ loại bỏ đi thành phần đó một cách khác nhau và cuối cùng cho ta màu sắc cần in. Khi cần in màu đen, thay vì phải in cả 3 màu người ta dùng màu đen để in lên. Nguyên lý này khác với nguyên lý làm việc của hệ RGB ở chỗ hệ RGB là sự kết hợp của các thành phần màu, còn hệ CMYK là sự loại bỏ lẫn nhau của các thành phần màu. Không gian màu HSV. HSV và cũng gần tương tự như HSL là không gian màu được dùng nhiều trong việc ch ỉnh sữa ảnh, phân tích ảnh và một phần của lĩnh vực thị giác máy tính. Hệ không gian này dựa vào 3 thông số sau để mô tả màu sắc H = Hue: màu sắc, S = Saturation: độ đậm đặc, sự bảo hòa, V = value: giá trị cường độ sáng. Không gian màu này thường được biểu diễn dưới dạng hình trụ hoặc hình nón . Theo đó, Ứ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 14 Ví dụ: màu đen là sự kết hợp của các kênh màu (R, G, B) với giá trị tương ứng (0, 0, 0) màu trắng có giá trị (255, 255, 255), màu vàng có giá trị (255, 255, 0), màu tím đậm có giá trị (64, 0, 128) ...Nếu ta dùng 16bit để mã hóa một kênh màu (48bit cho toàn bộ 3 kênh màu) thì dãi màu sẽ trãi rộng lên tới 3*2^16 = ... Một con số rất lớn. Không gian màu CMYK. CMYK là không gian màu được sử dụng phổ biến trong ngành công nghiệp in ấn.Ý tưởng cơ bản của hệ không gian này là dùng 4 màu sắc cơ bản để phục vụ cho việc pha trộn mực in. Trên thực tế, người ta dùng 3 màu là C=Cyan: xanh lơ, M=Magenta: hồng xẫm, và Y=Yellow: vàng để biểu diễn các màu sắc khác nhau. Nếu lấy màu hồng xẫm cộng với vàng sẽ ra màu đỏ, màu xẫm kết hợp với xanh lơ sẽ cho xanh lam ... Sự kết hợp của 3 màu trên sẽ cho ra màu đen, tuy nhiên màu đen ở đây khôn phải là đen tuyệt đối và thường có độ tương phản lớn, nên trong ngành in, để tiết kiệm mực in người ta thêm vào màu đen để in những chi tiết có màu đen thay vì phải kết hợp 3 màu sắc trên. Và như vậy ta có hệ màu CMYK. chữ K ở đây là để kí hiệu màu đen (Black), có nhẽ chữ B đã được dùng để biểu diễn màu Blue nên người ta lấy chữ cái cuối K để biểu diễn màu đen? Nguyên lý làm việc của hệ màu này như sau : Trên một nền giấy trắng, khi mỗi màu này được in lên sẽ loại bỏ dần đi thành phần màu trắng. 3 màu C, M, Y khác nhau in theo những tỉ lệ khác nhau sẽ loại bỏ đi thành phần đó một cách khác nhau và cuối cùng cho ta màu sắc cần in. Khi cần in màu đen, thay vì phải in cả 3 màu người ta dùng màu đen để in lên. Nguyên lý này khác với nguyên lý làm việc của hệ RGB ở chỗ hệ RGB là sự kết hợp của các thành phần màu, còn hệ CMYK là sự loại bỏ lẫn nhau của các thành phần màu. Không gian màu HSV. HSV và cũng gần tương tự như HSL là không gian màu được dùng nhiều trong việc ch ỉnh sữa ảnh, phân tích ảnh và một phần của lĩnh vực thị giác máy tính. Hệ không gian này dựa vào 3 thông số sau để mô tả màu sắc H = Hue: màu sắc, S = Saturation: độ đậm đặc, sự bảo hòa, V = value: giá trị cường độ sáng. Không gian màu này thường được biểu diễn dưới dạng hình trụ hoặc hình nón . Theo đó, Ứ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 14 Ví dụ: màu đen là sự kết hợp của các kênh màu (R, G, B) với giá trị tương ứng (0, 0, 0) màu trắng có giá trị (255, 255, 255), màu vàng có giá trị (255, 255, 0), màu tím đậm có giá trị (64, 0, 128) ...Nếu ta dùng 16bit để mã hóa một kênh màu (48bit cho toàn bộ 3 kênh màu) thì dãi màu sẽ trãi rộng lên tới 3*2^16 = ... Một con số rất lớn. Không gian màu CMYK. CMYK là không gian màu được sử dụng phổ biến trong ngành công nghiệp in ấn.Ý tưởng cơ bản của hệ không gian này là dùng 4 màu sắc cơ bản để phục vụ cho việc pha trộn mực in. Trên thực tế, người ta dùng 3 màu là C=Cyan: xanh lơ, M=Magenta: hồng xẫm, và Y=Yellow: vàng để biểu diễn các màu sắc khác nhau. Nếu lấy màu hồng xẫm cộng với vàng sẽ ra màu đỏ, màu xẫm kết hợp với xanh lơ sẽ cho xanh lam ... Sự kết hợp của 3 màu trên sẽ cho ra màu đen, tuy nhiên màu đen ở đây khôn phải là đen tuyệt đối và thường có độ tương phản lớn, nên trong ngành in, để tiết kiệm mực in người ta thêm vào màu đen để in những chi tiết có màu đen thay vì phải kết hợp 3 màu sắc trên. Và như vậy ta có hệ màu CMYK. chữ K ở đây là để kí hiệu màu đen (Black), có nhẽ chữ B đã được dùng để biểu diễn màu Blue nên người ta lấy chữ cái cuối K để biểu diễn màu đen? Nguyên lý làm việc của hệ màu này như sau : Trên một nền giấy trắng, khi mỗi màu này được in lên sẽ loại bỏ dần đi thành phần màu trắng. 3 màu C, M, Y khác nhau in theo những tỉ lệ khác nhau sẽ loại bỏ đi thành phần đó một cách khác nhau và cuối cùng cho ta màu sắc cần in. Khi cần in màu đen, thay vì phải in cả 3 màu người ta dùng màu đen để in lên. Nguyên lý này khác với nguyên lý làm việc của hệ RGB ở chỗ hệ RGB là sự kết hợp của các thành phần màu, còn hệ CMYK là sự loại bỏ lẫn nhau của các thành phần màu. Không gian màu HSV. HSV và cũng gần tương tự như HSL là không gian màu được dùng nhiều trong việc ch ỉnh sữa ảnh, phân tích ảnh và một phần của lĩnh vực thị giác máy tính. Hệ không gian này dựa vào 3 thông số sau để mô tả màu sắc H = Hue: màu sắc, S = Saturation: độ đậm đặc, sự bảo hòa, V = value: giá trị cường độ sáng. Không gian màu này thường được biểu diễn dưới dạng hình trụ hoặc hình nón . Theo đó,
  • 15. NguyễnVănLong Ứ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 15 đi theo vòng tròn từ 0 -360 độ là trường biểu diễn màu sắc(Hue). Trường này bắt đầu từ màu đỏ đầu tiên (red primary) tới màu xanh lục đầu tiên (green primary) nằm trong khoảng 0-120 độ, từ 120 - 240 độ là màu xanh lục tới xanh lơ (green primary - blue primary). Từ 240 - 360 là từ màu đen tới lại màu đỏ. Không gian màu HSV Hình tròn biểu diễn màu sắc (HUE) Chuyển đổi giữa các không gian màu. Chuyển đổi RGB sang CMYK và ngược lại. Như đã nói ở trên, thành phần K là thành phần phụ dùng để in cho những điểm màu có màu đen trong hệ CYMK, do vậy để chuyển không gian màu từ RGB sang CMYK trước hết ta chuyển RGB sang CMY sau đó tìm thành phần K còn lại. Cô ng thức chuyển từ RGB sang CMY: (C', M', Y') = ((255 - R), (255 - G), (255 - B)). Việc tính giá trị của K lại là một vấn đề khác vì nó liên quan tới nhà sản xuất công nghệ in, tuy nhiên về mặt lý thuyết có thể chấp nhận rằng K = min {C'/2,55, M'/2,55, Y'/2,55} , như vậy 0<= K <=100. Nếu K = 100, thì C = M = Y =0 (trương hợp in màu đen) Nếu 0< K < 100: C = (C'/2.55 - K) * 100 /(100 - K), M = (M'/2.55 - K) * 100 /(100 - K), Y = (Y'/2.55 - K) *100 /(100 - K) và K = K. Trong đó, C, M, Y, K được làm tròn tới để lấy chỉ số nguyên. Chuyển đổi RGB sang HSV và ngược lại Giả sử ta có một điểm màu có giá trị trong hệ RGB là (R, G, B). ta chuyển sang không gian HSV như sau: Đặt M = Max(R, G, B), m = Min(R, G, B) và C = M - m. Nếu M = R, H' = (G - B)/C mod 6. Nếu M = G, H' = (B - R)/C + 2. Nếu M = B, H' = (R - G)/C + 4. Và H = H'x60. Trong trường hợp C = 0, H = 00 V = M. Ứ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 15 đi theo vòng tròn từ 0 -360 độ là trường biểu diễn màu sắc(Hue). Trường này bắt đầu từ màu đỏ đầu tiên (red primary) tới màu xanh lục đầu tiên (green primary) nằm trong khoảng 0-120 độ, từ 120 - 240 độ là màu xanh lục tới xanh lơ (green primary - blue primary). Từ 240 - 360 là từ màu đen tới lại màu đỏ. Không gian màu HSV Hình tròn biểu diễn màu sắc (HUE) Chuyển đổi giữa các không gian màu. Chuyển đổi RGB sang CMYK và ngược lại. Như đã nói ở trên, thành phần K là thành phần phụ dùng để in cho những điểm màu có màu đen trong hệ CYMK, do vậy để chuyển không gian màu từ RGB sang CMYK trước hết ta chuyển RGB sang CMY sau đó tìm thành phần K còn lại. Cô ng thức chuyển từ RGB sang CMY: (C', M', Y') = ((255 - R), (255 - G), (255 - B)). Việc tính giá trị của K lại là một vấn đề khác vì nó liên quan tới nhà sản xuất công nghệ in, tuy nhiên về mặt lý thuyết có thể chấp nhận rằng K = min {C'/2,55, M'/2,55, Y'/2,55} , như vậy 0<= K <=100. Nếu K = 100, thì C = M = Y =0 (trương hợp in màu đen) Nếu 0< K < 100: C = (C'/2.55 - K) * 100 /(100 - K), M = (M'/2.55 - K) * 100 /(100 - K), Y = (Y'/2.55 - K) *100 /(100 - K) và K = K. Trong đó, C, M, Y, K được làm tròn tới để lấy chỉ số nguyên. Chuyển đổi RGB sang HSV và ngược lại Giả sử ta có một điểm màu có giá trị trong hệ RGB là (R, G, B). ta chuyển sang không gian HSV như sau: Đặt M = Max(R, G, B), m = Min(R, G, B) và C = M - m. Nếu M = R, H' = (G - B)/C mod 6. Nếu M = G, H' = (B - R)/C + 2. Nếu M = B, H' = (R - G)/C + 4. Và H = H'x60. Trong trường hợp C = 0, H = 00 V = M. Ứ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 15 đi theo vòng tròn từ 0 -360 độ là trường biểu diễn màu sắc(Hue). Trường này bắt đầu từ màu đỏ đầu tiên (red primary) tới màu xanh lục đầu tiên (green primary) nằm trong khoảng 0-120 độ, từ 120 - 240 độ là màu xanh lục tới xanh lơ (green primary - blue primary). Từ 240 - 360 là từ màu đen tới lại màu đỏ. Không gian màu HSV Hình tròn biểu diễn màu sắc (HUE) Chuyển đổi giữa các không gian màu. Chuyển đổi RGB sang CMYK và ngược lại. Như đã nói ở trên, thành phần K là thành phần phụ dùng để in cho những điểm màu có màu đen trong hệ CYMK, do vậy để chuyển không gian màu từ RGB sang CMYK trước hết ta chuyển RGB sang CMY sau đó tìm thành phần K còn lại. Cô ng thức chuyển từ RGB sang CMY: (C', M', Y') = ((255 - R), (255 - G), (255 - B)). Việc tính giá trị của K lại là một vấn đề khác vì nó liên quan tới nhà sản xuất công nghệ in, tuy nhiên về mặt lý thuyết có thể chấp nhận rằng K = min {C'/2,55, M'/2,55, Y'/2,55} , như vậy 0<= K <=100. Nếu K = 100, thì C = M = Y =0 (trương hợp in màu đen) Nếu 0< K < 100: C = (C'/2.55 - K) * 100 /(100 - K), M = (M'/2.55 - K) * 100 /(100 - K), Y = (Y'/2.55 - K) *100 /(100 - K) và K = K. Trong đó, C, M, Y, K được làm tròn tới để lấy chỉ số nguyên. Chuyển đổi RGB sang HSV và ngược lại Giả sử ta có một điểm màu có giá trị trong hệ RGB là (R, G, B). ta chuyển sang không gian HSV như sau: Đặt M = Max(R, G, B), m = Min(R, G, B) và C = M - m. Nếu M = R, H' = (G - B)/C mod 6. Nếu M = G, H' = (B - R)/C + 2. Nếu M = B, H' = (R - G)/C + 4. Và H = H'x60. Trong trường hợp C = 0, H = 00 V = M.
  • 16. NguyễnVănLong Ứ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 16 S = C/V. Trong trường hợp V hoặc C bằng 0, S = 0. Để chuyển từ HSV sang RGB ta làm như sau: Giả sử ta có không gian màu HSV với H = [0, 360], S = [0, 1], V = [0, 1]. Khi đó, ta tính C = VxS. H' = H/60. X = C(1 - |H' mod2 -1|). Ta biểu diễn hệ (R1, G1, B1) như sau: ( 1, 1, 1) = ⎩ ⎪ ⎪ ⎨ ⎪ ⎪ ⎧ (0, 0, 0) ế ℎư đượ á đị ℎ ( , , 0) ế 0 ≤ < 1 ( , , 0) ế 1 ≤ < 2 (0, , ) ế 2 ≤ < 3 (0, , ) ế 3 ≤ < 4 ( , 0, ) ế 4 ≤ < 5 , 0, ) ế 5 ≤ < 6 Chương trình chuyển đổi các không gian màu Trong OpenCV, các không gian màu được được chuyển đổi qua lại nhờ hàm cvtColor (convert color), nguyên mẫu hàm này như sau: cv::cvtColor(cv::InputArray src, cv::OutputArray dst, int code) Trong đó, src, dst là ảnh gốc và ảnh thu được sau khi chuyển đổi không gian màu. code mà mã chuyển đổi không gian màu. OpenCV định nghĩa khá nhiều chuyển đổi giữa các không gian màu chẳng hạn như code = CV_BGR2GRAY sẽ chuyển ảnh ở không gian màu RGB sang ảnh xám, code = CV_HSV2BGR sẽ chuyển ảnh ở không gian màu HSV sang không gian màu RGB … #include "stdafx.h" #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv; void main() { Mat src = imread("LucBinh.jpg", CV_LOAD_IMAGE_COLOR); Mat gray, hsv, ycrcb; cvtColor(src, gray, CV_BGR2GRAY); cvtColor(src, hsv, CV_BGR2HSV); cvtColor(src, ycrcb, CV_BGR2YCrCb); imshow("src", src); imshow("gray", gray); imshow("hsv", hsv); imshow("ycrcb", ycrcb); waitKey(0);
  • 17. NguyễnVănLong Ứ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 17 } Sau đây là hình ảnh khi chuyển đổi các không gian màu trên 3. Điều chỉnh độ sang và độ tương phản trong ảnh Trong bài này ta sẽ tìm hiểu về cấu trúc của một bức ảnh, cách tiếp cận và điều chỉnh tới từng điểm ảnh. Một ảnh số được lưu trữ trên máy tính là một ma trận các điểm ảnh (hay pixel). Trong OpenCV nó được biểu diễn dưới dạng cv::Mat. Ta xét một kiểu ảnh thông thường nhất, đó là ảnh RGB. Với ảnh này, mỗi pixel ảnh quan sát được là sự kết hợp của các thành phần màu R (Red), Green (Green) và Blue (Blue). Sự kết hợp này theo những tỉ lệ R, G, B khác nhau sẽ tạo ra vô số các màu sắc khác nhau. Giả sử ảnh được mã hóa bằng 8 bit với từng kênh màu, khi đó mỗi giá trị của R, G, B sẽ nằm trong khoảng [0, 255]. Như vậy ta có thể biểu diễn tới 255*255*255 ~ 1.6 triệu màu sắc từ ba màu cơ bản trên. Ta có thể xem cách biểu diễn ảnh trong OpenCV ở định dạng cv::Mat qua hình ảnh sau:
  • 18. NguyễnVănLong Ứ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 18 Cột 0 Cột 1 Cột m Hàng 0 0, 0 0, 0 0, 0 0, 1 0, 1 0, 1 0, m 0, m 0, m Hàng 1 1, 0 1, 0 1, 0 1, 1 1, 1 1, 1 1, m 1, m 1, m Hàng 2 2, 0 2, 0 2, 0 2, 1 2, 1 2, 1 2, m 2, m 2, m Hàng n n, 0 n, 0 n, 0 N, 1 n, 1 n, 1 n, m n, m n, m Như vậy, mỗi ảnh sẽ có n hàng và m cột, m gọi là chiều dài của ảnh (width) và n gọi là chiều cao của ảnh (heigh). Mỗi pixel ở vị trí (i,j) trong ảnh sẽ tương ứng với 3 kênh màu kết hợp trong nó. Để truy xuất tới từng pixel ảnh với những kênh màu riêng rẽ ta sử dụng mẫu sau: img.at<cv::Vec3b>(i,j)[k] Trong đó, i ,j là pixel ở hàng thứ i và cột thứ j, img là ảnh mà ta cần truy xuất tới các pixel của nó. cv::Vec3b là kiểu vector uchar 3 thành phần, dung để biểu thị 3 kênh màu tương ứng. k là kênh màu thứ k, k = 0, 1, 2 tương ứng với kênh màu B, G, R. Chú ý là trong OpenCV, hệ màu RGB được biểu diễn theo thứ tự chữ cái là BGR. Sau đây ta sẽ áp dụng kiến thức trên để làm tăng, giảm độ sang và tương phản của một ảnh màu, việc làm này cũng hoàn toàn tương tự đối với ảnh xám, chỉ khác biệt là ảnh ta dung một kênh duy nhất để biểu diễn ảnh xám. Chương trình tăng, giảm độ sáng và độ tương phản của một ảnh Giả sử f là một hàm biểu diễn cho một ảnh nào đó, f(x,y) là giá trị của pixel trong ảnh ở vị trí (x,y). Đặt g(x,y) = αf(x,y) + β. Khi đó, nếu α ≠ 1, thì ta nói ảnh g(x,y) có độ tương phản gấp α lần so với ảnh f(x,y). Nếu β ≠ 0ta nói độ sáng của ảnh g(x,y) đã thay đổi một lượng là β. Dựa vào công thức trên ta có chương trình thay đổi độ sáng và tương phản của ảnh như sau: #include "stdafx.h" #include <iostream> #include <opencv2corecore.hpp> #include <opencv2highguihighgui.hpp> using namespace std; using namespace cv; int main() { cout<<"Chuong trinh dieu chinh do sang va tuong phan"<<endl; Mat src = imread("hoa_huong_duong.jpg", 1); Mat dst = src.clone(); double alpha = 2.0; int beta = 30; for(int i = 0; i < src.rows; i++) for(int j = 0; j < src.cols; j++) for(int k = 0; k < 3; k++)
  • 19. NguyễnVănLong Ứ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 19 dst.at<Vec3b>(i,j)[k] = saturate_cast<uchar>( alpha*(src.at<Vec3b>(i,j)[k] ) + beta); imshow("anh goc", src); imshow("anh co sau khi chinh do tuong phan va do sang", dst); waitKey(0); return 0; } Trong chương trình trên, hàm clone() sẽ sao chép một ảnh giống hệt như ảnd gốc cho vào ảnh đích (dst = src.clone()). Giá trị của các pixel ảnh f(x,y) và g(x,y) ở đây phải nằm trong khoảng [0, 255], trong khi phép biến đổi g(x,y) = αf(x,y) + β có thể khiến cho giá trị của g(x,y) vượt qua ngưỡng đó. Để tránh tình trạng tràn số hoặc kiểu dữ liệu không tương thích, ta dùng thêm hàm saturate_cast<uchar>(type). Hàm này sẽ biến kiểu dữ liệu type nếu không phải là uchar thành kiểu dữ liệu uchar Sau đây là kết quả chương trình với giá trị α = 2.0 và β = 30 4. Ả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ến mộ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
  • 20. NguyễnVănLong Ứ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 20 Ảnh xám Ảnh nhị phân 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. T = 50 T = 100 T = 150 Để 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ĩ
  • 21. NguyễnVănLong Ứ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 21 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 đó (ta 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: 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 <opencv2corecore.hpp> #include <opencv2highguihighgui.hpp> #include <opencv2imgprocimgproc.hpp> #include <iostream> using namespace std; using namespace cv; int main() { cout<<"Nhi phan anh voi nguong dong"<<endl; 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); Ứ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 21 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 đó (ta 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: 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 <opencv2corecore.hpp> #include <opencv2highguihighgui.hpp> #include <opencv2imgprocimgproc.hpp> #include <iostream> using namespace std; using namespace cv; int main() { cout<<"Nhi phan anh voi nguong dong"<<endl; 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); Ứ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 21 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 đó (ta 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: 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 <opencv2corecore.hpp> #include <opencv2highguihighgui.hpp> #include <opencv2imgprocimgproc.hpp> #include <iostream> using namespace std; using namespace cv; int main() { cout<<"Nhi phan anh voi nguong dong"<<endl; 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);
  • 22. NguyễnVănLong Ứ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 22 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: Ảnh xám Ảnh nhị phân
  • 23. NguyễnVănLong Ứ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 23 5. Histogram, cân bằng histogram trong ảnh Histogram của một ảnh là một biểu đồ nói lên mối quan hệ giữa các giá trị của pixel ảnh (điểm ảnh) và tần suất xuất hiện của chúng. Nhìn vào biểu đồ histogram ta có thể đoán được một ảnh sáng tối như thế nào. Nếu một ảnh có histogram lệch về phía phải biểu đồ, ta nói ảnh đó thừa sáng. Nếu lệch về phía trái thì ảnh đó thiếu sáng. Hình bên mô tả histogram của một ảnh xám, ảnh này có histogram lệch về phía trái của biểu đồ và do đó ảnh này là khá tối. Đối với ảnh màu, ta có thể tính toán histogram cho từng kênh màu một. Sau đây là chương trình tính và vẽ biểu đồ histogram của một ảnh màu. #include <iostream> #include <opencv2highguihighgui.hpp> #include <opencv2imgprocimgproc.hpp> using namespace std; using namespace cv; int main() { std::cout<<"Tim histogram anh mau"<<std::endl; Mat src = imread("buoi.jpg"); vector<Mat> img_rgb; Mat img_r, img_g, img_b; int w = 400, h = 400; int size_hist = 255; float range[] = {0, 255}; const float* hist_range = {range}; split(src, img_rgb); calcHist(&img_rgb[0], 1, 0, Mat(), img_b, 1, &size_hist, &hist_range, true, false); calcHist(&img_rgb[1], 1, 0, Mat(), img_g, 1, &size_hist, &hist_range, true, false); calcHist(&img_rgb[2], 1, 0, Mat(), img_r, 1, &size_hist, &hist_range, true, false); int bin = cvRound((double)w/size_hist); Mat disp_r(w, h, CV_8UC3, Scalar( 255,255,255) ); Mat disp_g = disp_r.clone(); Mat disp_b = disp_r.clone(); normalize(img_b, img_r, 0, disp_b.rows, NORM_MINMAX, -1, Mat() ); normalize(img_g, img_g, 0, disp_g.rows, NORM_MINMAX, -1, Mat() ); normalize(img_r, img_b, 0, disp_r.rows, NORM_MINMAX, -1, Mat() );
  • 24. NguyễnVănLong Ứ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 24 for( int i = 1; i < 255; i++ ) { line(disp_r, Point(bin*(i), h), Point(bin*(i), h - cvRound(img_r.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0 ); line(disp_g, Point(bin*(i), h), Point(bin*(i), h - cvRound(img_g.at<float>(i))), Scalar( 0, 255, 0), 2, 8, 0 ); line(disp_b, Point( bin*(i), h), Point(bin*(i), h - cvRound(img_b.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0 ); } namedWindow("src", 0); imshow("src", src); imshow("Histogram of Blue chennel", disp_b); imshow("Histogram of Green chennel", disp_g); imshow("Histogram of Red chennel", disp_r); cv::waitKey(0); return 1; } Trong chương trình trên, đầu tiên ảnh được đưa vào là một ảnh mầu, để tính histogram của từng kênh mầu một ta sẽ phân tách ảnh này thành 3 kênh mầu riêng rẽ theo thứ tự là Blue, Green và Red. Hàm cv::split(const cv::Mat src, cv::Mat *mvbegin) sẽ tách thành src thành các kênh màu tương ứng lưu trong mvbegin. Hàm cv:: calcHist(const cv::Mat *images, int nimages, const int *channels, cv::InputArray mask, cv::OutputArray hist, int dims, const int histSize, const float **ranges, bool uniform = true, bool accumulate = false) sẽ tính histogram của ảnh đầu vào images và lưu kết quả tính toán vào mảng hist. Các thông số khác bao gồm: nimages là số lượng ảnh đầu vào, channels là danh sách chiều các kênh dung để tính histogram, mask là một mặt nạ tùy chỉnh, nếu không dung gì thì để là cv::Mat(). dims là chiều của histogram, bản OpenCV hiện tại hỗ trợ tính toán histogram với số chiều lên tới 32. histSize là kích thước dãy histogram mỗi chiều, hai tham số cuối có thể để mặc định, Sau đây là kết quả chương trình
  • 25. NguyễnVănLong Ứ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 25 Đối với ảnh xám, ta có thể xem như nó là một kênh màu, do vậy để tính histogram của ảnh xám ta cũng có thể làm hoàn toàn tương tự bằng cách gọi hàm caclHist() Cân bằng histogram Cân bằng histogram (histogram equalization) là phương pháp làm cho biểu đồ histogram của ảnh được phân bố một cách đồng đều. Đây là một biến đổi khá quan trọng giúp nâng cao chất lượng ảnh, thông thường đây là bước tiền xử lý của một ảnh đầu vào cho các bước tiếp theo. Để cân bằng histogram, ta dung hàm equalizeHist(cv::InputArray src, cv::OuputArray dst) trong đó, src là ảnh đầu vào một kênh màu (ảnh xám chẳn hạn), dst là ảnh sau khi cân bằng. Ví dụ: Mat src = imread("src.jpeg", CV_LOAD_IMAGE_GRAYSCALE); // Load anh xam imshow("Anh xam goc", src); Mat dst; equalizeHist(src, dst); imshow("anh xam sau khi can bang histogram", dst); Ta có kết quả sau:
  • 26. NguyễnVănLong Ứ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 26 Để cân bằng histogram của một ảnh màu, trước hết ta chuyển ảnh màu ở dạng RGB sang HSV, sau đó cân bằng thành phần kênh màu V (Value tức độ sáng) và biến đổi ngược lại. Chương trình sau cân bằng histogram của ảnh màu // Can bang histogram #include <opencv2corecore.hpp> #include <opencv2highguihighgui.hpp> #include <opencv2imgprocimgproc.hpp> #include <iostream> using namespace std; using namespace cv; int main() { cout<<"Chuong trinh can bang histogram"<<endl; Mat src = imread("Cho_Ben_Thanh.jpg", CV_LOAD_IMAGE_COLOR); Mat hsv, disp; cvtColor(src, hsv, CV_BGR2HSV); vector<Mat> hsv_channels; // Tach hsv thanh 3 kenh mau split(hsv, hsv_channels); // Can bang histogram kenh mau v (value) equalizeHist(hsv_channels[2], hsv_channels[2]); // Tron anh merge(hsv_channels, hsv); // Chuyen doi hsv sang rgb de hien thi cvtColor(hsv, disp, CV_HSV2BGR); imshow("anh mau goc", src); imshow("anh mau sau khi can bang histogram", disp); waitKey(0); } Sau đây là kết quả của chương trình trên
  • 27. NguyễnVănLong Ứ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 27 6. Phóng to, thu nhỏ và xoay ảnh Như đã nói ở trên, ảnh số thực chất là một ma trận các điểm ảnh, do đó để có thể phóng to, thu nhỏ hay xoay một tấm ảnh ta có thể sử dụng các thuật toán tương ứng trên ma trận. Ta sẽ sử dụng biển đổi affine để quay và thay đổi tỉ lệ to, nhỏ của một ma trận. Biến đổi affine: Giả sử ta có vector = [ , ] và ma trận M 2x2. Phép biển đổi affine trong không gian hai chiều có thể được định nghĩa p’ = Mp trong đó = [ , ] . Viết một cách tường minh ta có: ′ ′ = Hay x’ = αx + δy, y’ = γx + βy . Xét ma trận = . Nếu δ = γ = 0, khi đó x’ = αx và y’ = βy, phép biến đổi này làm thay đổi tỉ lệ của ma trận. Nếu là trong ảnh nó sẽ phóng to hoặc thu nhỏ ảnh. Hình sau mô tả phép biến đổi với tỉ lệ α = β = 2
  • 28. NguyễnVănLong Ứ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 28 Nếu ta định nghĩa ma trận = cos ( ) −sin ( ) sin ( ) cos ( ) thì phép biến sẽ quay p thành p’ với góc quay là θ. Nếu ma trận M được định nghĩa thành = α. cos (θ) −sin ( ) sin ( ) . cos ( ) thì phép biến đổi sẽ vừa là phép biến đổi theo tỉ lệ và quay. Bây giờ ta sẽ xét chương trình phóng to, thu nhỏ và quay ảnh. // Chuong trinh phong to, thu nho va quay anh #include <opencv2corecore.hpp> #include <opencv2highguihighgui.hpp> #include <opencv2imgprocimgproc.hpp> using namespace cv; int main() { Mat src = imread("HoaSen.jpg"); Mat dst = src.clone(); double angle = 45.0;
  • 29. NguyễnVănLong Ứ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 29 double scale = 1.5; Point2f center(src.cols/2, src.rows/2); Mat mat_rot = getRotationMatrix2D(center, angle, scale); warpAffine(src, dst, mat_rot, src.size()); imshow("Anh goc", src); imshow("Anh sau phep bien doi", dst); waitKey(0); return 1; } Trong chương trình trên, hàm cv::getRotationMatrix2D(cv::Point center, double angle, double scale) sẽ tạo ra ma trận với tâm quay center, góc quay angle và tỉ lệ scale. Ma trận này được tính toán trong Opencv là ma trận như sau: = (1 − ). . − . . − . . − (1 − ). . Với = . cos ( ) và = . sin ( ) Ta thấy rằng ma trận này là hoàn hoàn tương đương với ma trận của phép biến đổi affine đã nói ở trên, ngoại trừ thành phần thứ 3 là thành phần giúp dịch chuyển tâm quay vào chính giữa của bức ảnh. Chú ý là có sự khác biệt một chút về chiều của hệ tọa độ trong ảnh, hệ tọa độ trong ảnh lấy góc trên bên trái làm gốc tọa độ (0,0) còn hệ tọa độ thông thường ta hay lấy điểm dưới bên trái làm gốc, do đó có sự ngược chiều. Kết quả của chương trình trên với tỉ lệ scale = 1.5 và góc quay = 450 như hình sau Ngoài hai phép biến đổi là tỉ lệ và quay như trên, ta có thể thực hiện các biến đổi khác của phép biến đổi affine như phép trượt (shearing), hoặc phép phản chiếu (reflection) bằng
  • 30. NguyễnVănLong Ứ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 30 việc định nghĩa lại ma trận M. Ta thử định nghĩa lại ma trận M để được một ảnh trượt của ảnh gốc. Quay lại ma trận M như trên, nếu ta định nghĩa α = β = 1 còn δ nh ận một giá trị bất kì, khi đó ta sẽ có: = + = ta sẽ định nghĩa ma trận = 1 0.5 0 0 1 0 để trượt ảnh ban đầu thành ảnh mới với hệ số trượt δ = 0.5, chú ý là thành phần thứ ba 0 0 định nghĩa ma trận trong Opencv sẽ thể hiện dộ dịch chuyển, giống như trong ví dụ trên ta chuyển tâm quay về tâm của bức ảnh chẳng hạn. Ta sẽ làm giống hệt ví dụ trên, chỉ thay ma trận M là ma trận ta tự định nghĩa double I[2][3] = {1,0.5,0, 0,1,0}; // cac phan tu cua ma tran Mat mat_rot(2,3,CV_64F, I); // khoi tao ma tran warpAffine(src, dst, mat_rot, src.size()); và ta có kết quả: 7. Lọc số trong ảnh Lọc số trong ảnh có ý nghĩa quan trọng trong việc tạo ra các hiệu ứng trong ảnh, một số hiệu ứng nhờ sử dụng các bộ lọc như làm mờ ảnh(Blur), làm trơn ảnh(Smooth) … Nguyên tắc chung của phương pháp lọc ảnh là cho ảnh nhân chập với một ma trận lọc, Idst = M*Isrc
  • 31. NguyễnVănLong Ứ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 31 Isrc, Idst là ảnh gốc và ảnh sau khi thực hiện phép lọc ảnh bằng cách nhân với ma trận lọc M. Ma trận M đôi khi còn gọi là mặt nạ (mask), nhân (kernel). Với mỗi phép lọc ta có những ma trận lọc M khác nhau, không có quy định cụ thể nào cho việc xác định M, tuy nhiên ma trận này có một số đặc điểm như sau: - Kích thước của ma trận thường là một số lẻ chẳng hạn 3x3, 5x5 … Khi đó, tâm của ma trận sẽ nằm ở giao của hai đường chéo và là điểm áp đặt lên ảnh mà ta cần tính nhân chập. - Tổng các phần tử trong ma trận thông thường bằng 1. Nếu tổng này lớn hơn 1, ảnh qua phép lọc sẽ có độ sáng lớn hơn ảnh ban đầu. Ngược lại ảnh thu được sẽ tối hơn ảnh ban đầu. Ví dụ về ma trận lọc (ma trận lọc Sobel theo hướng x, y và ma trận Gausian Blur) −1 0 +1 −2 0 +2 −1 0 +1 −1 −2 −1 0 0 0 +1 +2 +1 ⎣ ⎢ ⎢ ⎢ ⎡ 1 4 7 4 1 4 16 26 16 4 7 26 41 26 7 4 16 26 16 4 1 4 7 4 1⎦ ⎥ ⎥ ⎥ ⎤ Công thức cụ thể cho việc lọc ảnh như sau: ( , ) = ( , ) ∗ ( , ) = ( − , − ) × ( , ) Trong đó, ta đang tính phép nhân chập cho điểm ảnh có tọa độ (x,y) và vì ta lấy tâm của ma trận lọc là điểm gốc nên u chạy từ -n (điểm bên trái) và v chạy từ -n (điểm phía trên) đến n, với n = (kích thước mặt nạ - 1)/2. Để dễ hiểu hơn ta xét một ví dụ về việc làm trơn nhờ sử dụng một ma trận lọc như sau: 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 100 100 100 100 100 100 200 205 203 100 100 195 200 200 100 100 200 205 195 100 100 100 100 100 100 100 100 100 100 100 100 144 205 203 100 100 195 200 200 100 100 200 205 195 100 100 100 100 100 100 * = nhân chập pixel (2,2)
  • 32. NguyễnVănLong Ứ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 32 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 …… Và kết quả cuối cùng ta có: 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 1/9 Ta thấy rằng, ảnh ban đầu với là ảnh có độ tương phản khá lớn (các giá trị độ lớn pixel chênh lệch lớn: 100, 200, …), sau phép lọc ảnh có độ tương phản giản đi hay bị làm mờ đi(lúc này độ chênh lệch giá trị giữa các pixel giảm đi: 100, 144, 167 …). Sau đây ta sẽ xem xét một số bộ lọc trong OpenCV. Lọc Blur: 100 100 100 100 100 100 200 205 203 100 100 195 200 200 100 100 200 205 195 100 100 100 100 100 100 100 100 100 100 100 100 144 167 203 100 100 195 200 200 100 100 200 205 195 100 100 100 100 100 100 100 100 100 100 100 100 200 205 203 100 100 195 200 200 100 100 200 205 195 100 100 100 100 100 100 100 100 100 100 100 100 144 167 145 100 100 167 200 168 100 100 144 166 144 100 100 100 100 100 100 * = nhân chập pixel (2,3) * = nhân chập
  • 33. NguyễnVănLong Ứ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 33 Ma trận lọc của phương pháp này có dạng : = ∗ ⎣ ⎢ ⎢ ⎢ ⎡ 1 1 . . 1 1 1 . . 1 . . . . . . . . . . 1 1 . . 1⎦ ⎥ ⎥ ⎥ ⎤ Bộ lọc này có tác dụng làm trơn ảnh, khử nhiễu hạt. Hàm cài đặt trong OpenCV có dạng: cv::blur(const Mat& src, const Mat& dst, Size ksize, Point anchor, int borderType) trog đó, src và dst là ảnh gốc và ảnh sau phép lọc. ksize là kích thước ma trận lọc, ksize = Size(rows, cols), anchor là điểm neo của ma trận lọc, nếu để mặc định là (- 1,-1) thì điểm này chính là tâm của ma trận. borderType là phương pháp để ước lượng và căn chỉnh các điểm ảnh nếu qua phép lọc chúng bị vượt ra khỏi giới hạn của ảnh. Thông thường giá trị mặc định của nó là 4. Ảnh qua phép lọc blur Lọc Sobel: Lọc sobel chính là cách tính xấp xỉ đạo hàm bậc nhất theo hướng x và y, nó cũng chính là cách tính gradient trong ảnh. Bộ lọc này thông thường được áp dụng cho mục đích tìm biên trong ảnh. Ma trận lọc theo các hướng x, y lần lượt như sau: −1 0 +1 −2 0 +2 −1 0 +1 −1 −2 −1 0 0 0 +1 +2 +1 Trong OpeCV, hàm cài đặt phép lọc này như sau: cv::Sobel(const Mat& src, Mat& dst, int ddepth, int xorder, int yorder, int ksize, double scale, double delta, int borderType) Trong đó, src và dst là ảnh gốc và ảnh qua phép lọc. ddepth là độ sâu của ảnh sau phép lọc, có thể là CV_32F, CV_64F … . xoder và yoder là các đạo hàm theo
  • 34. NguyễnVănLong Ứ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 34 hướng x và y, để tính đạo hàm theo hướng nào ta đặt giá trị đó lên 1, ngược lại nếu giá trị bằng 0, hàm cài đặt sẽ bỏ qua không tính theo hướng đó. Scale và delta là hai thông số tùy chọn cho việc tính giá trị đạo hàm lưa giá trị vi sai vào ảnh sau phép lọc, chúng có giá trị mặc định là 1 và 0. borderType là tham số như trên. Ảnh qua phép lọc Sobel: Lọc Laplace: Lọc Laplace là cách tính xấp xỉ đạo hàm bậc hai trong ảnh, nó có ý nghĩa quan trọng trong việc tìm biên ảnh và phân tích, ước lượng chuyển động của vật thể. = ∆ = + Ma trận lọc có dạng như sau: 0 1 0 1 −4 1 0 1 0 Trong OpenCV, bộ lọc này được cài đặt qua hàm: cv::Laplacian(const Mat& src, Mat& dst, int ddepth, int ksize=1, double scale=1, double delta=0, int borderType) Các thông số này có ý nghĩa giống như các thông số trong bộ lọc Sobel, chỉ khác ở chỗ ksize là một giá trị int mặc định bằng 1 và khi đó ma trận lọc laplace trên được áp dụng. Ảnh qua phép lọc Laplace:
  • 35. NguyễnVănLong Ứ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 35 Ngoài 3 bộ lọc trên, OpenCV còn cài đặt khá nhiều bộ lọc khác như lọc trung vị (medianBlur), lọc Gause (gaussianBlur), pyrDown, pyrUp … Tuy nhiên, ta hoàn toàn có thể cài đặt bộ lọc cho riêng mình thông qua hàm cv::filter2D. Nguyên mẫu hàm này như sau: filter2D(const Mat& src, Mat& dst, int ddepth, const Mat& kernel, Point anchor, double delta, int borderType). Trong đó, src và dst là ảnh gốc và ảnh thu được qua phép lọc, kernel là ma trân lọc. Thông số anchor để chỉ ra tâm của ma trận, delta điều chỉnh độ sáng của ảnh sau phép lọc (ảnh sau phép lọc được cộng với delta và borderType là kiểu xác định những pixel nằm ngoài vùng ảnh. Hàm cv::filter2D thực chất là hàm tính toán nhân chập giữa ảnh gốc và ma trận lọc để cho ra ảnh cuối sau phép lọc. Như vậy qua trên ta thấy rằng để tiến hành việc lọc ảnh ta chỉ cần định nghĩa một ma trận lọc kernel. Có rất nhiều nghiên cứu về toán học đã định nghĩa các ma trận này, do đó việc áp dụng vào lọc ảnh sẽ là khá đơn giản. Chương trình demo phương pháp lọc ảnh. Chương trình sau sẽ thực hiện một số bộ lọc ảnh do chính ta định nghĩa, chẳng hạn ta có ma trận lọc = −1 −1 0 −1 0 1 0 1 1 , ma trận này là ma trận sẽ làm nổi bật ảnh giống như ảnh khắc 3D, ta sẽ áp dụng ma trận này để lọc một ảnh. #include "stdafx.h" #include <opencv2corecore.hpp> #include <opencv2imgprocimgproc.hpp> #include <opencv2highguihighgui.hpp>
  • 36. NguyễnVănLong Ứ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 36 using namespace cv; void main() { Mat src = imread("HoaDao.jpg", CV_LOAD_IMAGE_COLOR); Mat dst; double m[3][3] = { -1, -1, 0, -1, 0, 1, 0, 1, 1 }; Mat M = cv::Mat(3,3,CV_64F, m, Point(-1,-1), 128.0); cv::filter2D(src, dst, src.depth(), M); imshow("Anh goc", src); imshow("Anh qua phep loc", dst); cv::waitKey(0); } Kết quả của chương trình như sau: Một số bộ lọc sau có thể hữu ích cho việc tạo ra các hiệu ứng ảnh đẹp mắt: = 1 1 1 1 −7 1 1 1 1 , = 0
  • 37. NguyễnVănLong Ứ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 37 = −1 −1 −1 −1 8 −1 −1 −1 −1 , = 0 = −1 −1 −1 −1 8 −1 −1 −1 −1 , = 0 8. 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). Phép toán giãn nở (dilation) Phép toán giãn nở được định nghĩa ⊕ = ⋃ ớ ⊂ 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)
  • 38. NguyễnVănLong Ứ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 38 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 Ta hãy 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 và phần giản nở ra ta đánh dấu là dấu x. x x x x x Ứ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ỏ … Phép toán co (erosion) Phép toán co trong ảnh được định nghĩa ⊖ = { |( ) ⊆ } 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.
  • 39. NguyễnVănLong Ứ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 39 0 x Ta 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. Phép toán mở (opening) và đóng (closing) là sự kết hợ của phép co (erosion) và giản (dialation) như trên, chúng được định nghĩa như sau: Phép toán mở : ∘ = ( ⊖ ) ⊕ Phép toán đóng: ∙ = ( ⊕ ) ⊖ 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 đối tượng trong ảnh trở lên mượt mà hơn. Phép toán đóng được ứng dụng trong việc làm trơn đường bao đố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)
  • 40. NguyễnVănLong Ứ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 40 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à khí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 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, nó có ý nghĩa như các ví dụ trong bài trước. 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 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 đó (dĩ nhiên đây là một cách tiếp cận rất đơn giản!). Tuy nhiên, ta 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
  • 41. NguyễnVănLong Ứ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 41 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ở lên liền lơn. #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); vector<vector<Point> > contours1; findContours(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); } imshow("Ket qua phat hien truoc phep gian no", src1); vector<vector<Point> > contours2; findContours(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); }
  • 42. NguyễnVănLong Ứ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 42 imshow("Ket qua phat hien sau khi phep gian no", src2); waitKey(0); } Trong chương trình trên, 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àm findContours 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 Ta 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 vit ở giữ mà số 2 và số 9 gần như nối liền. Đây là lúc ta cần 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 đó bạn đọc hoàn toàn có thể cài đặt để tách ra các kí tự này.
  • 43. NguyễnVănLong Ứ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 43 9. Tìm biên ảnh dựa trên bộ lọc Canny Bộ lọc Canny là sự kết hợp của nhiều bước khác nhau để tìm và tối ưu đường biên, kết quả là cho ra một đường biên khá mảnh và chính xác. Quá trình tìm biên sử dụng phương pháp canny có thể được thực hiện qua 4 bước sau: Bước 1: Loại bớt nhiễu trong ảnh. Người ta loại nhiễu trong ảnh, làm cho ảnh mờ đi bằng cách nhân chập ảnh với một bộ lọc Gause, chẳng hạn bộ lọc Gaus 5x5 với hệ số σ = 1.4: = 1 159 ⎣ ⎢ ⎢ ⎢ ⎡ 2 4 5 4 2 4 9 12 9 4 5 12 15 12 5 4 9 12 9 4 2 4 5 4 2⎦ ⎥ ⎥ ⎥ ⎤ Bước 2: Tính toán giá trị gradient trong ảnh Vì đường biên trong ảnh là nơi phân cách giữa các đối tượng khác nhau, nên tại đó gradient của nó sẽ biến đổi mạnh mẽ nhất. Để tính toán gradient trong ảnh, ta có thể sử dụng bộ lọc Sobel, hoặc trực tiếp nhâp chập ma trận ảnh với các mặ nạ theo hướng x và y chẳng hạn = −1 0 +1 −2 0 +2 −1 0 +1 , = −1 −2 −1 0 0 0 +1 +2 +1 Sau đó tính độ lớn gradient trong ảnh : = + và = Trong đó, Gx, Gy chính là đạo hàm theo hướng X, Y của điểm ảnh ta đang xét. Góc θ sẽ được làm tròn theo các hướng thẳng đứng, nằm ngang và hướng chéo, nghĩa là nó sẽ được làm tròn để nhận các giá trị 0, 45, 90 và 135 độ. Bước 3: Loại bỏ các giá trị không phải là cực đại Bước này sẽ tìm ra những điểm ảnh có khả năng là biên ảnh nhất bằng cách loại bỏ đi những giá trị không phải là cực đại trong bước tìm gradient ảnh ở trên. Ta thấy rằng, với giá trị của góc θ ở trên thì biên của đối tượng có thể tuân theo bốn hướng, và ta có bốn khả năng sau:
  • 44. NguyễnVănLong Ứ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 44 4. Nếu θ = 00 , khi đó, điểm A sẽ được xem là một điểm trên biên nếu độ lớn gradient tại A lớn hơn độ lớn gradient của các điểm tại A3, A7. 5. Nếu θ = 450 , khi đó, điểm A sẽ được xem là một điểm trên biên nếu độ lớn gradient tại A lớn hơn độ lớn gradient của các điểm tại A4, A8 6. Nếu θ = 900 , khi đó, điểm A sẽ được xem là một điểm trên biên nếu độ lớn gradient tại A lớn hơn độ lớn gradient của các điểm tại A1, A5. 7. Nếu θ = 1350 , khi đó, điểm A sẽ được xem là một điểm trên biên nếu độ lớn gradient tại A lớn hơn độ lớn gradient của các điểm tại A2, A6 Bước 4: Chọn ra biên của đối tượng trong ảnh Sau bước trên, ta thu được tập các điểm tương ứng trên đường biên khá mỏng. Vì những điểm có giá trị gradient lớn bao giờ cũng có xác suất là biên thật sự hơn những điểm có giá trị gradient bé, đo đó để xác định chính xác hơn nữa biên của các đối tượng, ta sử dụng các ngưỡng. Theo đó, bộ lọc canny sẽ sử dụng một ngưỡng trên (upper threshold) và một ngưỡng dưới (lower threshold), nếu gradient tại một điểm trong ảnh có giá trị lớn hơn ngưỡng trên thì ta xác nhận đó là một điểm biên trong ảnh, nếu giá trị này bé hơn ngưỡng dưới thì đó không phải điểm biên. Trong trường hợp giá trị gradient nằm giữa ngưỡng trên và ngưỡng dưới thì nó chỉ được tính là điểm trên biên khi các điểm liên kết bên cạnh của nó có giá trị gradient lớn hơn ngưỡng trên. Tìm biên ảnh bằng bộ lọc canny trong OpenCV: OpenCV cung cấp một hàm cho ta xác định biên trong ảnh của các đối tượng. Nguyên mẫu của hàm này như sau : canny(Mat src, Mat dst, int lower_threshold, int upper_threshold, int kernel_size) Trong đó, src là ảnh cần phát hiện biên (là ảnh xám), dst là ảnh chứa biên được phát hiện, lower_threshold, upper_threshold là ngưỡng dưới, ngưỡng trên như đã nói bên trên, kernel_size là kích thước của mặt nạ dùng cho bước thứ hai để tính toán gradient của các điểm trong ảnh. Chương trình demo tìm biên trong ảnh dựa trên bộ lọc canny:
  • 45. NguyễnVănLong Ứ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 45 #include "stdafx.h" #include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> using namespace cv; void main() { Mat gray = cv::imread("TuoiTho.jpg", CV_LOAD_IMAGE_GRAYSCALE); Mat dst1, dst2; imshow("Anh xam", gray); GaussianBlur(gray, gray, Size(9,9), 2); double t1 = 30, t2 = 200; Canny(gray, dst1, t1, t2, 3, false); t1 = 100; t2 = 120; Canny(gray, dst2, t1, t2, 3, false); imshow("Bien trong anh voi nguong 1", dst1); imshow("Bien trong anh voi nguong 2", dst2); waitKey(0); } Trong chương trình trên, trước khi tìm biên bằng phương pháp canny ta đã làm trơn một ảnh xám bằng bộ lọc GaussianBlur (việc làm này có ý rất lớn trong việc giảm thiểu các tiểu tiết không mong muốn trong đường biên sau này). Về nguyên tắc, bộ lọc GaussianBlur cũng là một bộ lọc số như đã giới thiệu ở bài trước về lọc số trong ảnh, cấu trúc của hàm GaussianBlur như sau: cv::GaussianBlur(cv::InputArray src, cv::OutputArray dst, cv::Size ksize, double sigmaX, double sigmaY = 0, int borderType = 4), trong đó src và dst sẽ là các mảng dữ liệu đầu vào và kết quả. Một ảnh cũng có thể coi là một mảng dữ liệu, đo đó src và dst chính là ảnh đầu và ảnh thu được sau khi biến đổi, ksize là kích thước của ma trận lọc, sigmaX, sigmaY là độ lệch chuẩn theo hướng x và y. Nếu sigmaY = 0, độ lệch chuẩn theo hướng y sẽ được lấy theo sigmaX. BorderType là cách nội suy biên đối với những điểm ảnh tràn ra ngoài kích thước của ảnh. Kết quả thu được sau các ngưỡng t1, t2 khác nhau, ta được những biên có độ chi tiết khác nhau như hình sau.
  • 46. NguyễnVănLong Ứ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 46 10.Chuyển đổi Hough, Phát hiện đường thẳng, đường tròn trong ảnh Chuyển đổi Hough (Hough transformation) là một phương pháp được dùng nhiều trong phân tích và xử lý ảnh, mục đích chính của phương pháp này là tìm ra những hình dáng đặc trưng trong ảnh bằng cách chuyển đổi không gian ảnh ban đầu sang một không gian của các tham số nhằm đơn giản quá trình tính toán, trong bài này ta xét chuyển đổi Hough cho đường thẳng và đường tròn.
  • 47. NguyễnVănLong Ứ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 47 Chuyển đổi Hough cho đường thẳng. Ta đã biết rằng, một đường thẳng trong không gian hai chiều có thể được biểu diễn dưới dạng y = kx + m và cặp hệ số góc k, giá trị m có thể được chọn để làm đặc trưng cho một đường thẳng. Tuy nhiên, cách biểu diễn theo cặp (k, m) khó thỏa mãn với những đường thẳng thẳng đứng khi mà hệ số góc là một số vô cùng. Để tránh trường hợp này, ta sẽ biểu diễn đường thẳng trong hệ tọa độ cực. Phương trình đường thẳng trong hệ tọa độ cực có dạng như sau: = ( ) + ( ) Trong đó, r là khoảng cách từ gốc tọa độ O tới đường thẳng, θ là góc cực. Như vậy, với mỗi điểm (x0, y0) ta có một họ các đường thẳng đi qua thõa mãn phương trình = ( ) + ( ) Phương trình này biểu diễn một đường cong, như vậy trong một tấm ảnh có n điểm (n pixel) ta sẽ có n các đường cong. Nếu đường cong của các điểm khác nhau giao nhau, thì các điểm này cùng thuộc về một đường thẳng. Bằng cách tính các giao điểm này, ta sẽ xác định được đường thẳng, đó là nội dung ý tưởng của thuật toán Hough cho đường thẳng. Chuyển đổi Hough cho đường tròn Chuyển đổi Hough cho đường tròn cũng tương tự như với đường thẳng, phương trình đường tròn được xác định bởi: = + = + Trong đó, (u,v) là tâm đường tròn, R là bán kính đường tròn, θ là góc có giá trị từ 0 tới 360 độ. Một đường tròn sẽ hoàn toàn được xác định nếu ta biết được bộ ba thông số (u,v,R). Từ phương trình trên ta có thể chuyển đổi tương đương = − = −
  • 48. NguyễnVănLong Ứ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 48 Ta xét với trường hợp đã biết trước giá trị của R. Khi đó, với mỗi điểm ảnh (x,y) ta sẽ xác định được một giá trị (u,v) và lưu nó vào một mảng. Tâm của đường tròn sẽ là giá trị xuất hiện trong mảng với tần suất lớn nhất. Trong trường hợp R chưa biết, ta tăng giá trị của R từ một ngưỡng min tới ngưỡng max nào đó và tiến hành như với trường hợp đã biết trước giá trị R Tìm đường thẳng, đường tròn trong ảnh. Để tìm đường thẳng trong ảnh, thư viện OpenCV có hỗ trợ hàm cv::HoughLines và cv::HoughLinesP, hai hàm này về cơ bản đều thực hiện một thuật toán, nhưng đưa ra kết quả ở hai dạng khác nhau. Dạng 1: đưa ra kết quả của đường thẳng là một cặp giá trị (r, θ) cv::HoughLines(src, lines, rho, theta, threshold, param) Trong đó, src là ảnh nhị phân chứa biên của các đối tượng cần được phát hiện đường thẳng (trong thực tế ta có thể sử dụng là một ảnh xám), lines là vector chứa kết quả đầu ra của (r, θ) đã được phát hiện, rho là độ phân giải của r (tính theo pixel, thực chất đó là bước tăng nhỏ nhất của r để tính toán), theta là độ phân giải của góc θ (có giá trị từ 0 tới 360 độ), threshold là giá trị nhỏ nhất của tổng các giao điểm của các đường cong để xác định đường thẳng, param là một thông số mặc định của OpenCV chưa sử dụng đến (nó có giá trị bằng 0) Dạng 2: đưa ra kết quả là tọa độ điểm đầu và điểm cuối của đường thẳng cv::HoughLinesP(src, lines, rho, theta, threshold, minLenght, maxGap) Trong đó, các thông số src, rho, theta, threshold giống như dạng 1, lines là vector chứa tọa độ điểm đầu và tọa độ điểm cuối của đường thẳng phát hiện được (x1, y1, x2, y2), minLength là độ dài nhỏ nhất để có thể xem nó là một đường thẳng (tính theo đơn vị pixel), maxGap là khoảng cách lớn nhất của hai điểm cạnh nhau để xác định chúng có thuộc về một đường thẳng hay không (tính theo đơn vị pixel) Đối với đường tròn, ta cũng áp dụng hàm tương tự: cv::HougCircles(), nguyên mẫu của hàm như sau: cv::HougCircles(src, circles, method, dp, min_dist, param1, param2, min_radius, max_radius) Trong đó, src có thể là một ảnh nhị phân chứa biên của đối tượng hoặc ảnh xám (chương trình sẽ tự động dò biên bằng phương pháp canny), circles là vector chứa kết quả phát