Python과 OpenCV – 28 : Watershed 알고리즘을 이용한 이미지 분할

이 글의 원문은 https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_watershed/py_watershed.html 입니다.

회색조 이미지는 지형처럼 해석할 수 있는데, 값이 높은 픽셀 위치는 산꼭대기이고 값이 낮은 픽셀 위치는 계곡이라고 해석할 수 있습니다. 지형이므로 고립되어 분리된 계곡이 있을 것이고 이 계곡들을 서로 다른 색의 물로 채우기 시작하면 물이 점점 차오르다가 이웃한 계곡의 언저리에서 물이 합쳐지게 됩니다. 물이 합쳐지는 것을 피하기 위해서 합쳐지는 순간에서의 위치에 경계를 생성하는거죠. 그럼 이 경계선이 이미지 분할의 결과가 됩니다. 이것이 바로 Watershed 알고리즘의 기본철학입니다. 아래의 동영상 이미지를 보면 좀더 직관적으로 이해할 수 있습니다.

이 방식을 통해 이미지를 분할하게 되면 분할에 오류가 발생할 수 있는데, 이는 이미지의 잡음이나 어떤 불규칙한 것들로 인한 요소 등이 이유입니다. 그래서 OpenCV는 마커 기반의 Watershed 알고리즘을 구현해 제공하는데.. 각 계곡을 구성하는 화소들을 병합시켜 번호를 매기고, 병합 수 없는 애매한 화소는 0값을 매깁니다. 이를 인터렉티브한 이미지 분할 기법이라고 합니다. 우리가 알고 있는 객체에 각각에 대해 0 이상의 번호를 매기는 것인데요. 전경이 되거나 객체인 것에, 또 배경에도 0 이상의 값을 매깁니다. 그러나 그외 불명확하다라고 판단되는 것은 0을 매깁니다. 이 불명확한 것이 어떤 요소, 즉 배경인지 전경인지 또는 어떤 객체의 소유인지는 Watershed 알고리즘을 통해 결정됩니다. Watershed 알고리즘을 통해 분할 경계선이 생길 것이고 이 경계선에 대해서는 -1 값을 매깁니다.

자, 이제 이론에 대한 설명은 끝났으므로 예제 코드를 살펴보겠습니다.

실행 결과는 다음과 같습니다.

코드와 실행 결과를 비교해 가며, 설명을 해 보면.. 먼저 5번 코드에서 입력 이미지를 파일로부터 읽고 이 이미지를 2진 이미지로 생성하는 것이 5-9번 코드이고 결과 이미지의 Binary입니다. 잡음을 제거 하기 위해 12-13번 코드가 실행되고 결과 이미지의 Opening입니다. 잡음을 제거한 이미지에 dilate 함수를 통해 이미지의 객체를 확장시킨 것이 16번 코드이고 결과 이미지의 Sure_BG입니다. 이제 확실한 전경 또는 객체에 대한 화소를 얻기 위해 18-22번 코드가 실행되고 그 결과 이미지는 Sure_FG입니다. Sure_FG는 결과 이미지의 Distance 이미지로부터 threshold 처리를 통해 얻어진 것입니다. 이제 배경인 Sure_BG에서 전경인 Sure_FG를 빼면 애매모호한 영역을 얻을 수 있게 되는데, 25번 코드가 이에 해당되고 그 결과 이미지는 Unknonw입니다. 즉 어떤 문제를 해결하기 위해 문제의 범위를 좁혀 나가고 있다는 것을 직감할 수 있습니다. 이제 마커 이미지를 sure_fg를 이용해 생성하는데 28-30번 코드입니다. 머커는 0값부터 지정되므로 결과 마커에 1씩 증감시키고, 애매모호한 부분에 대해서는 0 값을 지정합니다. 앞서 이론에 언급했던 것처럼요. 마커가 준비되었으므로, 이제 Watershed 알고리즘을 적용하고 분할 경계선에 해당되는 화소에 지정된 값인 -1을 가지는 부분을 [255,0,0] 색상으로 지정하는 것이 33-34번 코드이며, 최종 결과 이미지인 Result입니다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다