๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ–ฑ๏ธ ๊ธฐ์ˆ  ๊ฒ€ํ† 

[React] Cornerstone3D์—์„œ NIfTI๋ฅผ ์“ด๋‹ค๋ฉด? 1024×1024 ํ•ด์ƒ๋„๊นŒ์ง€

Cornerstone3D NIfTI ๊ธฐ์ˆ ๊ฒ€ํ† 
๊ธฐ์ˆ  ๊ฒ€ํ†  (Tech Review)

Cornerstone3D์—์„œ NIfTI๋ฅผ ์“ด๋‹ค๋ฉด?
1024ร—1024 ํ•ด์ƒ๋„๊นŒ์ง€

DICOM ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์—†์ด NIfTI ํŒŒ์ผ์„ Cornerstone3D์— ๋กœ๋“œํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๊ตฌ์กฐ์  ์ฐจ์ด, ์ œ์•ฝ์‚ฌํ•ญ, ๊ทธ๋ฆฌ๊ณ  1024ร—1024 ๊ณ ํ•ด์ƒ๋„ ๋กœ๋“œ ์‹œ ์˜ˆ์ƒ๋˜๋Š” ๋ฌธ์ œ๋ฅผ ๊ธฐ์ˆ ์ ์œผ๋กœ ๊ฒ€ํ† ํ•ฉ๋‹ˆ๋‹ค.

NIfTI vs DICOM ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ถ€์žฌ ์ขŒํ‘œ๊ณ„ ์ถฉ๋Œ 1024ร—1024 ๋ฉ”๋ชจ๋ฆฌ GPU ํ…์Šค์ฒ˜ ํ•œ๊ณ„ WebGL OOM
01 ยท Background

์™œ ์ด ๊ฒ€ํ† ๊ฐ€ ํ•„์š”ํ•œ๊ฐ€

Cornerstone3D๋Š” DICOM์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๊ณ„๋œ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. ๋‚ด๋ถ€ ๋ Œ๋”๋ง ํŒŒ์ดํ”„๋ผ์ธ, ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์‹œ์Šคํ…œ, ์ธก์ • ๋„๊ตฌ, ์–ด๋…ธํ…Œ์ด์…˜ ์ €์žฅ ๋ชจ๋‘ DICOM ํƒœ๊ทธ ๊ตฌ์กฐ๋ฅผ ์ „์ œ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ AI ์ถ”๋ก  ๊ฒฐ๊ณผ๋ฌผ, ์—ฐ๊ตฌ์šฉ ๋ฐ์ดํ„ฐ, ๋‡Œ์˜์ƒ ๋ถ„์„ ๋“ฑ ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ DICOM์ด ์•„๋‹Œ NIfTI(.nii, .nii.gz) ํฌ๋งท์„ Cornerstone3D๋กœ ๋ Œ๋”๋งํ•ด์•ผ ํ•˜๋Š” ์š”๊ตฌ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— 1024ร—1024 ํ•ด์ƒ๋„๋ผ๋Š” ์กฐ๊ฑด์ด ์ถ”๊ฐ€๋˜๋ฉด, ์ผ๋ฐ˜ CT ํ‘œ์ค€(512ร—512)์˜ 4๋ฐฐ ํ”ฝ์…€ ์ˆ˜๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์™€ GPU ํ…์Šค์ฒ˜์— ์–ด๋–ค ์••๋ฐ•์„ ์ฃผ๋Š”์ง€๋„ ํ•จ๊ป˜ ๋ถ„์„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธ€์€ ํ•ด๋‹น ์กฐํ•ฉ์ด ์‹ค์ œ ํ”„๋กœ๋•์…˜์—์„œ ์–ด๋–ค ๋ฆฌ์Šคํฌ๋ฅผ ๋‚ดํฌํ•˜๋Š”์ง€ ๊ธฐ์ˆ ์ ์œผ๋กœ ์ ๊ฒ€ํ•ฉ๋‹ˆ๋‹ค.

4ร—
512โ†’1024 ํ”ฝ์…€ ์ฆ๊ฐ€
2GB+
Float32 ๋ณผ๋ฅจ ์˜ˆ์ƒ ๋ฉ”๋ชจ๋ฆฌ
์—†์Œ
ํ™˜์ž ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
RASโ†”LPS
์ขŒํ‘œ๊ณ„ ์ถฉ๋Œ ์œ„ํ—˜
02 ยท Format Difference

NIfTI์™€ DICOM โ€” ๊ตฌ์กฐ์  ์ฐจ์ด

