Nội dung bài viết
Đăng ký học lập trình C++
Tại STDIO bạn được dạy nền tảng lập trình tốt nhất.
Đăng ký học
Trương Xuân Đạt Nẳm trong loạt bài viết trong chương trình Tự Học OpenCV Qua Các Ví Dụ Thực Tế. Bài viết giới thiệu những thuật toán cơ sở trong xử lý hình thái học, và đã giới thiệu những thuật toán và ứng dụng phổ biến hiện nay của xử lý hình thái học trên ảnh nhị phân và ảnh đa mức xám.

Giới thiệu

OpenCV (Open Computer Vision) là một thư viện mã nguồn mở chuyên dùng để xử lý các vấn đề liên quan đến thị giác máy tính. Nhờ một hệ thống các giải thuật chuyên biệt, tối ưu cho việc xử lý thị giác máy tính, vì vậy tính ứng dụng của OpenCV là rất lớn.

Xử lý ảnh là quá trình xử lý, thao tác hình ảnh để có một hình ảnh khác phù hợp với nhu cầu của người dùng,...

Tiền đề bài viết

Bài viết nằm trong loạt bài viết chương trình Tự Học OpenCV Qua Các Ví Dụ Thực Tế được tài trợ bởi STDIO.

Trong bài biết này sẽ giới thiệu về các thuật toán hình thái học trên ảnh.

Đối tượng hướng đến

Bài viết hướng tới các bạn đọc mới tìm hiểu về xử lý ảnh, đặc biệt là với OpenCV và chưa có kiến thức tương đương.

Xử lý hình thái học (Morphology)

Hình thái học toán học (Mathematical morphology) là một lý thuyết và kỹ thuật để phân tích và xử lý cấu trúc hình học, dựa trên lý thuyết tập hợp, lý thuyết lưới, cấu trúc liên kết và chức năng ngẫu nhiên. Hình thái học toán học phổ biến nhất được áp dụng cho hình ảnh kỹ thuật số. Ngoài ra hình thái học toán học nó có thể được sử dụng là tốt trên đồ thị, bề mặt mắt lưới, chất rắn, và nhiều các cấu trúc không gian khác.

Hình thái học toán học đã được phát triển cho hình ảnh nhị phân, và sau đó được mở rộng cho ảnh đa mức xám (Image Grayscale),... Đây là một trong những kỹ thuật được áp dụng trong giai đoạn tiền xử lý. Hai phép toán thường dùng là phép giãn nở (Dilation) và phép co (Erosion) . Từ hai phép toán cơ bản này người ta phát triển thành một số phép toán như phép đóng (Closing) và phép mở (Opening).

  • Dilation gọi là D(i): giãn nở.
  • Erosion gọi là E(i): co.
  • Một chu trình E(i)-D(i) gọi là phép mở (Opening).
  • Một chu trình D(i)-E(i) gọi là phép đóng (Closing).

Trong các ứng dụng thị giác máy tính, xử lý hình thái học có thể được sử dụng để nhận dạng đối tượng, nâng cao chất lượng ảnh, phân đoạn ảnh và kiểm tra khuyết điểm trên ảnh, được sử dụng rất nhiều để giảm các lỗi trong quá trình nhận dạng.

  • Trích lọc biên ảnh (Boundary extraction).
  • Tô đầy vùng (Region fill).
  • Trích lọc các thành phần liên thông (Extracting connected components).
  • Làm mỏng đối tượng trong ảnh (Thinning).
  • Làm dày đối tượng trong ảnh (Thickening).
  • Tìm xương đối tượng trong ảnh (Skeletons).
  • Cắt tỉa đối tượng trong ảnh (Pruning).

Bạn có thể tìm hiểu nội dung ảnh nhị phân và ảnh xám cụ thể hơn trong bài viết Kỹ Thuật Grayscale Và Nhị Phân Hoá Ảnh (Adaptive Threshold).

Phần tử cấu trúc (Structuring element)

Phần tử cấu trúc ả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 đó . Là một ma trận nhỏ có hai giá trị 0 và 1, các giá trị 0 được bỏ qua trong quá trình tính toán. Một số hình dáng của phần tử cấu trúc thường xuyên sử dụng trên ảnh nhị phân:

  • Dạng đường theo chiều ngang và dọc.
  • Dạng chữ thập.
  • Dạng hình vuông.
  • Dạng hình ellipse.
  • ...

