IDL/Data Type & Format

HDF5 형식의 데이터 파일 읽기

이상우_IDL 2021. 2. 1. 16:52
728x90

HDF 형식은 산업 및 과학 분야에서 널리 사용되어온 파일 형식으로서 그 이름(Hierarchical Data Format)에서 알 수 있듯이 데이터를 계층적 구조의 형태로 저장하는 것이 핵심이라고 볼 수 있습니다. 특히 다양한 종류의 대용량의 데이터들을 한꺼번에 저장하거나 또는 추출하는데 있어서의 편의성과 속도, 그리고 플랫폼에 상관없이 유저들간의 교환이 용이하다는 등의 장점들을 갖고 있기 때문에 다양한 분야에서 널리 사용되어오고 있는 형식이기도 합니다. 원래 예전에는 HDF라는 형식으로 널리 사용되었지만, 최근 들어서는 여러가지 개선점들이 반영된 HDF5라고 하는 새로운 형식이 널리 사용되고 있습니다. 즉 HDF와 HDF5는 서로 다른 형식입니다. 물론 이러한 형식에 대한 정확한 식별은 파일명의 확장자를 보면 알 수 있지만, IDL에서는 HDF_ISHDF 및 H5F_IS_HDF5 함수를 이용하여 명확하게 확인할 수 있습니다. 즉 확인하고자 하는 파일이 있을 때 다음과 같이 확인하면 됩니다.

 

PRINT, HDF_ISHDF('test.hdf')

      1

PRINT, H5F_IS_HDF5('test.h5')

      1

 

이렇게 했을 때 출력되는 값이 1이면 그 형식이 맞다는 것이고 0이면 틀리다는 것입니다. 그리고 IDL에서는 HDF 형식 및 HDF5 형식의 파일들 모두 다룰 수 있습니다. IDL 도움말에서 Contents -> Input/Output -> HDF, NetCDF, and CDF Formats 섹션을 보면, 다음과 같이 하위 섹션들 목록에서 HDF Routines 항목과 HDF5 Routines 항목이 서로 구분되어 있다는 것도 주목해야 합니다.

 

 

따라서 취급하고자 하는 파일이 정확히 어떤 형식에 속하는가에 따라서 내용을 구분하여 보셔야 합니다. HDF 형식에 관해서는 제가 예전에 관련문서 하나를 소개하는 방식으로 간략하게 언급했던 적이 있으므로, 필요하시다면 그 게시물의 내용을 참조하시기 바랍니다. 오늘 제가 다루고자 하는 내용은 HDF5 형식에 관한 것입니다. 특히 HDF5 형식의 파일을 읽는 방법에 대하여 관련 예제와 함께 소개해보고자 합니다. 예제로 사용할 파일은 IDL의 설치와 함께 딸려오는 'hdf5_test.h5'라는 이름의 파일이며, 먼저 다음과 같이 경로와 파일명을 file이라는 문자 변수로 정의합니다.

 

file = FILEPATH('hdf5_test.h5', SUBDIRECTORY=['examples', 'data'])

 

본격적으로 이 파일을 읽는 작업에 들어가기에 앞서서 먼저 이 파일 내에 수록된 정보들에 대한 전반적인 개요를 살펴보겠습니다. 이러한 목적을 위해서는 다음과 같이 H5_LIST 명령을 사용하면 됩니다.

 

H5_LIST, file

 