๋‘ ํฌ๋งท์€ ์„ค๊ณ„ ์ฒ ํ•™์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค. DICOM์€ ์ž„์ƒ ํ™˜๊ฒฝ์˜ ๋ชจ๋“  ์ •๋ณด๋ฅผ ๋‹ด๋Š” ํฌ๊ด„์  ํ‘œ์ค€์ด๊ณ , NIfTI๋Š” ์‹ ๊ฒฝ์˜์ƒ ์—ฐ๊ตฌ์ž๋ฅผ ์œ„ํ•œ ๋ฏธ๋‹ˆ๋ฉ€ํ•œ ํฌ๋งท์ž…๋‹ˆ๋‹ค. Cornerstone3D๊ฐ€ ์ „์ œํ•˜๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์˜ ์ƒ๋‹น์ˆ˜๊ฐ€ NIfTI์—๋Š” ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํ•ญ๋ชฉDICOMNIfTICornerstone3D ์˜ํ–ฅ
ํŒŒ์ผ ๊ตฌ์กฐ์Šฌ๋ผ์ด์Šค๋‹น 1๊ฐœ ํŒŒ์ผ๋ณผ๋ฅจ ์ „์ฒด 1๊ฐœ ํŒŒ์ผImageId ์ƒ์„ฑ ๋ฐฉ์‹ ์ƒ์ด
ํ™˜์ž ์ •๋ณดPatientName, PatientID, StudyDate ๋“ฑ์—†์Œ๋ทฐํฌํŠธ ์˜ค๋ฒ„๋ ˆ์ด ํ‘œ์‹œ ๋ถˆ๊ฐ€
๋ชจ๋‹ฌ๋ฆฌํ‹ฐCT, MR, PET ๋“ฑ ๋ช…์‹œ์—†์Œ์ž๋™ W/L ํ”„๋ฆฌ์…‹ ์ ์šฉ ๋ถˆ๊ฐ€
Window/LevelWindowCenter, WindowWidth ํƒœ๊ทธ์—†์Œ์ง์ ‘ ๊ณ„์‚ฐํ•ด์„œ ์ฃผ์ž… ํ•„์š”
์ขŒํ‘œ๊ณ„LPS (Left-Posterior-Superior)RAS (Right-Anterior-Superior)์ถ• ๋ฐ˜์ „ ์—†์œผ๋ฉด ์ขŒ์šฐ ๋’ค์ง‘ํž˜
Spacing/OriginPixelSpacing, ImagePositionpixdim, sform/qform ํ–‰๋ ฌ๋ณ€ํ™˜ ์ฒ˜๋ฆฌ ํ•„์š”
์Šฌ๋ผ์ด์Šค ์ˆœ์„œSliceLocation์œผ๋กœ ๋ช…์‹œ๋ฐฐ์—ด ์ˆœ์„œ ์˜์กดMPR ๋ฐฉํ–ฅ ์˜ค๋ฅ˜ ๊ฐ€๋Šฅ์„ฑ
์••์ถ•HTJ2K, JPEG2K ๋“ฑ (Progressive ์ง€์›)gzip ์ „์ฒด ์••์ถ•๋งŒProgressive Loading ๋ถˆ๊ฐ€
์ธก์ •๊ฐ’ ์ €์žฅDICOM SR ํ‘œ์ค€ ํ˜•์‹์—†์Œ์–ด๋…ธํ…Œ์ด์…˜ ํ‘œ์ค€ ์ €์žฅ ๋ถˆ๊ฐ€
์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜DICOM SEG ํ‘œ์ค€๋ณ„๋„ .nii ํŒŒ์ผCS3D SEG ์–ด๋Œ‘ํ„ฐ ์—ฐ๋™ ๋ถˆ๊ฐ€
03 ยท Coordinate System

์ขŒํ‘œ๊ณ„ ์ถฉ๋Œ โ€” RAS vs LPS

๊ฐ€์žฅ ๋จผ์ € ๋งˆ์ฃผ์น˜๋Š” ๊ธฐ์ˆ ์  ํ•จ์ •์ž…๋‹ˆ๋‹ค. DICOM์€ LPS(Left-Posterior-Superior), NIfTI๋Š” RAS(Right-Anterior-Superior)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. X์ถ•๊ณผ Y์ถ• ๋ฐฉํ–ฅ์ด ์ •๋ฐ˜๋Œ€์—ฌ์„œ, ๋ณ€ํ™˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ์•Š์œผ๋ฉด ๋ทฐํฌํŠธ์—์„œ ์ด๋ฏธ์ง€๊ฐ€ ์ขŒ์šฐยท์ „ํ›„ ๋ฐ˜์ „๋˜์–ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

DICOM โ€” LPS ์ขŒํ‘œ๊ณ„ +X Left(ํ™˜์ž ์™ผ์ชฝ) +Z Superior(์œ„) +Y Posterior(๋’ค) Cornerstone3D ๋‚ด๋ถ€ ๊ธฐ์ค€ ImageOrientationPatient ยท ImagePositionPatient ํƒœ๊ทธ๋กœ ๊ฒฐ์ • NIfTI โ€” RAS ์ขŒํ‘œ๊ณ„ +X Right(ํ™˜์ž ์˜ค๋ฅธ์ชฝ) +Z Superior(์œ„) +Y Anterior(์•ž) sform / qform ํ–‰๋ ฌ๋กœ ๊ฒฐ์ • X, Y์ถ• ๋ฐฉํ–ฅ์ด LPS์™€ ์ •๋ฐ˜๋Œ€ โ‰  XยทY ๋ฐ˜์ „
๐Ÿšจ ์ขŒํ‘œ๊ณ„ ๋ณ€ํ™˜ ์—†์ด NIfTI๋ฅผ ๊ทธ๋Œ€๋กœ ๋กœ๋“œํ•˜๋ฉด Axial ๋ทฐ์—์„œ ํ™˜์ž์˜ ์™ผ์ชฝ/์˜ค๋ฅธ์ชฝ์ด ๋’ค์ง‘ํ˜€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ž„์ƒ ํŒ๋… ํ™˜๊ฒฝ์—์„œ๋Š” ์น˜๋ช…์  ์˜ค๋ฅ˜์ž…๋‹ˆ๋‹ค. nifti-volume-loader๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ sform/qform ํ–‰๋ ฌ๋กœ ๋ณ€ํ™˜์„ ์ฒ˜๋ฆฌํ•˜์ง€๋งŒ, ์ปค์Šคํ…€ ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑ ์‹œ ๋ฐ˜๋“œ์‹œ ์ง์ ‘ ๊ฒ€์ฆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Cornerstone3D์˜ @cornerstonejs/nifti-volume-loader๋Š” v2.0๋ถ€ํ„ฐ sform/qform ํ–‰๋ ฌ์„ ์ฝ์–ด LPS๋กœ ์ž๋™ ๋ณ€ํ™˜์„ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ๋‹จ, ๋น„ํ‘œ์ค€์ ์œผ๋กœ ์ƒ์„ฑ๋œ NIfTI ํŒŒ์ผ์€ sform_code๊ฐ€ 0์ด๊ฑฐ๋‚˜ ํ–‰๋ ฌ์ด ์ž˜๋ชป ์„ค์ •๋œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด ์ˆ˜๋™ ๊ฒ€์ฆ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

