Trong bài 3 chúng ta sẽ tiếp tục tìm hiểu các phương pháp nâng cao chất lượng ảnh, sự khác biệt ở đây là các phương pháp này tận dụng cả thông tin từ các pixel xung quanh (neighborhood pixel) trong quá trình xử lý.
Biểu đồ tần suất - Historgram
Biểu đồ tần suất của một ảnh xám (gray image) cho chúng ta cái nhìn tổng quát về phân bố của các mức độ xám (gray level) trong hình. Biểu diển toán học của nó là một hàm số rời rạc (discrete function) như sau:
$h(r_{k}) = n_{k}$
Trong đó $r_{k}$ là mức độ xám thứ $k$, $n_{k}$ là số điểm ảnh (pixel) có mức độ xám $k$.
Chúng ta hãy cùng vẽ biểu đồ tần suất (histogram) của bức ảnh Lena nhé.
1
2
3
4
5
6
7
8
9
10
11
12
import cv2
from matplotlib import pyplot as plt
from google.colab.patches import cv2_imshow
img = cv2.imread('/content/lena.png')
# Convert ảnh sang ảnh xám
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2_imshow(img)
# Vẽ biểu đồ tần suất
# Hàm ravel để làm phẳng (flaten) bức ảnh
plt.hist(img.ravel(), 256, [0,256])
plt.show()
Từ biểu đồ tần suất (histogram) chúng ta có thể nhận xét được bức ảnh theo đặc điểm phân bố:
- Ảnh tối: Ảnh được coi là tối nếu như các thành phần của biểu đồ tập trung chủ yếu ở phần bên trái của biểu đồ.
- Ảnh sáng: Ảnh được coi là ảnh sáng nếu như các thành phần của biểu đồ tập trung chủ yếu ở phần bên phải của biểu đồ.
Bên cạnh đó còn có:
- Độ tương phản thấp (low contrast): Ảnh được coi là có độ tương phản thấp nếu dải tần suất hẹp, các cột tần suất tập trung cục bộ ở giữa của biểu đồ.
- Độ tương phản cao (high contrast): Ảnh được coi là có độ tương phản cao, nếu dải tần suất trải dài, phân bổ của các cột tần suất gần như đồng đều.
Từ biểu đồ tần suất của ảnh Lena, chúng ta có thể kết luận đây là một ảnh tối và có độ tương phản cao.
Cân bằng tần suất (Histogram equalization)
Cân bằng tần suất là xử lý với mục đích kéo dãn phân bố của các mức độ xám (gray levels) ở trên ảnh. Xử lý này giúp giảm thiểu việc vón cục độ xám ở các ảnh có độ tương phản thấp (low contrast) cũng như cân bằng sáng ở các bức ảnh quá tối và quá sáng từ đó cải thiện chất lượng của ảnh gốc.
Để làm được việc này, xử lý cân bằng tần suất sẽ chuyển phân phối của biểu đồ tần suất (histogram) của bức ảnh hiện tại sang một phân phối khác mà ở đó các giá trị được trải dài và đồng đều hơn. Việc chuyển đổi này dựa trên hàm chuyển đổi tích lũy (cumulative distribution function).
1
2
3
4
5
6
# Cân bằng tần suất
img_hiseq = cv2.equalizeHist(img)
cv2_imshow(img_hiseq)
# Vẽ lại biểu đồ sau khi cân bằng
plt.hist(img_hiseq.ravel(), 256, [0,256])
plt.show()
Sau khi cân bằng tần suất (Histogram equalization) phân bố mức độ xám (gray level) của chúng ta đã đồng đều hơn, Lena của chúng ta trông đã rõ ràng và nổi bật hơn đúng không ?
Một cách tiếp cận khác và linh hoạt hơn của cân bằng tần suất đó là cân bằng tần suất thích ứng (adaptive histogram equalization). Phương pháp này chia nhỏ bức ảnh ra thành từng mảnh nhỏ và thực hiện cân bằng tần suất (histogram equalization) trên từng mảnh đó. Bằng việc cân bằng theo từng cụm nhỏ như vậy mức độ xám (gray level) sẽ được phân bố chính xác và hiểu quả hơn theo từng khu vực, đồng thời bức ảnh sẽ sắc nét hơn do sự khác biệt rõ rệt hơn giữa các khu vực trong bức ảnh.
1
2
3
4
5
6
7
# clipLimit là tham số hạn chế nhiễu của bức ảnh ra, tileGridSize là kích thước của từng mảnh
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
img_clahe = clahe.apply(img)
cv2_imshow(img_clahe)
# Vẽ lại biểu đồ sau khi cân bằng thích ứng
plt.hist(img_clahe.ravel(), 256, [0,256])
plt.show()
Lọc không gian ảnh tuyến tính (Linear spatial filtering)
Lọc không gian ảnh tuyến tính (linear spatial filtering) sử dụng một mặt nạ lọc (window/kernel/template/mask) hình vuông hoặc chữ nhật chứa các hệ số lọc (coefficient filter). Mặc nạ lọc (kernel) này sẽ được dịch chuyển tới từng điểm của bức ảnh, xuất phát từ góc trên cùng bên trái, tại mỗi điểm khi di chuyển qua sẽ thực hiện tích chập (convolution) giữa mặt nạ lọc (kernel) và giá trị của điểm ảnh (pixel value). Mặt nạ lọc (kernel) phổ biến được sử dụng có dạng vuông và có kích cỡ lẻ như 3x3, 5x5. Biểu diễn toán học của tích chập (convolution) như sau:
$R = w_{1}z_{1} + w_{2}z_{2} + w_{3}z_{3}+…+w_{mn}z_{mn} = \sum_{i = i}^{mn}w_{i}z_{i}$
Source: analyticsindiamag.com
Với kích cỡ 3x3 chúng ta có các mặt nạ lọc phổ biển sau.
Source: wikipedia.org
Đầu tiên chúng ta sẽ áp dụng mặt nạ lọc (kernel) giúp làm sắc nét (sharpening) bức ảnh hơn nhé. Sau quá trình làm sắc nét (sharpening), chúng ta kỳ vọng sẽ thấy rõ các đường nét, chi tiết trong bức ảnh hơn so với ảnh gốc.
1
2
3
4
5
6
import numpy as np
from scipy.signal import convolve2d
sharpening_kernel = np.asarray([[0, -1, 0], [-1, 5 , -1], [0, -1, 0]])
out = convolve2d(img, sharpening_kernel)
cv2_imshow(out)
Ngược lại, khi làm mịn (smoothing) bức ảnh sẽ mờ đi, tuy nhiên nhiễu (noise) trong bức ảnh sẽ được lọc đi đáng kể.
1
2
3
smoothing_kernel = (1/9) * np.asarray([[1, 1, 1], [1, 1 , 1], [1, 1, 1]])
out_smooth = convolve2d(img, smoothing_kernel)
cv2_imshow(out_smooth)
Kết
Bằng việc áp dụng các phương pháp xử lý sử dụng giá trị của các điểm ảnh một cách độc lập (point processing), cho đến các phương pháp tận dụng thông tin từ các điểm ảnh xung quanh (neighborhood processing), chúng ta đã có thể nâng cao chất lượng của bức ảnh tốt hơn so với bức ảnh gốc. Tùy theo mục đích sử dụng của bức ảnh đầu ra, chúng ta có thể lựa chọn các phương pháp xử lý thích hợp cũng như kết hợp các phương pháp để mang lại kết quả tốt nhất.