이 명령을 실행하면 파일 내에 수록된 모든 데이터에 대한 정보가 표시됩니다. 통상적으로 HDF5 형식의 파일 내에서는 그룹(Group)과 데이터셋(Dataset)의 형태로 데이터가 수록됩니다. 데이터셋은 쉽게 생각하면 그냥 배열 데이터 자체인 경우가 많습니다. 그리고 그룹이라는 것은 데이터셋을 포함하는 카테고리에 해당됩니다. 즉 HDF5 형식의 파일 내에서는 데이터셋들이 특정한 그룹 내에 속하는 경우가 많습니다. 즉 계층적 구조를 갖는 저장 방식을 따릅니다. 물론 그룹 하나가 여러 개의 데이터셋들을 갖는 경우, 데이터셋이 특정 그룹에 속하지 않는 경우 등 여러가지 상황들이 있을 수 있습니다. 그리고 데이터셋, 그룹, 또 심지어는 HDF5 파일 자체는 각자의 메타자료(Metadata)를 갖고 있습니다. 그리고 메타자료의 세부 내용은 데이터공간(Dataspace), 데이터타입(Datatype), 특성(Attribute) 등으로 구성됩니다. 말로 하면 좀 복잡하긴 한데, 이 개념을 도식적으로 본다면 다음 그림과 같습니다.

 

 

사실 HDF5 형식의 이러한 기본적인 특성은 HDF 형식의 경우도 거의 비슷합니다. 어쨌든 H5_LIST 명령을 사용하면 대상이 되는 HDF5 파일에 대하여 내부적으로 어떠한 계층구조로 데이터가 저장되어 있는지를 일목요연하게 알 수 있습니다. 실제로 출력된 내용을 보면 다음과 같습니다.

 

file        /Applications/harris/idl88/bin/bin.darwin.x86_64/idlde.app/Contents/MacOS/../../../../../examples/data/hdf5_test.h5     

dataset     /2D int array                                                                                                           H5T_INTEGER [50, 100]

dataset     /A note                                                                                                                 H5T_STRING [2]

group       /arrays                                                                                                                 

dataset     /arrays/2D float array                                                                                                  H5T_FLOAT [50, 100]

dataset     /arrays/2D int array                                                                                                    H5T_INTEGER [50, 100]

dataset     /arrays/3D int array                                                                                                    H5T_INTEGER [10, 50, 100]

dataset     /arrays/Vdata with mixed types                                                                                          H5T_COMPOUND [20]

group       /datatypes                                                                                                              

group       /images                                                                                                                 

dataset     /images/Eskimo                                                                                                          H5T_INTEGER [600, 649]

dataset     /images/Eskimo_palette                                                                                                  H5T_INTEGER [3, 256]

dataset     /images/Iceberg                                                                                                         H5T_INTEGER [375, 375]

dataset     /images/iceberg_palette                                                                                                 H5T_INTEGER [3, 256]

group       /links                                                                                                                  

group       /links/hard links                                                                                                       

dataset     /links/hard links/Eskimo                                                                                                H5T_INTEGER [650, 600]

dataset     /links/hard links/RGB values                                                                                            H5T_COMPOUND [250, 300]

group       /links/soft links

 

이와 같이 꽤 여러 줄에 걸쳐 출력되었는데, 총 3개의 컬럼들로 구성됩니다. 첫번째 컬럼은 해당 개체(Object)에 대하여 그것이 그룹이냐 또는 데이터셋이냐 여부를 명시한 것이고, 두번째 컬럼은 그 개체의 고유 명칭에 해당되고, 세번째 컬럼은 해당 개체의 자료형 및 배열구조 정보입니다. 따라서 이러한 개요 정보를 훓어보면서 구체적으로 어떤 항목의 데이터를 추출해야 할 것인지에 대하여 가늠할 수 있게 됩니다. 따라서 처음 다루게 되는 HDF5 형식의 파일이 있을 경우에는 가장 먼저 이러한 과정을 거쳐서 그 파일 내에 수록된 데이터의 계층구조에 대한 전반적인 개요를 확인해두는 것이 좋습니다.

 

그러면 위의 목록에서 특정한 데이터를 지정하여 읽어봅시다. 이를 위하여 위의 목록에서 다음과 같은 내용을 주목해보겠습니다.

 

group       /images                                                                                                                 

dataset     /images/Eskimo                                                                                                          H5T_INTEGER [600, 649]

dataset     /images/Eskimo_palette                                                                                                  H5T_INTEGER [3, 256]

 