04 ยท Missing Metadata

๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๋ถ€์žฌ๊ฐ€ ๋งŒ๋“œ๋Š” ๊ธฐ๋Šฅ ๊ณต๋ฐฑ

DICOM์˜ ์ˆ˜๋ฐฑ ๊ฐœ ํƒœ๊ทธ์™€ ๋‹ฌ๋ฆฌ NIfTI ํ—ค๋”๋Š” ๊ณต๊ฐ„ ์ •๋ณด(spacing, origin, direction)์™€ ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ •๋„๋งŒ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. Cornerstone3D๊ฐ€ DICOM ํƒœ๊ทธ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์ด ํ•˜๋‚˜์”ฉ ๋ฌด๋„ˆ์ง‘๋‹ˆ๋‹ค.

โœ—
Window/Level ์ž๋™ ์„ค์ • ๋ถˆ๊ฐ€
DICOM์˜ WindowCenter/WindowWidth ํƒœ๊ทธ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. CT๋Š” Hounsfield Unit ๊ธฐ๋ฐ˜ ํ”„๋ฆฌ์…‹(ํ ์ฐฝ, ๋ผˆ ์ฐฝ ๋“ฑ)์ด ์ž๋™ ์ ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ ๋ฒ”์œ„๋ฅผ ์ง์ ‘ ๋ถ„์„ํ•ด ์ˆ˜๋™์œผ๋กœ W/L์„ ๊ณ„์‚ฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
โœ—
๋ทฐํฌํŠธ ํ™˜์ž ์ •๋ณด ์˜ค๋ฒ„๋ ˆ์ด ํ‘œ์‹œ ๋ถˆ๊ฐ€
PatientName, StudyDate, Modality, SeriesDescription ๋“ฑ ์ž„์ƒ ์‹๋ณ„ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋ทฐํฌํŠธ ์ฝ”๋„ˆ ์˜ค๋ฒ„๋ ˆ์ด(์™ผ์ชฝ ์ƒ๋‹จ ํ™˜์ž๋ช… ๋“ฑ)๊ฐ€ ๋ชจ๋‘ ๊ณต๋ฐฑ์œผ๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
โœ—
์ธก์ • ์–ด๋…ธํ…Œ์ด์…˜ DICOM SR ์ €์žฅ ๋ถˆ๊ฐ€
Ruler, ROI ์ธก์ •๊ฐ’์„ DICOM SR(Structured Report) ํ˜•์‹์œผ๋กœ ์ €์žฅํ•˜๋Š” Cornerstone3D Adapters ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ณ„๋„ ํฌ๋งท(JSON ๋“ฑ)์œผ๋กœ ์ž์ฒด ๊ด€๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
!
๋ชจ๋‹ฌ๋ฆฌํ‹ฐ๋ณ„ ๊ธฐ๋Šฅ ์ž๋™ ์ ์šฉ ์•ˆ ๋จ
PET SUV ๊ณ„์‚ฐ, CT HU ๋‹จ์œ„ ํ‘œ์‹œ, MR ๊ฐ•๋„ ์ •๊ทœํ™” ๋“ฑ ๋ชจ๋‹ฌ๋ฆฌํ‹ฐ ํŠนํ™” ๊ธฐ๋Šฅ์€ DICOM ํƒœ๊ทธ(RescaleSlope, RescaleIntercept ๋“ฑ)๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. NIfTI์—๋Š” scl_slope/scl_inter๋งŒ ์žˆ์–ด ํ•œ๊ณ„๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
!
Progressive Loading ์ ์šฉ ๋ถˆ๊ฐ€
DICOM์˜ HTJ2K์ฒ˜๋Ÿผ ๋ฐ”์ดํŠธ ์ผ๋ถ€๋งŒ ์ˆ˜์‹ ํ•ด์„œ ์ €ํ•ด์ƒ๋„๋ฅผ ๋จผ์ € ํ‘œ์‹œํ•˜๋Š” Progressive Loading์ด NIfTI gzip์—๋Š” ์—†์Šต๋‹ˆ๋‹ค. .nii.gz๋ฅผ ์„œ๋ฒ„์—์„œ ์ŠคํŠธ๋ฆฌ๋ฐํ•˜๋”๋ผ๋„ gzip ํŠน์„ฑ์ƒ ์ „์ฒด๋ฅผ ์ˆ˜์‹ ํ•ด์•ผ ์••์ถ• ํ•ด์ œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
๐Ÿ’ก NIfTI์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ๊ณต๋ฐฑ์€ ๋ณ„๋„ ์‚ฌ์ด๋“œ์นด ํŒŒ์ผ(JSON)๋กœ ๋ณด์™„ํ•˜๋Š” ํŒจํ„ด์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค. AI ํŒŒ์ดํ”„๋ผ์ธ์—์„œ NIfTI๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ํ™˜์ž ์ •๋ณด, ๋ชจ๋‹ฌ๋ฆฌํ‹ฐ, W/L ๋ฒ”์œ„ ๋“ฑ์„ JSON์œผ๋กœ ํ•จ๊ป˜ ์ƒ์„ฑํ•˜๊ณ , Cornerstone3D์˜ MetaData Provider์— ์ˆ˜๋™์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉด ์ผ๋ถ€ ๊ธฐ๋Šฅ์„ ๋ณต๊ตฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
05 ยท NIfTI in CS3D

Cornerstone3D์˜ NIfTI ๋กœ๋“œ ์•„ํ‚คํ…์ฒ˜

