Ảnh đa mức xám là gì

Lập trình

Kỹ Thuật Grayscale và Nhị Phân Hoá Ảnh (Adaptive Threshold)

Ảnh đa mức xám là gì
Trương Xuân Đạt
20/09/202010 min read
Giới thiệu và chi tiết các thuật toán Grayscale, ảnh nhị phân và một số thuật toán giúp biến đổi một ảnh xám thành ảnh nhị phân (Adaptive threshold).

Giới thiệu

OpenCV (Open Computer Vision) là 1 thư viện mã nguồn mở chuyên dùng để xử lý các vấn đề liên quan đến thị giác máy tính. Nhờ 1 hệ thống các giải thuật chuyên biệt, tối ưu cho việc xử lý thị giác máy tính, vì vậy tính ứng dụng của OpenCV là rất lớn.Xử lý ảnh là quá trình xử lý, thao tác hình ảnh để có 1 hình ảnh khác phù hợp với nhu cầu của người dùng, ...

Bài viết giới thiệu khái niệm và kỹ thuật ảnh xám (Grayscale) và ảnh nhị phân và nhị phân hóa (Adaptive Threshold).

GrayScale là gì?

  • Là 1 hệ thống màu cómô hình màu đơn giản nhất với 256 cấp độ xám biến thiên từ màu đenđến màu trắng.
  • Kết quả được xuất ra sẽ có màu trắng đen.
  • Đượcsử dụng cả trong công nghiệp in lẫn dùng trong việc thể hiện ảnh lên các thiết bị số.
  • Ảnh xám (Gray image)hay còn gọi là ảnh đơn sắc (Monochromatic), mỗi giá trị điểm ảnh (Pixel) trong ma trận điểm ảnh mang giá trị từ 0 đến 255.
  • Trong không gian màu RGB, để có 1 ảnh xám cần có phải có giá trị kênh màu Red(x, y) = Green(x, y) = Blue(x, y) (với x, y lần lượt là tọa độ của điểm ảnh).
    Ảnh đa mức xám là gì

Chuyển đổi hệ thống màuRGB sang Grayscale

Ảnh là tập hợp của 1 ma trận điểm ảnh (pixel), mỗi điểm ảnh có thể được biểu diễn bằng n bytes dưới các kênh màu khác nhau. Việc chuyển đổi giữa các hệ màu thông thường được thực hiện thông qua các phép biến đổi ma trận.

Bài viết sẽ giới thiệu cách chuyển đổi từ ảnh 24 bits RGB sang ảnh 8 bits Grayscale.

Công thức

Công thức tính cường độ sáng tại 1 điểm ảnh từ ảnh RGB:

I(x, y) = 0.3086 * Red(x, y) + 0.6094 * Green(x, y) + 0.0820 * Blue(x, y) I(x, y) = 0.299 * Red(x, y) + 0.587 * Green(x, y) + 0.114 * Blue(x, y)

Hoặc

I(x, y) = ( 2 * Red(x, y) + 5 * Green(x, y) + 1 * Blue(x, y) ) / 8

Phân tích

  • I(x, y): cường độ sáng tại điểm ảnh (x, y) của ảnh xám.
  • Red(x, y): giá trị của kênh màu Red (Đỏ) tại điểm ảnh (x, y) của ảnh màu (RGB).
  • Green(x, y): giá trị của kênh màu Green (Xanh lá cây) tại điểm ảnh (x, y) của ảnh màu (RGB).
  • Blue(x, y): giá trị của kênh màu Blue (Xanh lơ) tại điểm ảnh (x, y) của ảnh màu (RGB).

Chú ý

  • Các phép toán trong số nguyên (Int)nhanh hơn rất nhiều trong số thực(Float).
  • Trong OpenCV, hệ thống màu có thứ tự các kênh màu là Blue-Green-Red.
  • Các thông số dùng để tính toán cường độ sáng cho ảnh xám như: 0.3086, 0.6094, 0.0820,... được coi là những con số đẹp do người ta nghiên cứu ra. Các con số này có thể thay đổi. Có thể chọn 1 giá trị 1 kênh màu hoặc chia trung bình cộng của 3 kênh màu để tìm cường độ sáng tại 1 điểm ảnh (Pixel).

Chuyển đổi ảnh xám trong OpenCV

Phương thức cvtColor

Trong OpenCV, để chuyển 1 tấm ảnh có hệ màu RGB sang Grayscale, hay thậm chí là các không gian màu qua lại với nhau nhờ phương thức cvtColor()(Convert color).

cv::cvtColor(cv::InputArray src, cv::OutputArray dst, int code)

