IDL/New Graphics

VOLUME 함수를 이용한 3차원 큐브 데이터의 가시화 [1]

이상우_idl 2020. 1. 15. 23:01
728x90
반응형

이번 게시물의 제목을 "VOLUME 함수를 이용한 3차원 큐브 데이터의 가시화"라고 지어보았습니다. 말 그대로 3차원 큐브 형태의 구조를 갖는 데이터 배열이 있을 때, NG 체계의 VOLUME 함수를 이용하여 이 데이터를 3차원 볼륨의 형태로 가시화하는 과정에 관한 내용입니다. 사실 제가 이 블로그에서 VOLUME 함수에 관하여 소개했던 게시물들이 몇 개 있었습니다. 하지만 이번에는 단순한 가시화를 넘어서는 약간은 더 심화된 내용을 다뤄보고자 합니다. 아마도 2~3회 정도로 나누어 소개하게 될 것 같습니다.


먼저 이번에 사용할 예제 데이터를 먼저 다음과 같이 불러옵시다. 여기서 사용된 데이터 파일 jet.dat는 IDL 설치 디렉토리에 기본 제공되는 파일로서, 81x40x101의 구조를 갖는 3차원 큐브형 데이터를 담고 있는 바이너리(binary) 파일입니다. 따라서 이러한 바이너리 파일을 읽기 위해서 READ_BINARY 함수를 사용하였습니다.


file = FILEPATH('jet.dat', SUBDIR=['examples', 'data'])

data = READ_BINARY(file, DATA_DIMS=[81, 40, 101])

data = data/2B

HELP, data

PRINT, MIN(data), MAX(data)


여기서는 읽어온 데이터를 data라는 배열로 저장하였습니다. 다만 제가 설명을 위하여 이 데이터 배열에 대하여 약간의 추가 조정을 하였습니다. 원래 data 배열의 자료형은 바이트형이고 값 범위는 0~240이지만, 바이트형 값 2를 나눠주어서 값 범위가 0~120이 되도록 하였습니다. 물론 배열의 자료형은 여전히 바이트형입니다. 실제로 HELP 및 PRINT에 의하여 출력된 내용은 다음과 같습니다.


DATA            BYTE      = Array[81, 40, 101]

   0 120


그러면 일단 이 데이터를 3차원 볼륨의 형태로 가시화해봅시다. 이를 위하여 다음과 같이 NG 체계의 VOLUME 함수를 사용하였는데, 여기서는 RGB_TABLE0 및 ASPECT_RATIO 속성이 사용되었음에 주목해봅시다.


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

v = VOLUME(data, ASPECT_RATIO=1, RGB_TABLE0=34, /CURRENT)


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



먼저 RGB_TABLE0 속성은 볼륨 데이터를 구성하는 셀(복셀, voxel)마다의 값에 따라 색상을 입히는데 있어서 어떤 컬러테이블을 사용할 것인가를 설정하는 역할을 합니다. 속성의 이름이 RGB_TABLE이 아니라 RGB_TABLE0임에 유의해야 합니다. 여기서는 34번 컬러테이블을 사용하였습니다. 그리고 ASPECT_RATIO 속성의 값을 1로 설정하였는데, 이렇게 하면 X, Y, Z 각 방향의 범위에 따라 크기 스케일을 그대로 반영하게 됩니다. 이 데이터의 경우 Z축 방향 크기가 101으로 제일 길고 Y축 방향 크기가 40으로 가장 짧습니다. 이 스케일이 가시화에 있어서 그대로 반영되도록 한 것입니다. 만약 다음과 같이 이 속성을 사용하지 않고 그냥 표출할 경우에는 디폴트값인 0으로 처리가 되면서 원래 데이터 배열의 형태를 무시하고 그냥 그래픽창의 크기에 따라 적당히 표출하게 됩니다.


v = VOLUME(data, RGB_TABLE0=34, /CURRENT)



어차피 사용자의 판단의 문제가 되겠지만 여기서는 이후의 내용에서는 ASPECT_RATIO 값을 1로 설정하는 것으로 가겠습니다. 그러면 이제 VOLUME 함수로 표출된 모습에 주목해 봅시다. 기본적으로 VOLUME 함수에 의한 가시화에서는 큐브형 데이터 배열의 최소값부터 최대값의 범위에 대하여 컬러테이블의 모든 색상들을 사용하게 되어 있습니다. 방금 우리가 표출한 결과에서는 데이터 배열의 최소값인 0부터 최대값인 120까지의 범위에 대하여 34번 컬러테이블의 모든 색상들이 사용되었음을 일단 염두에 둡시다.


