ENVI API를 이용하여 영상을 읽는 방법

영상을 읽는 것까지가 목적이라면, 또는 간단한 영상처리를 하는 것까지가 목적이라면, IDL만을 이용하는 것이 더 편할지도 모릅니다. 그렇지만, 이후 영상처리가 Georeferencing이라든지, PanSharpening과 같은 일이라면, ENVI 체계 안에서 영상을 읽어 들이는 것이 훨씬 편할 것입니다. ENVI API를 이용하여 영상을 파일에서 배열로 읽어들이려면 어떻게 해야 할까요? ENVI Classic과 New ENVI 체계에서의 방법이 좀 다릅니다.

아래 예제는 ENVI Classic과 NEW ENVI에서 4밴드 영상을 읽어 화면상에 네 개의 밴드를 2X2 타일 형태로 디스플레이하는 것입니다. 맨 처음 얘기했듯이, 이것이 목적이라면 ENVI API를 사용하지 않아도 충분합니다만, 이 이후에 ENVI의 기능을 이용한 작업을 진행한다고 생각하고, 영상을 읽는 방법(간단합니다)을 살펴 보십시오. 이 예제는 ENVI의 인터페이스를 보여주지 않고, 최종적으로 IDL의 New Graphics를 통해 4개 밴드를 표출만 하기 때문에, ENVI Classic과 New ENVI 어느쪽 방법을 사용하더라도 최종 결과는 같습니다. IDL 8.3에서 ENVI Classic과 New ENVI 어느쪽이든 시동할 수 있기 때문에 겉보기 결과는 같습니다.

 

ENVI Classic API

아마도 간단한 기능이어서 코드를 보고 이해하는데는 별 어려움이 없을 것입니다.

compile_opt idl2 는 ENVI API를 사용하기 위해서 무조건 사용한다고 생각하십시오. Classic이든 New든 ENVI 체계가 여기에 맞춰져 있습니다. 이에 대한 설명은 이상우 박사의 블로그에서 “COMPILE_OPT의 활용(링크)”을 참고하시면 될 것 같습니다.

  • ENVI Classic의 Batch는 ENVI, /RESTORE_BASE_SAVE_FILES 로 루틴들을 불러와서 ENVI_BATCH_INIT로 시작하고 ENVI_BATCH_EXIT로 끝냅니다.
  • ENVI Classic의 파일 읽기는 ENVI_OPEN_FILE로 파일을 지정하여 R_FID 키워드의 리턴값을 쥐고 이 값으로 파일에 접근합니다.
  • ENVI Classic에서 어떤 작업을 수행할 때, DIMS(배열의 종횡방향 크기), NB(밴드 개수) 등등을 사용자가 파악하여 지정해 주어야 하는 일이 많습니다. 이런 일들은 ENVI_FILE_QUERY가 처리합니다.
  • ENVI Classic에서 영상 파일을 배열로 읽어올 때는 ENVI_GET_DATA() 함수를 이용합니다. fid(ENVI_OPEN_FILE의 R_FID 키워드 리턴값) 변수, DIMS 키워드(ENVI_FILE_QUERY로 조사함) 등이 사용되는 형태를 보아 두시면 됩니다(실제 옵션은 이보다 더 많습니다). ENVI_GET_DATA()를 사용할 때 저도 매번 깜빡하고 실수하는 키워드가 있는데 바로 POS입니다(밴드 번호-0번부터 시작하는-를 의미해요). IDL이 아무래도 배열 기반 언어다 보니 POS=[0,1,2,3] 과 같이 사용해서 4개 밴드를 동시에 읽을 수 있을 거라고 생각하는데, 그렇지 않습니다. 위 예제와 같이 반복문을 통해 하나씩 읽어야 합니다.
    data=ENVI_GET_DATA(FID=fid, DIMS=dims, POS=[0, 1, 2, 3]) 과 같이 사용하면 실제로 0번 밴드 하나만 읽습니다.

NEW ENVI의 API

위 예제와 같은 기능을 수행하는 New ENVI API 사용 예제는 다음과 같습니다.

  •  e=ENVI(/HEADLESS) 와 같이 /HEADLESS 키워드를 이용하면 ENVI GUI가 뜨지 않고 백그라운드로 실행됩니다. ENVI Classic의 Batch 모드와 유사합니다. 그리고 좌변(예제에서는 e 변수) 변수는 하나의 New ENVI를 가리키며(인터페이스만 보이지 않을 뿐 완전한 ENVI가 실행되고 있습니다) 이 변수를 통해 ENVI를 제어합니다. (객체지향식으로  말하자면 ENVI 오브젝트입니다)
  • ENVI 오브젝트의 OpenRaster 메쏘드를 이용하여 파일을 Open 합니다. 이제 이 파일을 가리키고 이 파일을 통제할 수 있는 모든 데이터와 메쏘드는 좌변 변수에 넘겨집니다(예제에서는 raster 변수. 오브젝트).
  • raster 오브젝트에는 GETDATA 메쏘드가 있습니다. 이를 이용하면 좌변에 배열 형태로 영상이 읽혀 들어옵니다. BANDS라는 키워드는 배열을 받아들일 수 있습니다. 반복문을 사용하지 않고 한번에 필요한 밴드들을 읽어들일 수 있는데, ENVI Classic에서 ENVI_GET_DATA가 POS 키워드에 배열을 사용하지 못하는 것과 차이가 있네요.

아무래도 New ENVI API는 ENVI Classic API에 비해 여러 부분에서 자동화가 되어 있습니다. 사용자가 DIMENSION을 직접 조사할 필요가 없이, 자동으로 처리하도록 되어있는 것을 보세요.  하지만 이런 부분이 꼭 ENVI Classic이 덜떨어져서 그랬던 것은 아닙니다. ENVI Classic의 시대에는 영상 전체를 읽는 것이 부담스러운 시기였고(컴퓨터 메모리 및 성능 상), 그래서 디폴트로 영상의 어떤 부분을 읽을 것인지 지정하게 해 놓았던 것으로 생각됩니다. DIMS 키워드가 존재하는 이유는 사실 그건데요, 영상 전체를 읽을 때도 DIMS를 조사해서 이 값을 넣어줘야 한다는 것이 지금에 와서는 좀 귀찮았던 거죠. 반대로 New ENVI에서는 디폴트로 영상의 전 영역을 읽게 해 놓았지만, 일부만 읽고 싶을 때는 어떻게 할까요? ENVIRaster::GetDATA 메쏘드에는 SUB_RECT라는 키워드가 있습니다. SUB_RECT=[x1, y1, x2, y2] 와 같이 사용해서 시작픽셀과 끝픽셀을 지정해 주지요.

예제에서는 간단한 뼈대만을 보였지만, ENVIRaster::GetData() 메쏘드는 다음과 같은 문법을 가지고 있습니다.

Result = ENVIRaster.GetData([BANDS=array] [, /COMPLEX_FUNCTION] [, ERROR=variable] [, INTERLEAVE=string] [, INTERPOLATION=string] [, SUB_RECT=array] [, XFACTOR=floating point] [, YFACTOR=floating point])

같은 목적의 ENVI Classic 대응 프로시저인 ENVI_GET_DATA는 다음과 같은 문법을 가지고 있습니다.

Result = ENVI_GET_DATA(/COMPLEX, DIMS=array, FID=file ID [, INTERP={0 | 1 | 2 | 3}], POS=long integer [, XFACTOR=integer] [, YFACTOR=integer])