Phân tích

  • src: Là hình ảnh gốc (Trong bài viết này là ảnh màu).
  • dst: Là ảnh thu được (Trong bài viết này là ảnh xám).
  • code: Là mã chuyển màu. Ví dụ: code = CV_BGR2GRAY là chuyển đổi ảnh màu thành ảnh xám,...

Code minh hoạ phương thức cvtColor trong OpenCV

// www.stdio.vn // www.stdio.vn/users/index/11/truong-dat #include #include "opencv2/core/core.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" using namespace cv; int main() { // Read image Mat image = imread("stdio.png", CV_LOAD_IMAGE_COLOR); Mat imageGrayscale; // Check for valid if (!image.data) { printf("Could not open or find the image\n"); return -1; } cvtColor(image, imageGrayscale, CV_BGR2GRAY); // Create and show image in window imshow("STDIO OpenCV Sample", imageGrayscale); // Wait input and exit waitKey(0); return 0; }
Ảnh đa mức xám là gì

Ảnh nhị phân

  • Là ảnh mà giá trị của các điểm ảnh chỉ được biểu diễn bằng hai giá trị là 0 (Đen) và 255 (Trắng) (Tương ứng với 0 và 1, nhưng để nguyên giá trị 0 và 255 để có thể hiểu hơn trong việc tính toán).
  • Vì giá trị của điểm ảnh được biểu diễn bởi 2 giá trị là 0 hoặc 1, nên 1 điểm ảnh được biểu diễn bằng 1 bit nên ảnh có kích thước rất nhỏ.

Nhị phân hóa

Là quá trình biến đổi 1 ảnh xám thành ảnh nhị phân.

  • Gọi giá trị cường độ sáng tại 1 điểm ảnh là I(x,y).
  • INP(x,y) là cường độ sáng của điểm ảnh trên ảnh nhị phân .
  • (Với0 < x < image.width) và (0 < y < image.height).

Để biến đổi ảnh xám thành ảnh nhị phân. So sánh giá trị cường độ sáng của điểm ảnh với 1 ngưỡng nhị phân T.

  • Nếu I(x,y) > T thì INP(x, y) = 0 (0).
  • Nếu I(x,y) > T thì INP(x, y) = 255 (1).

Chú ý

  • Có thể chọn giá trị T từ 0 đến 255, nhưng thông thường nhiều người hay chọn 1 giá trị đó là 128 tức là giá trị trung bình của max(255) và min(0) của cường độ sáng (Intensity) của điểm ảnh.
  • Dễ dàng nhận thấy với mỗi T thì có 1 ảnh nhị phân khác nhau (Khác nhau ở đây là cường độ sáng của các tấm ảnh nhị phân với mỗi giá trị T).

Có 1 kỹ thuật gọi là nhị phân hóa ngưỡng động giúp thu được ảnh nhị phân mà không quan tâm tới cường độ sáng.

Nhị phân hóa trong OpenCV

Phương thức threshold

Để chuyển 1 ảnh thành 1 ảnh nhị phân, sử dụng phương thức threshold().

threshold(cv::InputArray src, cv::OutputArray dst, double thresh, double maxval, int type);

Phân tích

  • src: hình ảnh gốc (Trong bài viết này là ảnh màu).
  • dst: ảnh thu được (Trong bài viết này là ảnh nhị phân).
  • thresh: ngưỡng nhị phân T.
  • maxval: giá trị lớn nhất trong ảnh (maxval = 255 đối với ảnh xám).
  • type: kiểu nhị phân.
Code minh hoạ phương thức threshold trong OpenCV
// www.stdio.vn // www.stdio.vn/users/index/11/truong-dat #include #include "opencv2/core/core.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" using namespace cv; int main() { // Read image Mat image = imread("stdio.png", CV_LOAD_IMAGE_GRAYSCALE); Mat imageBinary; // Check for valid if (!image.data) { printf("Could not open or find the image\n"); return -1; } threshold(image, imageBinary, 220, 255, CV_THRESH_BINARY); // Create and show image in window imshow("STDIO OpenCV Sample", imageBinary); // Wait input and exit waitKey(0); return 0; }
Ảnh đa mức xám là gì

Nhị phân hóa ngưỡng động

Ý tưởng:

  1. Chia ảnh thành nhiều khu vực, cửa sổ khác nhau (Region).
  2. Dùng 1 thuật toán để tìm 1 giá trị T phù hợp với từng khu vực, cửa sổ (Region).
  3. Áp dụng phương pháp nhị phân hóa cho từng khu vực, cửa sổ (Region) với T phù hợp.

Điều quan trọng trong kỹ thuật này là phải tìm 1 giá trị T phù hợp với từng khu vực, cửa sổ (Region) hoặc cả tấm ảnh. Có rất nhiều phương pháp để tìm T, ở nội dung tiếp theo sẽ giới thiệu 1 số thuật toán giúp tìm kiếm giá trị T này.