ss_1(1)

Các thành phần với một phần tử cấu trúc

  1. Kích thước của ma trận phần tử cấu trúc.
  2. Hình dáng của phần tử cấu trúc.
  3. Gốc của phần tử (Ogirin). Thông thường thì gốc của phần tử mang giá trị 1 nhưng trong một số trường hợp thì gốc phần tử mang giá trị 0 (Phần tử cấu trúc không có gốc).

Trong các phép toán hình thái học, một phần tử cấu trúc có kích thước (NxN) được di chuyển khắp ảnh và thực hiện phép tính toán với từng điểm ảnh (Pixel) của ảnh với (N2 -1) điểm ảnh (Pixel) lân cận (Không tính điểm ở tâm). Phép tính toán ở đây tùy thuộc vào nội dung của phép toán hình thái học mà từ đó cho ra một kết quả phù hợp:

  • Nếu gốc của phần tử cấu trúc (Ogirin) nằm ở phía bên trái thì ảnh sẽ có xu hướng co và giãn nở về phía bên phải.
  • Nếu gốc của phần tử cấu trúc (Ogirin) nằm ở phía bên phải thì ảnh sẽ có xu hướng co và giãn về nở phía bên trái.

Vì vậy: Trong các kết quả của phép toán xử lý hình thái học thì yếu tố quan trọng là phần tử cấu trúc.

Chú ý: Những nội dung kiến thức trên đây là phần tử cấu trúc dùng trong các phép toán hình thái học trên ảnh nhị phân. Với ảnh đa mức xám thì phần tử cấu trúc tương tự nhưng khác ở chỗ là các giá trị phần tử từ 0 đến 255 chứ không phải là chỉ 0 với 1 như phần tử cấu trúc trên ảnh nhị phân.

ss_111

Phép toán giãn nở (Dilation)

Là một trong các hoạt động cơ bản trong hình thái toán học. 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).

Phép giãn nở trên ảnh nhị phân (Binary operator)

Công thức

ss_14

Trong đó:

  • A: Ma trận điểm ảnh của ảnh nhị phân.
  • B: Là phần tử cấu trúc.

Phép giãn nở (Dilation) ảnh sẽ cho ra một tập điểm ảnh c thuộc D(i), bạn hoàn toàn dễ dàng thấy rằng đây là một phép tổng giữa A và B.

A sẽ là tập con của D(i) . Chú ý: Nhận xét này không toàn toàn đúng với trường hợp phần tử cấu trúc B không có gốc (Origin) hay nói cách khác là gốc (Origin) mang giá trị 0.

Ví dụ

  • Tôi có ma trận điểm ảnh Isrc, ma trận điểm ảnh sau phép giãn nở Idst và phần tử cấu trúc B.
  • Ứng với công thức ở trên, ta lần lượt đặt phần tử cấu trúc vào các điểm ảnh có giá trị 1 của ma trận điểm ảnh Isrc. Kết quả thu được là ma trận điểm ảnh Idst.

ss_2%20(1)

Tính toán

  • Tôi có ở ma trận điểm ảnh Isrc = {(1, 2), (2,1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 3), (3, 4), (3, 5), 
                                                      (4, 2), (4, 4), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)}.
  • Tôi có ở ma trận phần tử cấu trúc B = {(0,0), (-1, 0), (0, 1)} với (0,0) là điểm gốc.
  • Áp dụng công thức phép giãn nở tôi có:
    Isrc(0,0) =  {(1, 2), (2,1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 3), (3, 4), (3, 5), (4, 2), (4, 4), (5, 1), 
                      (5, 2), (5, 3), (5, 4), (5, 5)}.
    Isrc(-1,0) =  {(0, 2), (1,1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 4), (4, 1),
                      (4, 2), (4, 3), (4, 4), (4, 5)}.
    Isrc(0, 1) =  {(1, 3), (2,2), (2, 3), (2, 4), (2, 5), (2, 6), (3, 3), (3, 4), (3, 5), (3, 6), (4, 3), (4, 5), (5, 3), 
                       (5, 3), (5, 4), (5, 5), (5, 6)}
  • Phép giãn nở của Isrc bởi B là hợp của Isrc(0,0), Isrc(-1,0) và Isrc(0,1) hay là Idst.

