IDL/Direct Graphics

DG 체계에서 지도와 이미지 중첩 표출 [2]

이상우_idl 2023. 9. 5. 15:52
728x90
반응형

지난 회차 게시물에서는 DG 체계에서 2차원 데이터를 지도상에 이미지의 형태로 중첩 표출하는 방법을 소개하기 시작하였는데, 중첩된 이미지 데이터가 이상하게 보이는 문제가 발생한 상태입니다. 이번 회차에서는 그 해결책을 알아보기로 하겠습니다. 우선 지난 회차에서 발생한 문제의 표출 결과는 다음과 같습니다.

 

 

사실 이 모습을 보면 가장 문제가 되는 증상들은 이미지 내부의 데이터 값의 범위에 대한 색상 배정 그리고 데이터가 존재하지 않는 짜투리 공간에 대한 값 처리 및 색상 배정 등 두가지 정도 측면에서 당초 우리가 기대했던 바와 다르게 나타나고 있다는 것입니다. 일단은 원본 데이터 배열인 data의 값 범위가 대략 43~55였다는 점을 주목해야 합니다. 이 data라는 배열 데이터는 MAP_IMAGE 함수에 의하여 result라는 배열 데이터로 변환이 된 상태인데요. 사실 result 내에서도 의미있는 값들의 범위는 원본 데이터와 거의 유사하게 43~55를 유지합니다. 그런데 여기서는 먼저 MAP_IMAGE 함수의 MISSING 키워드에 -9999라는 값을 부여했다는 것에 주목해야 합니다. 사실 의미없는 데이터 값을 이렇게 -9999와 같은 값으로 간주하는 것이 그리 드문 일은 아닙니다. 다만 여기서는 이렇게 되면 result의 값의 범위가 43~55가 아니라 -9999~55가 되어버립니다. 이러한 상황이라면 TVSCL 명령에 의하여 이미지로 표출될 때 34번 컬러테이블의 색상이 배정되는 방식은 다음과 같습니다.

 

* result의 -9999~55 범위의 값들은 34번 컬러테이블의 모든 색상값 범위(0~255)로 대응되어 표시된다. 즉 데이터 값 -9999는 색상값 0으로 그리고 데이터 값 55는 색상값 255로 대응된다.

* 그렇기 때문에 result 내에서 43~55 범위안 값들은 34번 컬러테이블의 거의 255 근처의 극히 제한된 범위의 색상값들로만 대응되어 표시된다. 또한 result 내에서 -9999인 값들은 34번 컬러테이블의 0이라는 색상값에 대응되는 보라색으로 표시된다.

 

좀 복잡해 보이긴 하는데 이것은 컬러테이블의 색상값 체계 및 TVSCL 명령의 색상 대응 방식 등과 연관되는 부분입니다. 결국 TVSCL 명령은 result의 전체 값 범위를 바이트스케일링 처리한 다음 컬러테이블의 0~255의 색상을 배정하여 표출하게 되는데, -9999라는 값의 존재로 인하여 result의 값 범위가 실제보다 너무 크게 간주되는 바람에 이런 현상이 나타난 것이라고 보면 됩니다. 다소 혼란스럽게 느껴지신다면 그냥 그런가보다 하고 넘어가셔도 무방합니다. 과정이야 어쨌든 간에 데이터 값과 색상의 대응 관계가 우리의 의도와는 다른 상황이라고 생각하시면 됩니다. 어쨌든 이러한 문제점들을 해결하기 위한 올바른 방향은 다음과 같이 정리해볼 수 있을 것 같습니다.

 

* result의 유의미한 값 범위인 43~55의 값들이 34번 컬러테이블의 모든 색상값(0~255) 범위로 대응되어 표시되도록 하는 것이 바람직할 것 같다.

* result 내에서 -9999인 값들은 실제로는 데이터가 존재하지 않는 부분에 해당되므로, 지도의 배경 색상(여기서는 흰색)과 동일하게 표시되도록 하는 것이 좋을 듯 하다.

 