@cornerstonejs/nifti-volume-loader๋Š” v2.0์—์„œ imageId-first ๋ฐฉ์‹์œผ๋กœ ์ „๋ฉด ์žฌ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด volume-first ๋ฐฉ์‹๊ณผ ๋‹ฌ๋ฆฌ NIfTI ํŒŒ์ผ์„ ์Šฌ๋ผ์ด์Šค ๋‹จ์œ„ imageId๋กœ ๋ถ„ํ•ดํ•˜์—ฌ ์ผ๋ฐ˜ DICOM ๋ณผ๋ฅจ๊ณผ ๋™์ผํ•œ ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

1
NIfTI URL โ†’ ์ฒซ ๋ฐ”์ดํŠธ ์ŠคํŠธ๋ฆผ ํŒŒ์‹ฑ
์ „์ฒด ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•˜์ง€ ์•Š๊ณ  ํ—ค๋” ๋ถ€๋ถ„๋งŒ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋จผ์ € ์ˆ˜์‹ ํ•ด ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(dims, pixdim, sform ๋“ฑ)๋ฅผ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
2
์Šฌ๋ผ์ด์Šค ๋‹จ์œ„ imageId ์ƒ์„ฑ
nifti:https://server/file.nii.gz#0, #1, ... ํ˜•ํƒœ๋กœ ๊ฐ ์Šฌ๋ผ์ด์Šค๋ฅผ imageId๋กœ ๋ถ„ํ•ดํ•ฉ๋‹ˆ๋‹ค. DICOM๊ณผ ๋™์ผํ•œ imageId ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ์„ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
3
MetaData ์บ์‹œ ๋“ฑ๋ก (LPS ๋ณ€ํ™˜ ํฌํ•จ)
sform/qform ํ–‰๋ ฌ์„ ์ฝ์–ด LPS ์ขŒํ‘œ๊ณ„๋กœ ๋ณ€ํ™˜ํ•œ ImagePositionPatient, ImageOrientationPatient ๋“ฑ์„ MetaData Provider์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
4
Volume ์‚ฌ์ „ ํ• ๋‹น & ์ŠคํŠธ๋ฆฌ๋ฐ ๋กœ๋“œ
DICOM ๋ณผ๋ฅจ๊ณผ ๋™์ผํ•˜๊ฒŒ createAndCacheVolume โ†’ load()๋กœ ์Šฌ๋ผ์ด์Šค ๋‹จ์œ„ ์ŠคํŠธ๋ฆฌ๋ฐ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ๋‹จ, ๊ฐœ๋ณ„ ์Šฌ๋ผ์ด์Šค fetch ์‹œ ์ „์ฒด .nii.gz์—์„œ ํ•ด๋‹น ์˜คํ”„์…‹์„ Range Request๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
// @cornerstonejs/nifti-volume-loader v2 ์‚ฌ์šฉ๋ฒ•
import {
  cornerstoneNiftiImageLoader,
  createNiftiImageIdsAndCacheMetadata,
} from '@cornerstonejs/nifti-volume-loader';
import { imageLoader, volumeLoader } from '@cornerstonejs/core';

// 1. NIfTI ์ด๋ฏธ์ง€ ๋กœ๋” ๋“ฑ๋ก
imageLoader.registerImageLoader('nifti', cornerstoneNiftiImageLoader);

// 2. ํ—ค๋” ํŒŒ์‹ฑ & imageId ๋ฐฐ์—ด ์ƒ์„ฑ (์Šฌ๋ผ์ด์Šค ์ˆ˜๋งŒํผ ์ƒ์„ฑ๋จ)
const imageIds = await createNiftiImageIdsAndCacheMetadata({
  url: 'https://server/brain_1024.nii.gz',
});
// โ†’ ['nifti:https://...#0', 'nifti:https://...#1', ... '#N']

// 3. Stack Viewport (v2 ์‹ ๊ทœ โ€” Volume ์—†์ด๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅ)
viewport.setStack(imageIds);

// 4. Volume Viewport (๊ธฐ์กด ๋ฐฉ์‹)
const volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds });
await volume.load();

// โš ๏ธ Window/Level์€ ์ง์ ‘ ๊ณ„์‚ฐ ํ›„ ์„ค์ • ํ•„์š”
viewport.setProperties({ voiRange: { lower: -1000, upper: 3000 } });
โš ๏ธ NIfTI ์Šฌ๋ผ์ด์Šค๋ฅผ Range Request๋กœ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด ์„œ๋ฒ„๊ฐ€ Accept-Ranges: bytes๋ฅผ ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ฏธ์ง€์› ์‹œ ์Šฌ๋ผ์ด์Šค ์š”์ฒญ๋งˆ๋‹ค ์ „์ฒด ํŒŒ์ผ์„ ์žฌ๋‹ค์šด๋กœ๋“œํ•˜๋Š” ์ตœ์•…์˜ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. REST API๋กœ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐ˜๋“œ์‹œ Range Request ์ง€์› ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜์„ธ์š”.
06 ยท 1024ร—1024 Memory Analysis

1024ร—1024 ํ•ด์ƒ๋„ โ€” ๋ฉ”๋ชจ๋ฆฌ ์‹ค์ธก ๊ณ„์‚ฐ

ํ‘œ์ค€ CT๋Š” 512ร—512 ํ•ด์ƒ๋„์ž…๋‹ˆ๋‹ค. 1024ร—1024๋Š” ํ”ฝ์…€ ์ˆ˜๊ฐ€ 4๋ฐฐ์ด๋ฉฐ, ๋ฉ”๋ชจ๋ฆฌ ์ฆ๊ฐ€๋Š” ๋‹จ์ˆœํžˆ 4๋ฐฐ๊ฐ€ ์•„๋‹ˆ๋ผ CPU + GPU ์–‘์ชฝ์—์„œ ๋ณตํ•ฉ์ ์œผ๋กœ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

