IDL/Mapping

대륙 또는 해양의 마스킹(Masking) [2]

이상우_IDL 2023. 2. 6. 16:37
728x90

지난 회차에 이어서 오늘은 2)에 관한 내용, 즉 지도상에 2차원 데이터를 중첩 표출하면서 대륙 부분에서만 데이터가 보이도록 처리하는 방법을 소개해보겠습니다. 지난 회 게시물에서 잠시 언급했듯이 그 반대의 경우인 1)은 구현 방법이 꽤 간단하지만 2)는 좀 복잡합니다. 1)의 경우는 지도와 2차원 데이터의 중첩 처리를 한 이후에 대륙경계선을 표시하기 위하여 MAPCONTINENTS 함수를 사용할 때 FILL_COLOR 속성을 사용함으로써 대륙 부분을 색상으로 채우는 방식의 처리만 하면 됩니다. 꽤 간단하죠.

 

그런데 2)의 경우는 그냥 단순하게 생각해보면 MAPCONTINENTS 함수에서 대륙 대신 해양을 색상으로 채우는 기능만 있으면 간단하지않을까하는 생각을 가져볼 수 있습니다. 그렇게만 된다면야 매우 쉽겠죠. 하지만 안타깝게도 그러한 기능은 지원되지 않습니다. 즉 MAPCONTINENTS 함수에서 색상으로 채울 수 있는 것은 대륙 부분만 가능하고 해양에 대해서는 그런 기능이 없습니다. 그렇기 때문에 해양 부분만 가리고 대륙 부분만 보이도록 하려면 뭔가 다른 우회적인 방법을 동원해야하는데 그 과정이 그리 간단하지는 않다는 것입니다. 어쨌든 그 방법을 오늘 소개해보도록 하겠습니다.

 

지도의 범위 및 가상 데이터 등은 지난 회차에서와 동일합니다. 먼저 다음과 같이 기본적인 지도만 먼저 표출되도록 합시다. 즉 2차원 데이터의 중첩 과정은 일단 미뤄둡니다.

 

lon = [115:145:0.1]
lat = [30:50:0.1]
data = HANNING(301, 201)*100
ct = COLORTABLE(74, /REVERSE)
minv = 0
maxv = 100
win = WINDOW(DIMENSIONS=[800, 600], /NO_TOOLBAR)
m = MAP('geographic', LIMIT=[30, 115, 50, 145], FILL_COLOR=[200, 200, 200], $
  MARGIN=0.1, /CURRENT)
mc = MAPCONTINENTS(/HIRES, FILL_COLOR=[100, 100, 100])
m.MapGrid.LINESTYLE = 6
m.MapGrid.HORIZON_LINESTYLE = 6
m.MapGrid.LABEL_SHOW = 0

 

여기서는 지도를 표출하면서 대륙과 해양을 각각 진한 회색과 연한 회색으로 처리하였습니다. 그리고 경위도 격자선이라든지 라벨 문자 등은 모두 보이지 않도록 하였습니다. 여기까지의 과정에 의하여 표출된 그림은 다음과 같습니다.

 

 

이제 핵심적인 작업이 진행되어야 하는데, 일단 그 내용은 다음과 같습니다.

 

cap = win.CopyWindow()
HELP, cap
ww = WHERE(cap EQ 200, count)
HELP, ww
PRINT, count
win.Erase

 

여기서는 먼저 CopyWindow 메서드를 사용하여 그래픽창을 캡쳐하고 그 내용을 cap이라는 배열로 담습니다. HELP에 의하여 출력된 내용을 보면 다음과 같습니다.

 

CAP             BYTE      = Array[3, 800, 600]

 

즉 cap은 그래픽창을 그대로 캡쳐한 이미지이며, 그래픽창의 크기와 동일한 RGB 이미지 데이터를 담은 배열이 됩니다. 그리고 바로 이어서 WHERE 함수를 사용하여 cap 배열 내에서 화소값이 200인 부분들을 찾아냅니다. 캡쳐된 이미지에서 화소값이 200인 부분은 바로 연한 회색으로 표시된 해양 영역이 됩니다. 즉 대륙과 해양을 서로 다른 색상으로 표출한 후 해양에 해당되는 영역의 화소들만 식별하는 과정이라고 보면 됩니다. 즉 WHERE 함수로 얻은 ww는 해양 화소들의 위치 정보가 됩니다. 이 과정이 끝나면 이 표출 그림은 Erase 메서드를 사용하여 바로 지워버립니다. 어차피 해양 영역의 식별을 위해서 임시로 표출했던 그림일 뿐 이것이 우리의 최종 목표는 아니기 때문입니다.

 

이제 이번에는 지도 및 2차원 데이터의 중첩 표출을 진행하되, 격자선 및 라벨 문자 등은 보이지 않도록 하겠습니다. 그 과정은 다음과 같습니다.

 

