유역 알고리즘 소개

이전에는 Object Detection 알고리즘을 연구했으며 물체의 검출된 좌표, 회전 및 치수를 만듭니다. 이 프로젝트는 유역에 관한 것입니다. 기본적으로 Watershed 알고리즘은 이미지에서 다른 객체를 분리하는 데 사용됩니다. 이 알고리즘을 적용한 후 개체의 영역과 가장자리를 결정하기 위해 일부 저역 통과 필터링 및 형태학적 작업을 적용해야 합니다.

Watershed Algoritm에서는 다음 기술을 적용합니다.



1- 중앙값 흐림
2- 그레이 스케일
3- 이진 임계값
4- 열기
5- 거리 변환
6- 전경의 임계값
7- 배경에 사용할 이미지 확대를 위한 팽창
8- 연결된 구성 요소
9- 유역
10- 개체 주변의 윤곽 찾기 및 그리기

코드 셀을 설명할 때 이 주제를 다시 설명하겠습니다.

우선 내가 사용할 라이브러리를 가져와야 합니다.

import cv2
import numpy as np
import matplotlib.pyplot as plt


그런 다음 Watershed를 적용하려는 이미지를 읽어야 합니다.

coin = cv2.imread("data/coins.jpg")

plt.figure(), plt.title("Original"), plt.imshow(coin), plt.axis("off");




그런데 plt.axis("off") 끝에 있는 세미콜론(;)은 matplotlib의 일부 입력을 입력하기 위한 트릭입니다.

이미지에 있는 노이즈를 제거하기 위해 MedianBlurring이라는 저역 통과 필터링 방법 중 하나를 적용합니다.

coin_blur = cv2.medianBlur(src=coin, ksize=13)

plt.figure(), plt.title("Low Pass Filtering (Blurring)"), plt.imshow(coin_blur), plt.axis("off");




그런 다음 이미지의 색상을 회색으로 변환해야 합니다.

coin_gray = cv2.cvtColor(coin_blur, cv2.COLOR_BGR2GRAY)

plt.figure(), plt.title("Gray Scale"), plt.imshow(coin_gray, cmap="gray"), plt.axis("off");




Binary Threshold를 사용하여 동전과 배경 사이에 특정 이미지를 만듭니다.

ret, coin_thres = cv2.threshold(src=coin_gray, thresh=75, maxval=255, type=cv2.THRESH_BINARY)

plt.figure(), plt.title("Binary Threshold"), plt.imshow(coin_thres, cmap="gray"), plt.axis("off");




Thresholding 후에 볼 수 있듯이 동전과 배경 사이가 거의 명확합니다.

이제 이 윤곽선을 그리려고 합니다.

contour, hierarchy = cv2.findContours(image=coin_thres.copy(), mode=cv2.RETR_CCOMP, method=cv2.CHAIN_APPROX_SIMPLE)

for i in range(len(contour)):

    if hierarchy[0][i][3] == -1: # external contour
        cv2.drawContours(image=coin,contours=contour,contourIdx=i, color=(0,255,0), thickness=10)

plt.figure(figsize=(7,7)), plt.title("After Contour"), plt.imshow(coin, cmap="gray"), 
plt.axis("off");




하지만 보시다시피 작동하지 않습니다. 가장자리를 분리할 수 없었습니다.

Watershed라는 다른 방법을 사용하여 가장자리를 분리하고 그립니다. 첫 번째 방법은 유역이 아닙니다.


유역 전에 이 모든 기술을 적용해야 합니다. 그에 대한:

# read data
coin = cv2.imread("data/coins.jpg")
plt.figure(), plt.title("Original"), plt.imshow(coin), plt.axis("off");

# Blurring
coin_blur = cv2.medianBlur(src=coin, ksize=15)
plt.figure(), plt.title("Low Pass Filtering (Blurring)"), plt.imshow(coin_blur), plt.axis("off");

