STDIO
Tìm kiếm gần đây
    • Nội dung
    • QR Code
    • 0
    • 0
    • Sao chép

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

    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).
    23/01/2015
    20/09/2020
    10 phút đọc
    Kỹ Thuật Grayscale và Nhị Phân Hoá Ảnh (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.
    • Được sử 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).
      ss_1

    Chuyển đổi hệ thống màu RGB 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 <stdio.h>
    #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;
    }
    ss_2

    Ả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 01, nhưng để nguyên giá trị 0255 để 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ới 0 < 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 <stdio.h>
    #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;
    }
    ss_3

    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 T1 ban đầ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 T1T2

    • Nếu giá trị chênh lệch của T1T2 <= 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 T1T2 > Delta thì quay lại Bước 1.
    ss_4

    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ần suấ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);
    ss_5

    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ị intensityMin và 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 T bằ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ố:

    • ab: 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.
    ss_6

    Nhị phân hóa ngưỡng động trong 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 <stdio.h>
    #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;
    }
    ss_7
    0 Bình luận
    Computer Vision

    Computer Vision

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

    Đề xuất

    Xử Lý Ảnh Với OpenCV: Các Phép Toán Hình Thái Học
    Giới thiệu những thuật toán cơ sở trong xử lý hình thái học, những thuật ...
    Toán Tử Khung Xương trong Ảnh Nhị Phân - Skeleton Binary Morphology
    Giới thiệu giải thuật thực hiện toán tử khung xương (skeleton) dựa trên ...

    Khám phá

    Mã Hóa Base64
    Base64 không phải là một thuật toán mã hóa và trong mọi trường hợp, nó ...
    Tổng Quan về Ánh Sáng
    Một phong cách thường là kết quả của sự ưu tiên về mặt kỹ thuật, được sử ...
    16/10/2020
    Phép Tích Chập Trong Xử Lý Ảnh (Convolution)
    Convolution là kỹ thuật quan trọng trong Xử Lý Ảnh, được sử dụng chính ...
    OpenCV với Python trong Ứng Dụng Đếm Số Lượng
    Bài viết ứng dụng OpenCV để nhận dạng và đếm số lượng vật thể giúp giảm ...
    Giới Thiệu về Kỹ Thuật Phần Mềm – Software Engineering
    Software Engineering là một phần của System Engineering - liên quan đến ...
    22/09/2014
    Xử Lý Ảnh Với OpenCV: Lọc Số Trong Ảnh
    Giới thiệu lọc số ảnh, khái niệm và công thức nhân chập ma trận, một số ...
    Sự Thật về Web Design và Graphic Design
    Web Design thường được hiểu nghĩa tiếng Việt đó là thiết kế web, Graphic ...
    Tìm Hiểu về fstream
    Kiến thức về file là một trong những kiến thức quan trọng đối với các ...
    11/05/2015
    Khi bạn nhấn vào liên kết sản phẩm do STDIO đề xuất và mua hàng, STDIO có thể nhận được hoa hồng. Điều này hỗ trợ STDIO tạo thêm nhiều nội dung hữu ích. Tìm hiểu thêm.
    STDIO
    Trang chính
    Công ty TNHH STDIO

    30, Trịnh Đình Thảo, Hòa Thạnh, Tân Phú, Hồ Chí Minh
    +84 28.36205514 - +84 942.111912
    developer@stdio.vn

    383/1 Quang Trung, Phường 10, Quận Gò Vấp, Hồ Chí Minh
    Số giấy phép ĐKKD: 0311563559 do sở Kế hoạch và Đầu Tư TPHCM cấp ngày 23/02/2012

    ©STDIO, 2013 - 2020