ENVI 인터페이스에서, 영상 위에 마우스를 이동하면, 인터페이스 좌측 하단에 현재 위치의 경위도(또는 설정에 따라 Map 좌표 등 다양한 좌표계 표시 가능)가 표시됩니다. Cursor Value를 실행하면 마우스를 클릭하는 지점의 경위도(Geo), Map 좌표(Map : UTM, 또는 TM 등 투영법 기준의 좌표를 의미합니다), 군용좌표(MGRS; Military Grid Reference System) 이 표시되고, 아래쪽에 영상의 Pixel 좌표(File) 그리고 해당 지점의 Pixel Value를 표시해 줍니다. Go To 창에는 이동하고자 하는 좌표를 경위도좌표라든지 Map 좌표로 입력하면 해당 위치로 바로 이동합니다. 한번 방문했던 좌표는 메모리에 남아 위 그림과 같이 풀다운 메뉴 형태로 목록화 됩니다. 재방문이 가능한 거죠.
이러한 작업에서 등장하는 것이 몇가지 좌표들입니다. 사실상 같은 위치인데, 좌표계 정의에 따라 다르게 표출되는 것입니다. 당연히 상호 변환이 가능합니다. ENVI에서 좌표변환 작업의 특징은, 지정된 영상을 기준으로 정의가 된다는 것입니다. (물론 Vector 파일을 올릴 경우에는 Vector 기준으로 정의가 됩니다). 앞선 글 “투영좌표 변환(TM과 UTM)”에서는, IDL에서 지도 좌표변환 방법과 관련된 함수를 소개하며, IDL의 방식은 경위도와 특정 투영법 간의 변환이라는 취지의 설명을 드린 바 있습니다.
ENVI에서는 영상이 주축이 됩니다. 영상 없는 ENVI는 의미가 없는 것이죠. 두가지를 기억해 두시면 될 것 같습니다.
- 영상의 투영법과 관련된 Map 좌표가 주축이 됩니다. Map 좌표와 경위도 좌표간의 변환, Map 좌표와 File 좌표(Pixel 좌표)간의 변환 기능이 제공됩니다.
- 그러므로 내가 가진 영상의 Map 정보를 아는 것이 중요한데, 이는 Raster 데이터의 SPATIALREF 속성으로 가져옵니다.
예제 코드를 보시면 오히려 쉽게 정리가 될 수 있을 것 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
; ENVI를 시작합니다. /HEADLESS 키워드를 사용하면 ENVI는 메모리 속에서 실행됩니다. ; 화면에 보이지 않아요. 화면에 보여질 필요가 없다면 /HEADLESS를 쓰는 것이 더 빠릅니다. IDL> e = envi(/HEADLESS) ; 이제부터 e 변수는 ENVI를 상징합니다. (ENVI의 Reference 변수입니다). ENVI> file=filepath('qb_boulder_msi', ROOT_DIR=e.ROOT_DIR, subdir=['data']) ENVI> print, file C:\Program Files\Harris\ENVI54\data\qb_boulder_msi ; filepath 함수를 이용하여 ENVI 사용자라면 지겹게 열어 보는 qb_boulder_msi 파일을 지정합니다. ENVI> Raster = e.OpenRaster(file) ; 영상을 여는 과정은 거의 이렇게 정해져 있습니다. ; Raster 변수는 이제 읽어온 영상입니다. ENVI> SpatialRef = Raster.SpatialRef ; 읽어온 영상에서 투영 정보를 가진 속성은 SPATIALREF 입니다. ENVI> LON = -105.22 ENVI> LAT = 39.99 ; 테스트하고자 하는 경위도 좌표 (관심 위치의 좌표라고 생각하면 되겠습니다). ; 1) 영상의 투영정보에 대한 모든 것을 쥔 변수 SPATIALREF를 가지고, 경위도를 Map 좌표로 변환합니다. ENVI> SpatialRef.ConvertLonLatToMap, LON, LAT, MAPX, MAPY ENVI> PRINT, 'MAPX, MAPY : ', MAPX, MAPY MAPX, MAPY : 481218.02 4426670.7 ; 2) SPATIALREF를 가지고, Map좌표를 File 좌표(Pixel 좌표)로 변환합니다. ENVI> SpatialRef.ConvertMaptoFile, MAPX, MAPY, FILEX, FILEY ENVI> PRINT, 'FILEX, FILEY : ', FILEX, FILEY FILEX, FILEY : 339.57684 824.18666 ; 3) 1)에서 변환된 Map 좌표를 다시 역으로 경위도로 변환해 봅니다. ENVI> SpatialRef.ConvertMapToLonLat, MAPX, MAPY, RLON, RLAT ENVI> PRINT, 'Lon, Lat converted from Map Coordinate : ', RLON, RLAT Lon, Lat converted from Map Coordinate : -105.22000 39.990002 ; 당연히 같은 값이 나와야 겠지만, 약간의 수치계산 상의 오차는 존재합니다. ; 4) MGRS 좌표계는 경위도 좌표계와 대응합니다. ENVI> SpatialRef.ConvertLonLatToMGRS, LON, LAT, MGRS ENVI> PRINT, "MGRS : ", MGRS MGRS : 13SDE8121826671 |
SpatialRef를 이용한 좌표변환 메쏘드는 다음과 같은 것이 존재합니다. 이 중 몇가지는 위 예제에서 보여 드렸지만, 사용법은 모두 비슷합니다.
- ConvertLonLatToMap / ConvertMapToLonLat
- ConvertMapToFile / ConvertFileToMap
- ConvertLonLatToMGRS / ConvertMGRSToLonLat
- ConvertFileToFile / ConvertLonLatToLonLat / ConvertMapToMap
경위도와 Map 좌표간의 변환, Map좌표와 File 좌표 간의 변환은 투영된 영상을 다루는 ENVI의 특성상 Map좌표가 기준이 되도록 설계되어 있습니다. MGRS 체계는 경위도 좌표와 대응되도록 개발되어 있습니다. 다른 표현으로 MGRS에서 바로 Map 좌표나 File 좌표로 변환되지 않습니다. MGRS에서 File 좌표로 변환하고자 한다면 MGRS > LonLat > Map좌표 > File 좌표 로 변환의 단계를 거쳐야 합니다.
재미있는 것은 마지막 줄의 ConvertFileToFile, ConvertLonLatToLonLat, ConvertMapToMap 인데, 얼듯 보면, 뭐하러 경위도를 다시 경위도로 바꾸는가 하는 생각이 들 것입니다. 영상이 두 개 일 때, 두 영상의 SpatialRef를 따로 가지고 두 영상 서로간의 좌표체계로 변환하려고 존재하는 메쏘드들입니다. 예를 들어, 지구타원체 정의가 다른 영상이거나, 1번 영상은 UTM, 2번영상은 TM 좌표계일 수 있지요. 이럴 때 서로간의 좌표계로 상호 변환을 할 때 사용합니다.
지금까지는 ENVI의 API를 이용한 좌표변환을 소개하였습니다. 아래부터는 ENVI의 Task를 이용하여 같은 작업을 수행하는 과정입니다. Task 방식은 작업흐름(Workflow)을 따르는 방식과 유사합니다. 해당 작업을 ENVI GUI에서 수행한다고 생각하고, ENVI가 사용자에게 어떤 것들을 물어볼지 추정해 보면 흐름이 대강 잡힙니다. 물론 그렇다고 해서 매뉴얼(도움말) 안보고 하자는 얘기는 아닙니다. 도움말에 다 나오는 과정이고 그 과정 그대로 따르면 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
; 위경도를 Map좌표로 변환하는 과정입니다. 이 과정 역시 SpatialRef 가 사용됩니다. ENVI> Task1 = ENVITask('ConvertGeographicToMapCoordinates') ENVI> Task1.INPUT_COORDINATE = [LON, LAT] ENVI> Task1.SPATIAL_REFERENCE = SpatialRef ; Raster.SpatialREF ENVI> Task1.Execute ENVI> PRINT, 'MAPX, MAPY(TaskVersion) : ', Task1.OUTPUT_COORDINATE MAPX, MAPY(TaskVersion) : 481218.02 4426670.7 ; Map 좌표를 Pixel 좌표로 변환하는 과정입니다. ENVI> Task2 = ENVITask('ConvertMapToPixelCoordinates') ENVI> Task2.INPUT_COORDINATE=Task1.OUTPUT_COORDINATE ENVI> Task2.SPATIAL_REFERENCE = SpatialRef ENVI> Task2.Execute ENVI> PRINT, 'FILEX, FILEY(TaskVersion) : ', Task2.OUTPUT_COORDINATE FILEX, FILEY(TaskVersion) : 339.57684 824.18666 ; Map 좌표를 다시 위경도로 변환해 봅니다. ; 내부적으로는 API와 똑같은 프로세스를 사용하기 때문에 수치 오차도 같습니다. ENVI> Task3 = ENVITask('ConvertMapToGeographicCoordinates') ENVI> Task3.INPUT_COORDINATE = Task1.OUTPUT_COORDINATE ENVI> Task3.SPATIAL_REFERENCE = SpatialRef ENVI> Task3.Execute ENVI> PRINT, 'Lon, Lat converted from Map Coord (Task) : ', Task3.OUTPUT_COORDINATE Lon, Lat converted from Map Coord (Task) : -105.22000 39.990002 |
ENVI의 API가 먼저 개발되고, 이중 일부가 Task로 제공되고 있습니다. 앞으로 점차 많은 기능이 Task로 제공될 텐데, ENVI 5.4 기준으로는 다음과 같이 네 가지 변환 기능만 제공됩니다.
- ConvertMapToGeographicCoordinates / ConvertGeographicToMapCoordinates
- ConvertMapToPixelCoordinates / ConvertPixelToMapCoordinates
마지막으로, 예제에서는 모두 좌표 하나에 대해서만 변환을 수행했는데요, 배열을 이용하여 여러개의 좌표를 동시에 변환하는 것이 당연히 가능합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
ENVI> LONS = [-105.22, -104.77] ENVI> LATS = [39.99, 40.01] ENVI> SpatialRef.ConvertLonLatToMap, LONS, LATS, MAPXs, MAPYs ENVI> print, MAPXs, MAPYs 481218.02 519630.16 4426670.7 4428892.3 ENVI> Task4 = ENVITask('ConvertGeographicToMapCoordinates') ENVI> Task4.INPUT_COORDINATE = Transpose([[LONS], [LATS]]) ENVI> Task4.SPATIAL_REFERENCE = SpatialRef ENVI> Task4.Execute ENVI> PRINT, Task4.OUTPUT_COORDINATE 481218.02 4426670.7 519630.16 4428892.3 |
SpatialRef를 이용하여 영상의 투영 정보를 확보하는 방식은, 여러개의 영상을 순차적으로 처리할 때 유용하게 됩니다. 100여장의 영상이 있고, 이 영상으로부터 우리 동네 공원(위경도를 알고 있는)의 NDVI 값을 추출하는 작업을 수행한다고 생각해 보면, 100여개의 영상이 Landsat 영상이든, Sentinel 영상이든, 읽는 방법은
Raster = e. OpenRaster(file)
이고, 투영정보를 가져 오는 방법은
SpatialRef = Raster.SpatialRef
입니다. 즉, 앞의 예제를 각각의 영상에 대해 반복문을 돌린다고 해도 코드를 수정할 부분은 사실상 전혀 없다고 보아도 되는 것입니다.