결국은 앞서 문제점으로 제시했던 두가지 항목 각각에 대한 개선책이라고 보면 됩니다. 그러면 이러한 방향으로 문제점들을 해결해봅시다. 이를 위하여 제가 얼마전에 올렸던 게시물에서 제시된 방법을 여기서 적용해보고자 합니다. 즉 컬러테이블에서 유의미한 색상값 범위는 0~254로 설정하고 255의 색상값이 배경색(여기서는 흰색)과 동일하도록 별도의 설정 과정을 거친 후 데이터가 존재하지 않는 부분(result에서 값이 -9999인 격자점들)을 이 값으로 대체하는 방식으로 처리하고자 합니다. 그 전체 과정은 다음과 같습니다.

 

tmp = RANDOMU(1, 100, 100)
FOR j = 0, 4 DO tmp = SMOOTH(tmp, 9, /EDGE_TRUNCATE)
data = CONGRID(tmp, 500, 500, /INTERP)*100
HELP, data
PRINT, MIN(data), MAX(data)

MAP_SET, 35, 125, /CONIC, LIMIT=limit, STANDARD_PARALLELS=[30, 60], $
  XMARGIN=[4, 4], YMARGIN=[2, 2]
result = MAP_IMAGE(data, stx, sty, COMPRESS=1, /BILINEAR, $
  LATMIN=25, LONMIN=115, LATMAX=45, LONMAX=135, MISSING=-9999)
HELP, result
PRINT, MIN(result), MAX(result)

result_scl = BYTSCL(result, MIN=MIN(data), MAX=MAX(data), TOP=254)
PRINT, MIN(result_scl), MAX(result_scl)
ww = WHERE(result LT -9000, count)
IF count NE 0 THEN result_scl[ww] = 255
ct = COLORTABLE(34)
ct[255, *] = [255, 255, 255]
HELP, ct
TVLCT, ct
TV, result_scl, stx, sty
LOADCT, 0

MAP_CONTINENTS, /HIRES, /COASTS, COLOR=0
MAP_GRID, BOX_AXES=0.1, COLOR=0, LONDEL=5, LATDEL=5

 

여기서는 가상 데이터를 정의하고 기본적인 바탕 지도를 표출하는 부분까지는 지난 회차에서 소개했던 내용과 동일합니다. 다만 앞서 언급했던 문제점들을 해결하기 위하여 수정 및 추가된 부분이 볼드체로 표시되어 있습니다. 이 부분의 내용을 보면 먼저 result에 대하여 바이트스케일링을 적용하여 0~254의 범위값을 갖도록 조정한 결과를 result_scl이라는 새로운 2차원 배열로 생성합니다. 그리고 result 내에서 값이 -9999인 위치들을 WHERE 함수로 판별하고, 이 정보를 바탕으로 result_scl 내의 해당 위치에 대하여 255라는 값을 부여합니다. 그리고 34번 컬러테이블의 RGB 정보를 ct로 가져온 다음 여기서 255의 색상을 흰색으로 따로 정의한 다음, TVLCT 명령을 사용하여 이 컬러테이블을 불러온 후 TV 명령을 사용하여 result_scl을 표출하는 과정입니다. 표출 결과는 다음과 같습니다.

 

 

이 그림을 보면 원본 데이터의 유의미한 값 범위인 43~55에 대하여 34번 컬러테이블의 색상들이 골고루 배정되어 있을 뿐 아니라 데이터가 존재하지 않는 짜투리 공간에 대해서는 배경색과 동일한 흰색이 적용된 것을 확인할 수 있습니다. 아무래도 다소 귀찮은 측면이 없지는 않지만 대략 이러한 방식의 처리에 의하여 2차원 데이터를 지도상에 중첩 표출하는 작업을 원활하게 수행할 수 있습니다.

 

그리고 지금까지는 원본 데이터 배열의 이미지를 중첩할 지도의 투영법에 맞춰서 변형하기 위하여 MAP_IMAGE 함수를 사용하였는데요. 사실 유사한 기능을 하는 다른 함수가 또 있습니다. 바로 MAP_PATCH 함수입니다. 따라서 MAP_IMAGE 대신 MAP_PATCH를 사용해도 거의 동일한 결과를 얻을 수 있습니다. 물론 MAP_PATCH 함수의 경우는 문법이 조금 다릅니다. 일단 위의 과정에서 MAP_IMAGE 함수가 사용된 부분만 따로 떼어서 보면 다음과 같습니다.

 

