[컴퓨터 비전] 12 Image Segmentation

이찬영·2024년 2월 24일
0

컴퓨터 비전

목록 보기
11/20

[컴퓨터비전 STUDY / KOCW 한동대학교 황성수 교수님 강의 Review]

Introduction

Image/video segmentation이란, 여러 개의 영역으로 분할하는 과정을 일컫는 말이다.

Object classification에 유용하게 쓰일 수 있다.

다음 그림은, Image segmentation 전후 사진을 나타낸 것으로, Image segmentation 이전에는 0~255 사이의 다양한 값의 pixel들이 있지만, 이후에는 0, 255 두 개의 pixel로만 Image가 이루어져 있다.

따라서, 영역을 더 잘 구분할 수 있다는 장점이 있다.

Input : gray-scale image
Output : binary image (0, 255 또는 0, 1로만 이루어진다.)


Thresholding

Thresholding은 Image segmentation의 가장 기본적인 방법 중 하나이다.

Thresholding을 수행하기 위해 먼저 다음과 같은 가정 2가지를 할 수 있다.

  1. 배경과 물체의 Intensity는 다르다.
  2. 배경과 물체는 단조롭다.

다음은 하나의 물체와 하나의 배경만 존재하는 경우이다.
이 경우에는 segmentation이 한 번만 필요하기 때문에 임계값도 하나만 존재한다.
임계값을 기준으로 픽셀을 나누어서 적용할 수 있다.

다음은 하나의 물체와 2개의 배경이 존재하는 경우이다.
이 경우에는 위와 달리, segmentation이 두 번 필요하며, 임계값도 2개 존재한다.
역시 임계값을 기준으로 픽셀을 나누어서 적용할 수 있다.

따라서, 적절한 임계값(Threshold)을 찾는 것은 매우 중요하다.


하지만 Thresholding에는 2가지 문제가 있다.

  1. Noise (잡음)

잡음이 섞여 있으면, threshold를 구하기 어려워진다.

  1. 조도 및 반사율

조도 및 반사율에 따라서 threshold를 구할 수 있는 정도가 달라진다.


또한, Thresholding을 적용하기 전에 smoothing을 먼저 진행하면, 더 좋은 결과를 얻을 수 있다.

Thresholding에는 다음과 같이 2가지 방법이 있다.

  1. Global thresholding : 동일한 임계값을 전체 pixel에 적용함

  2. Local thresholding : 각 픽셀마다 임계값을 다르게 적용함


1. Global Thresholding

Global Thresholding은 동일한 임계값을 전체 pixel에 적용하는 방식이다.

기본 방법

  1. 임의로 하나의 threshold T를 설정한다.

  2. T를 이용해 이미지를 두 개의 그룹으로 나눈다.

  3. 각각의 영역 평균 m1, m2를 계산한다.

  4. 새로운 임계값 T = 0.5 x (m1 + m2)를 정한다.

  5. 새로운 임계값 - 원래 임계값 차이가 크면 작아질 때까지 2~4 과정을 반복한다.


Otsu's method

개념

  • 임계값이 잘 설정된 클래스들은 픽셀의 Intensity가 잘 구별되어야 한다.

  • threshold가 굉장히 잘 설정되면, 두 영역 간 밝기 차이가 최대가 된다.

  • thresholding이 잘 이루어졌냐를 Histogram을 사용하여 판단할 수 있다.

방법

  1. normalized histogram을 계산한다.

  2. 각각의 threshold k에 대해, 변화량 𝜎^2B를 구한다.

  3. 변화량 𝜎^2B가 가장 큰 지점에서 threshold를 가장 잘 선택할 수 있다.

아래는 위의 그림에서 thresholding을 진행한 결과이다.

아래에서 왼쪽은 임의로 Thresholding이 적용된 것이고, 오른쪽은 Otsu's method를 적용한 것이다.

Otsu's method가 더 thresholding이 잘 된 것을 확인할 수 있다.