# Gray Scale
coin_gray = cv2.cvtColor(coin_blur, cv2.COLOR_BGR2GRAY)
plt.figure(), plt.title("Gray Scale"), plt.imshow(coin_gray, cmap="gray"), plt.axis("off");

# Binary Threshold
ret, coin_thres = cv2.threshold(src=coin_gray, thresh=65, maxval=255, type=cv2.THRESH_BINARY)
plt.figure(), plt.title("Binary Threshold"), plt.imshow(coin_thres, cmap="gray"), 
plt.axis("off");







먼저 코인 간의 연결을 제거해야 합니다. 거의 모든 동전은 서로 연결되어 있으므로 형태학적 작업에서 열기를 사용하여 열겠습니다.

kernel = np.ones((3,3), np.uint8)

opening = cv2.morphologyEx(coin_thres, cv2.MORPH_OPEN, kernel=kernel, iterations=2)

plt.figure(), plt.title("Opening"), plt.imshow(opening, cmap="gray"), plt.axis("off");




동전 사이의 연결을 romevo하기 위해 거리 변환을 사용합니다.
그 후 물체(동전) 사이의 거리를 볼 수 있습니다.

dist_transform = cv2.distanceTransform(src=opening, distanceType=cv2.DIST_L2, maskSize=5)

plt.figure(), plt.title("Distance Transform"), plt.imshow(dist_transform, cmap="gray"), plt.axis("off");




거리를 찾은 후 전경에 있는 이미지를 찾기 위해 Threshold를 사용하여 최소화하겠습니다.

ret, sure_foreground = cv2.threshold(src=dist_transform, thresh=0.4*np.max(dist_transform), maxval=255, type=0)

plt.figure(), plt.title("Fore Ground"), plt.imshow(sure_foreground, cmap="gray"), plt.axis("off");




배경이 무엇인지 찾기 위해 Dilate를 사용하여 이미지를 확대합니다.

sure_background = cv2.dilate(src=opening, kernel=kernel, iterations=1) #int

sure_foreground = np.uint8(sure_foreground) # change its format to int


이제 이미지를 더 잘 이해할 수 있도록 서로를 Subtrack(BackGround - ForeGround)할 수 있습니다. 다음은 Open 및 Dilated 이미지의 결과입니다.

unknown = cv2.subtract(sure_background, sure_foreground)

plt.figure(), plt.title("BackGround - ForeGround = "), plt.imshow(unknown, cmap="gray"), plt.axis("off");




이 단계 후에 Watershed 알고리즘에 대한 입력을 제공하기 위한 마커를 찾아야 합니다. 이제 구성 요소 간의 연결을 제공하겠습니다.

ret, marker = cv2.connectedComponents(sure_foreground)

marker = marker + 1

marker[unknown == 255] = 0 # White area is turned into Black to find island for watershed

plt.figure(), plt.title("Connection"), plt.imshow(marker, cmap="gray"), plt.axis("off");




그 후, 이제 Watershed Algorithm을 적용하고 세분화를 할 수 있습니다.

marker = cv2.watershed(image=coin, markers=marker)

plt.figure(), plt.title("Watershed"), plt.imshow(marker, cmap="gray"), plt.axis("off");




마지막 단계로 코인 주변의 윤곽선을 찾아 그립니다.

contour, hierarchy = cv2.findContours(image=marker.copy(), mode=cv2.RETR_CCOMP, method=cv2.CHAIN_APPROX_SIMPLE)

for i in range(len(contour)):

    if hierarchy[0][i][3] == -1:
        cv2.drawContours(image=coin,contours=contour,contourIdx=i, color=(255,0,0), thickness=3)

plt.figure(figsize=(7,7)), plt.title("After Contour"), plt.imshow(coin, cmap="gray"), plt.axis("off");





여기에서 노트북을 찾을 수 있습니다: https://github.com/ierolsen/Object-Detection-with-OpenCV/blob/main/7-watershed.ipynb

개체 감지에 대한 다른 사항: https://github.com/ierolsen/Object-Detection-with-OpenCV

좋은 웹페이지 즐겨찾기