IDL/Programming

격자점들의 다각형 내부/외부 판별 (Grids inside Polygon) (Part 2)

이상우_idl 2019. 10. 31. 15:35
728x90
반응형

* 지난 회차 게시물의 내용에서 바로 이어집니다.


지난 회 게시물에서는 다각형 내부의 격자점들을 POLYFILLV 함수를 사용하여 판별하고 그 결과를 표출하는 과정을 살펴보았습니다. 이어지는 내용으로서 오늘은 동일한 데이터에 대하여 IDLanROI 객체를 이용하여 판별하는 방법에 관하여 살펴보겠습니다. 우선 예제 2차원 데이터를 이미지 형태로 표출하고 원형 다각형을 그 위에 중첩하여 표출하는 과정은 다음과 같습니다. 이 결과로 표출되는 그림은 이미 지난 회에서 봤기 때문에 여기서 굳이 다시 첨부하지는 않습니다.


dxsz = 50

dysz = 50

img = HANNING(dxsz, dysz)*10

xrn = [0, dxsz]

yrn = [0, dysz]

win = WINDOW(DIMENSIONS=[600, 600], /NO_TOOLBAR)

im = IMAGE(img, XRANGE=xrn, YRANGE=yrn, RGB_TABLE=67, AXIS_STYLE=2, $

  MARGIN=0.1, /CURRENT)

theta = [0:360:10.]

xpts = COS(theta*!dtor)*15+19

ypts = SIN(theta*!dtor)*15+28

plg = POLYGON(xpts, ypts, COLOR='blue', FILL_BACKGROUND=0, THICK=2, /DATA)


그러면 IDLanROI 객체를 활용하여 다각형 내부 격자들을 판별하는 과정을 살펴봅시다. IDLanROI 객체는 얼마전에 다른 게시물에서 포인트들에 대하여 다각형 내부/외부 여부를 판별하는 방법에 관하여 소개할 때 이미 언급이 되었는데, 그 내용에서도 사용 문법 자체는 꽤 간단한 편이었습니다. 이번에도 마찬가지입니다. 이 과정은 다음과 같습니다.


oROI = OBJ_NEW('IDLanROI', xpts, ypts)

roi_mask = oROI -> ComputeMask(DIMENSIONS=[dxsz, dysz], MASK_RULE=1)

HELP, roi_mask

PRINT, MIN(roi_mask), MAX(roi_mask)


이와 같이 다각형을 구성하는 꼭지점들의 X 좌표값들로 구성된 xpts 및 Y 좌표값들로 구성된 ypts를 인수로 투입하여 IDLanROI 클래스의 객체를 oROI라는 이름으로 먼저 생성합니다. 그 다음에는 oROI 객체에 대하여 ComputeMask 메서드를 적용하여 roi_mask라는 이름의 마스킹 결과 데이터를 얻게 됩니다. 이 때 ComputeMask 메서드의 DIMENSIONS 키워드에 대해서는 원래 2차원 데이터의 X 및 Y 방향 크기인 dxsz, dysz 값들을 부여해야 합니다. 또한 MASK_RULE 키워드에 대하여 1이란 값이 부여된 것을 볼 수 있는데, 이와 관련해서는 뒤에서 다시 언급하겠습니다. 어쨌든 이렇게 얻어진 roi_mask는 원래 2차원 데이터인 img와 배열 구조가 동일합니다. 다만 마스킹된 결과이기 때문에, 내부적으로는 다각형 내부로 판별된 부분과 그렇지 않은 부분의 격자값이 서로 다릅니다. HELP 및 PRINT로 출력된 결과를 보면 다음과 같습니다.


ROI_MASK        BYTE      = Array[50, 50]

   0 255


실제로 roi_mask 배열에서는 다각형 내부로 판별된 격자들에 대한 격자값은 255가 되고 외부로 판별된 격자들에 대한 격자값은 0이 됩니다. 즉 roi_mask 배열을 구성하는 값들은 0 아니면 255입니다. 우선 이 결과를 다음과 같이 표출해 봅시다.


win_mask = WINDOW(DIMENSIONS=[600, 600], /NO_TOOLBAR)

