Xin chào,
Trong bài viết này chúng ta sẽ tìm hiểu về Morphological operations.
ERODE AND DILATE
- Erode được sử dụng để:
- Loại bỏ white noise trong Binary Image;
- Tách hai đối tượng bị dính với nhau.
A foreground pixel in the input image will be kept only if ALL pixels inside the structuring element are > 0. Otherwise, the pixels are set to 0 (i.e. background).
- Dilate được sử dụng để:
- Phục hồi lại object sau khi áp dụng Erode để loại bỏ nhiễu (vì Erode sẽ làm cho object trong bức ảnh bị giảm kích thước);
- It is also useful in joining broken parts of an object.
A center pixel p of the structuring element is set to white if ANY pixel in the structuring element is > 0.
Chúng ta thường sử dụng phối hợp Dilate và Erode để lọc nhiễu cho Binary Image.
Functions:
outputImage = cv2.erode(inputImage, StructuringElement, iterations)
outputImage = cv2.dilate(inputImage, StructuringElement, iterations)
Trong đó:
- outputImage – hình ảnh nhận được sau khi áp dụng erode, dilate;
- inputImage – ở dạng Binary Image;
- StructuringElement – với kích thước là 3, 5 hoặc 7; None tương ứng với 3×3 structuring element;
- iterations – số lần lặp lại quá trình erode, dilate.
Structuring Element có thể được tạo bởi function ones() của NumPy hoặc function cv2.getStructuringElement() của OpenCV:
StructuringElement = cv2.getStructuringElement(TypeOfStructuring, SizeOfStructuring)
Trong đó:
- TypeOfStructuring – cấu trúc của Structuring Element, gồm cv2.MORPH_RECT, cv2.MORPH_ELLIPSE, cv2.MORPH_CROSS;
- SizeOfStructuring – một tuple (width, height) chứa kích thước của Structuring Element, ví dụ (3,3), (5,5) hoặc (7,7);
- StructuringElement – một array chứa structuring element được trả về từ function.
Example 1 – Erode và dilate
import cv2 import numpy as np image = cv2.imread("image.jpg") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # binarization thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY_INV)[1] # kernel 5x5 kernel = np.ones((5,5), dtype="uint8") output = cv2.erode(thresh.copy(), kernel, iterations=1) cv2.imshow("Eroded", output) output = cv2.dilate(thresh.copy(), kernel, iterations=1) cv2.imshow("Dilated", output) cv2.waitKey(0)
Output:
OPENING
Opening tương đương với việc áp dụng Dilate sau khi đã sử dụng Erode. Opening cho phép chúng ta loại bỏ nhiễu nhưng vẫn giữ nguyên kích thước của các đối tượng trong bức ảnh.
OpenCV cung cấp một function để thực hiện các Morphological operations mà chúng ta mong muốn:
outputImage = cv2.morphologyEx(inputImage, MorphologicalOperation, StructuringElement)
Trong đó:
- outputImage – hình ảnh sau khi được áp dụng Morphological Operation;
- inputImage – hình ảnh ban đầu;
- MorphologicalOperation – có thể là cv2.MORPH_OPEN, cv2.MORPH_CLOSE, cv2.MORPH_GRADIENT, cv2.MORPH_TOPHAT và cv2.MORPH_BLACKHAT;
- StructuringElement – structuring element mà chúng ta đã tạo với function cv2.getStructuringElement().
Example 2: Opening
import cv2 import numpy as np image = cv2.imread("image.jpg") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # binarization thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY_INV)[1] for i in [3,5,7]: # kernel 5x5 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (i,i)) output = cv2.morphologyEx(thresh.copy(), cv2.MORPH_OPEN, kernel) cv2.imshow("Opening size {}".format(i), output) cv2.waitKey(0)
Output:
Từ kết quả trên chúng ta thấy rằng, sau khi áp dụng Opening, các đường nhiễu đã bị loại bỏ.
CLOSING
Closing tương đương với việc áp dụng Erode sau khi đã sử dụng Dilate. Closing được sử dụng để lấp đầy các chỗ trống bên trong các đối tượng hoặc nối các thành phần của đối tượng.
Example 3 – Closing
import cv2 import numpy as np image = cv2.imread("image.jpg") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # binarization thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY_INV)[1] for i in [3,5,7]: # kernel 5x5 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (i,i)) output = cv2.morphologyEx(thresh.copy(), cv2.MORPH_CLOSE, kernel) cv2.imshow("Opening size {}".format(i), output) cv2.waitKey(0)
Output:
Với kết quả trên chúng ta thấy rằng, các lỗ trống trong phần logo OpenCV đã được lấp đầy nhờ áp dụng Closing.
MORPHOLOGICAL GRADIENT
Morphological Gradient chính là sự khác biệt của outputImage khi áp dụng Dilate và Erode. Morphological Gradient được sử dụng để tìm ra “Outline” của đối tượng trong bức ảnh.
Example 4 – Morphological Gradient
import cv2 import numpy as np image = cv2.imread("image.jpg") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # binarization thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY_INV)[1] for i in [3,5,7]: # kernel 5x5 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (i,i)) output = cv2.morphologyEx(thresh.copy(), cv2.MORPH_GRADIENT, kernel) cv2.imshow("Opening size {}".format(i), output) cv2.waitKey(0)
Output:
Bằng cách áp dụng Morphological Gradient, chúng ta đã tách được outline của logo OpenCV.
TOP HAT/WHITE HAT
A top hat (also known as a white hat) morphological operation is the difference between the original input image and the opening.
Top hat/White hat được dùng để làm nổi bật những vùng sáng của bức ảnh trên nền tối. Khác với các Morphological Operation như Opening, Closing và Gradient, việc áp dụng Top hat phù hợp với ảnh grayscale hơn là ảnh binary.
Example 5 – Whitehat
import cv2 import numpy as np image = cv2.imread("image.jpg") cv2.imshow("Image", image) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (13,5)) tophat = cv2.morphologyEx(gray.copy(), cv2.MORPH_TOPHAT, kernel) opening = cv2.morphologyEx(gray.copy(), cv2.MORPH_OPEN, kernel) cv2.imshow("gray", gray) cv2.imshow("opening", opening) cv2.imshow("tophat", tophat) cv2.waitKey(0)
Output:
Từ kết quả trên chúng ta thấy rằng, sau khi áp dụng Opening, phần biển số màu trắng đã bị nhòe đi, chỉ còn lại màu xám. Thực hiện phép toán trừ giữa gray và opening (function cv2.subtract(gray, opening)) ta sẽ nhận được kết quả tương tự với bức ảnh tophat.
BLACK HAT
The black hat operation is the difference between the closing of the input image and the input image itself. In fact, the black hat operator is simply the opposite of the white hat operator!
Back hat được dùng để làm nổi bật những vùng hình ảnh có màu tối trên nền có màu sáng.
Example 6: Black hat
import cv2 import numpy as np import argparse image = cv2.imread("image.jpg") cv2.imshow("Image", image) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (13,5)) blackhat = cv2.morphologyEx(gray.copy(), cv2.MORPH_BLACKHAT, kernel) closing = cv2.morphologyEx(gray.copy(), cv2.MORPH_CLOSE, kernel) cv2.imshow("gray", gray) cv2.imshow("closing", closing) cv2.imshow("blackhat", blackhat) cv2.waitKey(0)
Output:
Với kết quả nhận được chúng ta thấy rằng, phần biển số chỉ còn lại màu trắng sau khi áp dụng Closing. Thực hiện phép trừ giữa closing và gray, chúng ta sẽ nhận được kết quả tương tự với bức ảnh blackhat.
SUMMARY
Như vậy chúng ta đã tìm hiểu qua một số Morphological Operations. Đây là kỹ thuật rất đơn giản nhưng cũng rất mạnh mẽ. Morphological Operations sẽ được sử dụng để xử lý dữ liệu hình ảnh trước khi áp dụng các thuật toán khác phức tạp hơn, như Automatic Number Plate Recognition (ANPR).
Cảm ơn các bạn đã theo dõi bài viết.
Thân ái và quyết thắng.