Skip to content

Commit a7be039

Browse files
committed
updates
1 parent 6047a5d commit a7be039

1 file changed

Lines changed: 78 additions & 37 deletions

File tree

_sources/projects/Project_02_Radiotherapy.ipynb

Lines changed: 78 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,6 @@
5353
"* https://github.com/ababier/open-kbp"
5454
]
5555
},
56-
{
57-
"cell_type": "markdown",
58-
"metadata": {},
59-
"source": [
60-
"Link to data\n",
61-
"* https://github.com/ababier/open-kbp"
62-
]
63-
},
6456
{
6557
"cell_type": "markdown",
6658
"metadata": {},
@@ -94,7 +86,7 @@
9486
"\\end{aligned}\n",
9587
"$$\n",
9688
"\n",
97-
"What physical phenomena govern this loss of intensity (state at least 3 specific processes)? Which one dominates radiotherapy (6-15 MV energies)? It's easy to conclude that the highest dose of radiation is delivered at the skin, why is this untrue?"
89+
"What physical phenomena govern this loss of intensity (state at least 3 specific processes)? Which one dominates radiotherapy (which uses ~6 MeV photons)? It's easy to conclude that the highest dose of radiation is delivered at the skin, why is this untrue?"
9890
]
9991
},
10092
{
@@ -147,14 +139,24 @@
147139
"cell_type": "markdown",
148140
"metadata": {},
149141
"source": [
150-
"Run the cell below and unzip the contents of `openkbp_patient_data` into a folder. It should be present in Colab's (`/content/..`) or local directory. Note that you will need to adjust `base_path` to lead to this folder.\n",
142+
"Run the cell below and unzip the contents of `openkbp_patient_data` into a folder. It should be present in Colab's (`/content/..`) or local directory. Note that you will need to adjust `base_path` to lead to this folder. \n",
151143
"\n",
152144
"Each patient hosts the following three files: \n",
153145
"`ct.csv` - 3D grayscale CT scan of patient anatomy composed of 2D slices. Each voxel represents how much X-ray is absorbed by the tissue in Hounsfield Units (HU) \n",
154-
"`PTV63.csv` - Planning Target Volume (PTV) is a binary mask that maps the location of the tumor (tumor is 1, everything else is 0) \n",
155-
"`SpinalCord.csv` - This is a similar binary mask of our Organ at Risk (OAR), representing what we would like our beam to avoid. \n",
146+
"`PTV63.csv` - Planning Target Volume (PTV) is a sparse mask that maps the location of the tumor. We'd like binary mask so that 1 is tumor, 0 is no-tumor.\n",
147+
"\n",
148+
"The following are sparse masks of Organs at Risk (OAR), representing what we'd like our beams to avoid\n",
149+
"- `SpinalCord.csv` - Irradiating the spine can cause a serious condition known as radiation myelopathy.\n",
150+
"- `Brainstem.csv` - Radiation causes a vast myriad of devastating effects like RIBN, Ataxia, or even comas.\n",
151+
"- `LeftParotid.csv`, `RightParotid.csv` - Irradiating salivary glands can cause xerostomia (dry mouth) or worse\n",
152+
"- `Mandible.csv` - The mandible has a limited blood supply, and osteoradionecrosis can occur YEARS after treatment.\n",
153+
"\n",
154+
"These are flattened volumes with voxel indices. The cell below converts the csv files into binary 3D volumes [128, 128, 128] where each point represents an intensity (for the ct scan) or binary value (for ptv & spinal cord). You will have an optional dictionary of `patient_data` to access for your convenience.\n",
155+
"\n",
156+
"Your tasks:\n",
157+
"1) Add a line to the for loop that stacks `ct`, `ptv`, and `oars` (Organs at Risk) into a single tensor. Note that oars is a dictionary you may need to unpack. What's the final shape of this tensor? Draw an analogy to an RGB image. \n",
156158
"\n",
157-
"These are currently flattened 1D rows. The cell below converts the csv files into 3D volumes [64, 128, 128] where each point represents an intensity (for the ct scan) or binary value (for ptv & spinal cord). Add a line to the for loop that stacks `ct`, `ptv`, and `spine` into a single tensor. What's the final shape of this tensor? Draw an analogy to an RGB image."
159+
"2) Visualize a single 2D axial slice (z-axis slice) of a patient's CT scan with the tumor(ptv) overlaid...as a sanity check."
158160
]
159161
},
160162
{
@@ -163,8 +165,8 @@
163165
"metadata": {},
164166
"outputs": [],
165167
"source": [
166-
"!wget https://github.com/florilegium7/Physics-informed-DQN-Radiotherapy/releases/download/v1.0/openkbp_patient_data.zip\n",
167-
"!unzip patient_data.zip"
168+
"!wget https://github.com/florilegium7/Physics-informed-DQN-Radiotherapy/releases/download/v1/openkbp_patient_data.zip\n",
169+
"!unzip openkbp_patient_data.zip -d openkbp_patient_data"
168170
]
169171
},
170172
{
@@ -179,20 +181,60 @@
179181
"\n",
180182
"base_path = 'openkbp_patient_data' #you may adjust this (e.g. /content/openkbp_patient_data)\n",
181183
"\n",
182-
"patient_ids = [\"patient_1\", \"patient_2\", \"patient_3\",\"patient_5\",\"patient_7\",\"patient_9\", \"patient_10\", \"patient_12\" , \"patient_14\", \"patient_16\"]\n",
184+
"patient_ids = [\"pt_1\", \"pt_2\", \"pt_9\",\"pt_40\",\"pt_68\",\"pt_70\", \"pt_90\", \"pt_91\" , \"pt_99\", \"pt_187\"]\n",
183185
"patient_tensors = []\n",
184186
"\n",
185-
"#64 slices of 128 x 128 pixels : (depth, height, width)\n",
187+
"def mask_from_sparse(path,shape=(128, 128,128)): #converts voxel indices to 3D binary masks!\n",
188+
" indices = pd.read_csv(path, header=None)[0].dropna().astype(int).values\n",
189+
" mask_flat = np.zeros(np.prod(shape), dtype=np.uint8)\n",
190+
" mask_flat[indices] = 1\n",
191+
" return mask_flat.reshape(shape)\n",
192+
"\n",
193+
"def sparse_to_ct_volume(path, shape=(128, 128, 128)): #turns the csv into full 3D volume CT scans\n",
194+
" df = pd.read_csv(path, header=None).dropna()\n",
195+
" indices = df[0].astype(int).values\n",
196+
" values = df[1].astype(float).values\n",
197+
" ct_flat = np.zeros(np.prod(shape), dtype=np.float32)\n",
198+
" ct_flat[indices] = values\n",
199+
" return ct_flat.reshape(shape)\n",
200+
"\n",
201+
"\n",
202+
"#128 x 128 x 128 pixels : (depth, height, width)\n",
186203
"for pt_id in patient_ids:\n",
187-
" ct = pd.read_csv(os.path.join(base_path, pt_id, \"ct.csv\"), header=None).values.reshape((64, 128, 128))\n",
188-
" ptv = pd.read_csv(os.path.join(base_path, pt_id, \"PTV63.csv\"), header=None).values.reshape((64, 128, 128))\n",
189-
" spine = pd.read_csv(os.path.join(base_path, pt_id, \"SpinalCord.csv\"), header=None).values.reshape((64, 128, 128))\n",
190204
"\n",
191-
" pt_tensor = #Your Code Here \n",
192-
" patient_tensors.append(pt_tensor)\n",
205+
" pt_dir = os.path.join(base_path, pt_id)\n",
206+
"\n",
207+
" ct = sparse_to_ct_volume(os.path.join(pt_dir, \"ct.csv\"))\n",
208+
" ptv = mask_from_sparse(os.path.join(pt_dir, \"PTV63.csv\"))\n",
209+
"\n",
210+
" oars = {} #dictionary\n",
211+
" organs = [\"SpinalCord\", \"Brainstem\", \"LeftParotid\", \"RightParotid\", \"Mandible\"]\n",
212+
" for organ in organs:\n",
213+
" organ_path = os.path.join(pt_dir, f\"{organ}.csv\")\n",
214+
" if os.path.exists(organ_path):\n",
215+
" oars[organ] = mask_from_sparse(organ_path)\n",
216+
" \n",
217+
" patient_data = {\n",
218+
" \"id\": pt_id,\n",
219+
" \"ct\": ct, #ct scan -> 3D volume with intensities\n",
220+
" \"ptv\": ptv, #tumor -> 3D binary mask (1 means tumor!)\n",
221+
" \"oars\": oars #dictionary of organs at risk -> each is a 3D binary mask\n",
222+
" }\n",
193223
" \n",
194224
"\n",
195-
"#patient_tensors[0] --> patient 1\n"
225+
" pt_tensor = #Your Code Here \n",
226+
" patient_tensors.append(pt_tensor)\n",
227+
"\n"
228+
]
229+
},
230+
{
231+
"cell_type": "code",
232+
"execution_count": null,
233+
"metadata": {},
234+
"outputs": [],
235+
"source": [
236+
"#Your slice visualization here\n",
237+
"import matplotlib.pyplot as plt"
196238
]
197239
},
198240
{
@@ -225,6 +267,8 @@
225267
"metadata": {},
226268
"outputs": [],
227269
"source": [
270+
"import random\n",
271+
"\n",
228272
"beam_angles = np.arange(0, 360, 10) #[0, 10, 20, ..., 350]\n",
229273
"max_beams = 5 #ensures beams are chosen strategically\n",
230274
"episodes = 500\n",
@@ -259,7 +303,7 @@
259303
" mid = ct.shape[2] // 2 \n",
260304
" ct_slice = ct[:, :, mid]\n",
261305
" ptv_slice = ptv[:, :, mid]\n",
262-
" spine_slice = spine[:, :, mid]\n",
306+
" #extract organ slices HERE\n",
263307
"\n",
264308
" dose = np.zeros(slice_shape, dtype=np.float32)\n",
265309
" selected_angles = []\n",
@@ -269,18 +313,19 @@
269313
"\n",
270314
" beam = generate_beam(angle, slice_shape)\n",
271315
" dose += beam.astype(np.float32) #adds 'radiation' to the pixels \n",
272-
" chosen_angles.append(angle)\n",
316+
" selected_angles.append(angle)\n",
317+
"\n",
273318
" \n",
274-
" reward_score = reward(dose, ptv, spine)\n",
319+
" reward_score = reward(dose, ptv, organs)\n",
275320
"\n",
276-
" for angle in chosen_angles:\n",
321+
" for angle in selected_angles:\n",
277322
" #Q-learning update here\n",
278323
"\n",
279324
"\n",
280325
"\n",
281-
"def reward(dose, ptv, spine): #your reward function HERE\n",
326+
"def reward(dose, ptv, organs): #your reward function HERE\n",
282327
" raise NotImplementedError()\n",
283-
"\n",
328+
" \n",
284329
"\n",
285330
"Q = np.zeros(len(beam_angles)) #Q-table\n"
286331
]
@@ -300,6 +345,7 @@
300345
"source": [
301346
"import matplotlib as plt\n",
302347
"\n",
348+
"\n",
303349
"patient = random.choice(patient_tensors)\n",
304350
"mid = patient.shape[3] // 2\n",
305351
"ct, ptv, cord = patient[0, :, :, mid], patient[1, :, :, mid], patient[2, :, :, mid]\n",
@@ -375,8 +421,7 @@
375421
" beam_mask[r_spread, c_spread] += decay * spread_value \n",
376422
"\n",
377423
" beam_mask = np.clip(beam_mask, 0, 1.0) \n",
378-
" return beam_mask\n",
379-
"\n"
424+
" return beam_mask"
380425
]
381426
},
382427
{
@@ -437,10 +482,6 @@
437482
"metadata": {},
438483
"outputs": [],
439484
"source": [
440-
"import numpy as np\n",
441-
"import matplotlib.pyplot as plt\n",
442-
"from skimage.draw import line_nd\n",
443-
"\n",
444485
"#your conclusions\n",
445486
"selected_angles = \n",
446487
"\n",
@@ -501,7 +542,7 @@
501542
],
502543
"metadata": {
503544
"kernelspec": {
504-
"display_name": "Python 3 (ipykernel)",
545+
"display_name": "Python 3",
505546
"language": "python",
506547
"name": "python3"
507548
},
@@ -515,7 +556,7 @@
515556
"name": "python",
516557
"nbconvert_exporter": "python",
517558
"pygments_lexer": "ipython3",
518-
"version": "3.9.7"
559+
"version": "3.9.6"
519560
}
520561
},
521562
"nbformat": 4,

0 commit comments

Comments
 (0)