m = MAP('geographic', LIMIT=[30, 115, 50, 145], FILL_COLOR='blue', MARGIN=0.1, /CURRENT)
cn = CONTOUR(data, lon, lat, /FILL, GRID_UNITS=2, RGB_TABLE=ct, $
  MIN_VALUE= minv, MAX_VALUE=maxv, N_LEVELS=10, /OVERPLOT)
cno = CONTOUR(data, lon, lat, GRID_UNITS=2, N_LEVELS=10, COLOR='black', $
  C_LABEL_SHOW=0, C_THICK=2, /OVERPLOT)
mc = MAPCONTINENTS(/HIRES)
m.MapGrid.LINESTYLE = 6
m.MapGrid.HORIZON_LINESTYLE = 6
m.MapGrid.LABEL_SHOW = 0

 

이 과정에 의하여 표출된 그림은 다음과 같습니다.

 

 

이제 이미지 캡쳐를 한번 더 해야 합니다. 즉 다음과 같이 CopyWindow 메서드를 한번 더 사용합니다.

 

cap_new = win.CopyWindow()
cap_new[ww] = 255b
HELP, cap_new
win.Erase

 

여기서는 먼저 캡쳐된 이미지 배열 cap_new를 얻습니다. 그리고 앞서 식별했던 해양 영역에 해당되는 화소들의 위치 정보인 ww를 여기서 투입하여, 이번에 캡쳐된 cap_new에서 해양에 해당되는 화소들의 값을 모두 255로 대체합니다. 이렇게 하면 해양 영역만 그 색상이 흰색으로 변경됩니다. 그리고 이 과정이 끝나면 Erase 메서드를 사용하여 그림을 한번 더 지웁니다. 역시 이 그림도 중간 과정에서만 필요할 뿐 최종 목표는 아니기 때문입니다.

 

그러면 이제 최종 단계로 갑니다. 그 과정은 다음과 같습니다.

 

  i = IMAGE(cap_new, MARGIN=0, /CURRENT)
  m = MAP('geographic', LIMIT=[30, 120, 50, 150], MARGIN=0.1, FONT_SIZE=11, /CURRENT)
  m.MapGrid.LABEL_POSITION = 0

 

이와 같이 해양 부분이 흰색으로 처리된 cap_new를 그래픽창에 그대로 표출합니다. 다만 이제는 지도의 격자선 및 라벨 문자들 등이 보이도록 하기 위하여 MAP 함수를 다시 실행합니다. 그래야 우리가 원했던 최종적인 그림이 완성될 것입니다. 이 과정까지 완료되면 결과는 다음 그림과 같습니다.

 

 

이 그림을 보면 우리가 원했던 결과를 얻은 것 같습니다. 물론 이러한 결과를 얻기 위한 과정은 그리 간단하지는 않습니다. 어떻게 보면 "굳이 이렇게까지 해야하는 것인가?"라는 생각이 들 수도 있습니다. 오로지 우리가 목표로 하는 결과를 얻는 것에만 촛점을 맞춰서 다소 무리수처럼 보이는 과정들이 포함된 것이 사실입니다. 어쩌면 이보다 더 깔끔하고 좋은 방법이 존재할 수도 있습니다만, 일단 제가 제시할 수 있는 최선은 이 정도인 것 같습니다.

 

그리고 지난 회차 및 이번 회차의 예제들에서는 2차원 데이터를 등위선(Contour)의 형태로 표출하는 경우로 예를 들었는데요. 이미지(Image) 형태로 표출하는 경우에도 방법은 똑같습니다. 즉 오늘 제시된 예제 코드에서 등위선의 형태로 2차원 데이터를 표출하는 부분이 다음과 같은데요.

 

cn = CONTOUR(data, lon, lat, /FILL, GRID_UNITS=2, RGB_TABLE=ct, $
  MIN_VALUE= minv, MAX_VALUE=maxv, N_LEVELS=10, /OVERPLOT)
cno = CONTOUR(data, lon, lat, GRID_UNITS=2, N_LEVELS=10, COLOR='black', $
  C_LABEL_SHOW=0, C_THICK=2, /OVERPLOT)

 

이 내용을 다음과 같이 이미지의 형태로 표출하는 방식으로 변경해볼 수도 있습니다.

 

i = IMAGE(data, lon, lat, RGB_TABLE=ct, /OVERPLOT)

 

이렇게 할 경우의 결과는 다음 그림과 같습니다.

 

 

따라서 이러한 형태의 그림을 표출해야만 하는 경우에는 이 방법을 한번 고려해보시기 바랍니다. 그리고 오늘 제시된 이 방법에 대한 기본적인 아이디어는 David Fanning의 웹페이지에 소개된 Sea Masks on Map Projections라는 게시물의 내용을 참조로 한 것임을 밝혀둡니다.

LIST