Pyradiomics: Pyradiomics๋Š” nrrd ํŒŒ์ผ๋กœ ๋ถ„ํ• ๋œ ์—ฌ๋Ÿฌ ๊ตฌ์กฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๊นŒ? [ํŠน์ง• ์ถ”์ถœ]

์— ๋งŒ๋“  2019๋…„ 09์›” 15์ผ  ยท  10์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: AIM-Harvard/pyradiomics

DICOM ๋ฐ์ดํ„ฐ์™€ DICOM RTSS ๊ตฌ์กฐ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜์—ฌ CT ์Šค์บ”์—์„œ pyradiomics๋ฅผ ์‹œ๋„ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. RTSS ํŒŒ์ผ์—๋Š” ์—ฌ๋Ÿฌ ๊ตฌ์กฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ช…๋ น์ค„์„ ํ†ตํ•ด plastimatch๋ฅผ ์„ฑ๊ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ dicom ์ด๋ฏธ์ง€ ํŒŒ์ผ์„ ๋‹จ์ผ 3d nrrd ํŒŒ์ผ๋กœ ๋ณ€ํ™˜ํ•œ ๋‹ค์Œ RTSS dicom ํŒŒ์ผ์„ ๋‹ค๋ฅธ nrrd ํŒŒ์ผ๋กœ ๋ณ€ํ™˜ํ–ˆ์Šต๋‹ˆ๋‹ค.
pydicom์œผ๋กœ ํŠน์ง•์ถ”์ถœ์„ ํ•˜๋ฉด ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๊ธด ํ•œ๋ฐ ํ•˜๋‚˜์˜ ์ˆซ์ž ์ง‘ํ•ฉ์ž…๋‹ˆ๋‹ค. nrrd ๊ตฌ์กฐ ์„ธํŠธ ์ด๋ฏธ์ง€์˜ ๊ฐ ๊ตฌ์กฐ์— ๋Œ€ํ•œ ๊ฐ’์„ ์–ป์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. pydicom์€ ๋งˆ์Šคํฌ๋‹น ํ•˜๋‚˜์˜ ๊ตฌ์กฐ์—์„œ๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?

๋ฒ„์ „(๋‹ค์Œ ์ •๋ณด๋ฅผ ์ž‘์„ฑํ•˜์‹ญ์‹œ์˜ค):

  • OS: [์œˆ๋„์šฐ 10]
  • Python ๋ฒ„์ „: [์˜ˆ: 3.6]
  • PyRadiomics ๋ฒ„์ „[์˜ˆ: 2.2.0]
question

๋ชจ๋“  10 ๋Œ“๊ธ€

๊ฐ ๊ฒฝ์šฐ์— ๋Œ€ํ•ด PyRadiomics๋Š” ๋งˆ์Šคํฌ ํŒŒ์ผ( label ๊ฐ’์œผ๋กœ ์‹๋ณ„)์˜ 1 ROI์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ๋งŒ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.

์ด ํ”Œ๋ผ์Šคํ‹ฐ๋งค์น˜์˜ ์˜ˆ๋„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค. ์—ฌ๋Ÿฌ ROI๊ฐ€ ์ถœ๋ ฅ ๋ณผ๋ฅจ์˜ i๋ฒˆ์งธ ๋น„ํŠธ์— ํ• ๋‹น๋˜์–ด ๊ตฌ์กฐ๊ฐ€ ๊ฒน์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ plastimatch๋Š” ์„ธ๊ทธ๋จผํŠธ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํŒŒ์ผ์„ ์ถœ๋ ฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒน์น˜๋Š” ์„ธ๊ทธ๋จผํŠธ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ PyRadiomics๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์‹ญ์‹œ์˜ค! PyRadiomics๋Š” ํŠน์ • ์ธ๋ฑ์Šค๊ฐ€ ์•„๋‹Œ ์ „์ฒด ๊ฐ’๋งŒ ๋ด…๋‹ˆ๋‹ค. 4D ๋ณผ๋ฅจ์„ ๋งˆ์Šคํฌ๋กœ ๊ณต๊ธ‰ํ•˜์—ฌ ๋งˆ์Šคํฌ์—์„œ ๊ฒน์น˜๋Š” ๊ตฌ์กฐ๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฒน์นจ์ด ์—†์œผ๋ฉด ์ œ๋Œ€๋กœ ์ž‘๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: ๊ฐ€๋Šฅํ•œ ๋ ˆ์ด๋ธ”์€ 1, 2, 4, 8 ๋“ฑ).

