Opencv Image Processing

Opencv - Watershed 알고리즘 이용한 이미지 분할

KimTory 2021. 11. 25. 11:51

소스 코드 및 이미지  출처 - https://docs.opencv.org/4.0.1/d3/db4/tutorial_py_watershed.html

 

OpenCV: Image Segmentation with Watershed Algorithm

Goal In this chapter, We will learn to use marker-based image segmentation using watershed algorithm We will see: cv.watershed() Theory Any grayscale image can be viewed as a topographic surface where high intensity denotes peaks and hills while low intens

docs.opencv.org


[ CODE ]

 

import cv2
import numpy as np
from matplotlib import image, pyplot as plt


# img = cv2.imread('images/watershed.jpg')
img = cv2.imread('coins.jpg')

# binaray image로 변환
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

# bin image
# cv2.imshow("threshold", thresh)

#Morphology의 opening, closing을 통해서 노이즈나 Hole제거
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel,iterations=3)

# dilate를 통해서 확실한 Backgroud (침식)
sure_bg = cv2.dilate(opening,kernel,iterations=3)
# cv2.imshow("sure_bg", sure_bg)


#distance transform을 적용하면 중심으로 부터 Skeleton Image를 얻을 수 있음.
# 즉, 중심으로 부터 점점 옅어져 가는 영상.
# 그 결과에 thresh를 이용하여 확실한 FG를 파악
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)

# 정규화
dist_transform = cv2.normalize(dist_transform, None, 255, 0, cv2.NORM_MINMAX, cv2.CV_8UC1)
ret, sure_fg = cv2.threshold(dist_transform, 0.5*dist_transform.max(),255,0)

sure_fg = np.uint8(sure_fg)
# cv2.imshow("sure_fg", sure_fg)

# Background에서 Foregrand를 제외한 영역을 Unknow영역으로 파악
# background - foreground = unknown
unknown = cv2.subtract(sure_bg, sure_fg)


# FG에 Labelling작업
ret, markers = cv2.connectedComponents(sure_fg)
markers = markers + 1
markers[unknown == 255] = 0

# watershed를 적용하고 경계 영역에 색지정
# watershed 알고리즘 적용 후, 동전 외곽은 -1의 라벨 값을 가짐       
# 배경은 1값을 가짐
markers = cv2.watershed(img,markers)
img[markers == -1] = [255,0,0] # 동전 외곽의 값은 -1을 라벨 번호를 가짐
img[markers == 1] = [0,0,255] # 동전이 아닌 배경 부분은 Red로 덮음

cv2.imshow("image", img)

images = [gray, thresh, sure_bg,  dist_transform, sure_fg, unknown, markers, img]
titles = ['Gray','Binary','Sure BG','Distance','Sure FG','Unknow','Markers','Result']

for i in range(len(images)):
    plt.subplot(2,4,i+1),plt.imshow(images[i]),plt.title(titles[i]),plt.xticks([]),plt.yticks([])

plt.show()


# distanceTransform 알고리즘은 바이너리 이미지에서
# 0값 즉, 배경에서 픽셀값이 떨어진 만큼 밝기가 변경됨

 

[ Result ]