Computer Vision

Morphological operations

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 để:
  1. Loại bỏ white noise trong Binary Image;
  2. Tách hai đối tượng bị dính với nhau.

Với erode, giá trị của pixel nằm ở trung tâm sẽ được thay thế bởi local minimum của vùng ảnh được “covered” bởi kernel. Nếu bức ảnh là Binary Image, giá trị minimum là 0.

erode

  • Dilate được sử dụng để:
  1. 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);
  2. It is also useful in joining broken parts of an object.

Với dilate, giá trị của pixel nằm ở trung tâm sẽ được thay thế bởi local maximum của vùng ảnh được “covered” bởi kernel. Nếu bức ảnh là Binary Image, giá trị maximum là 255.

dilate

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:

erodedilate


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

opening

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:

closing

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.

grad

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:

gradient

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.

tophat

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

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!

blackhat

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

blackhat

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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s