Kỹ Thuật Phân Ngưỡng Ảnh Cơ Bản Với Thư Viện OpenCV

Nguyên Lý Các Phép Phân Ngưỡng

Trong xử lý ảnh số, phân ngưỡng (thresholding) là thao tác cơ bản để chuyển đổi ảnh thang độ xám thành ảnh nhị phân. Quá trình này dựa trên việc so sánh giá trị pixel với một mức ngưỡng xác định để quyết định giá trị đầu ra. Dưới đây là 5 phương thức phân ngưỡng thường gặp:

  • Phân ngưỡng nhị phân (Binary): Nếu giá trị pixel lớn hơn ngưỡng, gán giá trị tối đa (maxVal), ngược lại gán bằng 0.
  • Phân ngưỡng nhị phân đảo (Binary Inv): Ngược lại với kiểu trên, pixel lớn hơn ngưỡng sẽ về 0, các pixel còn lại nhận giá trị maxVal.
  • Phân ngưỡng截断 (Truncate): Khi pixel vượt quá ngưỡng, giá trị của nó sẽ bị cắt bằng chính giá trị ngưỡng. Các pixel nhỏ hơn ngưỡng giữ nguyên.
  • Phân ngưỡng về 0 (To Zero): Pixel lớn hơn ngưỡng giữ nguyên giá trị gốc, những pixel nhỏ hơn sẽ bị đưa về 0.
  • Phân ngưỡng về 0 đảo (To Zero Inv): Pixel lớn hơn ngưỡng bị đưa về 0, các pixel nhỏ hơn ngưỡng giữ nguyên giá trị ban đầu.

Phương Pháp Xác Định Ngưỡng Tự Động

Việc chọn ngưỡng thủ công thường không tối ưu cho các điều kiện ánh sáng khác nhau. OpenCV hỗ trợ các thuật toán tự động tính toán ngưỡng phù hợp:

1. Thuật Toán Otsu (THRESH_OTSU)

Phương pháp Otsu dựa trên nguyên lý cực đại hóa phương sai giữa hai lớp (foreground và background). Giả sử阈值 là t, tỷ lệ điểm ảnh前景 là w0 với trung bình灰度 u0, tỷ lệ điểm ảnh背景 là w1 với trung bình灰度 u1. Phương sai giữa các lớp được tính như sau:

g = w0 * w1 * (u0 - u1)^2

Khi giá trị g đạt cực đại, sự phân tách giữa前景 và背景 là rõ rệt nhất, đó chính là ngưỡng tối ưu.

2. Thuật Toán Tam Giác (THRESH_TRIANGLE)

Phương pháp này xây dựng một đường thẳng nối đỉnh cao nhất của histogram với điểm cuối của đường cong histogram. Ngưỡng được xác định tại vị trí có khoảng cách vuông góc lớn nhất từ đường cong đến đường thẳng này. Lưu ý rằng phương pháp này hoạt động tốt khi đỉnh histogram không nằm ở giữa mà lệch về một phía.

Hàm API Trong OpenCV

Thư viện OpenCV cung cấp hàm threshold để thực hiện các thao tác trên. Cấu trúc hàm như sau:

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

Chi tiết tham số:

  • src: Ảnh đầu vào (thường là ảnh đơn kênh).
  • dst: Ảnh đầu ra sau khi phân ngưỡng.
  • thresh: Giá trị ngưỡng cố định (không có tác dụng nếu dùng Otsu/Triangle).
  • maxval: Giá trị tối đa áp dụng cho các kiểu phân ngưỡng nhị phân.
  • type: Kiểu phân ngưỡng, có thể kết hợp bằng phép bitwise OR.
    • THRESH_BINARY (0)
    • THRESH_BINARY_INV (1)
    • THRESH_TRUNC (2)
    • THRESH_TOZERO (3)
    • THRESH_TOZERO_INV (4)
    • THRESH_OTSU (8)
    • THRESH_TRIANGLE (16)

Khi sử dụng THRESH_OTSU hoặc THRESH_TRIANGLE, tham số thresh truyền vào thường để là 0 vì hàm sẽ tự tính toán. Ảnh đầu vào bắt buộc phải là ảnh đơn kênh (grayscale).

Ví Dụ Minh Họa

Đoạn mã dưới đây demonstrates cách sử dụng thuật toán Otsu kết hợp với phân ngưỡng nhị phân trong C++:

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // Đọc ảnh ở chế độ thang độ xám
    cv::Mat matSource = cv::imread("input_image.jpg", cv::IMREAD_GRAYSCALE);
    if (matSource.empty()) {
        std::cerr << "Không thể tải ảnh!" << std::endl;
        return -1;
    }

    cv::Mat matResult;
    double valThreshold = 0;
    double valMax = 255.0;
    
    // Kết hợp cờ THRESH_OTSU và THRESH_BINARY
    int modeType = cv::THRESH_BINARY | cv::THRESH_OTSU;

    // Thực hiện phân ngưỡng, hàm trả về ngưỡng thực tế đã tính
    double computedThreshold = cv::threshold(matSource, matResult, valThreshold, valMax, modeType);

    std::cout << "Ngưỡng tự động tìm được: " << computedThreshold << std::endl;

    // Lưu ảnh kết quả
    cv::imwrite("threshold_output.jpg", matResult);

    return 0;
}

Thẻ: opencv image-thresholding otsu-method computer-vision cpp

Đăng vào ngày 30 tháng 5 lúc 00:54