이 내용을 보면 images라는 그룹이 있고, 이 그룹 내에 Eskimo라는 데이터셋과 Eskimo_palette라는 데이터셋이 포함되어 있다는 것을 알 수 있습니다. 그리고 Eskimo라는 데이터셋은 구체적으로는 600x649의 배열 구조를 가지며 Eskimo_palette는 3x256의 배열 구조를 갖는다는 것도 알 수 있습니다. 그러면 이 두개의 데이터셋들을 읽어봅시다. HDF5 형식의 파일로부터 특정한 데이터셋을 읽는 방법은 두가지 정도가 있습니다. 첫번째 방법은 H5_GETDATA 함수를 사용하는 것으로서 비교적 간단한 방법이라고 할 수 있습니다. 그 과정은 다음과 같습니다.

 

data = H5_GETDATA(file, '/images/Eskimo')

rgb = H5_GETDATA(file, '/images/Eskimo_palette')

HELP, data, rgb

 

이 내용을 보면 H5_GETDATA 함수를 사용하는 방법을 확인할 수 있는데요. 대상이 될 HDF5 형식 파일의 이름을 첫번째 인수로 주고, 읽고자 하는 데이터셋의 고유 명칭을 두번째 인수로 주면 됩니다. 여기서는 Eskimo라는 데이터셋을 data라는 배열로 그리고 Eskimo_palette라는 데이터셋을 rgb라는 배열로 읽었습니다. HELP에 의하여 출력된 각 배열에 대한 정보는 다음과 같습니다.

 

DATA            BYTE      = Array[600, 649]

RGB             BYTE      = Array[3, 256]

 

이와 같이 각 데이터셋을 배열로 읽어왔으므로 이후의 작업에서 이 배열들을 활용하면 됩니다. 즉 data는 2차원 이미지 배열이고 rgb는 컬러테이블 정보이기 때문에 다음과 같은 방식으로 표출할 수 있습니다.

 

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

im = IMAGE(REVERSE(data, 2), RGB_TABLE=rgb, /CURRENT)

 

 

어쨌든 이와 같이 H5_GETDATA 함수를 활용하는 것이 HDF5 형식의 파일로부터 데이터를 읽어오는 첫번째 방법이라고 볼 수 있습니다.

 

이제 바로 이어서 두번째 방법을 소개합니다. 두번째 방법에서는 몇가지 관련 기능 함수들을 연이어서 사용하게 됩니다. 이 방법에서는 다음과 같이 H5F_OPEN 함수를 가장 먼저 사용하고 바로 이어서 H5G_OPEN 함수를 사용합니다.

 

fid = H5F_OPEN(file)

gid = H5G_OPEN(fid, 'images')

 

여기서 H5F_OPEN 함수의 역할은, 읽고자 하는 대상이 되는 HDF5 파일로 가는 연결 통로를 확보하는 것입니다. 그 연결 통로의 고유 번호가 fid라는 변수로 전달됩니다. 이 변수는 바로 뒤에서 H5G_OPEN 함수에서 사용됩니다. 즉 파일로의 연결 통로인 fid로 파일에 접근한 다음, 그 안에 있는 images라는 그룹으로 통하는 통로에 대한 고유 번호를 gid라는 변수로 받게 됩니다. 여기서 사용된 함수의 이름들에서 'F'는 File을 뜻하고 'G'는 Group을 뜻합니다. 이렇게 그룹으로의 연결 통로를 확보한 뒤에는 바로 데이터셋으로 접근하여 실제 데이터를 읽게 되는데, 먼저 Eskimo 데이터셋을 읽는 과정은 다음과 같습니다.

 

did1 = H5D_OPEN(gid, 'Eskimo')

data = H5D_READ(did1)

HELP, data

 

이와 같이 H5D_OPEN 함수 및 H5D_READ 함수를 사용하게 됩니다. 여기서는 H5D_OPEN 함수를 사용하여 데이터셋으로의 연결 통로를 확보하고 그 고유 번호를 did1이라는 변수로 가져온 다음, H5D_READ 함수를 사용하여 그 연결 통로를 통하여 데이터셋을 실제로 추출하여 data라는 배열로 읽어온 것입니다. 여기서 사용된 함수들의 이름에서 'D'는 Data를 의미합니다. 마찬가지 요령으로 Eskimo_palette 데이터셋은 다음과 같이 읽어오면 됩니다.

 

