IDL/Image Processing

영상 처리에서 ROI의 활용법 [4]

이상우_idl 2016. 8. 12. 16:19
728x90
반응형

오늘 소개할 내용은 제가 2013년 2월에 3회에 걸쳐서 올렸던 "영상 처리에서 ROI의 활용법"이라는 게시물의 연장선에 해당됩니다. 그 당시 소개했던 내용을 보면 이미지상에서 특정한 화소값에 대한 등위선을 구하고 이 영역을 ROI(Region of Interest)로 인식하여, 이 ROI에 대한 각종 정보들을 추출하는 방법까지 설명이 되어 있습니다. 이 게시물은 이 블로그의 Image Processing 카테고리에 있습니다.


사실 이 당시에는 ROI가 한 개만 탐지될 경우에 대한 예제 코드만 수록을 했었는데요. 실제로는 ROI가 한 개가 아닌 여러 개가 될 수도 있습니다. 물론 이러한 경우에도 처리 방법의 기본 흐름은 같습니다. 다만 ROI가 여러 개이기 때문에 문법적으로 그에 맞는 수정이 좀 필요합니다. 그래서 오늘은 이 방법에 관하여 소개를 해볼까 합니다. 먼저 오늘의 주제에 걸맞는 가상의 예제 데이터를 다음과 같이 만들고 표출해 봅시다. 그 모습은 다음 그림과 같습니다.


xgz = 600

ygz = 600

data1 = FLTARR(xgz, ygz)

data2 = FLTARR(xgz, ygz)

data3 = FLTARR(xgz, ygz)

data1[1:400, 1:400] = HANNING(400, 400)*10

data2[300:599, 300:599] = HANNING(300, 300)*12

data3[120:419, 300:599] = HANNING(300, 300)*9

data = TEMPORARY(data1) + TEMPORARY(data2) + TEMPORARY(data3)

HELP, data

PRINT, MIN(data), MAX(data)

sz = SIZE(data, /DIM)

WINDOW, XSIZE=sz[0], YSIZE=sz[1], RETAIN=2

TVSCL, data



이 이미지 데이터는 600X600의 격자 구조를 가지며, 최소값 0부터 최대값 12까지의 범위를 갖는 실수값들로 구성되어 있습니다. 그리고 그림에서 보이는 것처럼 국지적인 피크(Peak) 세 개가 보이는데,각 피크의 데이터값은 12, 10, 9가 되도록 하였습니다. 그래서 다음과 같이 CONTOUR 명령을 사용하여 데이터값이 8인 등위선을 중첩하여 그려보면 그 모습은 다음 그림과 같습니다.


CONTOUR, data, LEVEL=8.0, XMARGIN=[0, 0], YMARGIN=[0, 0], /NOERASE



예상했던 대로 세 개의 피크에 해당되는 부분들 주변으로 등위선들이 그려지는 것을 볼 수 있습니다. 그러면 지난 게시물에서 소개했던 것처럼 다음과 같이 CONTOUR 명령을 또 사용하여 이 등위선 영역들을 ROI로 추출합니다.


CONTOUR, data, LEVEL=8.0, XMARGIN=[0, 0], YMARGIN=[0, 0], $

  PATH_INFO=pathInfo, PATH_XY=pathXY, /PATH_DATA_COORDS

HELP, pathInfo

HELP, pathXY


기억을 되살리는 차원에서 다시 한번 언급해 본다면, 첫번째로 사용된 CONTOUR는 등위선을 화면상에 표출하기 위한 목적이고, 두번째로 사용된 CONTOUR는 그림을 전혀 그리지 않고 ROI를 추출하는 역할만을 합니다. 이렇게 얻어진 pathInfo, pathXY 항목에 대한 기본 정보를 HELP를 사용하여 출력해보면 다음과 같은 내용이 출력됩니다.


PATHINFO        STRUCT    = -> CONTOUR_PATH_STRUCTURE Array[3]

PATHXY          FLOAT     = Array[2, 1232]


여기서는 pathInfo가 배열이 되었다는 점을 주목해야 합니다. 따라서 이전 게시물에서처럼 pathInfo가 단일값 형태일 것으로 가정하고 이후의 작업을 다음과 같이 그대로 진행한다면 에러가 발생하게 됩니다.


line = [LINDGEN(PathInfo.N), 0]