512 ร— 512 ร— 300์Šฌ๋ผ์ด์Šค (ํ‘œ์ค€ CT) Int16 (2 bytes) ์•ฝ 150 MB Float32 (4 bytes) ์•ฝ 300 MB GPU ํ…์Šค์ฒ˜: +150~300 MB ์ด ์˜ˆ์ƒ: 300 ~ 600 MB โœ“ ์ผ๋ฐ˜ ํ™˜๊ฒฝ์—์„œ ์•ˆ์ •์  1024 ร— 1024 ร— 300์Šฌ๋ผ์ด์Šค Int16 (2 bytes) ์•ฝ 600 MB Float32 (4 bytes) ์•ฝ 1.2 GB GPU ํ…์Šค์ฒ˜: +600MB ~ 1.2 GB ์ด ์˜ˆ์ƒ: 1.2 ~ 2.4 GB โš ๏ธ ๋‚ด์žฅ ๊ทธ๋ž˜ํ”ฝยท๋ชจ๋ฐ”์ผ OOM ์œ„ํ—˜
1024ร—1024ร—300์Šฌ๋ผ์ด์Šค Float32 ์ƒ์„ธ ๊ณ„์‚ฐ
๋ณต์…€ ์ˆ˜1,024 ร— 1,024 ร— 300 = 314,572,800 ๋ณต์…€
CPU ๋ฉ”๋ชจ๋ฆฌ (Float32)314,572,800 ร— 4 bytes โ‰ˆ 1.2 GB
GPU 3D ํ…์Šค์ฒ˜๋™์ผ ๋ณผ๋ฅจ ์ถ”๊ฐ€ โ‰ˆ 1.2 GB
์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜ ์˜ค๋ฒ„๋ ˆ์ดRGBA ร— ๊ฐ™์€ ํฌ๊ธฐ โ‰ˆ 1.2 GB ์ถ”๊ฐ€
์ด ์˜ˆ์ƒ ๋ฉ”๋ชจ๋ฆฌโ‰ˆ 2.4 ~ 3.6 GB
512ร—512 ํ‘œ์ค€ CT
~300 MB
1024ร—1024 Int16
~600 MB
1024ร—1024 Float32
~1.2 GB
+SEG ์˜ค๋ฒ„๋ ˆ์ด
~2.4 GB+

* CPU + GPU ํ•ฉ์‚ฐ / 300์Šฌ๋ผ์ด์Šค ๊ธฐ์ค€

07 ยท GPU Limits

WebGL 3D ํ…์Šค์ฒ˜ ํ•œ๊ณ„ โ€” ๊ฐ€์žฅ ๋จผ์ € ๋ง‰ํžˆ๋Š” ๋ฒฝ

๋ฉ”๋ชจ๋ฆฌ ์ด์ „์— WebGL 3D ํ…์Šค์ฒ˜ ํฌ๊ธฐ ์ œํ•œ์ด ๋จผ์ € ๋ฌธ์ œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์™€ GPU์— ๋”ฐ๋ผ ์ตœ๋Œ€ ํ…์Šค์ฒ˜ ํฌ๊ธฐ๊ฐ€ ๋‹ค๋ฅด๋ฉฐ, 1024ร—1024ร—300 ๋ณผ๋ฅจ์„ ๋‹จ์ผ 3D ํ…์Šค์ฒ˜๋กœ ์˜ฌ๋ฆฌ๋ ค๊ณ  ํ•˜๋ฉด ๋‚ด์žฅ ๊ทธ๋ž˜ํ”ฝ ํ™˜๊ฒฝ์—์„œ ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ™˜๊ฒฝMAX_3D_TEXTURE_SIZE1024ร—1024ร—300 ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋น„๊ณ 
์™ธ์žฅ GPU (๋ฐ์Šคํฌํƒ‘)2048 ~ 16384๋Œ€๋ถ€๋ถ„ ๊ฐ€๋Šฅ๊ณ ์„ฑ๋Šฅ GPU๋Š” ๋ฌธ์ œ์—†์Œ
๋‚ด์žฅ GPU (Intel/AMD)512 ~ 2048ํ™˜๊ฒฝ ์˜์กด512 ์ œํ•œ ์‹œ ์‹คํŒจ
Apple Silicon (M1/M2)2048๊ฐ€๋Šฅํ†ตํ•ฉ ๋ฉ”๋ชจ๋ฆฌ ๊ณต์œ 
๋ชจ๋ฐ”์ผ (iOS Safari)512 ~ 1024์œ„ํ—˜OOM ํฌ๋ž˜์‹œ ๋นˆ๋ฒˆ
๋ชจ๋ฐ”์ผ (Android Chrome)512 ~ 2048๊ธฐ๊ธฐ ์˜์กด๋ฉ”๋ชจ๋ฆฌ ์••๋ฐ• ์‹ฌ๊ฐ
๐Ÿšจ WebGL์—์„œ gl.MAX_3D_TEXTURE_SIZE๊ฐ€ 512์ธ ๊ธฐ๊ธฐ์— 1024ร—1024 ํ…์Šค์ฒ˜๋ฅผ ์˜ฌ๋ฆฌ๋ ค ํ•˜๋ฉด GL_INVALID_VALUE ์—๋Ÿฌ์™€ ํ•จ๊ป˜ ํ…์Šค์ฒ˜ ์ƒ์„ฑ์ด ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. Cornerstone3D๋Š” ์ด ์ƒํ™ฉ์—์„œ ๋ Œ๋”๋ง์ด ์™„์ „ํžˆ ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ์ „ ๋ฐ˜๋“œ์‹œ ์ตœ์†Œ ์‚ฌ์–‘ ๊ธฐ๊ธฐ์—์„œ ๊ฒ€์ฆํ•˜์„ธ์š”.
// ๋Ÿฐํƒ€์ž„์—์„œ WebGL ์ตœ๋Œ€ ํ…์Šค์ฒ˜ ํฌ๊ธฐ ํ™•์ธ
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
const maxTexSize = gl.getParameter(gl.MAX_3D_TEXTURE_SIZE);
console.log(`MAX_3D_TEXTURE_SIZE: ${maxTexSize}`);

