본문 바로가기

프로그래밍 강좌/C++ - OpenCV

[OpenCV][C++] Thresholding 이진화 영상 만들기 총정리 (1) - image threshold binarization otsu triangle 히스토그램

지난번에는 함수 실행 시간을 측정하는 방법에 대해 알아봤습니다.

https://blog.naver.com/dorergiverny/223079726064 

 

[OpenCV][C++] 함수 실행 시간 측정 쉬운 방법 - TickMeter 사용법 총정리 elapsed time chrono getTimeMilli reset b

지난 번에 함수 실행 시간 측정하는 방법으로 chrono 라이브러리를 사용하는 방법에 대해 알아 보았습니다....

blog.naver.com

이번에는 그레이 영상을 이진화 하는 방법에 대해 알아보겠습니다.

이진화는 특정 밝기 범위 또는 밝은 영역 어두운 영역 등으로 이분화해서

전경과 배경으로 나누는 방법입니다

Thresholding (이진화)

 

이진화 영상의 픽셀들을 두 개의 부류로 나누는 작업입니다.

아래와 같은 사진에서 흰색 탁구공을 구분하려고 합니다.

그 때 아래와 같이 cv::threshold() 함수를 사용하면 됩니다.

픽셀 밝기가 180 이상인 값을 255로, 180보다 작은 값은 0으로 처리하는 함수는 아래와 같습니다.

cv::threshold(src, binImage, 180, 255, cv::THRESH_BINARY);
 

결과 영상은 아래처럼 나오네요.

자 그럼 threshold 함수에 대해 좀 더 알아봐요.

src
입력 영상
dst
출력 영상, 이진화 영상
thresh
임계값(threshold)
maxval
임계값 이상일 때 이진화 영상의 최대값(보통 255 사용)
type
thresholding 연산 방법 (하기 설명 참조)
반환 (double)
자동으로 결정되는 경우의 threshold 값(THRESH_OTSU, THRESH_TRIANGLE)

 

cv::threshold() 함수의 동작은 연산 방법인 type에 따라 결정됩니다.

OpenCV 4.7.0 에는 아래와 같이 8가지가 지원됩니다.

type에 대한 설명을 자세히 살펴보면(docs.opencv.org를 재구성함),

원본 영상이 아래와 같이 생겼다고 가정하면

각 방법은 아래와 같이 동작합니다.

 

이는 밝기 분포를 분석하여 클래스 내의 분산 클래스 간의 분산을 계산하여

분산의 비율이 최대가 되는 위치를 threshold로 결정하는 방법 입니다.

(수식은 생략할께요.)

그럼 아래와 같은 그림을 얻을 수 있습니다.

[THRESH_TRIANGLE]

이 알고리즘은 그래프 상에서 peak를 이용하는 방법으로

그래프의 peak 점과 양 끝 중에서 peak에서 더 먼쪽의 값 2개를 선으로 그어 본 후

그 선과 그래프간 가장 먼 지점의 밝기를 threshold로 결정하는 방법입니다.

이처럼 THRESH_OTSU와 THRESH_TRIANGLE을 사용할 경우 threshold를 자동으로

설정하기 때문에 전체 밝기 값이 약간씩 바뀔 수 있는 경우(분포는 안바뀌고)에

유용하게 사용될 수 있는 방법입니다.

저는 THRESH_BINARY THRESH_OTSU를 가장 많이 사용하는 것 같습니다.

저는 THRESH_OTSU에서 얻은 thresh 값을 THRESH_BINARY에 한번 넣어 봤습니다.

아래 영상에서는 th 값이 97 값이 나오고 th 값을 그대로 넣으시면 똑같은 결과가 나오기 때문에 그것보다 좀 아래 값을 입력으로 넣어서 binarization을 해 봤습니다.

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

int main()
{
    cv::Mat src = cv::imread("sudoku.jpg", cv::IMREAD_GRAYSCALE);
    cv::Mat binImage1, binImage2;
    
    double th = cv::threshold(src, binImage1, 150, 255, cv::THRESH_OTSU);
    cv::threshold(src, binImage2, (th - 10), 255, cv::THRESH_BINARY);

    return 0;
}
 

결과 영상은 아래와 같습니다.

OTSU의 강점은 바로 아래와 같은 영상에서 발휘됩니다.

소스를 아래와 같이 작성후 결과를 내어 봤습니다.

cv::threshold(src, binImage1, 0, 255, cv::THRESH_OTSU);    
cv::threshold(src, binImage2, 120, 255, cv::THRESH_BINARY);
cv::threshold(src2, binImage3, 0, 255, cv::THRESH_OTSU);
cv::threshold(src2, binImage4, 120, 255, cv::THRESH_BINARY);
 

sudoku 영상 같이 한 영상 내에서 밝기 분포가 균일하지 않을 경우에는 어떻게 할까요?

이런 경우를 위해 adaptive threshold라는 기법이 있습니다.

이것은 다음에 다뤄보기로 해요.

https://blog.naver.com/dorergiverny/223059856814

 

[OpenCV][C++] Thresholding 이진화 영상 만들기 총정리(2) - adaptiveThreshold() image binarize trackbar gaussian

지난 번에는 일반적인 이진화 방법(binarization)에 대해 알아 보았습니다. 영상 내 밝기가 균일한 경우 적...

blog.naver.com