๋งˆ์Šคํฌ์— ์–ด๋–ค ๋ ˆ์ด๋ธ”์ด ์žˆ๋Š”์ง€ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด ๋ฐฐ์น˜ ๋ชจ๋“œ(์—ด "Label") ์—์„œ PyRadiomics๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ ˆ์ด๋ธ”์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค @JoostJM
์ด์ œ ๋ฌธ์ œ๋ฅผ ํ›จ์”ฌ ๋” ์ž˜ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค.
๋‚˜์—๊ฒŒ ์—ฌ์ „ํžˆ ์•ฝ๊ฐ„ ํ˜ผ๋ž€์Šค๋Ÿฌ์šด ๊ฒƒ์€ ์–ด๋–ค ๋ ˆ์ด๋ธ”์ด ์–ด๋–ค ๊ตฌ์กฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š”์ง€ ์•Œ์•„๋‚ด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
32๊ฐœ์˜ ๊ตฌ์กฐ๊ฐ€ ์žˆ๋Š” RTSS dicom ํŒŒ์ผ์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ ๋‚ด์šฉ์€ ์•„๋ž˜์— ๋ถ™์—ฌ๋„ฃ์Šต๋‹ˆ๋‹ค.

0|0 255 0|๋ฐ”๋””
1|0 0 160|์ •๋งฅ_IVC
2|0 255 64|์ •๋งฅ_PV
3|255 0 0|HepVeinRight
4|255 0 0|HepVeinMid
5|255 0 0|๋งฅ๋งฅ ์™ผ์ชฝ
6|255 0 0|์ขŒ์ธก ํฌํŠธ๋ฒ ์ธ
7|255 0 0|PortVeinRight
8|10 10 250|LivSegI
9|128 255 255|LivSegVII
10|255 128 128|LivSegVIII
11|128 64 64|LivSegVI
12|0 150 0|LivSegV
13|0 150 0|LivSegII
14|0 0 160|LivSegIII
15|255 255 128|๋ฆฌ๋ธŒ์„ธ๊ทธIVa
16|255 0 255|LivSegIVb
17|0 0 255|์ •๋งฅ_SMV
18|0 0 255|์ •๋งฅ_๋น„์žฅ
19|255 255 0|์ฝœ๋ก 
20|255 0 255|์žฅ์†Œ
21|0 0 255|์œ„
22|187 255 187|์‹ญ์ด์ง€์žฅ
23|128 64 64|์ทŒ์žฅ
24|0 255 255|๋‹ด๋‚ญ
25|0 127 255|๋น„์žฅ
26|255 128 128|์‹ ์žฅR
27|50 204 153|์‹ ์žฅ
28|255 255 0|์š”๊ด€R
29|255 255 0|์š”๊ด€
30|255 210 0|๋ถ€์‹ R
31|255 210 0|๋ถ€์‹ L
32|255 0 0|๋Œ€๋™๋งฅ ๋Œ€๋™๋งฅ
33|255 128 0|์•„ํŠธ_์…€๋ฆฌ์•…
34|255 128 0|์•„ํŠธ_SMA
35|255 128 0|์•„ํŠธ_IMA
36|255 128 0|์•„ํŠธ๋ ˆ๋‚ 
37|0 0 255|์ •๋งฅ_์‹ ์žฅ

๊ทธ๋Ÿฌ๋‚˜ ๋ ˆ์ด๋ธ”์€ ์—ฌ๊ธฐ์— ์žˆ๋Š” ์ˆซ์ž์™€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
๋ ˆ์ด๋ธ”์„ ๊ตฌ์กฐ์™€ ์ผ์น˜์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋‚ด๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ณ€ํ™˜๋œ ๋งˆ์Šคํฌ ํŒŒ์ผ์„ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‚˜์š”? ๊ทธ๋Ÿฌ๋ฉด ๋ฌด์—‡์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•„์š”.