// 1024ร—1024 ์ ์žฌ ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ์‚ฌ์ „ ์ฒดํฌ
if (maxTexSize < 1024) {
  // ๋‹ค์šด์ƒ˜ํ”Œ ๋ฒ„์ „์œผ๋กœ ํด๋ฐฑ
  loadLowResolutionVolume();
} else {
  loadFullResolutionVolume();
}
08 ยท Pros & Cons

NIfTI 1024ร—1024 โ€” ์žฅ์ ๊ณผ ๋‹จ์  ์ข…ํ•ฉ

โœ… ์žฅ์ 
  • AI ํŒŒ์ดํ”„๋ผ์ธ๊ณผ์˜ ์ง์ ‘ ์—ฐ๊ฒฐ
    AI ๋ชจ๋ธ์ด NIfTI๋กœ ๊ฒฐ๊ณผ๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๊ฒฝ์šฐ ๋ณ€ํ™˜ ์—†์ด ๋ฐ”๋กœ ๋ Œ๋”๋ง ๊ฐ€๋Šฅ
  • ๋‹จ์ผ ํŒŒ์ผ ๊ด€๋ฆฌ
    DICOM์ฒ˜๋Ÿผ ์Šฌ๋ผ์ด์Šค๋งˆ๋‹ค ํŒŒ์ผ์ด ๋ถ„๋ฆฌ๋˜์ง€ ์•Š์•„ ํŒŒ์ผ ๊ด€๋ฆฌ๊ฐ€ ๋‹จ์ˆœ
  • ๊ณ ํ•ด์ƒ๋„ ์„ธ๋ถ€ ํ‘œํ˜„
    1024ร—1024๋Š” 512ร—512 ๋Œ€๋น„ ๋ฏธ์„ธ ๊ตฌ์กฐ(ํ˜ˆ๊ด€, ๋ณ‘๋ณ€ ๊ฒฝ๊ณ„) ํ‘œํ˜„๋ ฅ 4๋ฐฐ ํ–ฅ์ƒ
  • ์—ฐ๊ตฌ/๋ถ„์„ ๋„๊ตฌ ํ˜ธํ™˜์„ฑ
    FSL, FreeSurfer, ANTs ๋“ฑ ์‹ ๊ฒฝ์˜์ƒ ๋ถ„์„ ๋„๊ตฌ์™€ ํฌ๋งท ์ผ์น˜
โš ๏ธ ๋‹จ์  / ์œ„ํ—˜
  • ๋ฉ”๋ชจ๋ฆฌ 2~4GB ์š”๊ตฌ
    ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜ ํฌํ•จ ์‹œ ์ €์‚ฌ์–‘ ๊ธฐ๊ธฐ์—์„œ ํƒญ ํฌ๋ž˜์‹œ ์œ„ํ—˜
  • Progressive Loading ๋ถˆ๊ฐ€
    gzip ์ „์ฒด ์••์ถ• ํŠน์„ฑ์ƒ ์ ์ง„์  ๋ Œ๋”๋ง ์—†์–ด ์ดˆ๊ธฐ ๋กœ๋”ฉ ๋А๋ฆผ
  • ์ขŒํ‘œ๊ณ„ ๋ณ€ํ™˜ ์˜ค๋ฅ˜ ์œ„ํ—˜
    sform/qform ๋น„ํ‘œ์ค€ ํŒŒ์ผ ์‹œ ์˜์ƒ ์ขŒ์šฐ ๋ฐ˜์ „ ๋“ฑ ์ž„์ƒ์  ์˜ค๋ฅ˜
  • ์ž„์ƒ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์™„์ „ ๋ถ€์žฌ
    ํ™˜์ž ์ •๋ณด, W/L ํ”„๋ฆฌ์…‹, ๋ชจ๋‹ฌ๋ฆฌํ‹ฐ ๊ธฐ๋ฐ˜ ๊ธฐ๋Šฅ ๋ชจ๋‘ ์ˆ˜๋™ ๊ตฌํ˜„
  • DICOM ํ‘œ์ค€ ๋„๊ตฌ ๋ฏธํ˜ธํ™˜
    ์ธก์ •๊ฐ’ SR ์ €์žฅ, DICOM SEG ์—ฐ๋™, PACS ์—ฐ๋™ ๋ถˆ๊ฐ€
  • WebGL ํ…์Šค์ฒ˜ ํ•œ๊ณ„ ์ถฉ๋Œ
    ๋‚ด์žฅ ๊ทธ๋ž˜ํ”ฝยท๋ชจ๋ฐ”์ผ ๊ธฐ๊ธฐ์—์„œ ํ…์Šค์ฒ˜ ์ƒ์„ฑ ์‹คํŒจ ๊ฐ€๋Šฅ
09 ยท Issues & Mitigations

์˜ˆ์ƒ ๋ฌธ์ œ์ ๊ณผ ๋Œ€์‘ ์ „๋žต

