영역 분할 및 추출 (Image Segmentation)
개요 및 목적
- 영상 전체를 픽셀 수준에서 분석하여 서로 다른 의미를 가지는 영역들로 나누는 과정.
- 영상 전체를 의미 있는 영역 단위로 쪼개어, 이후 처리의 정확성과 효율을 높이기 위한 핵심 전처리 단계.
- 불필요한 배경/노이즈를 제거하고 의미 있는 영역(전경)만 남겨 분석 대상을 단순화 할 수 있다.
종류 및 방법
- 픽셀 값 기반(Thresholding)
- Global/Local Thresholding 등 (2. 영상 이진화)
- 경계 기반(Boundary-based)
- Canny Edge + coutour 추출 등 (5-2. 엣지 검출 필터)
- 영역 기반(Region-based)
- Region Growing, Watershed 알고리즘 등
- 클러스터링 기반
- K-means Clustering, Mean-shift Segmentation 등 (K-Means)
- 딥러닝 기반
- FCN, U-Net, Deeplab 등
Watershed 방법
개요
- 영상처리에서 대표적인 영역 기반 분할 (Region-based Segmentation) 방법 중 하나로, 영상을 지형(terrain)으로 해석하여 픽셀 값을 고도로 보고 낮은 값은 계곡, 높은 값은 산봉우리로 간주함.
- 물을 계곡에서부터 흘려보내며 서로 만나는 경계를 경계선으로 사용하여 영역 분할하는 아이디어.
- 경계가 모호한 경우에도 정확한 경계 추출이 가능하나, 노이즈에 민감하여 지나치게 많이 분할되는 문제가 발생함.
- 이러한 문제를 해결하기 위해 전처리(스무딩, Morphology) 또는 Marker 기반 Watershed 방법을 사용한다.


방법
- 지역 최소값(Local minima) 찾기
- 영상에서 픽셀 값이 낮은 지점을 “계곡의 바닥”으로 간주 (그레이스케일)
- 이 지점들이 초기 마커(seed) 역할을 함
- 침수 시뮬레이션(Flooding)
- 물을 아주 천천히 올린다고 가정 (픽셀 값 기준으로 높이 증가)
- 각 최소값에서 시작된 물줄기가 주변 픽셀로 확장됨
- 영역 라벨링(Label propagation)
- 확장되는 물줄기(영역)는 각각 고유한 라벨을 가짐
- 인접 픽셀은 아직 물에 잠기지 않았다면 가장 가까운 영역의 라벨을 받음
- 경계 결정(When waters meet)
- 서로 다른 영역의 물줄기가 동시에 한 픽셀에 도달하면, 그 픽셀은 어떤 영역에도 속하지 않고 경계선(Watershed line) 으로 지정됨
- 결과
- 이미지가 여러 개의 catchment basin(집수 분지)으로 분할됨
- 경계선이 객체의 구분선 역할을 함

OpenCV 응용
1. 입력 이미지 전처리
- 입력 이미지를 이진화(thresholding)를 통해 바이너리 이미지로 변환.
| 입력 이미지 | 바이너리 이미지 |
|---|---|
![]() | ![]() |
import cv2 as cv
# 이미지 불러오기
img = cv.imread('coins.png')
# 그레이스케일 변환
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 이진화
ret, thresh = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU)2. 모폴로지를 통한 노이즈 제거 및 전경/배경 구분
- 바이너리 영상에서 작은 점이나 구멍을 제거하기 위해 모폴로지
Opening또는Closing을 통해 노이즈 제거. - 모폴로지
Dilation를 통해 확실한 배경 영역을 찾고,distanceTransform을 통해 확실한 전경 영역을 찾는다. - 배경 영역과 전경 영역의 차이를 불확실한 영역이라 정의함.

# 노이즈 제거
kernel = np.ones((3,3),np.uint8)
opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel, iterations = 2)
# 확실한 배경 영역
sure_bg = cv.dilate(opening,kernel,iterations=3)
# 확실한 전경 영역
dist_transform = cv.distanceTransform(opening,cv.DIST_L2,5)
ret, sure_fg = cv.threshold(dist_transform,0.7*dist_transform.max(),255,0)
# 불확실한 영역 (가장자리)
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg,sure_fg)Distance Transform
- 이진 이미지(Binary Image)를 입력으로 받아, 배경(0) 과 전경(255) 을 기준으로 전경 픽셀에서 가장 가까운 배경 픽셀까지의 거리를 계산하는 변환.
- 전경 내부에서 중심에 가까울수록 값이 크고, 경계선 근처일수록 값이 작아진다.
cv2.distanceTransform(src, distanceType, maskSize)
# - src : 입력 이진 영상
# - distanceType : 거리 계산 방식
# - cv2.DIST_L1
# - cv2.DIST_L2
# - cv2.DIST_C
# - maskSize : 거리 계산 시 사용하는 마스크 크기(3, 5 또는 c2.DIST_MASK_PRECISE)- 결과 영상은
float32형태로, 전경 픽셀에서 가장 가까운 배경 픽셀까지의 거리 값.
3. Marker 생성
connectedComponents를 이용해 확실한 전경 이미지를 배경을 0으로 레이블하고, 다른 객체는 1부터 시작하는 정수로 레이블을 지정한다.watershed알고리즘에서는 미확인 영역을 0으로 간주하므로 배경은 1, 객체는 2이상의 값들로 변환하고, 불확실한 영역을 0으로 설정한다.
# Marker 라벨링
ret, markers = cv2.connectedComponents(sure_fg)
# 라벨 값 보정: 배경은 1, 객체는 2 이상
markers = markers + 1
markers[unknown == 255] = 03. Watershed 적용
watershed에 이미지와 마커 정보 전달 및 수행. (경계는 -1)

# Watershed 실행
markers = cv2.watershed(img, markers)
img[markers == -1] = [0, 0, 255] # 경계 표시 (빨간색)Grapcut 방법
참고
- OpenCV: Image Segmentation with Watershed Algorithm
- OpenCV: Interactive Foreground Extraction using GrabCut Algorithm
- OpenCV: Image Segmentation with Distance Transform and Watershed Algorithm
- [Part Ⅶ. Semantic Segment.. : 네이버블로그
- [6] 영상분할(Segmentation, 영상기반 처리기법) :: 공대남독
- [OpenCV][C++] 영상 분할 image.. : 네이버블로그