result = MAP_IMAGE(data, stx, sty, COMPRESS=1, /BILINEAR, $
  LATMIN=25, LONMIN=115, LATMAX=45, LONMAX=135, MISSING=-9999)

 

그런데 이 부분을 MAP_PATCH 함수를 사용하여 대체할 수 있습니다. 즉 다음과 같습니다.

 

result = MAP_PATCH(data, LAT0=25, LON0=115, LAT1=45, LON1=135, $
  XSTART=stx, YSTART=sty, MISSING=-9999)

 

이렇게 대체한 후 전체 과정을 다시 실행해보면 결과는 위의 그림과 거의 동일합니다. 여러분도 직접 확인해보시기 바랍니다. 그러면 여기서 한가지 궁금증이 생길 수 있습니다. 과연 MAP_IMAGE와 MAP_PATCH의 차이점은 무엇일까요? 기본적으로는 DG 체계에서 표출된 지도상에 2차원 데이터를 중첩하기 위하여 지도 투영법에 맞도록 이미지를 변형하는 역할이라는 점은 서로 유사합니다. 다만 IDL 도움말에서 관련 내용을 찾아보면 다음과 같은 문구가 있습니다.

 

Note: MAP_IMAGE is more efficient than MAP_PATCH when the input data set is large compared to the destination area. If the converse is true, MAP_PATCH is more efficient.

 

이 문구는 MAP_IMAGE 함수에 관한 내용에 있습니다. 그리고 유사한 느낌의 문구가 MAP_PATCH 함수에 관한 내용에도 있는데 다음과 같습니다.

 

Note: MAP_PATCH is more efficient than MAP_IMAGE when the destination area is large compared to the input data set. If the converse is true, MAP_IMAGE is more efficient.

 

즉 중첩된 2차원 데이터의 영역 범위가 지도의 경위도 영역의 범위보다 넓으냐 좁으냐에 따라서 MAP_IMAGE 또는 MAP_PATCH가 더 효율적이라는 얘기입니다. 다만 그냥 "제 경험에 의하면" 중첩된 이미지의 표출 결과만 비교해보면 두 함수 사이에는 그리 큰 차이는 없지않나 생각은 들긴 합니다. 물론 이것은 경위도 격자형 분포를 하는 2차원 데이터를 중첩 표출할 경우에 한하여 제 경험상 서로 비슷하게 보인다는 것입니다. MAP_IMAGE와 MAP_PATCH의 기능상의 차이는 분명히 존재합니다. 특히 경위도 격자형 분포를 하지않고 지점별로 위치가 불규칙하게 떨어져있는 데이터를 중첩해야 할 경우에는 MAP_PATCH 함수만이 삼각법 내삽(Triangulation) 기반으로 그러한 기능을 지원한다는 점도 기억해두시면 좋을 것 같습니다(MAP_IMAGE 함수로는 그게 안됩니다).

 

그러면 DG 체계에서 지도를 표출하고 그 위에 2차원 데이터를 중첩하는 방법에 관해서는 일단 어느 정도 설명이 된 것 같습니다. 다만 여기서 제시된 예제는 2차원 데이터가 경도/위도 기반의 격자 분포를 하는 경우인데요. 사실 또 다른 경우가 있습니다. 바로 2차원 데이터가 거리 기반의 격자 분포를 하는 경우입니다. 사실 NG 체계에서 거리 기반의 격자 분포를 하는 2차원 데이터를 지도상에 중첩하는 예제는 제가 전에도 몇번 관련 게시물들을 통하여 소개한 바 있습니다. 그런데 이러한 방식의 중첩 표출을 DG 체계에서 하려면 어떻게 처리해야 할까요? 물론 방법은 있습니다. 다만 이를 위해서는 제가 이전 회차 게시물의 서두에서 언급했던 "방법 2"를 사용해야 합니다.

 

< 방법 2 >

MAP_PROJ_INIT 함수

PLOT 프로시저

MAP_CONTINENTS 프로시저

MAP_GRID 프로시저

 

즉 이와 같이 지도를 처음에 셋업할 때 MAP_SET 프로시저 대신 MAP_PROJ_INIT 함수를 사용하는 방법으로 가야한다는 의미입니다. 그러면 이와 관련된 구체적인 내용은 다음 회차에서 소개해보기로 하겠습니다.

반응형