Thuật toán Otsu

Bước 1:Xác định T1. Giá trị cho T1ban đầu nên chọn là (0+255) / 2 = 128.

Bước 2:Phân loại thành 2 nhóm điểm ảnh.

  • Loại 1 (Type1): chứa tất cả các điểm ảnh có giá trị cường độ sáng (Intensity) <= T.
  • Loại 2 (Type2): chứa tất cả các điểm ảnh có giá trị cường độ sáng (Intensity) > T.

Bước 3:Tính giá trị cường độ sáng trung bình (iAverage) cho Type1 (iAverage1) và Type2 (iAverage2).

Bước 4:Tính giá trị T2 theo công thức (iAverage1 + iAverage2) /2.

Bước 5:So sánh T1 và T2.

  • Nếu giá trị chênh lệch của T1 và T2 <= Delta (1 giá trị cho trước) thì T2 chính là T cần tìm.
  • Nếu giá trị chênh lệch của T1 và T2 > Deltathì quay lại Bước 1.
Ảnh đa mức xám là gì

Thuật toán đối xứng

Bước 1: khởi tạo mảng Histogram(histogram). Tìm giá trị cường độ sáng (intensityMax) có tuần suất xuất hiện nhiều nhất histogram[intensityMax].

Bước 2: duyệt toàn bộ các mức xám giảm từ 255 đến intensityMax. Nếu tại mức xám nào có tuầnsuất xuất hiện trên ảnh là 5% thì dừng lại. Lấy giá trị đối xứng qua histogram[intensityMax] là ngưỡng động T.

for (int indexIntensity = 255; indexIntensity >= intensityMax; indexIntensity--) { frequency = histogram[indexIntensity]; if ((float)frequency / (image.Width * image.Height) == 0.05f) { split = indexInteensity; break; } } T = intensityMax - (split - intensityMax);
Ảnh đa mức xám là gì

Thuật toán tam giác

Bước 1: Khởi tạo mảng Histogram(histogram).

  • Tìm giá trị intensityMax vàhistogram[intensityMax].
  • Tìm giá trịintensityMinvàhistogram[intensittyMin].

Bước 2: Duyệt toàn bộ các mức xám từ intensityMinđến intensityMax. Tính khoảng cách tương ứng sau đó xét ngưỡng Tbằng giá trị mức xám có khoảng cách lớn nhất.

for(int index = intensityMin+1; index < intensityMax; index++) { distance = findDistance (Point(intensityMax, histogram[intensityMax]), Point(intensityMin, histogram[intensityMin]), Point(index, histogram[index])); if (distanceMax < distance) { distanceMax = distance; T = index; } }

Phân tích

Phương thức findDistance(Point a, Point b, Point c) là tìm khoảng cách từ 1 điểm đến 1 đường thẳng với các tham số:

  • a và b: lần lượt là 2 điểm khác biệt trên đường thẳng.
  • c: là điểm cần tìm khoảng cách tới đường thẳng.
Ảnh đa mức xám là gì

Nhị phân hóa ngưỡng độngtrong OpenCV

Phương thức adaptiveThreshold

Để chuyển 1 ảnh thành 1 ảnh nhị phân, sử dụng phương thức adaptiveThreshold()

adaptiveThreshold(cv::InputArray src, cv::OutputArray dst, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C);

Phân tích

  • src: hình ảnh gốc (Trong bài viết này là ảnh màu).
  • dst: ảnh thu được (Trong bài viết này là ảnh nhị phân).
  • thresh: ngưỡng nhị phân T.
  • maxValue: giá trị lớn nhất trong ảnh (maxval = 255 đối với ảnh xám).
  • adaptiveMethod: cách thức nhị phân với ngưỡng động, nó chính là cách tính giá trị ngưỡng nhị phân trong từng vùng cần nhị phân.
  • thresholdType: kiểu nhị phân.
  • blockSize: kích thước của cửa sổ (Region) áp dụng cho việc tính toán ngưỡng động (nên chọn các giá trị %3 = 0 || %5 = 0 || %7 = 0).
  • C: thông số để bù trừ trong trường hợp ảnh có độ tương phản quá lớn.
Code minh hoạ phương thức adaptiveThreshold trong OpenCV
#include #include "opencv2/core/core.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" using namespace cv; int main() { // Read image Mat image = imread("stdio.png", CV_LOAD_IMAGE_GRAYSCALE); Mat imageBinary; // Check for valid if (!image.data) { printf("Could not open or find the image\n"); return -1; } adaptiveThreshold(image, imageBinary, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 9, 0); // Create and show image in window imshow("STDIO OpenCV Sample", imageBinary); // Wait input and exit waitKey(0); return 0; }
Ảnh đa mức xám là gì

Computer Vision

Thị giác máy tính.