Post

PMCT ① — 사후 CT 500건을 분할 가능한 데이터로 만들기

PMCT ① — 사후 CT 500건을 분할 가능한 데이터로 만들기

박사 과정 연구 주제로 사후 CT(PMCT, Postmortem CT)를 다루기 시작했습니다. 외상으로 사망한 사람의 CT에서 뼈가 부러진 곳을 자동으로 찾아 증거 수집을 돕는 것이 목표입니다. 이 글은 그 첫 단계로, 원본 DICOM 압축 파일 500건을 학습과 분석에 쓸 수 있는 NIfTI 영상과 뼈 마스크로 만든 과정과 현재 상태를 정리한 것입니다.

사용한 데이터는 NMDID(New Mexico Decedent Image Database)의 사후 CT입니다. 데이터 사용 조건을 확인하기 전이라 이 글에는 CT 영상을 싣지 않습니다.

데이터: 외상 사망 500건

500건 모두 사인 기록이 같습니다. “Multiple injuries (fractures, lacerations to internal organs)”, 즉 골절과 장기 열상을 동반한 다발성 손상입니다. 사망의 종류와 기전으로 나누면 이렇습니다.

사망의 종류세부 분류 (건수)합계
사고사차량탑승 225 · 보행자 102 · 추락 51 · 오토바이 36 · 항공기 12 · 기타 9 · 자전거 5 · 열차 4 · 동물 1445
타살둔력손상 21 · 미상 6 · 소아 4 · 총상 2 · 예기손상 1 · 차량 135
자살 10
미상 7
자연사 1

CT 영상이 있는 498건 기준이고, 나머지 2건은 위치 확인용 SCOUT 영상만 있었습니다. 사고사, 특히 교통사고가 대부분이고 나머지 분류는 표본이 매우 적다는 점을 이후 분석에서 계속 고려해야 합니다.

1. 압축 해제와 변환: 1.68TB를 USB HDD에서

원본은 케이스당 zip 하나, 평균 3.4GB, 합계 1.68TB였습니다. DICOM은 거의 압축이 되지 않아서 풀면 크기가 비슷하고, 케이스 하나가 파일 약 14,500개, 시리즈 약 30개입니다.

처음에는 같은 USB HDD에서 바로 풀었는데 케이스 하나 푸는 데 11분이 걸렸습니다. 같은 디스크에서 읽기와 쓰기를 동시에 하면 헤드 탐색이 늘어나고, exFAT은 파일마다 ._ 메타파일을 하나씩 더 만들기 때문입니다. 압축 해제와 변환을 내장 SSD 임시 폴더로 옮기자 1분 30초로 줄었습니다.

단계방식케이스당 시간
압축 해제 (HDD → HDD)처음 방식약 11분
압축 해제 (HDD → SSD)바꾼 방식약 1.5분
DICOM → NIfTI (dcm2niix)SSD약 1분

케이스 4개를 병렬로 처리해서 500건 전체에 약 23시간이 걸렸습니다. 변환이 확인된 케이스부터 DICOM과 zip을 지워서 디스크 여유 공간을 유지했습니다.

dcm2niix의 -i y 옵션은 쓰지 않았습니다. 이 옵션은 DERIVED로 표시된 영상을 건너뛰는데, 그러면 COR/SAG 재구성이 모두 빠져서 시리즈가 35개에서 11개로 줄어듭니다.

손상된 zip 9건

9건은 zip 자체가 손상돼 있었습니다. 손상 유형은 두 가지였습니다.

  • 일부 파일의 압축 데이터가 깨진 경우 (6건): unzip -t로 손상 파일을 찾아서 빼고 나머지만 풀었습니다.
  • zip 목차(central directory)의 위치 정보가 어긋난 경우 (3건): unzip과 bsdtar 모두 첫 오류에서 멈췄습니다. zip -FF로 파일 전체에서 로컬 헤더를 스캔해 zip을 다시 만드는 방식은 통했고, 파일의 99.9%를 되살렸습니다.

9건 모두 빠진 파일은 1% 안팎이고, 각 케이스에서 시리즈 하나에만 몰려 있었습니다. 결국 500건 전부 NIfTI가 생겼고, 부분 복구한 9건은 빠진 파일 목록을 함께 남겼습니다.

2. 시리즈 구성: 몸을 네 번 나눠 찍는다

이 프로토콜은 전신을 한 번에 찍지 않고, 부위별로 여러 번 촬영한 뒤 각 촬영을 여러 커널로 재구성합니다.