im_mask = IMAGE(roi_mask, XRANGE=xrn, YRANGE=yrn, RGB_TABLE=0, AXIS_STYLE=2, $

  MARGIN=0.1, /CURRENT)

plg = POLYGON(xpts, ypts, COLOR='crimson', FILL_BACKGROUND=0, THICK=2, /DATA)


표출된 모습은 다음 그림과 같습니다.



원형 다각형의 형태와 비교해보면 어떤 식으로 판별이 되었는지 알 수 있습니다. 그리고 지난번과 마찬가지로 이 결과도 다음과 같은 방식으로 원본 2차원 데이터의 모습을 함께 볼 수 있도록 표출하는 것이 더 좋을 것 같습니다.


win = WINDOW(DIMENSIONS=[600, 600], /NO_TOOLBAR)

im0 = IMAGE(img, XRANGE=xrn, YRANGE=yrn, RGB_TABLE=67, AXIS_STYLE=2, $

  MARGIN=0.1, /CURRENT)

im = IMAGE(roi_mask, RGB_TABLE=0, TRANSPARENCY=50, /OVERPLOT)

plg = POLYGON(xpts, ypts, COLOR='blue', FILL_BACKGROUND=0, /DATA)

tx = TEXT(0.5, 0.92, 'Masked with IDLanROI', FONT_SIZE=16, $

  ALIGNMENT=0.5, /NORMAL)


그 결과는 다음 그림과 같습니다.



그런데 지난 회에서 POLYFILLV 함수를 이용한 방법으로 얻은 결과와 비교해보면 이번에 IDLanROI 객체를 이용한 방법으로 얻은 결과는 서로 좀 다른 것을 알 수 있습니다. 그 이유는 POLYFILLV 함수에서 사용되는 판별 알고리즘과 IDLanROI의 ComputeMask 메서드에서 사용되는 판별 알고리즘이 서로 다르기 때문입니다. 각각의 알고리즘에 대한 세부적인 내용에 대해서는 제가 여기서는 언급하지 않겠습니다. 각각에 대한 IDL 도움말의 내용을 참조하시기 바랍니다. 어떻게 보면 IDLanROI 객체를 이용하여 얻은 결과가 좀 더 그럴듯해 보이기도 합니다만, 최종 판단은 분석의 당사자가 해야 할 것 같습니다.


그리고 앞서 언급했던 MASK_RULE 키워드에 관하여 좀 더 살펴보겠습니다. 앞에서는 이 속성의 값을 1로 설정했었는데, 만약 이 속성의 값만 1 대신 2로 변경하여 결과를 다시 얻어보면 그 모습은 다음 그림과 같습니다.



이와 같이 판별된 영역이 더 커진 것을 볼 수 있는데요. IDL 도움말에서 IDLanROI 객체의 ComputeMask 메서드의 MASK_RULE 키워드에관한 내용을 살펴보면 다음과 같습니다.


MASK_RULE

Set this keyword to an integer specifying the rule used to determine whether a given pixel should be set within the mask. Valid values include:

  • 0 = Boundary only. All pixels falling on a region’s boundary are set.
  • 1 = Interior only. All pixels falling within the region’s boundary, but not on the boundary, are set.
  • 2 = Boundary + Interior. All pixels falling on or within a region’s boundary are set. This is the default.


이 내용을 보면 MASK_RULE 키워드에 부여되는 값에 따라서 마스크 결과를 어떻게 산출하는지에 대하여 알 수 있습니다. 우리가 처음에는 이 값을 1로 설정했었는데, 그 경우에는 'Interior only' 즉 내부에 해당되는 격자들만 판별하게 됩니다. 하지만 2로 설정할 경우에는 내부 뿐아니라 경계선(Boundary)에 해당되는 격자들까지 모두 포함하게 되고, 0으로 설정할 경우에는 경계선 자체에 해당되는 격자들만 판별하게된다는 의미입니다. 실제로 이 값을 0으로 설정하여 다시 결과를 얻어보면 다음 그림과 같습니다.



