앞선 메디컬 이미지 개념 정리에서 포맷 차이를 봤다면, 이번에는 DICOM 폴더를 실제로 읽고 NIfTI로 변환한 뒤 3D 볼륨 슬라이스를 GIF로 확인하는 흐름을 실습해본다. 핵심은 DICOM 스택 확인 → NIfTI 변환 → 축 전환(transpose) → 애니메이션 시각화 순서다.
이번 글에서는 제공된 노트북 코드를 그대로 기준으로, 실행 흐름이 끊기지 않게 단계별로 정리한다.
1. 데이터 압축 해제 및 라이브러리 설치
!unzip -q '/content/drive/MyDrive/랭체인 AI 영상객체탐지분석 플랫폼 구축/14. 메디컬 이미지/data/brain_images.zip'
!pip install scikit-image
!pip install natsort
!pip install pydicom
import matplotlib.pyplot as plt
import pydicom
import numpy as np
from skimage.util import montage
from natsort import natsorted
from pathlib import Path
2. DICOM 슬라이스 로드 및 montage 시각화
BASE_PATH = Path('/content/brain_images/00825/T2w')
dicom_images = natsorted(list(BASE_PATH.glob('*.dcm')))
print(f'이미지의 총 개수: {len(dicom_images)}')
concat_images = np.array([pydicom.dcmread(i).pixel_array for i in dicom_images])
plt.figure(figsize=(10, 10))
# 여러 장의 2D 슬라이스를 3행 15열 격자로 붙여서 한 장으로 표시
plt.imshow(montage(concat_images, grid_shape=(3, 15)), cmap='bone')
여기서 montage는 폴더 안 슬라이스가 정상적으로 읽혔는지 빠르게 품질 점검할 때 유용하다.
3. DICOM → NIfTI 변환
!pip install nibabel
!pip install dicom2nifti
import dicom2nifti
import nibabel as nib
# .nii.gz 생성
dicom2nifti.convert_directory('/content/brain_images/00825/T2w', './')
nifiti_path = '/content/8_t2w.nii.gz'
sample_img = nib.load(nifiti_path)
sample_img = np.asanyarray(sample_img.dataobj)
print(f'nifti file shape: {sample_img.shape}') # (height, width, depth)
transpose_img = sample_img.transpose((2, 1, 0))
transpose_img.shape
transpose((2, 1, 0))는 축 순서를 바꿔 슬라이스 탐색 방향을 맞출 때 자주 쓰는 전처리다.
4. 두 번째 볼륨도 동일하게 변환
dicom2nifti.convert_directory('/content/brain_images/00829/T2w', './')
nifiti_path2 = '/content/501_t2w.nii.gz'
sample_img2 = nib.load(nifiti_path2)
sample_img2 = np.asanyarray(sample_img2.dataobj)
transpose_img2 = sample_img2.transpose((2, 1, 0))
transpose_img2.shape
5. 3D 슬라이스를 GIF로 저장하는 클래스
import matplotlib.animation as anim
from IPython.display import Image as show_gif
class ImageToGIF:
def __init__(self, size=(500, 500), xy_text=(80, 30), dpi=100, cmap='CMRmap'):
self.fig = plt.figure()
self.fig.set_size_inches(size[0] / dpi, size[1] / dpi)
self.xy_text = xy_text
self.cmap = cmap
# [left, bottom, width, height]
self.ax = self.fig.add_axes([0, 0, 1, 1])
self.ax.set_xticks([])
self.ax.set_yticks([])
self.images = []
def add(self, image, label, with_mask=False):
plt.set_cmap(self.cmap)
plt_img = self.ax.imshow(image, animated=True)
plt_text = self.ax.text(*self.xy_text, label, color='red')
to_plot = [plt_img, plt_text]
self.images.append(to_plot)
plt.close()
def save(self, filename, fps):
animation = anim.ArtistAnimation(self.fig, self.images)
animation.save(filename, writer='imagemagick', fps=fps)
6. 첫 번째 볼륨 GIF 생성
sample_data_gif = ImageToGIF()
label = nifiti_path.replace("/", ".").split('.')[-2]
filename = f'{label}_3d_2d.gif'
for i in range(transpose_img.shape[0]):
image = transpose_img[i]
sample_data_gif.add(image, label=f'{label}_{str(i)}')
sample_data_gif.save(filename, fps=15)
show_gif(filename, format='png')
7. 다른 축 방향으로 슬라이스 GIF 생성
첫 번째 축이 아니라 세 번째 축 방향으로 순회하면 다른 단면을 볼 수 있다. MRI 볼륨은 축 방향에 따라 보이는 해부학적 단면이 달라진다.
sample_data_gif2 = ImageToGIF()
label = nifiti_path.replace("/", ".").split('.')[-2]
filename = f'{label}_3d_2d_2.gif'
for i in range(transpose_img2.shape[2]):
image = transpose_img2[:, :, i]
sample_data_gif2.add(image, label=f'{label}_{str(i)}')
sample_data_gif2.save(filename, fps=15)
show_gif(filename, format='png')
8. 180도 회전 후 GIF 생성
np.rot90(..., k=2)를 쓰면 90도를 두 번 적용해 총 180도 회전시킬 수 있다.
sample_data_gif2 = ImageToGIF()
label2 = nifiti_path.replace("/", ".").split('.')[-2]
filename2 = f'{label2}_3d_2d_2.gif'
for i in range(transpose_img2.shape[2]):
# rot90: 90도 회전 함수
# k=2: 90도 2번 -> 총 180도 회전
# axes=(1,0): 1번 축과 0번 축 기준 회전
image = np.rot90(transpose_img2[..., i], k=2, axes=(1, 0))
sample_data_gif2.add(image, label=f'{label}_{str(i)}')
sample_data_gif2.save(filename2, fps=15)
show_gif(filename2, format='png')
마치며
- DICOM 폴더 단위 데이터를 먼저 montage로 확인하면 데이터 품질 점검이 빠르다.
dicom2nifti+nibabel조합으로 DICOM 스택을 NIfTI 볼륨으로 변환해 딥러닝 파이프라인에 쉽게 연결할 수 있다.transpose와rot90는 단면 방향/표시 방향을 맞추는 데 핵심 전처리다.- 다음에는 이 볼륨 데이터를 기준으로 3D 세그멘테이션 입력 텐서 구성과 증강 파이프라인까지 이어서 정리해보면 좋다.
'AI·머신러닝 > 딥러닝·비전' 카테고리의 다른 글
| 의료영상 신호처리와 MONAI - Spatial·Frequency, X-ray·CT·MRI, 전처리 실습 (0) | 2026.04.23 |
|---|---|
| 병리 WSI 실습 - OpenSlide, read_region, 피라미드 레벨 (0) | 2026.04.23 |
| 메디컬 이미지 - 일반 이미지 차이, DICOM·NIfTI·WSI, pydicom 실습 (0) | 2026.04.20 |
| 오토인코더 - 개념, MNIST·CIFAR10 구현, Denoising과 유사 이미지 탐색 (0) | 2026.02.04 |
| WLASL 수화 인식 실습 - VideoDataset, R3D, 학습과 추론 (0) | 2026.02.03 |