그러면 이제 볼륨 가시화에 있어서 불투명도(Opacity)의 개념을 좀 살펴보고자 합니다. 이것은 볼륨 데이터를 구성하는 각각의 복셀에 대하여 그 복셀이 얼마나 불투명하게 보이도록 할 것이냐를 정량화하는 개념으로서, 그 값은 완전투명(0)부터 완전불투명(255)까지의 범위 내에서 정량적인 값을 갖게 됩니다. 사실 볼륨 형태의 가시화에 있어서는 이 개념이 반드시 따라다니게 되어 있습니다. 그리고 이러한 불투명도의 처리 방식에 따라서 눈에 보이는 모습이 현저히 달라질 수 있습니다. 만약에 모든 복셀들이 완전불투명으로 처리가 될 경우에는 3차원 볼륨의 겉면에 해당되는 부분들만 눈에 보일 뿐 그 안쪽의 복셀들은 제대로 보이지 않을 것입니다. 그리고 반대로 모든 복셀들이 완전투명으로 처리가 될 경우에는 우리 눈에는 아무런 복셀들도 보이지 않을 것입니다.


* 물론 모든 복셀들이 완전불투명으로 처리된다고 해서 안쪽의 복셀들이 전혀 안보이지는 않습니다. 이것은 볼륨이라는 3차원 개체를 우리 눈이 바라보는 시선 방향에 존재하는 모든 복셀들의 값들을 어떤 식으로 계산하여 보여주느냐를 결정하는 블렌딩(Blending) 과정의 방식과 연관지어 생각해야 하는데 좀 복잡한 내용이어서 여기서는 생략합니다. 이와 관련해서는 IDL 도움말의 VOLUME 함수에 관한 내용에서 COMPOSITE_FUNCTION 속성에 대한 설명 부분을 참조하시기 바랍니다.


실제로 VOLUME 함수에 의한 가시화에서 불투명도의 처리에 있어서 어떤 값들이 사용되었는가를 직접 보는 방법이 있습니다. 앞서 생성된 볼륨 개체에 대하여 다음과 같이 OPACITY_TABLE0라는 속성의 정보를 추출하여 살펴보는 것입니다.


opa = v.OPACITY_TABLE0

HELP, opa

PRINT, opa


출력된 내용을 보면 다음과 같습니다.


OPA             BYTE      = Array[256]

   0   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  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59

  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89

  90  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119

 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179

 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209

 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239

 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255


즉 불투명도의 처리에 있어서는 256개의 바이트형 값들로 구성된 배열이 사용되었으며, 이 배열은 0부터 255까지 순차적으로 증가하는 값들로 구성되어 있다는 의미입니다. 그런데 불투명도가 왜 하필 이렇게 256개의 값들로 구성된 배열의 형태를 띄는 것일까요? 그것은 불투명도의 처리 단위가 배열 구조 기반이 아니라 배열 내 값 범위 기반이기 때문입니다. 이 얘기는 결국 3차원 데이터 배열 내 최소값부터 최대값까지를 0~255 범위의 256단계의 값들로 바이트스케일링을 하고, 각 단계별 값에 대한 불투명도(0~255) 값이 각각 지정되어 이러한 불투명도 값들 256개로 구성된 배열이 바로 볼륨 가시화의 불투명도 배열 정보로 사용된다는 것입니다. 위에서 opa라는 이름으로 가져온 정보가 그것이며, 이것이 바로 볼륨 가시화에 있어서 불투명도 처리의 디폴트 방식입니다. 이 값들을 보면 3차원 데이터 배열 내에서 작은 값들일수록 불투명도가 낮으며 높은 값들일수록 불투명도가 높습니다. 즉 최소값으로 갈수록 투명하게 처리되고 최대값으로 갈수록 불투명하게 처리되는 방식이 바로 볼륨 가시화에 있어서 기본적인 디폴트 처리 방식이라는 얘기입니다. 지금의 예제에서 사용중인 34번 컬러테이블에서는 낮은 데이터 값이 주로 푸른색 계열이고 높은 데이터 값은 주로 붉은색 계열로 표시되기 때문에, 적어도 이번 예제들에서의 가시화에 있어서는 푸른색 계열의 복셀들은 비교적 투명하게 그리고 붉은색 계열의 복셀들은 비교적 불투명하게 표시되었다고 보면 됩니다. 아마 위의 가시화 그림들을 보면 보면 그러한 느낌을 받게 될 것입니다.


그런데 이러한 불투명도 처리 방식은 디폴트 방식을 따르는 대신 사용자가 직접 커스터마이즈할 수도 있습니다. 그러기 위해서는 불투명도 값들로 구성된 배열을 내가 직접 만들어서 사용하면 됩니다. 어차피 256개의 바이트형 값들로 구성된 배열이면 되기 때문에, 내가 원하는 형태로 배열을 직접 만들면 됩니다. 예를 들어서 낮은 데이터 값들만 주로 보이도록 하고 그 외의 값들은 아예 안보이도록 하고 싶다면 다음과 같이 처리해 볼 수 있습니다.


opa = BYTARR(256)

opa[0:50] = 255B

v = VOLUME(data, ASPECT_RATIO=1, RGB_TABLE0=34, OPACITY_TABLE0=opa, /CURRENT)