부위대표 시리즈범위비고
머리THIN_BONE_HEAD약 37cm픽셀 0.5mm로 가장 정밀함
머리 + 목 + 상지THIN_BN_H_N_UEXT약 65~71cm 
몸통THIN_BONE_TORSO약 80cm늑골, 척추, 골반
하지THIN_BONE_L-EXT약 80~94cm골반부터 발끝까지
  • 부위마다 ST(연부조직), BONE(뼈), LUNG(폐) 커널이 있고, 0.5mm 박층(THIN), 3mm 두께(3X3), COR/SAG 재구성이 함께 있습니다.
  • 시리즈 이름은 병원 쪽 표기가 조금씩 달라서 이름이 정확히 같은 시리즈 중 모든 케이스에 있는 것은 없습니다. 예를 들어 THIN_BONE_L-EXT와 THIN_BN_L-EXT, THIN_ST_TORSO와 THIN_S.T._TORSO는 같은 시리즈입니다. 커널과 부위로 묶어야 비교할 수 있습니다.
  • 촬영마다 좌표계가 같다는 보장이 없습니다. 몸통과 하지는 좌표가 그대로 이어져서 바로 붙일 수 있었습니다. 반면 머리·목·상지 촬영은 몸통과 약 28cm 어긋나 있어서, 두 촬영에 함께 담긴 척추 45개의 중심을 맞춰 정렬했습니다. 처음에는 두 촬영에 일부씩만 걸친 대퇴골까지 정렬 기준에 넣었다가 다리가 골반을 뚫고 올라가는 실수를 했습니다. 그 뒤로는 뼈 전체가 양쪽에 담긴 레이블이 3개 이상이고 이동값이 서로 일치할 때만 정렬합니다.

3. 뼈 마스크: TotalSegmentator + WholeBody 모델

분할에는 모델 두 개를 썼습니다.

모델출력비고
TotalSegmentator 2.11 (total 중 뼈만)뼈 63개: 척추 C1~S1, 천골, 늑골 24개, 흉골, 늑연골, 견갑골, 쇄골, 상완골, 골반, 대퇴골, 두개골--roi_subset으로 필요한 하위 모델만 실행
nnU-Net 전신 모델 (자체 학습, Dataset600)7개 클래스클래스 2가 뼈 전체

근육을 걷어내기

TotalSegmentator total의 근육 하위 모델에는 상완골이나 대퇴골 같은 뼈와 함께 둔근, 척추기립근, 장요근이 들어 있습니다. 근육 레이블을 거르기 전에 각 레이블이 WholeBody 모델의 뼈 클래스와 얼마나 겹치는지 재봤습니다.

레이블 묶음뼈 클래스와 겹침
근육 10개 (둔근 대·중·소, 척추기립근, 장요근)0 ~ 0.6%
뼈 (늑연골이 가장 낮음)66 ~ 99%

두 묶음이 깔끔하게 갈려서, 근육 10개는 이름을 기준으로 제거했습니다. 겹침 비율만 기준으로 잡으면 다리 시리즈의 skull 같은 작은 오검출 조각도 함께 지워지는데, 이번에는 뼈 레이블을 모두 남겨 두었습니다.

속도와 운영

  • 학습과 GPU를 같이 쓰는 RTX A6000 2장에서, 케이스 하나에 THIN 시리즈 약 9개를 처리하는 데 35~40분이 걸립니다.
  • nnU-Net의 TTA(반전 앙상블)를 끄면 nnU-Net 단계가 크게 빨라집니다. TotalSegmentator는 코드에서 TTA가 항상 꺼져 있습니다.
  • 데이터는 USB 디스크에 있고 GPU 서버는 VPN 너머에 있어서, 케이스마다 이미지를 올리고 추론한 뒤 마스크만 받아오는 방식으로 돌립니다. 이미지 업로드는 2~7분 걸립니다.

현재 상태

단계상태
DICOM → NIfTI500건 완료 (부분 복구 9건 포함)
경우별 3건씩, 45건뼈 마스크와 WholeBody 마스크 완료
전체 498건진행 중 (57건 완료)

지금 확인된 한계

  • 다리 아래쪽 뼈 마스크가 없습니다. TotalSegmentator total은 대퇴골까지만 나눕니다. 정강뼈, 종아리뼈, 무릎뼈, 발뼈는 appendicular_bones 모델에 있는데, 이 모델은 라이선스가 필요합니다. 추락과 교통사고에서 다리 골절이 흔해서 꼭 채워야 할 부분입니다.
  • 골절 위치 정답이 없습니다. 500건의 사인 기록이 모두 같고, 어느 뼈가 부러졌는지는 적혀 있지 않습니다. 병력 테이블의 “Broken Bone”은 생전에 있었던 골절이라 정답으로 쓸 수 없습니다.
  • 모델이 사후 CT로 학습된 것이 아닙니다. 생존자 CT로 학습한 모델이라 부패 가스나 혈액 침하 같은 사후 변화에서 오분할이 생길 수 있습니다. 뼈는 연부조직보다 사후 변화가 적어서 영향이 비교적 작을 것으로 기대합니다.

다음 글에서는 이 마스크를 바탕으로 골절을 찾는 연구 계획을 정리합니다.

This post is licensed under CC BY 4.0 by the author.