Xử lý ảnh - OpenCV cân bằng sáng (histogram equalization)

  Oct 27, 2018      2m
   

OpenCV - tut 6: histogram equalization

Xử lý ảnh - OpenCV cân bằng sáng (histogram equalization)

Môi trường làm việc với OpenCV

  • Linux (bài viết sử dụng Ubuntu 16.04)
  • OpenCV (bài viết sử dụng OpenCV 3.4.1)
  • Python (bài viết sử dụng Python 3.5.5)
  • Ảnh mẫu để xử lý: img_6.jpg

Bạn có thể download ảnh mẫu về:

img_6.jpg (Nguồn: ảnh lụm từ FB Trang Đoàn)

Anh girl xinh 6 opencv

Cân bằng sáng là gì?

Cân bằng sáng (histogram equalization) là sự điều chỉnh histogram của ảnh về mức cân bằng.

can bang sang

Vậy, histogram của ảnh là gì? Hãy xem mục dưới nhé.

Histogram

Histogram của ảnh (intensity histogram) là biểu đồ cột thống kê số lần xuất hiện của các mức sáng trong ảnh.

  • Nói cách khác, histogram là biểu đồ thống kê tần suất xuất hiện của mức sáng.
  • Histogram thường được chuẩn hóa bằng cách: lấy mỗi cột chia cho giá trị tổng –> sau khi chuẩn hóa, tổng các giá trị cột trong histogram sẽ bằng 1.
  • Histogram đã chuẩn hóa mang ý nghĩa xác suất xuất hiện của các mức sáng trong ảnh.

Ví dụ histogram của 1 ảnh vẽ bằng MATLAB (trục x là mức sáng [0, 255] - intensity, trục y là số lần xuất hiện của mức sáng đó trong ảnh - frequency):

histogram MATLAB

Công dụng của cân bằng sáng

Tác dụng của histogram equalization thường được dùng:

  • Cân bằng sáng thường được dùng ở bước tiền xử lý.
  • Nhằm giảm sự ảnh hưởng do chiếu sáng (chói), thiếu ánh sáng (ảnh tối), …
  • Ta có thể hiểu cân bằng sáng giúp ta "chuẩn hóa" ảnh đầu vào trước khi tiến hành xử lý.
  • Các giải thuật xử lý ảnh thường nhạy cảm với ánh sáng, cùng nội dung ảnh nhưng với các điều kiện ánh sáng khác nhau có thể làm sai lệch kết quả xử lý (giả sử trong bài toán phát hiện đối tượng, bài toán nhận dạng, bài toán đếm đối tượng, …). Do đó, cân bằng sáng ở bước tiền xử lý là một trong những cách giúp làm giảm các ảnh hưởng này.

Giải thuật cân bằng sáng

Link giải thuật cân bằng sáng trong OpenCV:

https://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.html#how-does-it-work

Giải thuật cân bằng sáng:

  1. Thống kê histogram cho ảnh: .
  2. Áp dụng hàm biến đổi: .
  3. Chuẩn hóa histogram mới vừa biến đổi () về [0, 255].
  4. Mapping mức sáng ảnh kết quả theo : . Với là ảnh gốc, là ảnh đã cân bằng sáng.

Hiện thực Histogram Equalization

Chương trình bên dưới là mình đã hiện thực giải thuật Histogram Equalization từ đầu. Tính năng chương trình bao gồm:

  • Tạo image histogram từ ảnh img_6.jpg.
  • Trực quan hóa histogram bằng biểu đồ cột dùng thư viện seaborn. Các bạn cài đặt seaborn bằng lệnh: $ pip install seaborn.
  • Hiện thực giải thuật cân bằng sáng.
  • In ảnh đã cân bằng sáng.
  • Các bạn có thể thử với ảnh khác bằng cách thay img_6.jpg trong lệnh chạy bằng đường dẫn đến ảnh bạn muốn.
  • Lệnh thực thi chương trình: $ python hist_eq.py img_6.jpg

hist_eq.py

import os, sys
import cv2
import numpy as np

try:
    import seaborn as sns
    import pandas as pd
except:
    raise Exception('Seaborn package not found. Installation: $ pip install seaborn')
    
def create_histogram(img):
    assert len(img.shape) == 2 # check grayscale image
    histogram = [0] * 256 # list of intensity frequencies, 256 zero values
    for row in range(img.shape[0]): # traverse by row (y-axis)
        for col in range(img.shape[1]): # traverse by column (x-axis)
            histogram[img[row, col]] += 1
    return histogram