1
๋ฌธ์ œ: gzip ์ „์ฒด ๋‹ค์šด๋กœ๋“œ โ†’ ์ดˆ๊ธฐ ๋กœ๋”ฉ ์ˆ˜์‹ญ ์ดˆ
1024ร—1024ร—300 Float32 ๋ณผ๋ฅจ์€ ์••์ถ• ์ „ ~1.2GB์ž…๋‹ˆ๋‹ค. gzip ์••์ถ•๋ฅ  3:1 ๊ฐ€์ • ์‹œ ์•ฝ 400MB๋ฅผ ๋„คํŠธ์›Œํฌ๋กœ ์ˆ˜์‹ ํ•œ ํ›„ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์••์ถ• ํ•ด์ œํ•ด์•ผ ์ฒซ ๋ Œ๋”๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. 4G ํ™˜๊ฒฝ ๊ธฐ์ค€ 1๋ถ„ ์ด์ƒ ์†Œ์š”๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€์‘: ์„œ๋ฒ„์—์„œ Content-Encoding: gzip์œผ๋กœ ์ „์†กํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ž๋™ ํ•ด์ œํ•˜๋ฏ€๋กœ nifti-reader-js์˜ JS gzip ํ•ด์ œ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜๋Š” ์„œ๋ฒ„์—์„œ Progressive ๋ฐฉ์‹ ๋‹ค์šด์ƒ˜ํ”Œ ๋ฒ„์ „(256ร—256)์„ ๋จผ์ € ์ œ๊ณตํ•˜๊ณ  ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๊ณ ํ•ด์ƒ๋„๋ฅผ ๋กœ๋“œํ•˜๋Š” 2๋‹จ๊ณ„ ์ „๋žต์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.
2
๋ฌธ์ œ: ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜ ์˜ค๋ฒ„๋ ˆ์ด ํฌํ•จ ์‹œ OOM
๋ณผ๋ฅจ(1.2GB) + ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜ RGBA(1.2GB) + GPU ํ…์Šค์ฒ˜ ๋ณต์‚ฌ(1.2GB+) = 3.6GB+. 16GB RAM ๊ธฐ๊ธฐ๋„ ๋ธŒ๋ผ์šฐ์ € ํƒญ ๋ฉ”๋ชจ๋ฆฌ ํ•œ๋„(์ผ๋ฐ˜์ ์œผ๋กœ 2~4GB)์— ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€์‘: ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜์„ ํ”ฝ์…€ ๋ฐ์ดํ„ฐ๋กœ ์˜ฌ๋ฆฌ์ง€ ์•Š๊ณ  BBox/Contour ์ขŒํ‘œ JSON์œผ๋กœ ๋ฐ›์•„ Canvas 2D๋กœ ๊ทธ๋ฆฌ๋Š” ๋ฐฉ์‹์œผ๋กœ ์ „ํ™˜ํ•ฉ๋‹ˆ๋‹ค(์ด์ „ Cornerstone3D ๋…ผ์˜์—์„œ ๊ฒ€ํ† ํ•œ ์ ‘๊ทผ). ์„ธ๊ทธ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์‹ค์ƒ 0์— ๊ฐ€๊น๊ฒŒ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
3
๋ฌธ์ œ: Window/Level ์ž๋™ ์„ค์ • ์—†์Œ
NIfTI ํ—ค๋”์— WindowCenter/Width๊ฐ€ ์—†์–ด Cornerstone3D๊ฐ€ ๊ธฐ๋ณธ๊ฐ’(์ „์ฒด ๋ฐ์ดํ„ฐ ๋ฒ”์œ„)์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. CT ์˜์ƒ์ด ์™„์ „ํžˆ ํ•˜์–—๊ฒŒ ๋˜๋Š” ๊ฒ€๊ฒŒ ํ‘œ์‹œ๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋Œ€์‘: ๋ณผ๋ฅจ ๋กœ๋“œ ํ›„ ์ƒ˜ํ”Œ๋ง ๊ธฐ๋ฐ˜ ๋ฐฑ๋ถ„์œ„์ˆ˜ ๊ณ„์‚ฐ์œผ๋กœ W/L์„ ์ž๋™ ์ถ”์ •ํ•ฉ๋‹ˆ๋‹ค. ๋˜๋Š” ์„œ๋ฒ„์—์„œ W/L ์ถ”์ฒœ๊ฐ’์„ JSON ์‚ฌ์ด๋“œ์นด๋กœ ํ•จ๊ป˜ ์ œ๊ณตํ•˜๊ณ  Cornerstone3D MetaData Provider์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.
4
๋ฌธ์ œ: ์ขŒํ‘œ๊ณ„ ๋ฐ˜์ „ (์ž„์ƒ ์•ˆ์ „ ์œ„ํ—˜)
sform_code = 0์ด๊ฑฐ๋‚˜ ๋น„ํ‘œ์ค€ NIfTI ํŒŒ์ผ์€ nifti-volume-loader์˜ ์ž๋™ ๋ณ€ํ™˜์ด ์‹คํŒจํ•ด ์ขŒ์šฐ ๋ฐ˜์ „์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋Œ€์‘: ๋กœ๋“œ ํ›„ ๋ฐ˜๋“œ์‹œ ํ•ด๋ถ€ํ•™์  ๋žœ๋“œ๋งˆํฌ(์ฝ”, ๊ท€ ๋“ฑ)๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ทฐํฌํŠธ ๋ฐฉํ–ฅ์„ ์‹œ๊ฐ์ ์œผ๋กœ ๊ฒ€์ฆํ•˜๋Š” QA ๋‹จ๊ณ„๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. L/R ๋ฐฉํ–ฅ ๋ ˆ์ด๋ธ” ํ‘œ์‹œ ์—ฌ๋ถ€๋ฅผ ์ž๋™ ํ…Œ์ŠคํŠธ์— ํฌํ•จ์‹œํ‚ต๋‹ˆ๋‹ค.
5
๋ฌธ์ œ: Range Request ๋ฏธ์ง€์› ์„œ๋ฒ„์—์„œ ์Šฌ๋ผ์ด์Šค ๋กœ๋“œ ํญ๋ฐœ
nifti-volume-loader v2๋Š” ์Šฌ๋ผ์ด์Šค๋ณ„ imageId๋กœ ๋ถ„ํ•ด ํ›„ ๊ฐ๊ฐ Range Request๋ฅผ ์‹œ๋„ํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ๋ฏธ์ง€์›ํ•˜๋ฉด ์Šฌ๋ผ์ด์Šค 300๊ฐœ ร— ์ „์ฒด ํŒŒ์ผ ํฌ๊ธฐ ์š”์ฒญ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๋Œ€์‘: ์„œ๋ฒ„์— Accept-Ranges: bytes ํ—ค๋” ์ง€์›์„ ๋ฐ˜๋“œ์‹œ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜, Range Request ๋ฏธ์ง€์› ์‹œ ์ „์ฒด ํŒŒ์ผ 1ํšŒ ๋‹ค์šด๋กœ๋“œ ํ›„ ํด๋ผ์ด์–ธํŠธ์—์„œ ์Šฌ๋ผ์ด์Šค ๋ถ„ํ• ํ•˜๋Š” ํด๋ฐฑ ๋กœ์ง์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
10 ยท Conclusion

