opencv

자동 2진화 - OTSU

꼰대코더 2026. 2. 26. 19:59

오브젝트 분석을 위해서는 그레이 이미지로 변화한 후 2진화를 통해 바이너리 이미지로 만들어야 한다.

보통 바이너리 이미지는 이미지 헤더에 Index 0, 255 를 만들고 0과 1로 표현하지만, OpenCV에서는 헤더없이 0(Black)과 255(White) 로 표현한다.

 

2진화 방법의 Threshold 값으로는 크게 3가지가 있다.

1. (전체대상) 고정값

2. (전체대상)  자동으로 분리값 계산 후 분리

3. 전체를 작은 블럭으로 나눈 후 고정값이나, 평균, 자동으로 Threshold를 계산

 

그중 자동 2진화 방법인 OTSU 에 대해 알아보자.

일본인 大津(OOTSU) 박사에 의해 1979년 발표되었는데 간단히 설명하면 두 산봉오리(배경과 전경) 사이의 계곡을 찾는 원리이다.

double getOtsuThreshold(const cv::Mat& src) {
    // 1. 히스토그램 생성 (0~255 밝기가 각각 몇 개인지 세기)
    int hist[256] = {0};
    for (int r = 0; r < src.rows; r++) {
        const uchar* ptr = src.ptr<uchar>(r);
        for (int c = 0; c < src.cols; c++) {
            hist[ptr[c]]++;
        }
    }

    // 2. Otsu 알고리즘 계산
    double total = (double)src.rows * src.cols;
    double sum = 0;
    for (int i = 0; i < 256; i++) sum += i * hist[i];

    double sumB = 0;
    int wB = 0;
    double varMax = 0;
    double threshold = 0;

    for (int i = 0; i < 256; i++) {
        wB += hist[i];               // 배경의 픽셀 개수 가중치
        if (wB == 0) continue;
        int wF = total - wB;         // 전경의 픽셀 개수 가중치
        if (wF == 0) break;

        sumB += (double)(i * hist[i]);
        double mB = sumB / wB;       // 배경 평균
        double mF = (sum - sumB) / wF; // 전경 평균

        // 클래스 간 분산(Between-class variance) 계산
        double varBetween = (double)wB * (double)wF * (mB - mF) * (mB - mF);

        if (varBetween > varMax) {
            varMax = varBetween;
            threshold = i;
        }
    }
    return threshold;
}

 

OpenCV : cv::threshold(src, dst, 0, 255, cv::THRESH_BINARY | cv::THRESH_OTSU);

 

아래 이미지를 보며 설명해 보자.


 

이미지의 오른쪽과 같이 히스토그램을 표현하면 가로축은 픽셀의 값(0~255), 세로축은 그 값들을 가지는 픽셀수가 된다.

배경 Foreground는 각 왼쪽(어두운색)이나 오른쪽(밝은색) 혹은 오르쪽이나 왼쪽으로 나뉠 수 있다.

히스토그램을 0 ⇒ 255 방향으로 이동하면서 누적픽셀수(wB)과 누적평균(mB) 을 구해간다. 그럼 그 시점에서의 반대편은 전체에서 wB와 mB를 뺀 나머지의 wF, mF가 된다.  

이때 double varBetween = (double)wB * (double)wF * (mB - mF) * (mB - mF); 계산에 의해서 두 값들의 차가 벌어질 수록 값이 커지기 때문에 가장 많이 벌어진 지점이 Threshold 값으로 정해지는 것이다.

빨간바가 위치한 지점의 wB mB / wF mF의 계산 영역을 표시

 

 

'opencv' 카테고리의 다른 글

Color -> Gray 변환방법  (0) 2026.02.26
Color Transform  (0) 2025.10.30
findContours 의 CV_RETR_TREE 옵션과 hierarchy 의 관계  (0) 2025.06.26
findContours 의 결과 포인트들을 좀 더 심플하게 가공  (1) 2025.06.25
Barcode 읽기  (0) 2025.02.23