์ด๊ฒƒ์€ .nrrd ํŒŒ์ผ์— ๋Œ€ํ•œ ๋งํฌ์ž…๋‹ˆ๋‹ค.
https://www.dropbox.com/s/mdavn9gxk4fpt5d/abdomen_rtss1.nrrd?dl=0
์ด๊ฒƒ์ด ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ถœ๋ ฅ ํŒŒ์ผ์€ ์‹ค์ œ๋กœ plastimatch ๋ฌธ์„œ์— ์ง€์ •๋œ ๊ฒƒ๊ณผ ๊ฑฐ์˜ ๋น„์Šทํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ฐ์ดํ„ฐ ์œ ํ˜•์€ uint8์ž…๋‹ˆ๋‹ค(8๋น„ํŠธ = 8๊ฐœ์˜ ๊ฐ€๋Šฅํ•œ ๋ ˆ์ด๋ธ”์„ ์˜๋ฏธ). ๋” ๋งŽ์€ ์„ธ๊ทธ๋จผํŠธ(๊ท€ํ•˜์˜ ๊ฒฝ์šฐ 38๊ฐœ)๋ฅผ ํ—ˆ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ณผ๋ฅจ์ด 4D ๋ณผ๋ฅจ์œผ๋กœ ๋ณ€ํ™˜๋˜๋ฏ€๋กœ ์ฑ„๋„๋‹น ๋ ˆ์ด๋ธ”์ด 8๊ฐœ์ž…๋‹ˆ๋‹ค.

Slicer์™€ PyRadiomics๊ฐ€ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์„ ์–ป์œผ๋ ค๋ฉด ๋ช‡ ๊ฐ€์ง€ ๊ตฌ์กฐ ์กฐ์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

import numpy as np
import SimpleITK as sitk

ma = sitk.ReadImage(r'abdomen_rtss1.nrrd')
ma_arr = sitk.GetArrayFromImage(ma)

labels = []
for channel in range(ma_arr.shape[3]):
    for bit in range(8):
        label_map = np.zeros(ma_arr.shape[:3], dtype='uint8')
        roi = np.bitwise_and(ma_arr[..., channel], 2 ** bit) > 0
        if np.sum(roi) > 0:
            label_map[roi] = 1
            labels.append(label_map)

mask_arr = np.array(labels).transpose(1, 2, 3, 0)
mask_arr.shape

mask = sitk.GetImageFromArray(mask_arr)
mask.CopyInformation(ma)

sitk.WriteImage(mask, r'segmentation.seg.nrrd', True)  # Specify True to enable compression

์ด ์ฝ”๋“œ ์กฐ๊ฐ์€ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“  ๋ ˆ์ด๋ธ”์„ ๋ฐ˜๋ณตํ•˜๊ณ  ์ผ์น˜ํ•˜๋Š” ๋ณต์…€์„ ์ฐพ์œผ๋ฉด ๋ ˆ์ด๋ธ” ๋งต์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค(์ด๋Š” uint8 ๋ฐ์ดํ„ฐ ์œ ํ˜•์˜ 3D ๋ณผ๋ฅจ์„ ๊ฐ€์ •ํ•œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์‹ญ์‹œ์˜ค).

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋งˆ์ง€๋ง‰์— 1๊ฐœ์˜ 4D ํ–‰๋ ฌ์„ ๋งŒ๋“ค๊ณ  ์ด๋ฏธ์ง€๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„๋กœ ๋งˆ์Šคํฌ์˜ ๊ธฐํ•˜ํ•™์  ์ •๋ณด๊ฐ€ ๋ณต์‚ฌ๋˜๊ณ  ๋ถ„ํ• ์ด ๋ถ„ํ• ๋กœ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์Šฌ๋ผ์ด์„œ์— ๋กœ๋“œํ•˜์—ฌ ์˜ฌ๋ฐ”๋ฅธ์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ถœ๋ ฅ ํŒŒ์ผ์˜ ์ฒซ ๋ฒˆ์งธ ๊ฐ’(0-37)์€ ๋ถ„ํ• ์˜ ์ธ๋ฑ์Šค์™€ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด "Art_IMA"์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ์„ ์ถ”์ถœํ•˜๋ ค๋ฉด label_channel=35 ์„ค์ •์œผ๋กœ PyRadiomics๋ฅผ ์‹คํ–‰ํ•˜์‹ญ์‹œ์˜ค( label=1 ์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•„์•ผ ํ•จ).