따라서 이러한 결과들을 보면 MASK_RULE 키워드의 역할이 어떤 것인지 알 수 있습니다. 또한 이와 같이 마스킹의 세부적인 방법을 차별적으로 적용하는 기능은 POLYFILLV 함수에서는 지원되지 않습니다. 그렇기 때문에 제가 보기에는 POLYFILLV 함수를 사용하는 방법보다는 IDLanROI 객체의 ComputeMask 메서드를 활용하는 것이 더 낫지 않겠나 생각도 듭니다. 만약 내부로 판별된 화소들의 갯수를 구하여 격자 단위의 내부 면적을 산출하고자 한다면 다음과 같이 WHERE 함수를 이용하면 됩니다.


ww = WHERE(roi_mask EQ 255, count)

PRINT, count


MASK_RULE 키워드 값을 1로 설정하여 결과를 얻은 상태에서 이 값을 산출해 보면 649가 나옵니다. 즉 원형 다각형 내부에 있는 것으로 판별된 격자들의 갯수가 649개라는 뜻입니다. 또한 원본 2차원 데이터의 값들 중에서 다각형 내부에 있는 것으로 판별된 격자들에 대한 데이터 값들에 대해서 평균값을 산출하려면 위에서 얻은 결과를 다음과 같이 이용하면 됩니다.


PRINT, MEAN(img[ww])


어쨌든 IDLanROI 객체 및 ComputeMask 메서드를 이용하여 다각형 내부에 포함되는 격자들을 판별하는 작업을 이와 같은 방식으로 수행할 수 있습니다. 그리고 앞서 잠시 언급했듯이, POLYFILLV 함수를 이용하여 얻은 결과와 IDLanROI 객체를 이용하여 얻은 결과가 서로 좀 다른 것을 볼 수 있었는데요. 사실 2차원 데이터의 격자 구조가 좀 더 촘촘할 경우에는 두 방법 사이의 차이는 상당히 줄어들게 됩니다. 만약 2차원 데이터의 격자 구조가 더 촘촘할 경우를 가정하여 다음과 같이 50x50 대신 500x500의 형태로 대체해보면 어떻게 될까요?


dxsz = 500

dysz = 500

img = HANNING(dxsz, dysz)*10

theta = [0:360:10.]

xpts = COS(theta*!dtor)*150+190

ypts = SIN(theta*!dtor)*150+280


2차원 데이터 및 다각형 꼭지점 데이터를 이와 같이 대체한 다음 나머지 과정들을 그대로 진행하여 얻은 두 종류의 결과를 서로 비교해보면 다음과 같습니다.



두 그림을 서로 비교해보면 그렇게까지 큰 차이가 느껴지지는 않습니다. 물론 아주 세세하게 따진다면 아주 미세한 차이는 물론 존재할 것이고, 이러한 차이가 얼마나 중요한 문제가 될 수 있는가는 작업의 성격에 따라 좌우될 것입니다. 사실 제가 처음에 50x50의 구조를 갖는 2차원 배열을 사용했던 것은 두 방법 사이의 미묘한 차이를 극대화하여 제시하기 위해서였던 것이고, 우리가 실제로 접하는 실전 데이터에 대한 결과에서는 두 방법 사이의 차이는 크게 느껴지지 않을 것 같다는 것이 제 생각입니다. 그리고 앞서 언급했듯이 IDLanROI 객체를 사용하는 방법이 여러모로 활용의 폭이 좀 더 넓다는 장점은 있지만, 선택은 결국 분석 당사자의 몫이라고 보면 될 것 같습니다.


지금까지 2회에 걸쳐서 다각형의 내부의 격자점들을 판별하는 방법을 소개해드렸습니다. 다각형의 형태는 예제로서 제가 원(Circle)을 사용했지만, 어떤 형태가 되든 그 다각형을 구성하는 꼭지점 데이터를 확보할 수만 있다면 얼마든지 확대 응용이 가능합니다. 예를 들어, 사각형, 타원형, 다이아몬드형, 자유형 등의 다른 도형이 될 수도 있고, 어떤 국가 또는 행정구역의 경계선 데이터가 될 수도 있을 것입니다. 따라서 여러분의 실제 데이터 처리 작업에서도 이러한 방법을 응용해보시면 좋을 것 같습니다.

반응형