본문 바로가기
코딩/OpenCV

[C++ opencv] Thresholding 임계값 처리로 binary 이미지 만들기

by DIYver 2020. 6. 30.

본문 목표

영상처리에 있어서 제일 중요한 건 처리 속도이다.

 

여태 언급했던 노이즈 제거 및 grayscale 사용은 다 처리 속도 때문이었다.

 

처리속도가 빨라야 여러장을 처리할 수 있고,

 

여러장을 처리해야 정확도가 올라간다.

 

grayscale은 0~255 까지 값을 저장하는 8 bit 크기를 가지고 있는데,

 

이제 여기서 더 속도를 빠르게 하기 위해서는 2 bit 크기를 다뤄야 한다.

 

그게 바로 binary 이미지 이다.

 

회색의 이미지에 0~255 사이의 값을 기준으로해서

 

기준 값(임계 값) 이상은 1(white), 이하는 0 (black) 으로 처리하는 방법을 사용한다.

 

이렇게 binary 이미지로 만드는 작업을 '이진화' 라고 한다.

 

연산 처리를 빠르게 하고 정확하게 하기위해 사용하므로, 꼭 알아야 하는 부분이다.

 

 

 

 

 

 

 

키워드 :  binary, 이진화, thresholding, threshold, 임계값

 

 

 

 

 

알아볼 함수 원형

- 임계값 처리 ( Threshold )

...

Mat img = imread("Lenna.png", 0);
Mat img_threshold;

threshold(img, img_threshold, 125, 255, THRESH_BINARY);
    
...

threshold( src, dst, threshold_value, Max_value, threshold_type)

 

  ○ src : 입력할 이미지 변수 (grayscale 이미지를 입력해야함! )

 

  ○ dst : 필터가 적용되어 저장될 이미지 변수

 

  ○ threshold_value : 임계 값 (0~255), 이진화 시킬 기준 값을 입력

 

  ○ Max_value :  임계 값 이상의 픽셀들에  적용할 값,

     0 또는 Max_value 의 두 값으로만 이미지를 표현하게 됨, 보통 255 를 사용.

 

  ○ threshold_type : 이진화 하는 방법 

    ■ THRESH_BINARY  :  이진화, threshold 값 이상 : 1, 이하 : 0(black) 으로 처리
    ■ THRESH_BINARY_INV  :  역 이진화, threshold 값 이상 : 0 (black), 이하 : 1 로 처리
    ■ THRESH_MASK : 흑색 이미지로 변경
    ■ THRESH_OTSU : Otsu 알고리즘 사용
    ■ THRESH_TOZERO : threshold 값 이상: 원본값, 이하 : 0
    ■ THRESH_TOZERO_INV : threshold 값 이상 : 0, 이하 : 원본값
    ■ THRESH_TRIANGLE : Triangle 알고리즘 사용
    ■ THRESH_TRUNC : threshold 값 이상 : threshold 값, 이하 : 원본값

 

 

좀 더 보기 쉽게 정리하자면 아래와 같다.

 

방법

임계 값 이상

임계 값 이하

THRESH_BINARY

Max_value 

0

THRESH_BINARY_INV

0

Max_value 

THRESH_MASK 

   

THRESH_OTSU 

   

THRESH_TOZERO

원본 값

0

THRESH_TOZERO_INV 

0

원본 값

THRESH_TRIANGLE 

   

THRESH_TRUNC 

임계 값

원본 값

 

 

제일 많이 사용하는 방법은

 

THRESH_BINARY 또는 THRESH_BINARY_INV 이다.

 

THRESH_OTSU 방식도 많이 사용한다.

 

 

 

 

 

 

코드 테스트 결과

- CODE

#include <opencv2/opencv.hpp>


using namespace cv;
using namespace std;

int main(int ac, char** av) {
	Mat img = imread("Lenna.png", 0);	//이미지를 grayscale로 불러옴

	Mat img_threshold;

	threshold(img, img_threshold, 150, 255, THRESH_BINARY);

	imshow("original", img);
	imshow("threshold", img_threshold);
	waitKey(0);

	return 0;
}

 

- RESULT

원본 이미지

 

threshold 150 적용

위의 결과는 원본 이미지에 임계 값을 150으로 설정했을 때의 결과이다.

 

물론 원본에서 밝은 값이 흰색을 띄고 있으므로, 방법은 THRESH_BINARY 를 사용했음을 간접적으로 알 수 있다.

 

 

 

 

 

 

THRESH_BINARY 이외에도 다양한 방법을 사용한 결과를 확인해보자.

 

 

 

 

THRESH_BINARY_INV

확실히 THRESH_BINARY 의 결과에서 정반대의 결과임을 확인할 수 있다.

 

임계 값 이상의 밝은 부분이 0 (black) 으로 처리가 되었다.

 

 

 

 

THRESH_MASK