did2 = H5D_OPEN(gid, 'Eskimo_palette')

rgb = H5D_READ(did2)

HELP, rgb

 

그리고 HELP에 의하여 출력된 내용은 다음과 같습니다. 앞서 H5_GETDATA 함수를 사용했던 경우와 결과는 같습니다.

 

DATA            BYTE      = Array[600, 649]

RGB             BYTE      = Array[3, 256]

 

결국 두번째 방법에서는 H5F_OPEN, H5G_OPEN, H5D_OPEN, H5D_READ 함수들을 연달아서 사용하게 됩니다. 사실 첫번째 방법에 비해서는 약~간 복잡해 보일 수도 있겠지만, 파일이나 그룹에 대한 연결 통로 정보를 확보해두고 계속 재활용하는 방식이기 때문에 나름대로의 장점이 있는 것도 사실입니다. 만약 데이터셋을 추출하는 것에만 주안점을 두는 경우에는 첫번째 방법을 사용해도 무방합니다. 그렇지만 만약 데이터셋을 추출하는 것 뿐만 아니라 데이터공간(Dataspace), 특성(Attribute) 등과 같이 데이터셋과 연결되어 있는 메타정보들까지도 필요한 경우라면 두번째 방법으로 가는 것이 좋습니다. 예를 들어서 Eskimo 데이터셋에 대하여 배열 크기에 관한 정보를 데이터공간으로부터 추출하는 과정은 다음과 같습니다.

 

dsid1 = H5D_GET_SPACE(did1)

dims = H5S_GET_SIMPLE_EXTENT_DIMS(dsid1)

HELP, dims

PRINT, dims

 

여기서는 먼저 H5D_GET_SPACE 함수를 사용하여 Eskimo 데이터셋과 연결되어 있는 데이터공간에 대한 고유 번호를 dsid1이라는 변수로 가져온 다음, H5S_GET_SIMPLE_EXTENT_DIMS 함수를 사용하여 데이터 배열의 크기에 관한 정보를 추출한 것입니다. 참고로 이 함수의 이름에서 'S'는 DataSpace를 뜻합니다. 출력된 내용은 다음과 같습니다.

 

DIMS            ULONG64   = Array[2]

                   600                   649

 

그리고 Eskimo 데이터셋과 연결되어 있는 특성(Attribute) 정보들도 있어서 필요할 경우 이들을 추출하는 것도 가능합니다. 일단 특성 정보들이 몇가지 있는가를 확인하려면 다음과 같이 H5A_GET_NUM_ATTRS 함수를 사용하면 됩니다.

 

n_att = H5A_GET_NUM_ATTRS(did1)

PRINT, n_att

 

실제로 출력 결과는 7로 나오기 때문에 총 7종의 특성 정보들이 존재함을 알 수 있습니다. 이들 중 배열값의 범위에 관한 특성(Attribute) 정보를 추출하는 과정은 다음과 같습니다.

 

aid = H5A_OPEN_IDX(did1, 4)

HELP, aid

att_name = H5A_GET_NAME(aid)

HELP, att_name

att = H5A_READ(aid)

HELP, att

PRINT, att

 

실제로 배열값 범위에 관한 정보는 7종의 특성 정보들 중 5번째에 해당되기 때문에 H5A_OPEN_IDX 함수를 사용하여 그 특성에 대한 고유 번호를 aid라는 변수로 먼저 가져옵니다. 이 aid 변수를 통하여 해당 특성에 접근하면 되는데, 먼저 그 특성의 명칭을 H5A_GET_NAME 함수를 사용하여 가져와서 출력하였고, 또 H5A_READ 함수를 사용하여 그 특성의 실제 값들을 출력하였습니다. 여기서 출력된 내용은 다음과 같습니다.

 