๋งˆ์ง€๋ง‰์œผ๋กœ SlicerRT ํ™•์žฅ์„ ์‚ฌ์šฉํ•˜์—ฌ RTSTRUCT๋ฅผ ์Šฌ๋ผ์ด์„œ ๋…ธ๋“œ์— ์ง์ ‘ ๋กœ๋“œํ•˜๊ณ  ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ„ํ•  ํŒŒ์ผ์„ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค(๊ทธ๋Ÿฌ๋ฉด ์ด๋ฆ„๋„ ์ž๋™์œผ๋กœ ํ†ตํ•ฉ๋จ).

์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! @JoostJM
์•„๋ฆ„๋‹ต๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์Šฌ๋ผ์ด์„œ ๋ฐ ํŒŒ์ด์ฌ ์ถœ๋ ฅ์—์„œ โ€‹โ€‹ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ณ„ํš ์‹œ์Šคํ…œ์—์„œ ์ƒˆ ๋‚ด๋ณด๋‚ด๊ธฐ๋ฅผ ์ˆ˜ํ–‰ํ•˜์—ฌ ์ž‘์—… ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ–ˆ์Šต๋‹ˆ๋‹ค. ์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋„์™€ ์ค„ ์ˆ˜์žˆ์–ด์„œ ๊ธฐ๋ป

ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ๋ฐฐ์น˜ ํŒŒ์ผ ์˜ˆ์ œ "batchprocessing.py"์— ์–ด๋–ป๊ฒŒ ํ†ตํ•ฉํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

@JE-Jimenez, PyRadiomics์˜ ์ผ๊ด„ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๊ถŒ์žฅ ์ง„์ž…์ ์€ ๋ช…๋ น์ค„์„ ํ†ตํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค(๋” ๋‚˜์€ ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ, ๋‹ค์ค‘ ์ฒ˜๋ฆฌ ์ง€์› ๋“ฑ). ์ด ๊ฒฝ์šฐ ๊ฐ๊ฐ "Image", "Mask" ๋ฐ "Label"/"Label_channel" ์—ด์„ ์‚ฌ์šฉํ•˜์—ฌ csv ํŒŒ์ผ์—์„œ ์ด๋ฏธ์ง€, ๋งˆ์Šคํฌ ๋ฐ ๋ ˆ์ด๋ธ” ์กฐํ•ฉ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค("Label"์€ ๋ ˆ์ด๋ธ” ๋งต์˜ ๋ ˆ์ด๋ธ” ๊ฐ’์„ ๋‚˜ํƒ€๋‚ด๊ณ , "Label_channel" ์„ธ๊ทธ๋จผํŠธ์˜ 0 ๊ธฐ๋ฐ˜ ์ธ๋ฑ์Šค, ์ฐจ์ด์ ์€ ๋ ˆ์ด๋ธ” ๋งต์˜ 3D ์Šฌ๋ผ์ด์„œ ๋ฐ ์„ธ๋ถ„ํ™” ์ฐธ์กฐ).

batch processing.py์—์„œ ๋น„์Šทํ•œ ๊ฒƒ์„ ์–ป์„ ์ˆ˜ ์žˆ์ง€๋งŒ ํ˜„์žฌ๋Š” label ์—๋งŒ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. L81-84 ์ฐธ์กฐ
๋ ˆ์ด๋ธ” ๊ฐ’ ๊ตฌ๋ฌธ ๋ถ„์„์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