Thresh_mask 방법은 그냥 검은색 이미지를 만드는데 사용 되는 듯 하다.

 

threshold 값은 그냥 상관이 없다.

 

단지 검은색 이미지를 만들 뿐...

 

 

 

 

THRESH_OTSU

OTSU 알고리즘이 적용된 임계 값 검출 결과이다.

 

그냥 THRESH_BINARY 방식보다 더 깔끔한 이진 영상을 얻은 것 같은 느낌이다.

 

경계선 검출할 때, 더 적합한 알고리즘이 아닐까 싶다.

 

 

 

OTSU 알고리즘은 일본의 Otsu 라는 사람이 개발한 알고리즘이다.

 

히스토그램값을 적용하여 이미지를 분할하여 이진화 시켜주는 알고리즘이다.

 

단순히 임계 값으로 이진화 하는 것이 아니라는 뜻이다.

 

그래서 당연히 여기에 쓰이는 threshold 값은 결과에 아무런 영향이 없다.

 

쉽게 background 와 forward 를 구분할 때, 사용한다고 받아들이면 쉽다.

 

 

 

 

 

 

 

 

THRESH_TOZERO

앞 서 설명한 대로

 

threshold (임계 값) 이상에서는 원본 값을 나타내고 있으며,

 

임계 값 이하는 전부 0 으로 바뀌었다.

 

굳이 사용하는 방법은 아니다.

 

 

 

 

 

 

THRESH_TOZERO_INV

임계 값 이상은 0으로 바꾸고,

 

그 이하의 값들은 원본값을 띄게 하는 방식이다.

 

이 방법 역시 잘 사용하는 방법은 아니다.

 

분명 쓸데는 있겠지...

 

 

 

 

 

 

 

THRESH_TRIANGLE

이 방법은 TRIANGLE 알고리즘을 적용한 이진화 결과이다.

 

역시 알고리즘을 사용하는 경우로, 사용자가 아무리 threshold 값을 설정해주어도 결과가 변하지 않는다.

 

나도 이 알고리즘은 잘 모르겠다.

 

그냥 잘 안 쓰고, 나도 이번에 포스팅 하면서 처음 봤다.

 

 

 

 

 

 

 

 

THRESH_TRUNC

 

임계 값 이상 부분을 임계값으로 해주고,

 

임계 값 이하 부분은 원본값을 유지하게 하는 방식이다.

 

이 방식도 잘 사용하는 방식은 아니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

OpenCV 를 사용하다보니 헷갈리는 부분이 있는게,

 

Matlab 에서 영상처리를 다룰 때에는

원래 색 채널은 쉽게 말해서 Binary ( 2 bit) , grayscale ( 8 bit) , color ( 8 bit 3 channel) 이렇게 있다고 할 수 있는데,

 

연산을 할 때, 각 채널끼리만 연산이 된다.

 

근데 OpenCV는 2 bit가 따로 없다.

 

그러니깐 binary 이긴 binary 인데

 

그냥 grayscale 에서 값을 두개만 사용하는 것 같다.

 

이러면 연산처리할 때 좀,, 느려지지 않나 싶지만

 

요새 cpu가 워낙 빨라서 사람이 느낄 수 없을 정도인가... 싶기도 하고

 

 

 

 

 

 

아무튼 이러면 이해 되는게

 

THRESH_TOZERO 같은 방법은 잘 사용 안 하는데,

 

이게 유리할 때가 있을 수 있는게

 

만약 THRESH_BINARY 를 사용하게 되면

 

과정이 비교적 복잡하다고 할 수 있다.

 

임계 값과의 비교연산 이후에, 0 또는 max_value 로 값을 바꿔줘야 한다.

 

그런데 THRESH_TOZERO 는

 

임계 값과의 비교연산 이후에, 임계값 이하만 0으로 만들면 되므로

 

THRESH_BINARY 보다 간편해진다.

 

왜냐하면 임계값 이상은 max_value 로 바꿔줄 필요가 없이 원본 값을 유지하면 되기에

 

시간 이득이 생긴다.

 

 

 

즉, 굳이 0과 255 값만을 이용할 것이 아니라면

 

연산 시간에서 THRESH_TOZERO 같은 방식이 훨씬 유리할 수 있다는 것이다.

 

물론 연산 시간만 따져서는 안되고,

 

내가 어떤 결과물을 얻어야 하는지 충분한 이해가 된 다음에 고려해야 할 사항이므로

 

처음부터 심도있게 고민하지 않는게 좋다.

 

 

 

 

일단 쉽게 쉽게 만들고

 

연산 시간을 단축하는 과정에서 다른 알고리즘을 시도해볼까? 하는 도전을 하면 충분하다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

도움이 되었거나, 문제가 있는 경우 댓글로 알려주세요~!

감사의 댓글은 작성자에게 큰 힘이 됩니다 ^^

 

댓글