Xử lý ảnh - OpenCV ảnh nhị phân

  Oct 20, 2018      2m
   

OpenCV - tut 5: kỹ thuật Thresholding, Adaptive Thresholding

Xử lý ảnh - OpenCV ảnh nhị phân

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ý (bài viết sử dụng ảnh img_5.jpg, xem bên dưới)

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

Anh girl xinh 5 opencv

Ảnh nhị phân là gì?

Ảnh nhị phân (hay còn gọi là binary image trong tiếng Anh) là ảnh đen trắng chỉ có 2 giá trị là 0 và 255 (miền số nguyên) hoặc 0 và 1 (miền số thực / đối với ROI).

Minh họa ảnh nhị phân bạn sẽ thấy ở các ảnh demo các phần bên dưới.

Công dụng ảnh nhị phân

  • Ảnh nhị phân thường được dùng cho phân đoạn ảnh (segmentation). Ví dụ: phân đoạn ảnh lá cây (những pixel nào là của cái lá), ta được ảnh nhị phân từ ảnh gốc (ảnh màu hoặc ảnh xám), từ đó ta biết trích xuất được thông tin "diện tích" lá.
  • Nhị phân hóa ảnh là bước tiền xử lý rất hữu ích cho các giải thuật nhận dạng chữ viết / ký tự (OCR: Optical Character Recognition).
  • Nhị phân hóa ảnh để tạo mặt nạ region of interest: xem bài post Tut 4: OpenCV vùng quan tâm (ROI) là gì? (code Python). Từ đó ta có thể áp dụng các phép biến đổi xử lý ảnh chỉ trên vùng ROI (thường thấy trong Photoshop).
  • Trong Photoshop ta thường nhị phân hóa ảnh để loại bỏ nền (ví dụ như nền trắng) tạo ảnh có độ trong suốt (transparent) file ảnh có đuôi .png.

Các bước nhị phân hóa ảnh

  1. Biến đổi ảnh màu (color) sang ảnh xám (grayscale) hoặc đọc ảnh lên bằng cờ ảnh xám.
  2. Thiết lập ngưỡng (threshold) để nhị phân hóa ảnh.
  3. Áp dụng ngưỡng vào ảnh xám để tạo ảnh nhị phân hoặc áp dụng giải thuật nhị phân hóa ảnh. Các pixel có giá trị lớn hơn ngưỡng ta thiết lập bằng 255 (hoặc 1), nhỏ hơn ngưỡng ta thiết lập bằng 0.

Thực hành tạo ảnh nhị phân từ ảnh màu

Kỹ thuật Thresholding

  1. Đọc ảnh xám, dùng cờ cv2.IMREAD_GRAYSCALE.
  2. Thiết lập ngưỡng là 100 (hoặc ngưỡng giá trị khác bạn có thể sửa code lại).
  3. Áp dụng ngưỡng vào ảnh bằng hàm cv2.threshold của OpenCV.

Chạy lệnh:

$ python color2binary.py img_5.jpg

color2binary.py

import os, sys
import cv2

def convert_to_binary(img_grayscale, thresh=100):
    thresh, img_binary = cv2.threshold(img_grayscale, thresh, maxval=255, type=cv2.THRESH_BINARY)
    return img_binary

if __name__ == "__main__":
    assert len(sys.argv) == 2, '[USAGE] $ python color2binary.py img_5.jpg'
    input_image_path = sys.argv[1]
    
    assert os.path.isfile(input_image_path), 'Image not found @ %s' % input_image_path
    
    # read color image with grayscale flag: "cv2.IMREAD_GRAYSCALE"
    img_grayscale = cv2.imread(input_image_path, cv2.IMREAD_GRAYSCALE)       # shape: (960, 960)
    # print grayscale image
    cv2.imwrite('grey_%s' % input_image_path, img_grayscale)
    print('Saved grayscale image @ grey_%s' % input_image_path)
    
    img_binary = convert_to_binary(img_grayscale, thresh=100)
    cv2.imwrite('binary_%s' % input_image_path, img_binary)
    print('Saved binary image @ binary_%s' % input_image_path)

binary_img_5.jpg

binary image

Giải thuật Adaptive Thresholding

Đôi khi giải thuật Thresholding đơn giản phía trên chưa cho ra kết quả tốt. Lúc này ta cần xem xét đến các giải thuật nhị phân hóa hình ảnh mạnh mẽ hơn như là Adaptive Thresholding. Adaptive Thresholding lựa chọn ngưỡng (threshold) động trong vùng lân cận (neighborhood). Cụ thể giải thuật nó sẽ làm như sau:

  • Đối với mỗi pixel ảnh, ta xét vùng ảnh con có blockSize x blockSize (blockSize là số lẻ) với pixel đang xét là trung tâm của vùng ảnh con này.
  • Các mức sáng trong vùng ảnh con blockSize x blockSize -> ta tính giá trị trung bình M (đối với phương pháp adaptive "cv2.ADAPTIVE_THRESH_MEAN_C") -> threshold áp dụng cho pixel đang xét: threshold = M - C (C là hằng số xác định trước).
  • Như vậy độ tốt của Adaptive Thresholding phụ thuộc vào 3 siêu tham số (hyper parameter):
    • adaptiveMethod: cv2.ADAPTIVE_THRESH_MEAN_C / cv2.ADAPTIVE_THRESH_GAUSSIAN_C
    • blockSize: kích thước vùng lân cận
    • C: hằng số mà ta sẽ trừ đi (C có thể là số dương, số âm hay bằng 0)

adaptive_thresholding.py

import os, sys
import cv2

def convert_to_binary(img_grayscale):
    # adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C or cv2.ADAPTIVE_THRESH_GAUSSIAN_C
    img_binary = cv2.adaptiveThreshold(img_grayscale, 
                                       maxValue=255, 
                                       adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C, 
                                       thresholdType=cv2.THRESH_BINARY,
                                       blockSize=15,
                                       C=8)
    return img_binary

if __name__ == "__main__":
    assert len(sys.argv) == 2, '[USAGE] $ python adaptive_thresholding.py img_5.jpg'
    input_image_path = sys.argv[1]
    
    assert os.path.isfile(input_image_path), 'Image not found @ %s' % input_image_path
    
    # read color image with grayscale flag: "cv2.IMREAD_GRAYSCALE"
    img_grayscale = cv2.imread(input_image_path, cv2.IMREAD_GRAYSCALE)       # shape: (960, 960)
    # print grayscale image
    cv2.imwrite('grey_%s' % input_image_path, img_grayscale)
    print('Saved grayscale image @ grey_%s' % input_image_path)
    
    img_binary = convert_to_binary(img_grayscale)
    cv2.imwrite('adaptive_%s' % input_image_path, img_binary)
    print('Saved binary image @ adaptive_%s' % input_image_path)

adaptive_img_5.jpg

adaptive thresholding result


Sẽ có series các bài tiếp theo về dùng thư viện OpenCV trong xử lý ảnh, các bạn nhớ like trang Facebook để đón xem thông báo bài viết mới nhé! : https://www.facebook.com/minhng.info

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