oROI = OBJ_NEW('IDLanROI', $

  (pathXY[*, pathInfo.OFFSET + line])[0, *], $

  (pathXY[*, pathInfo.OFFSET + line])[1, *])

HELP, oROI


% Unable to concatenate variables because the dimensions do not agree: <INT      (       0)>.


따라서 pathInfo가 배열의 형태를 갖는 경우에도 문제가 발생하지 않도록 코드의 수정이 필요합니다. 이를 위해서는 pathInfo 배열의 각 원소값에 대하여 순차적으로 처리가 되도록 전체적으로 반복문의 형태로 구성하는 것이 필요합니다. 그래서 각 ROI마다 주요 정보들을 추출하여 출력하는 내용까지 담아서 다음과 같이 반복문 블록의 형태로 구성해 보았습니다.


nr = N_ELEMENTS(pathInfo)

FOR j = 0, nr-1 DO BEGIN

  line = [LINDGEN(PathInfo[j].N), 0]

  oROI = OBJ_NEW('IDLanROI', $

    (pathXY[*, pathInfo[j].OFFSET + line])[0, *], $

    (pathXY[*, pathInfo[j].OFFSET + line])[1, *])

  PRINT, 'ROI Index :', j

  HELP, oROI

  oROI -> GetProperty, N_VERTS=nvts

  PRINT, 'Number of Vertices :', nvts

  oROI -> GetProperty, ROI_XRANGE=rxr

  PRINT, 'X-direction Range :', rxr

  ROIStats = oROI -> ComputeGeometry(AREA=area, CENTROID=centroid)

  PRINT, 'Geometrical Area :', area

  PRINT, 'Center Coordinate :', centroid

  roi_mask = oROI -> ComputeMask(DIMENSIONS=sz)

  IMAGE_STATISTICS, data, MASK=roi_mask, COUNT=pixel_area, MEAN=roi_mean, STDDEV=roi_stddev

  PRINT, 'Pixel Area :', pixel_area

  PRINT, 'Mean Value :', roi_mean

  PRINT, 'Standard Deviation :', roi_stddev

  PRINT, ''

  XYOUTS, centroid[0], centroid[1], STRTRIM(STRING(j+1), 2), COLOR=0, CHARSIZE=2, /DATA

ENDFOR


실제로 출력된 내용은 다음과 같습니다.


ROI Index :       0

OROI            OBJREF    = <ObjHeapVar75(IDLANROI)>

Number of Vertices :         497

X-direction Range :       377.84045       508.77332

Geometrical Area :       11810.896

Center Coordinate :       446.03546       450.00000       0.0000000

Pixel Area :       12072

Mean Value :      9.78828

Standard Deviation :      1.17782


ROI Index :       1

OROI            OBJREF    = <ObjHeapVar77(IDLANROI)>

Number of Vertices :         477

X-direction Range :       141.96674       260.03323

Geometrical Area :       11049.698

Center Coordinate :       200.99999       200.99999       0.0000000

Pixel Area :       11301

Mean Value :      8.95026

Standard Deviation :     0.589302


ROI Index :       2

OROI            OBJREF    = <ObjHeapVar79(IDLANROI)>

Number of Vertices :         261

X-direction Range :       237.55116       302.60461

Geometrical Area :       3325.9313

Center Coordinate :       270.02056       450.00000       0.0000000

Pixel Area :        3450

Mean Value :      8.47413

Standard Deviation :     0.299097


이와 같이 총 3개의 ROI 각각에 대한 주요 정보들이 출력됩니다. 여기서 인덱스 0~2의 순서는 면적 내림차순입니다. 즉, 면적이 가장 큰 ROI가 앞 번호에 배정되고 가장 작은 ROI가 끝 번호로 배정되는 방식입니다. 출력된 각 정보들에 관한 개별적인 자세한 설명은 이전 게시물 중 2회차의 내용을 참조하시기 바랍니다. 그리고 위의 반복문이 실행되면 그림상에 다음과 같이 일련 번호가 매겨지도록 하였습니다.



이 작업을 위해서 centroid라는 이름으로 얻은 각 ROI의 중심점 좌표의 값을 XYOUTS 명령에 사용하였다는 점 참조하시기 바랍니다. 오늘은 이와 같이 ROI가 여러 개 탐지될 경우의 처리 방법을 구체적으로 소개해 보았습니다.

반응형