def visualize_histogram(histogram, output='histogram.png'):
    hist_data = pd.DataFrame({'intensity': list(range(256)), 'frequency': histogram})
    sns_hist = sns.barplot(x='intensity', y='frequency', data=hist_data, color='blue')
    sns_hist.set(xticks=[]) # hide x ticks
    
    fig = sns_hist.get_figure()
    fig.savefig(output)
    return output

def equalize_histogram(img, histogram):
    # build H', cumsum
    new_H = [0] * 257
    for i in range(0, len(new_H)):
        new_H[i] = sum(histogram[:i])
    new_H = new_H[1:]
       
    # normalize H'
    #max_H = max(new_H)
    #max_hist = max(histogram)
    #new_H = [(f/max_H)*max_hist for f in new_H]
    
    # scale H' to [0, 255]
    max_value = max(new_H)
    min_value = min(new_H)
    new_H = [int(((f-min_value)/(max_value-min_value))*255) for f in new_H]
    
    print("H':", new_H)
    
    # apply H' to img
    for row in range(img.shape[0]): # traverse by row (y-axis)
        for col in range(img.shape[1]): # traverse by column (x-axis)
            img[row, col] = new_H[img[row, col]]
    return img

if __name__ == "__main__":
    assert len(sys.argv) == 2, '[USAGE] $ python %s img_6.jpg' % (os.path.basename(__file__), INPUT)
    INPUT = sys.argv[1]
    assert os.path.isfile(INPUT), '%s not found' % INPUT
    
    # read color image with grayscale flag: "cv2.IMREAD_GRAYSCALE"
    img = cv2.imread(INPUT, cv2.IMREAD_GRAYSCALE)
    # print grayscale image
    cv2.imwrite('grey_%s' % INPUT, img)
    print('Saved grayscale image @ grey_%s' % INPUT)
    
    # create histogram from image
    histogram = create_histogram(img)
    print('histogram:', histogram)
    
    hist_img_path = visualize_histogram(histogram)
    print('Saved histogram @ %s' % hist_img_path)
    
    equalized_img = equalize_histogram(img, histogram)
    cv2.imwrite('equalized_%s' % INPUT, equalized_img)
    print('Saved equalized image @ equalized_%s' % INPUT)
    
    new_histogram = create_histogram(equalized_img)
    print('new_histogram:', new_histogram)
    hist_img_path = visualize_histogram(new_histogram, output='histogram_eq.png')
    print('Saved new histogram @ %s' % hist_img_path)
    
    print('Done Tut 6: Histogram Equalization. Welcome to minhng.info')
    

Histogram trước khi cân bằng sáng:

histogram trước khi cân bằng sáng

Histogram sau khi cân bằng sáng:

histogram sau khi cân bằng sáng

Ảnh sau khi cân bằng sáng:

ảnh sau khi cân bằng sáng

Histogram Equalization trong OpenCV

Trong OpenCV bạn chỉ cần gọi hàm để thực hiện cân bằng sáng: cv2.equalizeHist. Đoạn chương trình sau giúp ta cân bằng sáng ảnh (không in ra histogram).

$ python opencv_histeq.py đường_dẫn_đến_file_ảnh.jpg
$ python opencv_histeq.py img_6.jpg

opencv_histeq.py

import os, sys
import cv2

if __name__ == "__main__":
    assert len(sys.argv) == 2, '[USAGE] $ python %s img_6.jpg' % (os.path.basename(__file__), INPUT)
    INPUT = sys.argv[1]
    assert os.path.isfile(INPUT), '%s not found' % INPUT
    
    # read color image with grayscale flag: "cv2.IMREAD_GRAYSCALE"
    img = cv2.imread(INPUT, cv2.IMREAD_GRAYSCALE)       # shape: (960, 960)
    # print grayscale image
    cv2.imwrite('grey_%s' % INPUT, img)
    print('Saved grayscale image @ grey_%s' % INPUT)
    
    equalized_img = cv2.equalizeHist(img)
    cv2.imwrite('equalized_%s' % INPUT, equalized_img)
    print('Saved equalized image @ equalized_%s' % INPUT)
    
    print('Done Tut 6: Histogram Equalization. Welcome to minhng.info')
    

Danh sách bài viết series OpenCV: