CHƯƠNG 2: CƠ SỞ LÝ THUYẾT
2.4. Lý thuyết xử lý ảnh và các hàm hỗ trợ bởi OpenCV
2.4.3. Contours (đường viền) và Find contours (tìm contours)
Constours (đường viền) là tập hợp các điểm được nối với nhau, và hầu như vị trí của tập hợp điểm này là đường nét bao quanh của đối tượng trong hình.
Sự khác nhau giữa edges và contours là edges là những điểm có giá trị intensiy gradient lớn so với các điểm lân cận và các giá trị intensity gradient này không bao quanh đối tượng và chúng rất nhiễu.
findContours
Tìm contours trong hình ảnh binary và trích xuất ra hệ thống cấp bậc contours tree (cây contours) của tập hợp edges được kết nối với nhau được minh hoạ như sau:
Một hình ảnh có các vùng màu trắng A, B, C,... được dùng để tìm contours
Kết quả của contours được thể hiện ở 2 dạng:
• exterior boundaries (đường biên bên ngoài) của vùng màu trắng được minh hoạ bởi các đường đứt nét hay còn được gọi là contour (cN – N là số)
• interior boundaries (đường biên bên trong) được minh hoạ bởi các đường chấm hay còn gọi là hole (ký hiệu hN – N là số)
Hình 2.9: Hình ảnh dùng để tìm contours, có các vùng A, B, C,... màu trắng trên nền đen
A
B C
D E
Hình 2.10: Kết của của việc tìm contours, được thể hiện ở 2 dạng: exterior (đường đứt nét) và hole (đường chấm)
c0
h00 h01
h0000 c000 c010
h0100
c01000 c01001
Contours tree của hình ảnh ví dụ ở trên có contour c0 ở gốc, có 2 con là hole h00 và h01, tương tự contour c000 có 1 con là h0000, và tương tự cho các contour còn lại.
void findContours(InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset = Point())
void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
Trong đó,
• image – Hình ảnh nguồn đơn kênh 8-bit, trong quá trình tìm contours hàm sẽ chỉnh sửa, thay đổi image
• contours – Kết quả của tìm contours, mỗi contours được lưu trữ trong một vector điểm (thư viện chuẩn của C++), nên kiểu dữ liệu truyền là vector<vector<Point>>
• hierarchy – vector lưu trữ thông tin kết nối của các contour trong hệ thống contours tree nên kiểu dữ liệu truyền là vector<Vec4i>. Mỗi contour thứ i (contours[i]) có:
◦ hierarchy[i][0] – chỉ số của contour kế tiếp (h_next)
◦ hierarchy[i][1] – chỉ số của contour trước đó (h_prev)
◦ hierarchy[i][2] – chỉ số của contour con đầu tiên (v_next)
◦ hierarchy[i][3] – chỉ số của contour cha (v_prev)
Mọi chỉ số đều bắt đầu từ 0 (0-based indices). Nếu contours[i] không có phần tử tương ứng nào thì giá trị tại đó là một số âm.
• mode – Cách lưu trữ hay thể hiện của contour tree
◦ CV_RETR_EXTERNAL: chỉ tìm chính xác các exterior contours
◦ CV_RETR_LIST: tìm tất cả các contours và ko thiết lập hệ thống phân cấp, chỉ lưu trữ dạng danh sách
◦ CV_RETR_CCOMP: tìm tất cả các contours và tổ chức thành hệ thống 2 cấp bậc, trong đó cấp 1 là danh sách các exterior contours, cấp 2 là danh sách các interior contours
◦ CV_RETR_TREE: tìm tất cả các contours và tổ chức thành hệ thống cây phân cấp
• method – Cách hay phương pháp tìm contours
◦ CV_CHAIN_CODE: Sử dụng giải thuật Freeman chain code
◦ CV_CHAIN_APPROX_NONE: Sử dụng giải thuật Freemain chain code, nhưng dịch tất cả các điểm của chain code thành điểm bình thường
◦ CV_CHAIN_APPROX_SIMPLE:
◦ CV_CHAIN_APPROX_TC89_L1, CV_CHAIN_APPROX_TC89_KCOS: sử dụng giải thuật TehChin chain
• offset – Điểm tuỳ chọn mà ở đó các contour point sẽ dịch duyển. Chỉ sử dụng đối số này khi tìm contours trên image RoI (Region of Interest – một vùng ảnh quan tâm) và phân tích kết quả cho toàn bộ hình ảnh.
Contours là một công cụ hữu ích cho việc phân tích hình dạng hình học, phát hiện và nhận dạng đối tượng.
contourArea
Tính diện tích của contour.
double contourArea(InputArray contour, bool oriented = false)
Trong đó,
• contour – Vector điểm của contour, truyền vào std::vector<Point>
• oriented – Flag chỉ hướng của contour. Nếu truyền vào giá trị true, kết quả diện tích của contour sẽ có dấu (âm hoặc dương) tuỳ thuộc vào hướng của contour là cùng chiều hay ngược chiều với kim đồng hồ (clockwise or counter-clockwise)
boundingRect
Tính toán một hình chữ nhật thẳng đứng có diện tích nhỏ nhất bao quanh một tập hợp điểm.
Rect boundingRect(InputArray points)
Trong đó,
• points – tập hợp điểm được lưu trữ trong std::vector<Point>
Ví dụ 2.12: Tiếp theo ví dụ trên, cài đặt phát hiện đối tượng có diện tích contours >= 3500 và sau đó vẽ hình chữ nhật bao quanh đối tượng.
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
#define WINDOW_NAME "Detect object"
Hình 2.11: Minh hoạ cách lưu trữ / thể hiện của hệ thống contours tree
CV_RETR_EXTERNAL CV_RETR_TREE
first = c0 CV_RETR_LIST
first = c01000 - c01001 - h0100 - c010 - c000 - h01 - h00 - c0 CV_RETR_CCOMP
first = c01000 - c01001 - c010 - c000 - c0
h0100 h0000 h01 - h00| | |
first = c0
h00 - h01 c000 c010 h0000 h0100
c01000 - c010001
|
| |
| |
|
Mat brgImage, hsvImage;
vector<vector<Point>> contours;
int main(int argc, char const* argv[]) { brgImage = imread(argv[1], IMREAD_COLOR);
cvtColor(brgImage, hsvImage, COLOR_BGR2HSV);
// Only use Hue and Satuaration value Mat hsImage(brgImage.size(), CV_8UC2);
int fromTo[] = { 0, 0, 1, 1 };
mixChannels(&hsvImage, 1, &hsImage, 1, fromTo, 2);
// Threshold range of blue color in HS space Mat edgesImage(brgImage.size(), CV_8UC1);
inRange(hsImage, Scalar(110, 100), Scalar(130, 255), edgesImage);
// Canny edges detection
medianBlur(edgesImage, edgesImage, 3);
Canny(edgesImage, edgesImage, 40, 40 * 3, 3);
// Find and extract contours
findContours(edgesImage, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
// Only select object has area >= 3500
for (size_t i = 0; i < contours.size(); i++) {
Rect regionOfInterest = boundingRect(contours[i]);
if (contourArea(contours[i]) <= 3500) { contours.erase(contours.begin() + i);
i--;
} }
// Draw objec with a rectangle
for (size_t i = 0; i < contours.size(); i++) {
Rect regionOfInterest = boundingRect(contours[i]);
rectangle(brgImage, regionOfInterest, Scalar(0, 0, 255));
}
imshow(WINDOW_NAME, brgImage);
waitKey(0);
return 0;
}