Với phần tử cấu trúc không có điểm gốc (Origin), cách tính toán cũng tương tự.

Phép giãn nở trên ảnh đa mức xám (Grayscale dilation)

Công thức

ss_4

Trong đó

  • A: Ma trận điểm ảnh của ảnh xám.
  • B: Là phần tử cấu trúc.
  • DB: Là không gian ảnh của phần tử cấu trúc không phẳng B.

Ví dụ

Phần tử cấu trúc B (Structuring element):

ss_111

Tôi có một ma trận ảnh đa mức xám Isrc (Image grayscale):

ss_20

Tính toán

  1. Tại ô vuông khoanh tròn tôi có 3 giá trị Isrc(2,2) = 10, Isrc(3,2) = 50 và Isrc(3,3) = 70.
  2. Áp dụng công thức cho từng giá trị được liệt kê ở bước 1.
    Isrc(2,2) = Isrc(1,2) = Isrc(3,2) = Isrc(1,2) = Isrc(3,2) = 10 + 10 = 20.
    Isrc(3,2) = Isrc(3,1) = Isrc(3,3) = Isrc(2,2) = Isrc(4,2) = 50 + 10 = 60.
    Isrc(3,3) = Isrc(3,4) = Isrc(3,2) = Isrc(2,3) = Isrc(4,3) = 70 + 10 = 80.
  3. Bạn có thể dễ dàng thấy rằng có một số điểm ảnh Isrc trong tính toán ở trên có giá trị khác nhau. Với các điểm ảnh đó, lúc này tôi chỉ việc lấy giá trị lớn nhất (Max) mà tôi có được.
    Isrc(2,2) = 60, Isrc(2,3) = 80, Isrc(3,2) = 80, Isrc(3,3) = 80.
  4. Tương tự với các điểm ảnh còn lại, tôi tính toán ra được kết quả giãn nở của ảnh đa mức xám Isrc thành Idst như sau:

ss_21

Phép toán co (Erosion)

Phép toán co (Erosion) là một trong hai hoạt động cơ bản (khác phép giãn nở) trong hình thái học 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, làm mảnh và tìm xương của đối tượng.

Phép co trên ảnh nhị phân (Binary operator)

Công thức

ss_15

Trong đó:

  • A: Ma trận điểm ảnh của ảnh nhị phân.
  • B: Là phần tử cấu trúc.

Phép co ảnh sẽ cho ra một tập điểm ảnh c thuộc A, nếu bạn đi chuyển phần tử cấu trúc B theo c, thì B nằm trong đối tượng A.
E(i) là một tập con của tập ảnh bị co A. Chú ý: Nhận xét này không toàn toàn đúng với trường hợp phần tử cấu trúc B không có gốc (Origin) hay nói cách khác là gốc (Origin) mang giá trị 0.

Ví dụ

  • Tôi có ma trận điểm ảnh Isrc, ma trận điểm ảnh sau phép co Idst và cấu trúc phần tử B.
  • Ứng với công thức ở trên, ta lần lượt đặt phần tử cấu trúc vào các điểm ảnh có giá trị 1 của ma trận điểm ảnh Isrc. Kết quả thu được là ma trận điểm ảnh Idst.

ss_26

Tính toán

  • Tôi có ở ma trận điểm ảnh Isrc = {(1, 2), (2,1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 2), (3, 3), (3, 4), (3, 5), 
                                                      (4, 2), (4, 4), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)}.
  • Tôi có ở ma trận phần tử cấu trúc B = {(0,0), (-1, 0), (0, 1)} với (0,0) là điểm gốc.
  • Ở đây, tôi không quan tâm tới toàn bộ các điểm đen (Mang giá trị 1) ở Isrc, tôi chỉ quan tâm tới đến những tọa độ của các điểm đen (Mang giá trị 1) của Isrc khi mà tôi di chuyển phần tử cấu trúc trên đối tượng ảnh Isrc thì gốc của B trùng với một điểm ảnh và các điểm lân cận mang giá trị 1 của phần tử cấu trúc B trùng với điểm đen (Mang giá trị 1) của Isrc theo phần tử cấu trúc B. Ví dụ ở đây tôi có 6 điểm đen (Mang giá trị 1) trên Isrc phù hợp với điều kiện trên:
    Isrc(2, 2), Isrc(3, 2), Isrc(3, 3), Isrc(3, 4), Isrc(5, 2), Isrc(2, 4). 
  • Isrc(2,1) = Isrc(2,2) = 1 & Isrc(1,1) = 0. Vậy nên Isrc(2,1) không thỏa với cấu trúc phần tử. Nên Isrc(2,1) = 0.
  • Isrc(2,2) = Isrc(1,2) = Isrc(2,3) = 1. Vậy nên Isrc(2,2) thỏa với cấu trúc phần tử B. Nên Isrc(3,3) = 1.