여기서는 바이트 스케일 기준으로 0~50 범위에 대해서는 완전 불투명(255)으로 처리하고 50보다 큰 범위에 대해서는 완전 투명(0)으로 처리되도록 하는 불투명도 배열 opa를 직접 생성하여, 이 배열을 VOLUME 함수의 OPACITY_TABLE0 속성에 부여하였습니다. 실제로 배열 opa를 구성하는 값들을 모두 출력해보면 다음과 같습니다.


 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255

 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0


그리고 표출된 결과는 다음 그림과 같습니다.



이번에는 반대로 높은 데이터 값들만 주로 보이도록 하고 그 외의 값들은 아예 안보이도록 하는 경우를 생각해본다면 다음과 같이 처리해 볼 수 있습니다.


opa = BYTARR(256)

opa[180:255] = 255B

v = VOLUME(data, ASPECT_RATIO=1, RGB_TABLE0=34, OPACITY_TABLE0=opa, /CURRENT)


여기서는 바이트 스케일 기준으로 180~255 범위에 대해서는 완전 불투명(255)으로 처리하고 180보다 작은 범위에 대해서는 완전 투명(0)으로 처리되도록 하는 불투명도 배열 opa를 직접 생성하여, 이 배열을 VOLUME 함수의 OPACITY_TABLE0 속성에 부여하였습니다. 실제로 배열 opa를 구성하는 값들을 모두 출력해보면 다음과 같습니다.


   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0

 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255

 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255

 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255


그리고 표출된 결과는 다음 그림과 같습니다.



만약 중간 정도의 범위의 데이터 값들만 주로 보이도록 하고 그 외의 값들은 아예 안보이도록 하고 싶다면 다음과 같이 처리해 볼 수 있습니다.


opa = BYTARR(256)

opa[140:180] = 255B

v = VOLUME(data, ASPECT_RATIO=1, RGB_TABLE0=34, OPACITY_TABLE0=opa, /CURRENT)


여기서는 바이트 스케일 기준으로 140~180 범위에 대해서는 완전 불투명(255)으로 처리하고 그 이외의 범위에 대해서는 완전 투명(0)으로 처리되도록 하는 불투명도 배열 opa를 직접 생성하여, 이 배열을 VOLUME 함수의 OPACITY_TABLE0 속성에 부여하였습니다. 이렇게 하여 표출된 결과는 다음 그림과 같습니다.



그리고 불투명도 배열에서 255로 지정되는 값의 범위를 훨씬 더 좁히면 특정한 좁은 범위의 값 또는 아예 특정한 값에 해당되는 복셀들만 보이도록 할 수도 있게 됩니다.


opa = BYTARR(256)

opa[127] = 255B

v = VOLUME(data, ASPECT_RATIO=1, RGB_TABLE0=34, OPACITY_TABLE0=opa, /CURRENT)


여기서는 바이트 스케일 기준으로 127에 대해서만 완전 불투명(255)으로 처리하고 그 이외에는 모두 완전 투명(0)으로 처리되도록 하는 불투명도 배열 opa를 직접 생성하여, 이 배열을 VOLUME 함수의 OPACITY_TABLE0 속성에 부여하였습니다. 이렇게 하면 값이 127인 복셀들만 보게 되는 효과가 있습니다. 표출된 결과는 다음 그림과 같습니다.



이와 같이 불투명도 배열을 다양한 형태로 구성함으로써 관심 범위의 복셀들만 강조하는 방식의 가시화가 가능합니다. 다만 위의 예제들에서 한가지 유의해야 할 것은, 불투명도 배열 opa 내에서 255B라는 값이 대입된 배열 인덱스의 위치입니다. 배열 opa를 구성하는 256개의 값들은 표출 그림에서는 원본 3차원 데이터의 최소값부터 최대값까지 범위를 256 단계로 바이트 스케일링한 범위에 대응됩니다. 우리가 이미 초반에서 보았듯이 원본 3차원 데이터의 값 범위는 0~120입니다. 이 원본 데이터 값 범위를 바이트 스케일의 범위 0~255와 서로 대응시켜서 생각해야 합니다. 따라서 바로 위의 예제에서 opa[127]의 값을 255B로 설정한 것은 원본 데이터 범위로 환산해서 생각한다면 0~120의 중간쯤인 60 정도의 값에 해당되는 복셀들만 표시하는 것과 마찬가지가 될 것입니다. 이와 같이 원본 데이터의 값 범위와 바이트 스케일링된 불투명도 값 범위와는 서로 별개임을 인지하는 것이 필요합니다. 특히나 원본 데이터 값들의 자료형이 바이트형이 아닌 정수형 또는 실수형인 경우들도 있기 때문에, 이러한 특성을 잘 감안해야 할 것입니다.


그러면 오늘 얘기는 여기까지 하기로 하고 다음 회차에서는 볼륨 가시화와 관련된 또 다른 내용을 이어서 소개하도록 하겠습니다.

반응형