Global Thresholding 기본 방법 코드는 다음과 같다.

 int main() {
 	Mat image, thresh;
 	int thresh_T, low_cnt, high_cnt, low_sum, high_sum, i, j, th;
 
 	thresh_T= 200;		# 초기 임계값
 	th= 10;				# 허용 오차
 	low_cnt= high_cnt= low_sum= high_sum= 0;
 
 	image = imread("lena.png", 0);		# 이미지를 grayscale로 읽음
 	cout<< "threshold value:" << thresh_T<< endl;		
 
 	while (1) {
 		for (j = 0; j < image.rows; j++) {
 			for (i= 0; i< image.cols; i++) {
 				if (image.at<uchar>(j, i) < thresh_T) {
 					low_sum+= image.at<uchar>(j, i);
 					low_cnt++;
 				}
 				else {
 					high_sum+= image.at<uchar>(j, i);
 					high_cnt++;
 				}
 			}
 		}
        
		# 새로운 임계값을 계산해 이전 임계값과 가까우면 루프를 종료하고, 
          그렇지 않으면 새로운 임계값으로 업데이트 함
        if (abs(thresh_T- (low_sum / low_cnt + high_sum / high_cnt) / 2.0f) < th) {
 			break;
 		}
 		else {
 			thresh_T = (low_sum / low_cnt + high_sum / high_cnt) / 2.0f;
 			cout << "threshold value:" << thresh_T << endl;
 			low_cnt = high_cnt = low_sum = high_sum = 0;
 		}
 	}
    # 최종적으로 결정된 임계값으로 원본 이미지를 이진화 (255는 이진화 최댓값)
 	threshold(image, thresh, thresh_T, 255, THRESH_BINARY);
 
 	imshow("Input image", image);
 	imshow("thresholding", thresh);
 	waitKey(0);
 }

결과는 다음과 같다.


다음은 Otsu's algorithm을 적용한 코드이다.

 int main() {
 	Mat image, result;
 	image = imread("lena.png", 0);	  # grayscale로 읽음
    # image에 이진화 처리 적용, 임계값 0, 최댓값 255, 임계값 방법
 	threshold(image, result, 0, 255, THRESH_BINARY | THRESH_OTSU);	
 	imshow("Input image", image);
 	imshow("result", result);
 	
    waitKey(0);
 }

결과는 다음과 같다.


2. Local(Adaptive) Thresholding

Local Thresholding은 각 픽셀마다 임계값을 다르게 적용하는 것으로, 주변 pixel들의 Intensity 분포에 따라 threshold를 정한다.

2가지 방법이 있다. (Opencv에서 둘 다 제공한다.)

ADAPTIVE_THRESH_MEAN_C :
𝑇(𝑥, 𝑦) = 𝑚𝑒𝑎𝑛 𝑜𝑓 𝑡ℎ𝑒 𝑏𝑙𝑜𝑐𝑘 𝑠𝑖𝑧𝑒 × 𝑏𝑙𝑜𝑐𝑘𝑠𝑖𝑧𝑒 𝑛𝑒𝑖𝑔ℎ𝑏𝑜𝑟ℎ𝑜𝑜𝑑 𝑜𝑓 (𝑥, 𝑦) - C

ADAPTIVE_THRESH_GAUSSIAN_C :
𝑇(𝑥, 𝑦) = 𝑎𝑤𝑒𝑖𝑔ℎ𝑡𝑒𝑑𝑠𝑢𝑚(𝑐𝑟𝑜𝑠𝑠 −𝑐𝑜𝑟𝑟𝑒𝑙𝑎𝑡𝑖𝑜𝑛 𝑤𝑖𝑡ℎ 𝑎 𝐺𝑎𝑢𝑠𝑠𝑖𝑎𝑛 𝑤𝑖𝑛𝑑𝑜𝑛𝑤) 𝑜𝑓 𝑡ℎ𝑒 𝑏𝑙𝑜𝑐𝑘𝑠𝑖𝑧𝑒 × 𝑏𝑙𝑜𝑐𝑘𝑠𝑖𝑧𝑒 𝑛𝑒𝑖𝑔ℎ𝑏𝑜𝑟ℎ𝑜𝑜𝑑 𝑜𝑓 (𝑥, 𝑦) - C

가장 오른쪽에 있는 것이 Local Thresholding을 적용한 것이며, 배경을 segmentation으로 인식하는 global Thresholding의 문제점을 해결할 수 있다.

Image partitioning을 다음과 같이 수행할 수 있다.

다음은 Local Thresholding을 수행하는 코드이다.

 int main() {
 	Mat image, binary, adaptive_binary;
 	image = imread("opencv.jpg", 0);
 	
    # 임계값은 150, 최대값으로 255 사용 / THRESH_BINARY 방법 사용 / 
      픽셀 값이 임계값보다 크면 픽셀 값을 최대값으로, 그렇지 않으면 0으로 설정
 	threshold(image, binary, 150, 255, THRESH_BINARY);
    # 결과를 adaptive_binary에 저장, 최대값 255, 이진화 방식은 THRESH_BINARY, 
      블록 크기 85, C값은 15
 	adaptiveThreshold(image, adaptive_binary, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 85, 15);
 	
    imshow("Input image", image);
 	imshow("binary", binary);
 	imshow("adaptive binary", adaptive_binary);
 	waitKey(0);
 }

가장 오른쪽에 있는 것이 Local Thresholding을 수행한 결과이다.

profile
자율주행, AI, 클라우드

0개의 댓글