Với phần tử cấu trúc không có điểm gốc (Origin), cách tính toán cũng tương tự.

Phép giãn nở trên ảnh đa mức xám(Grayscale erosion)

Công thức

ss_5

Trong đó:

  • A: Ma trận điểm ảnh của ảnh xám.
  • B: Là phần tử cấu trúc.
  • DB: Là không gian ảnh của phần tử cấu trúc không phẳng B.

Ví dụ

Phần tử cấu trúc B (Structuring element).

ss_111

Tôi có một ma trận ảnh đa mức xám Isrc (Image grayscale).

ss_22

Tính toán trong vùng ô vuông đỏ.

  • Các điểm ảnh có trong ô Isrc (3,1) = 90, Isrc (4,2) = 50, Isrc (5,2) = 60, Isrc (5,3) = 70, Isrc (6,2) = 5, Isrc (5,1) = 10. 
  • Trừ(-) các giá trị ở trên cho 10 (Giá trị phần tử trong phần tử cấu trúc).

ss_23

  • Loại bỏ những điểm ảnh không tương ứng với hình dạng của phần tử cấu trúc. Ở đây giá trị Isrc (3,1) = 0.
  • Các giá trị còn lại vì tương ứng với hình dạng của phần tử cấu trúc (Hình chữ thập) nên tôi giữa lại. Và lúc này điểm ảnh trung tâm chính là Isrc (4,2) = 50 tương ứng với gốc của phần tử cấu trúc (Origin).

ss_24

  • Với những giá trị còn lại sau khi tôi loại bỏ những điểm ảnh không phù hợp. Theo công thức thì tôi cần phải thay điểm ảnh bằng giá trị nhỏ nhất trong tập điểm ảnh đang xét và các điểm lân cận. Ở đây giá trị nhỏ nhất là Isrc (6,2) = -5. Vì vậy, điểm ảnh tại Isrc (4,2) = 0. Cứ như vậy trên toàn ma trận tôi có kết quả của việc co ảnh Isrc chính là Idst

ss_25

Phép toán mở (Opening) và phép toán đóng (Closing)

Phép toán mở (Opening) và phép toán đóng (Closing) là sự kết hợp của phép co (Erosion) và phép giãn nở (Dilation) như trên. Ta được định nghĩa như sau.

Phép toán mở (Opening)

Thực hiện phép co (Erosion) trước sau đó mới thực hiện phép giãn nở (Dilation). 

Công thức

ss_11

Ứng dụng

Phép toán mở (Opening) được ứng dụng trong việc loại bỏ các phần lồi lõm và làm cho đường bao các đối tượng trong ảnh trở nên mượt mà hơn.

Phép toán đóng (Closing)

Thực hiện phép giãn nở (Dilation) trước sau đó mới thực hiện phép co (Erosion). 

Công thức

ss_12

Ứng dụng

Phép toán đóng (Closing) được dùng trong ứng dụng làm trơn đường bao các đối tượng, lấp đầy các khoảng trống biên và loại bỏ những hố nhỏ.

Các phép toán hình thái học trong OpenCV

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().

cv::morphologyEx( InputArray src, OutputArray dst, int op, InputArray kernel,
                  Point anchor = Point(-1,-1), int iterations = 1,
                  int borderType = BORDER_CONSTANT,
                  const Scalar& borderValue = morphologyDefaultBorderValue());

