|
109 | 109 | "import zipfile\n", |
110 | 110 | "\n", |
111 | 111 | "import itk\n", |
112 | | - "import pyvista as pv\n" |
| 112 | + "import pyvista as pv" |
113 | 113 | ] |
114 | 114 | }, |
115 | 115 | { |
|
133 | 133 | "metadata": {}, |
134 | 134 | "outputs": [], |
135 | 135 | "source": [ |
136 | | - "def post_image_to_fileio(input_image:itk.Image) -> str:\n", |
137 | | - " '''Post an image to file.io and return the link.'''\n", |
| 136 | + "def post_image_to_fileio(input_image: itk.Image) -> str:\n", |
| 137 | + " \"\"\"Post an image to file.io and return the link.\"\"\"\n", |
138 | 138 | "\n", |
139 | 139 | " # Save the image to a temporary file\n", |
140 | 140 | " # Note: The Vista-3D NIM on NVAIE is limited to reading .nii.gz files\n", |
141 | 141 | " tmp_dir = tempfile.mkdtemp()\n", |
142 | 142 | " tmp_filename = os.path.join(tmp_dir, \"tmp.nii.gz\")\n", |
143 | 143 | " itk.imwrite(input_image, tmp_filename)\n", |
144 | | - " \n", |
| 144 | + "\n", |
145 | 145 | " # Upload the file\n", |
146 | 146 | " with open(os.path.join(tmp_filename), \"rb\") as f:\n", |
147 | | - " res = requests.post(\n", |
148 | | - " \"https://file.io/\",\n", |
149 | | - " files={\"file\": f}\n", |
150 | | - " )\n", |
| 147 | + " res = requests.post(\"https://file.io/\", files={\"file\": f})\n", |
151 | 148 | " if res.status_code != 200:\n", |
152 | 149 | " raise RuntimeError(f\"Cannot upload file. The response {res}.\")\n", |
153 | | - " \n", |
| 150 | + "\n", |
154 | 151 | " # Get the link\n", |
155 | 152 | " res = res.json()\n", |
156 | 153 | " link = res[\"link\"]\n", |
157 | | - " \n", |
| 154 | + "\n", |
158 | 155 | " return link" |
159 | 156 | ] |
160 | 157 | }, |
|
177 | 174 | "metadata": {}, |
178 | 175 | "outputs": [], |
179 | 176 | "source": [ |
180 | | - "def nvaie_vista3d_nim(api_key:str, input_image:itk.Image) -> list:\n", |
181 | | - " '''Run the MONAI VISTA 3D model on the input image and return the result.'''\n", |
| 177 | + "def nvaie_vista3d_nim(api_key: str, input_image: itk.Image) -> list:\n", |
| 178 | + " \"\"\"Run the MONAI VISTA 3D model on the input image and return the result.\"\"\"\n", |
182 | 179 | "\n", |
183 | 180 | " # The API endpoint for the MONAI VISTA 3D model on NVIDIA AI Enterprise\n", |
184 | 181 | " invoke_url = \"https://health.api.nvidia.com/v1/medicalimaging/nvidia/vista-3d\"\n", |
185 | | - " \n", |
| 182 | + "\n", |
186 | 183 | " # Check the input image\n", |
187 | 184 | " assert len(input_image.GetSpacing()) == 3, \"The input image must be 3D.\"\n", |
188 | | - " isotropy = ((input_image.GetSpacing()[1] / input_image.GetSpacing()[0]) +\n", |
189 | | - " (input_image.GetSpacing()[2] / input_image.GetSpacing()[0])) / 2\n", |
| 185 | + " isotropy = (\n", |
| 186 | + " (input_image.GetSpacing()[1] / input_image.GetSpacing()[0])\n", |
| 187 | + " + (input_image.GetSpacing()[2] / input_image.GetSpacing()[0])\n", |
| 188 | + " ) / 2\n", |
190 | 189 | " if isotropy < 0.9 or isotropy > 1.1 or input_image.GetSpacing()[0] != 1.5:\n", |
191 | 190 | " print(\"WARNING: The input image should have 1.5 mm isotropic spacing. Performance will be degraded.\")\n", |
192 | 191 | " print(\" The input image has spacing:\", input_image.GetSpacing())\n", |
193 | 192 | " input_image_arr = itk.array_view_from_image(input_image)\n", |
194 | 193 | " minv = input_image_arr.min()\n", |
195 | 194 | " maxv = input_image_arr.max()\n", |
196 | 195 | " if minv < -1024 or maxv > 3071:\n", |
197 | | - " print(\"WARNING: The input image should have Hounsfield Units in the range [-1024, 3071]. Performance will be degraded.\")\n", |
| 196 | + " print(\n", |
| 197 | + " \"WARNING: The input image should have Hounsfield Units in the range [-1024, 3071]. Performance will be degraded.\"\n", |
| 198 | + " )\n", |
198 | 199 | " print(\" The input image has Hounsfield Units in the range:\", [minv, maxv])\n", |
199 | 200 | "\n", |
200 | 201 | " # Post the image to file.io and get the link\n", |
201 | 202 | " input_image_url = post_image_to_fileio(input_image)\n", |
202 | 203 | "\n", |
203 | 204 | " # Define the header and payload for the API call\n", |
204 | 205 | " header = {\n", |
205 | | - " \"Authorization\": \"Bearer \" + api_key, \n", |
| 206 | + " \"Authorization\": \"Bearer \" + api_key,\n", |
206 | 207 | " }\n", |
207 | | - " \n", |
| 208 | + "\n", |
208 | 209 | " payload = {\n", |
209 | 210 | " \"image\": input_image_url,\n", |
210 | 211 | " # Optionally limited processing to specific classes\n", |
211 | | - " #\"prompts\": {\n", |
| 212 | + " # \"prompts\": {\n", |
212 | 213 | " # \"classes\": [\"liver\", \"spleen\"]\n", |
213 | | - " #}\n", |
| 214 | + " # }\n", |
214 | 215 | " }\n", |
215 | 216 | "\n", |
216 | 217 | " # Call the API\n", |
217 | 218 | " session = requests.Session()\n", |
218 | 219 | " response = session.post(invoke_url, headers=header, json=payload)\n", |
219 | | - " \n", |
| 220 | + "\n", |
220 | 221 | " # Check the response\n", |
221 | 222 | " response.raise_for_status()\n", |
222 | | - " \n", |
| 223 | + "\n", |
223 | 224 | " # Get the result\n", |
224 | 225 | " with tempfile.TemporaryDirectory() as temp_dir:\n", |
225 | 226 | " z = zipfile.ZipFile(io.BytesIO(response.content))\n", |
|
230 | 231 | " if os.path.isfile(filepath) and filename.endswith(\".nrrd\"):\n", |
231 | 232 | " # SUCCESS: Return the results\n", |
232 | 233 | " return itk.imread(filepath, pixel_type=itk.SS)\n", |
233 | | - " \n", |
| 234 | + "\n", |
234 | 235 | " # FAILURE: Return None\n", |
235 | 236 | " return None" |
236 | 237 | ] |
|
252 | 253 | "metadata": {}, |
253 | 254 | "outputs": [], |
254 | 255 | "source": [ |
255 | | - "ngc_api_key = os.environ['NGC_API_KEY']" |
| 256 | + "ngc_api_key = os.environ[\"NGC_API_KEY\"]" |
256 | 257 | ] |
257 | 258 | }, |
258 | 259 | { |
|
280 | 281 | " os.makedirs(monai_data_directory, exist_ok=True)\n", |
281 | 282 | " else:\n", |
282 | 283 | " monai_data_directory = tempfile.mkdtemp()\n", |
283 | | - " input_image_filename = os.path.join(\n", |
284 | | - " monai_data_directory,\n", |
285 | | - " \"vista3d-example-1.nii.gz\"\n", |
286 | | - " )\n", |
| 284 | + " input_image_filename = os.path.join(monai_data_directory, \"vista3d-example-1.nii.gz\")\n", |
287 | 285 | " if not os.path.exists(input_image_filename):\n", |
288 | 286 | " resp = requests.get(\"https://assets.ngc.nvidia.com/products/api-catalog/vista3d/example-1.nii.gz\")\n", |
289 | | - " with open(input_image_filename, \"wb\") as f: \n", |
| 287 | + " with open(input_image_filename, \"wb\") as f:\n", |
290 | 288 | " f.write(resp.content)" |
291 | 289 | ] |
292 | 290 | }, |
|
386 | 384 | ], |
387 | 385 | "source": [ |
388 | 386 | "# For visualization purposes, we will clip the contours half-way along the x-axis\n", |
389 | | - "clipped = contours.clip('x')\n", |
| 387 | + "clipped = contours.clip(\"x\")\n", |
390 | 388 | "\n", |
391 | 389 | "# Render the clipped contours and the original image\n", |
392 | 390 | "pl = pv.Plotter()\n", |
393 | 391 | "pl.add_mesh(clipped, cmap=\"pink\", show_scalar_bar=False, opacity=1.0)\n", |
394 | | - "pl.add_volume(image, clim=[50,800], cmap=\"pink\", show_scalar_bar=False)\n", |
| 392 | + "pl.add_volume(image, clim=[50, 800], cmap=\"pink\", show_scalar_bar=False)\n", |
395 | 393 | "pl.set_background(\"black\")\n", |
396 | | - "pl.camera_position = 'xz'\n", |
| 394 | + "pl.camera_position = \"xz\"\n", |
397 | 395 | "pl.show()" |
398 | 396 | ] |
399 | 397 | }, |
|
423 | 421 | "pl2 = pv.Plotter(shape=(3, 1))\n", |
424 | 422 | "\n", |
425 | 423 | "# The normal directions (dirs) of the slices and the positions (pos) of the camera for each view\n", |
426 | | - "dirs = ['x', 'y', 'z']\n", |
427 | | - "pos = ['yz', 'xz', 'xy']\n", |
| 424 | + "dirs = [\"x\", \"y\", \"z\"]\n", |
| 425 | + "pos = [\"yz\", \"xz\", \"xy\"]\n", |
428 | 426 | "\n", |
429 | 427 | "# Extract the slices and generate the views for each subplot\n", |
430 | 428 | "for i, dir in enumerate(dirs):\n", |
431 | 429 | " image_slice = image.slice(normal=dir)\n", |
432 | 430 | " contours_slice = labels.slice(normal=dir, contour=True)\n", |
433 | | - " pl2.subplot(i,0)\n", |
434 | | - " pl2.add_mesh(image_slice, cmap=\"bone\", clim=[-200,500], show_scalar_bar=False, opacity=1.0)\n", |
| 431 | + " pl2.subplot(i, 0)\n", |
| 432 | + " pl2.add_mesh(image_slice, cmap=\"bone\", clim=[-200, 500], show_scalar_bar=False, opacity=1.0)\n", |
435 | 433 | " pl2.add_mesh(contours_slice, cmap=\"viridis\", show_scalar_bar=False, opacity=1.0, line_width=5)\n", |
436 | 434 | " pl2.camera_position = pos[i]\n", |
437 | 435 | "\n", |
|
0 commit comments