|
1 | 1 | {
|
2 | 2 | "cells": [
|
3 | 3 | {
|
4 |
| - "cell_type": "code", |
5 |
| - "execution_count": 1, |
6 |
| - "id": "4111cc1b-5123-407a-8ec6-56d65bc94bc4", |
7 | 4 | "metadata": {},
|
| 5 | + "cell_type": "markdown", |
| 6 | + "source": [ |
| 7 | + "# Positron emission tomography (PET) data realignment example\n", |
| 8 | + "\n", |
| 9 | + "This example shows how to estimate the head motion of a PET dataset using\n", |
| 10 | + "`NiFreeze`.\n", |
| 11 | + "\n", |
| 12 | + "The notebook uses the `sub-02` dataset that was generated synthetically from\n", |
| 13 | + "a real PET dataset by adding random motion. The dataset\n", |
| 14 | + "can be installed from [GIN G-node](https://gin.g-node.org/nipreps-data/tests-nifreeze):\n", |
| 15 | + "\n", |
| 16 | + "```\n", |
| 17 | + "$ datalad install -g https://gin.g-node.org/nipreps-data/tests-nifreeze.git\n", |
| 18 | + "```\n", |
| 19 | + "\n", |
| 20 | + "after which the environment variable `TEST_DATA_HOME` will need to be set to\n", |
| 21 | + "point to the corresponding folder." |
| 22 | + ], |
| 23 | + "id": "e8a4c20508512623" |
| 24 | + }, |
| 25 | + { |
| 26 | + "metadata": {}, |
| 27 | + "cell_type": "code", |
8 | 28 | "outputs": [],
|
| 29 | + "execution_count": 1, |
9 | 30 | "source": [
|
10 | 31 | "from os import getenv\n",
|
11 | 32 | "from pathlib import Path\n",
|
12 | 33 | "\n",
|
13 | 34 | "from nifreeze.data.pet import PET\n",
|
14 | 35 | "\n",
|
15 |
| - "# Install test data from gin.g-node.org:\n", |
16 |
| - "# $ datalad install -g https://gin.g-node.org/nipreps-data/tests-nifreeze.git\n", |
17 |
| - "# and point the environment variable TEST_DATA_HOME to the corresponding folder\n", |
18 | 36 | "DATA_PATH = Path(getenv(\"TEST_DATA_HOME\", str(Path.home() / \"nifreeze-tests\")))\n",
|
19 | 37 | "WORKDIR = Path.home() / \"tmp\" / \"nifreezedev\" / \"pet_data\"\n",
|
20 | 38 | "WORKDIR.mkdir(parents=True, exist_ok=True)\n",
|
|
30 | 48 | ")\n",
|
31 | 49 | "\n",
|
32 | 50 | "pet_dataset = PET.load(pet_file, json_file)"
|
33 |
| - ] |
| 51 | + ], |
| 52 | + "id": "a258948070bbc0c" |
34 | 53 | },
|
35 | 54 | {
|
36 | 55 | "cell_type": "code",
|
|
53 | 72 | "pet_dataset"
|
54 | 73 | ]
|
55 | 74 | },
|
| 75 | + { |
| 76 | + "metadata": {}, |
| 77 | + "cell_type": "markdown", |
| 78 | + "source": [ |
| 79 | + "## Model fitting and motion correction\n", |
| 80 | + "\n", |
| 81 | + "The relevant structure to model PET data is `nifreeze.model.PETModel`. We\n", |
| 82 | + "instantiate it by providing it with the loaded PET dataset." |
| 83 | + ], |
| 84 | + "id": "22dd60dcdd65f09d" |
| 85 | + }, |
56 | 86 | {
|
57 | 87 | "cell_type": "code",
|
58 | 88 | "execution_count": 4,
|
|
417 | 447 | "id": "d541ae17-8bf8-457a-8aeb-986a4324434a",
|
418 | 448 | "metadata": {},
|
419 | 449 | "outputs": [],
|
| 450 | + "source": "model.fit_predict(None)" |
| 451 | + }, |
| 452 | + { |
| 453 | + "metadata": {}, |
| 454 | + "cell_type": "markdown", |
420 | 455 | "source": [
|
421 |
| - "model.fit_predict(None)" |
422 |
| - ] |
| 456 | + "Let's now ask the model for a prediction on the `midframe[2]` time point. By\n", |
| 457 | + "calling `model.fit_predict` the model is fitted using all the available data,\n", |
| 458 | + "and a prediction is requested on the time provided as the argument. By\n", |
| 459 | + "default, the PET model employs a B-Spline based method for motion correction." |
| 460 | + ], |
| 461 | + "id": "fa33b648ed70d336" |
423 | 462 | },
|
424 | 463 | {
|
425 | 464 | "cell_type": "code",
|
426 | 465 | "execution_count": 7,
|
427 | 466 | "id": "dee05183-57b5-46ed-811a-c0b26a53a386",
|
428 | 467 | "metadata": {},
|
429 | 468 | "outputs": [],
|
| 469 | + "source": "predicted = model.fit_predict(pet_dataset.midframe[2])" |
| 470 | + }, |
| 471 | + { |
| 472 | + "metadata": {}, |
| 473 | + "cell_type": "markdown", |
430 | 474 | "source": [
|
431 |
| - "predicted = model.fit_predict(pet_dataset.midframe[2])" |
432 |
| - ] |
| 475 | + "We now save the uncorrected and corrected data so that we can visualize\n", |
| 476 | + "the difference." |
| 477 | + ], |
| 478 | + "id": "c4985826e2d8bc54" |
433 | 479 | },
|
434 | 480 | {
|
435 | 481 | "cell_type": "code",
|
|
451 | 497 | "nifti_img_after.to_filename(output_path_after)"
|
452 | 498 | ]
|
453 | 499 | },
|
| 500 | + { |
| 501 | + "metadata": {}, |
| 502 | + "cell_type": "markdown", |
| 503 | + "source": [ |
| 504 | + "Let's now visualize a number of axial, sagittal and coronal slices of the\n", |
| 505 | + "uncorrected and corrected data." |
| 506 | + ], |
| 507 | + "id": "7dfb887dcc76aa65" |
| 508 | + }, |
454 | 509 | {
|
455 | 510 | "cell_type": "code",
|
456 | 511 | "execution_count": 10,
|
|
2240 | 2295 | ")"
|
2241 | 2296 | ]
|
2242 | 2297 | },
|
| 2298 | + { |
| 2299 | + "metadata": {}, |
| 2300 | + "cell_type": "markdown", |
| 2301 | + "source": [ |
| 2302 | + "## Motion estimation\n", |
| 2303 | + "\n", |
| 2304 | + "We now want to have an estimate of the motion that the model corrects. We will\n", |
| 2305 | + "need to instantiate the `nifreeze.estimator.PETMotionEstimator`, which will\n", |
| 2306 | + "take an instance of the model. We will call `run` to get the parameters of the\n", |
| 2307 | + "affine transform estimation." |
| 2308 | + ], |
| 2309 | + "id": "95b6939bea2d1394" |
| 2310 | + }, |
2243 | 2311 | {
|
2244 | 2312 | "cell_type": "code",
|
2245 | 2313 | "execution_count": 13,
|
|
2431 | 2499 | "affines"
|
2432 | 2500 | ]
|
2433 | 2501 | },
|
| 2502 | + { |
| 2503 | + "metadata": {}, |
| 2504 | + "cell_type": "markdown", |
| 2505 | + "source": [ |
| 2506 | + "Let's now visualize the estimated motion: we will plot the translation and\n", |
| 2507 | + "rotation components in the affine transform for each axis." |
| 2508 | + ], |
| 2509 | + "id": "991990094e4a07f3" |
| 2510 | + }, |
2434 | 2511 | {
|
2435 | 2512 | "cell_type": "code",
|
2436 | 2513 | "execution_count": 16,
|
|
0 commit comments