Phân tích

  • src: Là ảnh ban đầu:
  • dst: Là ảnh sau khi xử lý hình thái học.
  • op: Là loại hình thái học, ví dụ: MORPH_ERODE. Bạn có thể tham kháo các loại phép toán hình thái học trong cv::MorphTypes.
  • kernel: Là phần tử cấu trúc. Bạn hoàn toàn có thể khởi tạo và sử dụng bằng cách sử dụng hàm getStructuringElement().
  • anchor: Là điểm neo của phần tử cấu trúc kernel. Giá trị mặc định là (-1, -1).
  • iterations: Số lần lặp đi lặp lại các phép toán hình thái học lên ảnh. Ví dụ: Bạn càng để phép toán giãn nở ảnh (Dialation) thì ảnh càng giãn nở nhiều.
  • borderType-borderValue: Là giới hạn biên của những điểm ảnh (Pixel) nằm ngoài kích thước của ảnh trong quá trình tính toán.

Hàm getStructuringElement():

cv::getStructuringElement(int shape, Size ksize, Point anchor = Point(-1,-1));

Phân tích

  • shape: Là hình dạng của phần tử cấu trúc. Ví dụ: MORPH_RECT. Bạn có thể tham khảo các loại hình dạng của phần tử cấu trúc trong cv::MorphShapes.
  • ksize: Là kích thước của ma tận phần tử cấu trúc.
  • anchor: Là điểm neo của phần tử cấu trúc. Giá trị mặc định là (-1, -1).

Ví dụ

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;

int main() {
    
    Mat imageSrc = imread("stdio.png", CV_LOAD_IMAGE_GRAYSCALE);
    Mat imageDst;
    Mat imageBinary;
    
    threshold(imageSrc, imageBinary, 220, 255, CV_THRESH_BINARY);
    cv::Mat kernel = cv::getStructuringElement(MORPH_CROSS, Size(5,5));
    cv::morphologyEx(imageBinary, imageDst, MORPH_ERODE, kernel);

    imshow("imageBinary", imageBinary);
    imshow("imageDst", imageDst);

    waitKey(0);
    return 0;
}

Build/Run

ss_13

Phép toán giãn nở và phép co có thể được gọi từ hàm cv::morphologyEx() thông qua tham số op lần lượt là MORPH_DILATE MORPH_ERODE. Ngoài ra, bạn có thể sử dụng phép giãn nở và phép co có thể được gọi trực tiếp từ hàm cv::dialate()cv::erode().

cv::dilate( InputArray src, OutputArray dst, InputArray kernel,
            Point anchor = Point(-1,-1), int iterations = 1,
            int borderType = BORDER_CONSTANT,
            const Scalar& borderValue = morphologyDefaultBorderValue());

cv::erode( InputArray src, OutputArray dst, InputArray kernel,
            Point anchor = Point(-1,-1), int iterations = 1,
            int borderType = BORDER_CONSTANT,
            const Scalar& borderValue = morphologyDefaultBorderValue());

Chú ý

  • Các tham số của các hàm cv::dialate()cv::erode() đều có ý nghĩ giống tham số trong hàm cv::morphologyEx()
  • Một điều thật sự chú ý với nội dung của hình thái học trong ảnh. Trong OpenCV có cách cài đặt ngược lại giữa đối tượng và nền ảnh, có nghĩa là trong phép giãn nở (Dilation), phần giãn nở là nền của ảnh (Backgroud) chứ không phải các đối tượng vật thể trong ảnh và phép co (Erotion) 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.

Tổng kết

Trong bài viết này, tôi đã giới thiệu những thuật toán cơ sở trong xử lý hình thái học, và đã giới thiệu những thuật toán và ứng dụng phổ biến hiện nay của xử lý hình thái học trên ảnh nhị phân và ảnh xám. Một trong những vấn đề quan trọng trong các thuật toán xử lý hình thái học là tìm và sử dụng phần tử cấu trúc phù hợp để có được kết quả tốt nhất. Hầu hết các thuật toán xử lý hình thái học đều dựa trên những thuật toán cơ bản như phép co ảnh, giãn ảnh, đóng ảnh và mở ảnh. 

Mọi thắc mắc có thể bình luận tại bài viết hoặc liên hệ với tác giả Trương Đạt.

Tham khảo

https://en.wikipedia.org/wiki

http://docs.opencv.org/doc/tutorials/tutorials.html

THẢO LUẬN
ĐÓNG