Xử lý ảnh với OpenCV - Tut3: Phương pháp lọc ảnh (Image Filtering)
Series bài viết
- Tut 1: Cài đặt OpenCV
- Tut 2: Chuyển đổi ảnh màu
- Tut 3: Phương pháp lọc ảnh
- Tut 4: Xác định viền trong ảnh
Mục tiêu bài viết
Phần đầu tiên của bài viết sẽ giúp các bạn hiểu được khái niệm Lọc ảnh (Image Filtering), nguyên lý hoạt động của việc Lọc ảnh. Ở mục kế tiếp, các bạn sẽ hình dung rõ ràng hơn với ví dụ về cách làm mờ ảnh (Blurring), và cách thực hiện trên OpenCV.
1. Image Filtering
1.1 Image Filtering là gì ?
Lọc ảnh (Filtering) là một kĩ thuật chỉnh sửa (Modifying) hoặc làm rõ (Enhancing) ảnh [1]. Việc loại bỏ những điểm lốm đốm trên một bức ảnh cũ, hay làm nét một bức ảnh bị nhòe, đấy là một số ví dụ về ứng dụng của việc lọc ảnh. Làm mịn/mờ ảnh (Smoothing/blurring), làm nét ảnh (Sharpening) hay làm sắc nét cạnh của ảnh (Edge enhancement) là một số phép xử lý ảnh phổ biến của Lọc ảnh.
(Bổ sung hình minh họa)
1.2 Nguyên lý hoạt động của Image Filtering
Filtering là phép toán thực hiện biến đổi một điểm ảnh dựa trên thông tin của các điểm ảnh (pixel) xung quanh điểm ảnh đó (neighborhood operation). Nói một cách đơn giản, khi bạn đưa một điểm ảnh vào, Filtering sẽ lấy thông tin của điểm ảnh lân cận (những con số về cường độ sáng), áp dụng công thức toán để tính ra giá trị đầu ra của điểm ảnh đấy.
Thông thường, trong xử lý ảnh, các công thức dùng để biến để giá trị thường ở dạng tuyến tính (Linear filtering) (Công thức tuyến tính là công thức có dạng a1x1 + a2x2 + ... + anxn=0). Và để thực hiện việc tính toán một cách nhanh chóng, công thức biến đổi sẽ được biểu diễn thành một ma trận nhân/lõi (kernel/mask/convolution matrix), và việc biến đổi ảnh sẽ được thực hiện bằng cách tính tích chập (Convolution) giữa ma trận nhân (Kernel).
1.3 Convolution
Trong toán học, Convolution (tích chập) là một phép toán với đầu vào là 2 hàm số (hàm f và g), với kết quả đầu ra là một hàm mới được tạo từ 2 hàm f và g. Đối với bài toán xử lý ảnh, ta có thể coi:
- Hàm f: ảnh đầu vào
- Hàm g: ma trận nhân kernel
- Kết quả Convolution (f*g): ảnh sau khi biến đổi
Công thức tính Convolution (1D) được định nghĩa như sau [2]:
Đối với bài toán xử lý ảnh, chúng ta sẽ áp dụng công thức tính Convolution 2D (sau khi đã sampling về dạng rời rạc) được định nghĩa tại [3] (chi tiết chứng minh xem tại [3]):
Áp dụng công thức trên vào, ta có kết quả như hình dưới
Như hình trên, mục tiêu của phép convolution này là tính giá trị mới của e (tọa độ [2,2]) sau khi biến đổi. Theo công thức tính Convolution 2D, ta có:
$$ f*g([2,2]) = f([2,2]) * g([2,2]) $$ (Chú ý: Phép * ở đấy là phép Convolution, không phải phép nhân thông thường)
$$= f[1,1].g[4-1, 4-1] + f[1,2].g[4-1, 4-2] + f[1,3].g[4-1, 4-2] +$$
$$f[2,1].g[4-2, 4-1]+ ... + f[3,3].g[4-3, 4-3]$$
$$= a.9 + b.8 + c.7 + d.6 + ... + i.1$$
2. Làm mờ ảnh (Blur) với OpenCV
2.1 Cách làm mờ ảnh
Trước khi bàn về cách làm mờ ảnh, chúng ta sẽ nói về vấn đề tại sao phải làm mờ ảnh.
Hình bên trên là một ví dụ minh họa cho ảnh bị nhiễu. Một cách trực quan, bạn có thể định nghĩa điểm nhiễu là những điểm đốm trắng đen khiếh cho hình khó nhìn. Nếu để ý kĩ hơn, bạn có thể thấy, các điểm nhiễu này có mức sáng (intensity) chênh lệch rõ ràng so với những điểm xung quanh (điểm trắng nổi lên giữa khu vực màu đen, etc.)
Để loại bỏ những điểm nhiễu này, hay nói cách khác, loại bỏ những điểm có mức sáng chênh lệch lớn bất thường, Làm mờ ảnh (blurring) là một trong những phương pháp phổ biến nhất được áp dụng.
Vậy làm thế nào để làm mờ ảnh ? Làm thế nào để làm mờ những điểm có độ sáng bất thường trên ảnh ? Biện pháp đơn giản nhất chính là thay thế những điểm có độ sáng bất thường bằng trung bình độ sáng của những điểm lân cận.
Với tư tưởng trên, chúng ta sẽ tính tích chập của ảnh với ma trận nhân (kernel) có giá trị
Khi nhân tích chập với ma trận này, giá trị đầu ra của điểm được tính sẽ bằng trung bình cộng của 8 điểm xung quanh và giá trị của chính điểm đó.
2.2 Implement với OpenCV
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('image009.png')
kernel = np.ones((3,3), np.float32)/9
blur_img = cv2.filter2D(img, -1, kernel)
f, axs = plt.subplots(1,2, figsize=(10,5))
axs[0].imshow(img)
axs[1].imshow(blur_img)
plt.show()
Đầu tiên, chương trình sẽ load hình ảnh vào bằng câu lệnh cv2.imread
. Câu lệnh kernel = np.ones((3,3), np.float32)/9
tạo ra một ma trận vuông 3x3 với tất cả các phần tử có giá trị là 1/9. Hàm cv2.filter2D
thực hiện việc nhân convolution giữa ảnh img
và ma trận nhân kernel
để cho ra kết quả là ảnh đã làm mờ blur_img
. Tham số -1
trong hàm cv2.filter2D
để chỉ ảnh đầu ra có cùng độ sâu màu ddepth
với ảnh gốc.
Tổng kết
Bài viết vừa đề cập một cách khái quát về nguyên lý Lọc ảnh (Filtering). Trong xử lý ảnh, việc lọc ảnh thường được biểu diễn bằng ma trận nhân Kernel. Quá trình lọc ảnh được thực hiện bằng cách tính tích chập Convolution giữa ảnh và Ma trận nhân. Bài viết cũng trình bày về cách thực hiện kĩ thuật Làm mờ ảnh (Blurring) trên OpenCV. Bài viết kế tiếp, chúng ta sẽ làm quen với một số bộ lọc ảnh khác như Làm sắc ảnh (Sharpening), xác định viền (Edge detection).
HMD.
References
[1] https://www.mathworks.com/help/images/what-is-image-filtering-in-the-spatial-domain.html
[2] https://en.wikipedia.org/wiki/Kernel_(image_processing)
[3] http://www.songho.ca/dsp/convolution/convolution.html#convolution_2d