๊ธฐ์ˆ  ๊ฒ€ํ†  ๊ฒฐ๋ก  โ€” ๋„์ž… ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์กฐ๊ฑด๋ถ€

Cornerstone3D์—์„œ NIfTI + 1024ร—1024 ์กฐํ•ฉ์€ ๊ธฐ์ˆ ์ ์œผ๋กœ ๋ถˆ๊ฐ€๋Šฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. @cornerstonejs/nifti-volume-loader v2๊ฐ€ imageId-first ๋ฐฉ์‹์œผ๋กœ ์žฌ์„ค๊ณ„๋˜๋ฉด์„œ DICOM ํŒŒ์ดํ”„๋ผ์ธ๊ณผ ์ƒ๋‹น ๋ถ€๋ถ„ ํ†ตํ•ฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹จ, ์•„๋ž˜ ์ „์ œ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์–ด์•ผ ํ”„๋กœ๋•์…˜ ์ ์šฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

ํ•ญ๋ชฉ์ƒํƒœํ•„์š” ์กฐ์น˜
๊ธฐ๋ณธ ๋ Œ๋”๋ง (MPR)๊ฐ€๋Šฅnifti-volume-loader ์„ค์น˜ + imageId ๋“ฑ๋ก
์ขŒํ‘œ๊ณ„ (LPS ๋ณ€ํ™˜)์ฃผ์˜sform/qform ์œ ํšจ์„ฑ ๊ฒ€์ฆ + ์‹œ๊ฐ QA ํ•„์ˆ˜
Window/Level์ˆ˜๋™ ํ•„์š”๋ฐฑ๋ถ„์œ„์ˆ˜ ์ถ”์ • or ์„œ๋ฒ„ JSON ์‚ฌ์ด๋“œ์นด
Progressive Loading๋ถˆ๊ฐ€2๋‹จ๊ณ„ ํ•ด์ƒ๋„ ์ „๋žต(256โ†’1024) ์„ค๊ณ„ ํ•„์š”
๋ฉ”๋ชจ๋ฆฌ (1024ร—1024)์œ„ํ—˜๋Œ€์ƒ ๊ธฐ๊ธฐ ์ตœ์†Œ ์‚ฌ์–‘ ์ •์˜ + OOM ํด๋ฐฑ ํ•„์ˆ˜
GPU ํ…์Šค์ฒ˜ ํ•œ๊ณ„๊ธฐ๊ธฐ ์˜์กด๋Ÿฐํƒ€์ž„ MAX_3D_TEXTURE_SIZE ์ฒดํฌ + ํด๋ฐฑ
์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜ ์˜ค๋ฒ„๋ ˆ์ด๋ฉ”๋ชจ๋ฆฌ ์œ„ํ—˜ํ”ฝ์…€ ๋Œ€์‹  BBox/Contour JSON ๋ฐฉ์‹ ์ „ํ™˜ ๊ฒ€ํ† 
DICOM SR ์ธก์ • ์ €์žฅ๋ถˆ๊ฐ€์ž์ฒด JSON ํฌ๋งท์œผ๋กœ ์–ด๋…ธํ…Œ์ด์…˜ ๊ด€๋ฆฌ
Range Request ์„œ๋ฒ„์„œ๋ฒ„ ์„ค์ • ํ•„์š”Accept-Ranges: bytes ํ—ค๋” ์ง€์› ์ถ”๊ฐ€
๐Ÿงญ ํ˜„์žฌ VTK.js ์ปค์Šคํ…€ ๋ทฐ์–ด์ฒ˜๋Ÿผ NIfTI REST API + ๋น„ํ‘œ์ค€ ๋ Œ๋”๋ง์ด ํ•ต์‹ฌ์ธ ํ”„๋กœ์ ํŠธ๋ผ๋ฉด, Cornerstone3D์˜ DICOM ์ค‘์‹ฌ ์ œ์•ฝ๋ณด๋‹ค ์ง์ ‘ ๊ตฌํ˜„์ด ์—ฌ์ „ํžˆ ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด ํ–ฅํ›„ DICOM ๊ธฐ๋ฐ˜ PACS ์—ฐ๋™, ์„ธ๊ทธ๋ฉ˜ํ…Œ์ด์…˜ ํŽธ์ง‘ ๋„๊ตฌ, ๋‹ค์ค‘ ๋ทฐํฌํŠธ ๋™๊ธฐํ™” ํ™•์žฅ์ด ์˜ˆ์ •๋˜์–ด ์žˆ๋‹ค๋ฉด ์ง€๊ธˆ๋ถ€ํ„ฐ Cornerstone3D ๊ธฐ๋ฐ˜์œผ๋กœ NIfTI ์ง€์›์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์ด ์žฅ๊ธฐ์ ์œผ๋กœ ์ด๋“์ž…๋‹ˆ๋‹ค.