99from .internals import Dataset , field , licenses , register
1010
1111
12- class NoduleBlock (NamedTuple ):
13- image : np .ndarray
14- metadata : Dict
15-
16-
1712class LUNA25Nodule (NamedTuple ):
1813 coords : Sequence [float ]
1914 lesion_id : int
@@ -29,8 +24,8 @@ class LUNA25Nodule(NamedTuple):
2924 license = licenses .CC_BY_40 ,
3025 link = 'https://luna25.grand-challenge.org/' ,
3126 modality = 'CT' ,
32- prep_data_size = None ,
33- raw_data_size = None ,
27+ prep_data_size = '214G' ,
28+ raw_data_size = '205G' ,
3429 task = 'Lung nodule malignancy risk estimation' ,
3530)
3631class LUNA25 (Dataset ):
@@ -47,31 +42,31 @@ class LUNA25(Dataset):
4742 Parameters
4843 ----------
4944 root : str, Path, optional
50- path to the folder containing the raw downloaded archives.
45+ path to the folder containing `luna25_images` and `luna25_nodule_blocks` folders and
46+ `LUNA25_Public_Training_Development_Data.csv` file obtained by the instruction at
47+ https://luna25.grand-challenge.org/datasets/.
5148 If not provided, the cache is assumed to be already populated.
5249
50+ Notes
51+ -----
52+ Join the challenge at https://luna25.grand-challenge.org/.
53+ Then follow the download and extraction instructions at https://luna25.grand-challenge.org/datasets/.
5354 """
5455
5556 @property
5657 def ids (self ):
5758 return [file .name [: - len ('.mha' )] for file in (self .root / 'luna25_images' ).iterdir ()]
5859
59- def _image (self , i ):
60+ def _sitk_image (self , i ):
6061 return sitk .ReadImage (self .root / f'luna25_images/{ i } .mha' )
6162
6263 @field
6364 def image (self , i ):
64- return sitk .GetArrayFromImage (self ._image (i ))
65+ return sitk .GetArrayFromImage (self ._sitk_image (i ))
6566
6667 @field
6768 def spacing (self , i ):
68- return self ._image (i ).GetSpacing ()[::- 1 ]
69-
70- def _image_origin (self , i ):
71- return self ._image (i ).GetOrigin ()[::- 1 ]
72-
73- def _direction (self , i ):
74- return self ._image (i ).GetDirection ()[::- 1 ]
69+ return self ._sitk_image (i ).GetSpacing ()[::- 1 ]
7570
7671 @cached_property
7772 def _data (self ):
@@ -101,30 +96,31 @@ def age(self, i):
10196 return self ._data_column_value (i , 'Age_at_StudyDate' )
10297
10398 @field
104- def sex (self , i ):
99+ def gender (self , i ):
105100 return self ._data_column_value (i , 'Gender' )
106101
107102 @field
108103 def nodules (self , i ):
109104 nodules = []
105+ sitk_image = self ._sitk_image (i )
106+ shape = self .image (i ).shape
107+ bbox_size = np .array ([64 , 128 , 128 ]) # all nodule blocks in LUNA25 are of the same size
110108 for row in self ._data_rows (i ).itertuples ():
111- coords = np .array ([row .CoordX , row .CoordY , row .CoordZ ])
109+ coords = (row .CoordX , row .CoordY , row .CoordZ )
110+ center_voxel = sitk_image .TransformPhysicalPointToIndex (map (int , coords ))[::- 1 ]
111+
112112 nodule_block_metadata = self .nodule_block_metadata (row .AnnotationID )
113- assert np .all (nodule_block_metadata ['spacing' ] == self .spacing (i ))
114- image_origin = self ._image_origin (i )
115- direction = np .array (self ._direction (i )[::4 ])
116- center_voxel = ((coords [::- 1 ] - image_origin ) / self .spacing (i )) * direction
117- bbox_start_point = ((nodule_block_metadata ['origin' ] - image_origin ) / self .spacing (i )) * direction
118- bbox = [bbox_start_point , np .minimum (bbox_start_point + np .array ([64 , 128 , 128 ]), self .image (i ).shape )]
113+ bbox_start_point = sitk_image .TransformPhysicalPointToIndex (map (int , nodule_block_metadata ['origin' ][::- 1 ]))[::- 1 ]
114+ bbox = np .array ([bbox_start_point , np .minimum (bbox_start_point + bbox_size , shape )])
119115 nodules .append (
120116 LUNA25Nodule (
121117 coords = coords ,
122118 lesion_id = row .LesionID ,
123119 annotation_id = str (row .AnnotationID ),
124120 nodule_id = str (row .NoduleID ),
125121 malignancy = row .label ,
126- center_voxel = np . round ( center_voxel ). astype ( int ) ,
127- bbox = np . round ( bbox ). astype ( int ) ,
122+ center_voxel = center_voxel ,
123+ bbox = bbox ,
128124 )
129125 )
130126 return nodules
0 commit comments