AID             LONG64    =     432345564227567890

ATT_NAME        STRING    = 'IMAGE_MINMAXRANGE'

ATT             BYTE      = Array[2]

   0 255

 

이와 같이 이 특성의 명칭은 IMAGE_MINMAXRANGE이고 그 값은 0, 255입니다. 즉 Eskimo 데이터셋의 배열 값들의 범위가 0~255임을 관련 특성 정보를 통해서도 확인할 수 있습니다. 이 과정에서 사용된 H5A_OPEN_IDX, H5A_GET_NAME, H5A_READ 함수들의 이름을 보면 공통적으로 알파벳 'A'가 있는데 바로 Attribute를 의미합니다.

 

지금까지 HDF5 형식의 파일로부터 데이터셋(Dataset)을 추출하는 방법을 소개하고, 바로 이어서 데이터공간(Dataspace) 및 특성(Attribute)과 같은 메타정보들을 추출하는 방법도 소개해보았습니다. HDF5 형식의 파일을 다루기 위해서는 계층적(Hierarchical) 구조에 대한 이해가 우선적으로 필요합니다. 그리고 데이터공간이나 특성 등과 같은 메타정보는 각각의 데이터셋마다 서로 다른 메타정보들이 연결되어 있다는 것도 이해해두는 것이 필요합니다. 위의 예제에서는 Eskimo라는 데이터셋을 예로 들었지만, 파일 내 다른 데이터셋에는 또 다른 종류의 메타정보들이 연결되어 있는 것입니다.

 

그리고 HDF5 형식의 경우 그 자체에 대한 버전이 존재합니다. 왜냐하면 HDF 및 HDF5 형식을 개발하고 배포하는 조직이 따로 있기 때문입니다. 바로 미국 일리노이 대학의 NCSA(National Center for Supercomputing Applications)라는 곳입니다. 홈페이지도 있는데 아래 링크와 같습니다.

 

www.hdfgroup.org

 

IDL에서 지원되는 HDF5 관련 기능들이 어떤 버전의 API를 기반으로 하는가를 확인하려면 다음과 같은 명령을 커맨드 입력창에서 실행해보면 됩니다.

 

HELP, 'hdf5', /DLM

 

제가 Mac OS용 IDL 8.8에서 위 명령을 실행했을 때 출력되는 내용은 다음과 같습니다.

 

** HDF5 - IDL Hierarchical Data Format 5 (HDF5) support DLM (loaded)

    Version: hdf5 1.10.5, szip 2.1, zlib 1.2.11, Build Date: JUN 29 2020, Source: Harris Geospatial Solutions, Inc.

    Path: /Applications/harris/idl88/bin/bin.darwin.x86_64/idl_hdf5.so

 

즉 IDL 8.8에는 HDF5 1.10.5 버전 기반의 HDF5 관련 기능들이 탑재되어 있다는 의미입니다. 이것은 IDL 버전마다 다르기 때문에 여러분들도 확인해보시면 또 다른 정보가 출력될 수 있습니다. 그리고 이 얘기는 HDF5 파일 자체도 어떤 버전의 HDF5 기반이냐에 따라서 IDL에서 제대로 읽을 수도 있고 또 그렇지 않을 수도 있다는 뜻이기도 합니다. 따라서 이러한 부분에 대한 고려도 경우에 따라서는 필요할 수도 있다는 점을 염두에 두는 것이 좋습니다.

 

오늘은 HDF5 파일을 읽는 방법에 대하여 저 나름대로 아는 한도 내에서 예제를 통하여 소개해보았습니다. IDL에서 HDF5 파일을 다루는 방법에 관하여 본사인 Harris Geospatial에서 제공하는 나름 볼만한 내용이 또 있어서 링크로 소개해드립니다. 이 내용도 함께 참조하시면 좋을 것 같습니다. 링크는 아래와 같습니다.

 

www.l3harrisgeospatial.com/docs/HDF5_Overview.html

LIST