- vừa được xem lúc

Xử lí ảnh: thuật toán cân bằng histogram ảnh

0 0 1k

Người đăng: Trung Thành Nguyễn

Theo Viblo Asia

Lý thuyết

1. Khái niệm.

Histogram là biểu đồ tần xuất thống kê số lần xuất hiện các mức sáng trong ảnh. Dưới đây là ảnh minh họa. Nhìn vào biểu đồ (chưa cần quan tâm tới đường màu đỏ), dựa vào các cột gía trị có thể dễ dàng thấy được rằng: có khoảng 2000 điểm ảnh mang giá trị 150, giá trị pixel chủ yếu trong khoảng [150, 200] nên độ tương phản không cao, không rõ nét.

Ảnh gốc

Cân bằng histogram (histogram equalization) là sự điều chỉnh histogram về trạng thái cân bằng, giá trị các điểm ảnh không bị co cụm tại một khoảng nhỏ mà được "kéo dãn" ra. Cân bằng histogram là một phương pháp tiền/hậu xử lí ảnh rất mạnh mẽ. Đặc biệt trong nhiều bài toán mình từng làm trong lĩnh vực compute vision, phương pháp tiền xử lí ảnh này cho chất lượng dữ liệu rất cao, cải thiện chất lượng model deep learning rất nhiều.

2. Công thức.

Mình nhận ra các bài viết về histogram equalization thường sơ sài chỉ có code, lại có những bài hơi nặng về công thức toán, gây khó hiểu cho những bạn mới. Trong bài này mình sẽ diễn giải rõ hơn về thuật toán. Mình sẽ làm việc với ảnh H1.

Gọi hàm biến đổi ta cần xác định là K(i)K(i) với iϵ[0,255]i \epsilon [0,255] . Với hình H1, ta cần xác định K sao cho K(150)0K(150) \approx 0, tức pixel có giá trị 150 được thay thế bằng giá trị 0.

B1: Thống kê số lượng pixel cho từng mức sáng, ta được histogram H(i)H(i)

B2: Tính "hàm tích lũy" HH' cho từng mức sáng theo công thức:

H(i)H'(i) = j=0iH(i)\sum_{j=0}^{i} H(i).

Trong đó H(i)H(i) chính là tổng số pixel có giá trị i\leqslant i . Trên hình H1, đường màu đỏ chính là đường minh họa HH' (hàm đồng biến). (Note: Giá trị H'(i) trên hình đã được thay đổi để dễ dàng show trên cùng 1 biểu đồ).

Giả sử H'(140) = 100, H'(150) = 200, H'(160) = 5000. Thấy H(150)H(140)H(150) - H(140) = 100, trong khi H(150)H(140)H(150) - H(140) = 4800 (tức có tận 4800 pixel nằm trong khoảng [150,160][150,160] ). Ta cần 1 hàm biến đổi sao cho K(150)K(140)K(150) - K(140) << K(160)K(150)K(160) - K(150) ... (<< là nhỏ hơn nhiều).

B3: Hàm biến đổi K tại một mức sáng i được tính như sau:

K(i)=H(i)min(H)max(H)min(H)255K(i) = \dfrac{H'(i) - min(H')}{max(H') - min(H')}* 255

Với hàm biến đổi K, với H'(i) - H'(j) nhỏ thì K(i) - K(j) nhỏ, và ngược lại. Nói cách khác, các khoảng sáng có nhiều pixel thì được giãn ra, những khoảng sáng có ít pixel thì được co lại.

Thực hành

Để hiểu rõ hơn về thuật toán, mình sẽ hướng dẫn code thuật toán hoàn toàn từ đầu.

1. Ảnh xám

Cân bằng histogram là cân bằng lại mức cường độ sáng, tức chỉ là 1 trong 3 chanel của hệ màu HSV. Vậy nên trước hết mình sẽ code với ảnh xám (gray)

Import thư viện và ảnh:

import numpy
import cv2
import matplotlib.pyplot as plt img = cv2.imread("img.png", 0)

Hàm tính histogram của một ảnh

def compute_hist(img): hist = np.zeros((256,), np.uint8) h, w = img.shape[:2] for i in range(h): for j in range(w): hist[img[i][j]] += 1 return hist

Hàm cân bằng histogram

def equal_hist(hist): cumulator = np.zeros_like(hist, np.float64) for i in range(len(cumulator)): cumulator[i] = hist[:i].sum() print(cumulator) new_hist = (cumulator - cumulator.min())/(cumulator.max() - cumulator.min()) * 255 new_hist = np.uint8(new_hist) return new_hist

Thử chạy:

hist = compute_hist(img).ravel()
new_hist = equal_hist(hist) h, w = img.shape[:2]
for i in range(h): for j in range(w): img[i,j] = new_hist[img[i,j]] fig = plt.figure()
ax = plt.subplot(121)
plt.imshow(img, cmap='gray') plt.subplot(122)
plt.plot(new_hist)
plt.show()

Và tất nhiên, kết quả mình thu được là hình H2 trên đầu bài viết.

Ngoài ra, với các bạn có thể dùng hàm của cv2 với cú pháp:

img = cv2.equalizeHist(img)

2. Ảnh màu

Mặc định ảnh màu là hệ RGB hoặc BGR, muốn cân bằng sáng ta cần biến đổi về hệ màu HSV. Hệ màu HSV bao gồm 3 chanel:

  • H-HUE: giá trị màu
  • S-SATURATION: độ bảo hòa.
  • V- VALUE: độ sáng của màu sắc.

Ta sẽ áp dụng cân bằng histogram chỉ trên độ sáng V của ảnh

img_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0]) # convert the YUV image back to RGB format
img_output = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)

Đây là kết quả demo, có thể thấy rõ màu sắc, hình ảnh sau khi cân bằng đã rõ nét hơn rất nhiều:

Cảm ơn các bạn đã đọc bài viết :p

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 496

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 373

- vừa được xem lúc

Đặt tên commit message sao cho "tình nghĩa anh em chắc chắn bền lâu"????

. Lời mở đầu. .

1 1 689

- vừa được xem lúc

Tìm hiểu về Resource Controller trong Laravel

Giới thiệu. Trong laravel, việc sử dụng các route post, get, group để gọi đến 1 action của Controller đã là quá quen đối với các bạn sử dụng framework này.

0 0 334

- vừa được xem lúc

Phân quyền đơn giản với package Laravel permission

Như các bạn đã biết, phân quyền trong một ứng dụng là một phần không thể thiếu trong việc phát triển phần mềm, dù đó là ứng dụng web hay là mobile. Vậy nên, hôm nay mình sẽ giới thiệu một package có thể giúp các bạn phân quyền nhanh và đơn giản trong một website được viết bằng PHP với framework là L

0 0 417

- vừa được xem lúc

Bạn đã biết các tips này khi làm việc với chuỗi trong JavaScript chưa ?

Hi xin chào các bạn, tiếp tục chuỗi chủ đề về cái thằng JavaScript này, hôm nay mình sẽ giới thiệu cho các bạn một số thủ thuật hay ho khi làm việc với chuỗi trong JavaScript có thể bạn đã hoặc chưa từng dùng. Cụ thể như nào thì hãy cùng mình tìm hiểu trong bài viết này nhé (go).

0 0 413