Showing preview only (5,417K chars total). Download the full file or copy to clipboard to get everything.
Repository: InsightSoftwareConsortium/ITKElastix
Branch: main
Commit: 63129ec62cdf
Files: 249
Total size: 33.3 MB
Directory structure:
gitextract_mgec5cpq/
├── .binder/
│ ├── postBuild
│ └── requirements.txt
├── .clang-format
├── .gitattributes
├── .github/
│ └── workflows/
│ ├── build-test-package.yml
│ ├── clang-format-linter.yml
│ └── wasm.yml
├── .gitignore
├── .jupyter/
│ └── jupyter_notebook_config.py
├── CMakeLists.txt
├── CTestConfig.cmake
├── LICENSE
├── README.md
├── environment.yml
├── examples/
│ ├── 1_NumPyArray.ipynb
│ ├── ITK_Example01_SimpleRegistration.ipynb
│ ├── ITK_Example02_CustomOrMultipleParameterMaps.ipynb
│ ├── ITK_Example03_Masked_3D_Registration.ipynb
│ ├── ITK_Example04_InitialTransformAndMultiThreading.ipynb
│ ├── ITK_Example05_PointRegistration.ipynb
│ ├── ITK_Example06_GroupwiseRegistration.ipynb
│ ├── ITK_Example07_MultimetricMultiImageRegistration.ipynb
│ ├── ITK_Example08_SimpleTransformix.ipynb
│ ├── ITK_Example09_PointSetAndMaskTransformation.ipynb
│ ├── ITK_Example10_Transformix_Jacobian.ipynb
│ ├── ITK_Example11_Transformix_DeformationField.ipynb
│ ├── ITK_Example12_DifferentSizeTransformation.ipynb
│ ├── ITK_Example13_ITKResampling.ipynb
│ ├── ITK_Example14_WorldCoordinatesExplanation_Napari.ipynb
│ ├── ITK_Example15_Transformix_image_TranslationTransform.ipynb
│ ├── ITK_Example16_Transformix_mesh_TranslationTransform.ipynb
│ ├── ITK_Example17_MONAIWithPreregistration.ipynb
│ ├── ITK_Example18_MONAI_affine_Elastix_nonlinear.ipynb
│ ├── ITK_Example20_PixelTypes.ipynb
│ ├── ITK_Example21_ConstrainedRegistration.ipynb
│ ├── ITK_Example22_ConvertToITKTransform.ipynb
│ ├── ITK_Example_RegistrationWithCorrespondingPointsInMemory.ipynb
│ ├── ITK_Example_TomlFileFormatForParameterFiles.ipynb
│ ├── ITK_Registration_App.ipynb
│ ├── ITK_UnitTestExample1_RigidRegistration.ipynb
│ ├── ITK_UnitTestExample2_AffineRegistration.ipynb
│ ├── ITK_UnitTestExample3_BsplineRegistration.ipynb
│ ├── ITK_UnitTestExample4_MaskedRegistration.ipynb
│ ├── ITK_UnitTestExample5_GroupwiseRegistration.ipynb
│ ├── ITK_UnitTestExample6_PointSetTransformation.ipynb
│ ├── ITK_UnitTestExample7_SizeTransformation.ipynb
│ ├── data/
│ │ ├── CT_2D_head_fixed.mha
│ │ ├── CT_2D_head_fixed_mask.mha
│ │ ├── CT_2D_head_moving.mha
│ │ ├── CT_2D_head_moving_mask.mha
│ │ ├── CT_2D_plus_time.nii
│ │ ├── CT_3D_lung_fixed.mha
│ │ ├── CT_3D_lung_fixed_mask.mha
│ │ ├── CT_3D_lung_fixed_point_set.txt
│ │ ├── CT_3D_lung_fixed_point_set_corrected.txt
│ │ ├── CT_3D_lung_moving.mha
│ │ ├── CT_3D_lung_moving_mask.mha
│ │ ├── CT_3D_lung_moving_point_set.txt
│ │ ├── CT_3D_lung_moving_point_set_corrected.txt
│ │ ├── TransformParameters.0.txt
│ │ ├── TransformParameters.1.txt
│ │ ├── fixed_point_set_test.txt
│ │ ├── lung_sem/
│ │ │ └── ParameterFile.txt
│ │ ├── parameters.3D.NC.affine.ASGD.001.txt
│ │ ├── parameters_Affine.txt
│ │ ├── parameters_BSpline.txt
│ │ ├── parameters_Bspline_Multimetric.txt
│ │ └── parameters_Rigid.txt
│ ├── exampleoutput/
│ │ ├── Parameters.0.txt
│ │ ├── Parameters.1.txt
│ │ ├── Parameters.2.txt
│ │ ├── Parameters.3.txt
│ │ ├── TransformParameters.0.txt
│ │ ├── TransformParameters.1.txt
│ │ ├── fullSpatialJacobian.nii
│ │ ├── itk_composite_transform.h5
│ │ ├── outputpoints.txt
│ │ ├── parameters_custom.txt
│ │ ├── result_image.mha
│ │ └── spatialJacobian.nii
│ ├── exampleoutput_unittests/
│ │ └── outputpoints.txt
│ └── requirements.txt
├── itk-module.cmake
├── itk_wasm_env.bash
├── package.json
├── pixi.toml
├── pnpm-workspace.yaml
├── pyproject.toml
├── test/
│ ├── Baseline/
│ │ ├── CT_2D_head_test.mha.sha512
│ │ ├── CT_3D_lung_test.mha.sha512
│ │ └── itkElastixRegistrationMethodTestOutput.mha.sha512
│ ├── CMakeLists.txt
│ ├── Input/
│ │ ├── CT_2D_head_fixed.mha.sha512
│ │ ├── CT_2D_head_fixed_mask.mha.sha512
│ │ ├── CT_2D_head_moving.mha.sha512
│ │ ├── CT_2D_head_moving_mask.mha.sha512
│ │ ├── CT_3D_lung_fixed.mha.sha512
│ │ ├── CT_3D_lung_fixed_mask.mha.sha512
│ │ ├── CT_3D_lung_fixed_small.mha.sha512
│ │ ├── CT_3D_lung_moving.mha.sha512
│ │ ├── CT_3D_lung_moving_mask.mha.sha512
│ │ ├── parameters.3D.NC.bspline.ASGD.001.txt
│ │ ├── parameters_BSpline.txt
│ │ ├── parameters_Rigid.txt
│ │ └── transformparameters.3DCT_lung.affine.txt
│ └── itkElastixRegistrationMethodTest.cxx
├── wasm/
│ ├── CMakeLists.txt
│ ├── default-parameter-map.cxx
│ ├── elastix-wasm.cxx
│ ├── python/
│ │ ├── itkwasm-elastix/
│ │ │ ├── .gitattributes
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── docs/
│ │ │ │ ├── Makefile
│ │ │ │ ├── conf.py
│ │ │ │ ├── index.md
│ │ │ │ ├── make.bat
│ │ │ │ └── requirements.txt
│ │ │ ├── itkwasm_elastix/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _version.py
│ │ │ │ ├── default_parameter_map.py
│ │ │ │ ├── default_parameter_map_async.py
│ │ │ │ ├── elastix.py
│ │ │ │ ├── elastix_async.py
│ │ │ │ ├── read_parameter_files.py
│ │ │ │ ├── read_parameter_files_async.py
│ │ │ │ ├── write_parameter_files.py
│ │ │ │ └── write_parameter_files_async.py
│ │ │ ├── pyproject.toml
│ │ │ └── tests/
│ │ │ ├── __init__.py
│ │ │ ├── fixtures.py
│ │ │ ├── test_default_parameter_map.py
│ │ │ ├── test_elastix.py
│ │ │ ├── test_itkwasm_elastix.py
│ │ │ ├── test_read_parameter_files.py
│ │ │ ├── test_write_parameter_files.py
│ │ │ └── test_write_parameter_files_async.py
│ │ ├── itkwasm-elastix-emscripten/
│ │ │ ├── .gitattributes
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── itkwasm_elastix_emscripten/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _version.py
│ │ │ │ ├── default_parameter_map_async.py
│ │ │ │ ├── elastix_async.py
│ │ │ │ ├── js_package.py
│ │ │ │ ├── read_parameter_files_async.py
│ │ │ │ └── write_parameter_files_async.py
│ │ │ ├── pyproject.toml
│ │ │ ├── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── fixtures.py
│ │ │ │ ├── test_itkwasm_elastix.py
│ │ │ │ └── test_write_parameter_files_async.py
│ │ │ └── tests/
│ │ │ ├── __init__.py
│ │ │ ├── fixtures.py
│ │ │ ├── test_default_parameter_map_async.py
│ │ │ ├── test_elastix_async.py
│ │ │ ├── test_read_parameter_files_async.py
│ │ │ └── test_write_parameter_files_async.py
│ │ └── itkwasm-elastix-wasi/
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── itkwasm_elastix_wasi/
│ │ │ ├── __init__.py
│ │ │ ├── _version.py
│ │ │ ├── default_parameter_map.py
│ │ │ ├── elastix.py
│ │ │ ├── read_parameter_files.py
│ │ │ ├── wasm_modules/
│ │ │ │ ├── default-parameter-map.wasi.wasm
│ │ │ │ ├── elastix.wasi.wasm
│ │ │ │ ├── read-parameter-file.wasi.wasm
│ │ │ │ ├── read-parameter-files.wasi.wasm
│ │ │ │ └── write-parameter-files.wasi.wasm
│ │ │ └── write_parameter_files.py
│ │ ├── pyproject.toml
│ │ └── tests/
│ │ ├── __init__.py
│ │ ├── common.py
│ │ ├── test_default_parameter_map.py
│ │ ├── test_elastix.py
│ │ ├── test_elastix_wasm.py
│ │ ├── test_read_parameter_files.py
│ │ └── test_write_parameter_files.py
│ ├── read-parameter-files.cxx
│ ├── typescript/
│ │ ├── .gitignore
│ │ ├── .nojekll
│ │ ├── .npmignore
│ │ ├── README.md
│ │ ├── build/
│ │ │ ├── rollup.browser.config.js
│ │ │ └── rollup.node.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── playwright.config.ts
│ │ ├── src/
│ │ │ ├── default-parameter-map-node-options.ts
│ │ │ ├── default-parameter-map-node-result.ts
│ │ │ ├── default-parameter-map-node.ts
│ │ │ ├── default-parameter-map-options.ts
│ │ │ ├── default-parameter-map-result.ts
│ │ │ ├── default-parameter-map.ts
│ │ │ ├── default-web-worker.ts
│ │ │ ├── elastix-node-options.ts
│ │ │ ├── elastix-node-result.ts
│ │ │ ├── elastix-node.ts
│ │ │ ├── elastix-options.ts
│ │ │ ├── elastix-result.ts
│ │ │ ├── elastix.ts
│ │ │ ├── index-all.ts
│ │ │ ├── index-common.ts
│ │ │ ├── index-node-only.ts
│ │ │ ├── index-node.ts
│ │ │ ├── index-only.ts
│ │ │ ├── index-worker-embedded.min.ts
│ │ │ ├── index-worker-embedded.ts
│ │ │ ├── index.ts
│ │ │ ├── itkConfig.js
│ │ │ ├── pipeline-worker-url.ts
│ │ │ ├── pipelines-base-url.ts
│ │ │ ├── read-parameter-files-node-options.ts
│ │ │ ├── read-parameter-files-node-result.ts
│ │ │ ├── read-parameter-files-node.ts
│ │ │ ├── read-parameter-files-options.ts
│ │ │ ├── read-parameter-files-result.ts
│ │ │ ├── read-parameter-files.ts
│ │ │ ├── version.ts
│ │ │ ├── write-parameter-files-node-result.ts
│ │ │ ├── write-parameter-files-node.ts
│ │ │ ├── write-parameter-files-options.ts
│ │ │ ├── write-parameter-files-result.ts
│ │ │ └── write-parameter-files.ts
│ │ ├── test/
│ │ │ ├── browser/
│ │ │ │ ├── common.ts
│ │ │ │ ├── default-parameter-map.spec.ts
│ │ │ │ ├── read-parameter-files.spec.ts
│ │ │ │ └── write-parameter-files.spec.ts
│ │ │ └── node/
│ │ │ ├── default-parameter-map-test.js
│ │ │ ├── elastix-test.js
│ │ │ ├── read-parameter-files-test.js
│ │ │ └── write-parameter-files-test.js
│ │ ├── tsconfig.json
│ │ └── vite.config.js
│ └── write-parameter-files.cxx
└── wrapping/
├── CMakeLists.txt
├── dockcross-manylinux-build-module-wheels-opencl.sh
├── dockcross-manylinux-download-cache.sh
├── elxParameterObject.wrap
├── itkElastixRegistrationMethod.wrap
├── itkTransformixFilter.wrap
├── stdParameterMap.i
├── test/
│ ├── CMakeLists.txt
│ ├── test_elx_parameter_object_dict.py
│ ├── test_itk_elastix_registration_method.py
│ ├── test_itk_elastix_registration_method_dict.py
│ └── test_itk_transformix_filter.py
└── transformix_extras.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .binder/postBuild
================================================
#!/bin/bash
conda install -c conda-forge nodejs
jupyter labextension install @jupyter-widgets/jupyterlab-manager@2.0.0 --dev-build=False --minimize=False
jupyter labextension install jupyter-matplotlib jupyterlab-datawidgets itkwidgets --dev-build=False --minimize=False
================================================
FILE: .binder/requirements.txt
================================================
itk-elastix>=0.25.1
itkwidgets>=0.32.0
jupyterlab>=2.2.0
imageio
ipywidgets>=7.5.1
ipympl>=0.5.7
numpy
torch>=2.0
monai>=1.3.0
matplotlib>=3.5.0
PyQt5==5.15.0
PyQt5-sip==12.8.0
QtPy==1.9.0
voila
tqdm
================================================
FILE: .clang-format
================================================
## This config file is only relevant for clang-format version 8.0.0
##
## Examples of each format style can be found on the in the clang-format documentation
## See: https://clang.llvm.org/docs/ClangFormatStyleOptions.html for details of each option
##
## The clang-format binaries can be downloaded as part of the clang binary distributions
## from http://releases.llvm.org/download.html
##
## Use the script Utilities/Maintenance/clang-format.bash to faciliate
## maintaining a consistent code style.
##
## EXAMPLE apply code style enforcement before commit:
# Utilities/Maintenance/clang-format.bash --clang ${PATH_TO_CLANG_FORMAT_8.0.0} --modified
## EXAMPLE apply code style enforcement after commit:
# Utilities/Maintenance/clang-format.bash --clang ${PATH_TO_CLANG_FORMAT_8.0.0} --last
---
# This configuration requires clang-format version 8.0.0 exactly.
BasedOnStyle: Mozilla
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
# clang 9.0 AllowAllArgumentsOnNextLine: true
# clang 9.0 AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
# clang 9.0 AllowShortLambdasOnASingleLine: All
# clang 9.0 features AllowShortIfStatementsOnASingleLine: Never
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: All
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BreakBeforeBraces: Custom
BraceWrapping:
# clang 9.0 feature AfterCaseLabel: false
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
## This is the big change from historical ITK formatting!
# Historically ITK used a style similar to https://en.wikipedia.org/wiki/Indentation_style#Whitesmiths_style
# with indented braces, and not indented code. This style is very difficult to automatically
# maintain with code beautification tools. Not indenting braces is more common among
# formatting tools.
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: None
#clang 6.0 BreakBeforeInheritanceComma: true
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
#clang 6.0 BreakConstructorInitializersBeforeComma: true
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
## The following line allows larger lines in non-documentation code
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
IndentPPDirectives: AfterHash
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
## The following line allows larger lines in non-documentation code
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Middle
ReflowComments: true
# We may want to sort the includes as a separate pass
SortIncludes: false
# We may want to revisit this later
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
# SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 2
UseTab: Never
...
================================================
FILE: .gitattributes
================================================
# Custom attribute to mark sources as using our C++/C code style.
[attr]our-c-style whitespace=tab-in-indent,no-lf-at-eof hooks.style=KWStyle,clangformat
*.c our-c-style
*.h our-c-style
*.cxx our-c-style
*.hxx our-c-style
*.txx our-c-style
*.txt whitespace=tab-in-indent,no-lf-at-eof
*.cmake whitespace=tab-in-indent,no-lf-at-eof
# ExternalData content links must have LF newlines
*.md5 crlf=input
*.sha512 crlf=input
================================================
FILE: .github/workflows/build-test-package.yml
================================================
name: Build
on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
branches:
- main
jobs:
cxx:
uses: InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction/.github/workflows/build-test-cxx.yml@v5.4.5
py-dev:
if: github.ref != 'refs/heads/master' && github.ref != 'refs/heads/main' && !startsWith(github.ref, 'refs/tags')
uses: InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction/.github/workflows/build-test-package-python.yml@v5.4.6
with:
python3-minor-versions: '["10","11"]'
test-notebooks: true
secrets:
pypi_password: ${{ secrets.pypi_password }}
py-main:
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags')
uses: InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction/.github/workflows/build-test-package-python.yml@v5.4.6
with:
python3-minor-versions: '["10","11"]'
test-notebooks: true
secrets:
pypi_password: ${{ secrets.pypi_password }}
================================================
FILE: .github/workflows/clang-format-linter.yml
================================================
name: clang-format linter
on: [push,pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 1
- uses: InsightSoftwareConsortium/ITKClangFormatLinterAction@main
================================================
FILE: .github/workflows/wasm.yml
================================================
name: WebAssembly
on:
push:
branches:
- main
tags:
- '*'
pull_request:
branches:
- main
jobs:
build-wasm:
name: "build-test-wasm"
runs-on: ubuntu-24.04
steps:
- name: Free Disk Space (Ubuntu)
uses: jlumbroso/free-disk-space@main
with:
large-packages: false
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
- uses: prefix-dev/setup-pixi@v0.8.1
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: true
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: pnpm
- name: Install Playwright Browsers
working-directory: wasm/typescript
run: pnpm exec playwright install --with-deps
- name: Build Typescript
run: |
pixi run bindgen-build-typescript
- name: Build Python
run: |
pixi run bindgen-build-python
- name: Test TypeScript
run: |
pixi run test-typescript
- name: Test Python WASI
run: |
pixi run test-python-wasi
================================================
FILE: .gitignore
================================================
ITK-cp27-cp27m-manylinux1_x64
ITK-cp27-cp27mu-manylinux1_x64
ITK-cp35-cp35m-manylinux1_x64
ITK-cp36-cp36m-manylinux1_x64
ITK-cp37-cp37m-manylinux1_x64
ITKPythonBuilds-linux.tar
ITKPythonBuilds-linux.tar.zst
ITKPythonPackage/
OpenCL-ICD-Loader-build/
OpenCL-ICD-Loader/
dist/
doxygen-1.8.11.linux.bin.tar.gz
itk_elastix_opencl.egg-info/
standalone-x64-build
tools/
zstd-1.2.0-linux.tar
zstd-1.2.0-linux/
.ipynb_checkpoints/
examples/Parameters.*.txt
node_modules/
wasi-build
emscripten-build
wasm/typescript/demo/
wasm/test
micromamba/
.pixi/
================================================
FILE: .jupyter/jupyter_notebook_config.py
================================================
# Configuration file for jupyter-notebook.
## Supply overrides for the tornado.web.Application that the Jupyter notebook uses.
c.NotebookApp.tornado_settings = {"websocket_max_message_size": 800 * 1024 * 1024} # 800 MB
c.VoilaConfiguration.theme = "dark"
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.16.3)
project(Elastix)
if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 17)
# SuperElastix/elastix uses C++17 specific features in some of its header files.
set(CMAKE_CXX_STANDARD 17)
endif()
if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif()
# To ease enablement with Python packaging
if(DEFINED ENV{ELASTIX_USE_OPENCL})
set(ELASTIX_USE_OPENCL ON CACHE BOOL "Enable OpenCL support in Elastix")
endif()
set(Elastix_LIBRARIES elastix_lib transformix_lib)
if(ELASTIX_USE_OPENCL)
list(APPEND Elastix_LIBRARIES elxOpenCL)
endif()
set(ELASTIX_BUILD_EXECUTABLE OFF)
set(ELASTIX_BUILD_EXECUTABLE OFF CACHE BOOL "Generate executable or library")
# Avoid LGPL code and ANN shared library
if(NOT DEFINED USE_KNNGraphAlphaMutualInformationMetric)
set(USE_KNNGraphAlphaMutualInformationMetric OFF)
set(USE_KNNGraphAlphaMutualInformationMetric OFF CACHE BOOL "Use KNN metric. Requires ANN library.")
endif()
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-aggressive-loop-optimizations")
endif()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if(NOT ITK_SOURCE_DIR)
find_package(ITK REQUIRED)
endif()
include(FetchContent)
# Set up Elastix build parameters for populate step
option(ELASTIX_BUILD_TESTING OFF)
set(_itk_build_testing ${BUILD_TESTING})
set(BUILD_TESTING ${ELASTIX_BUILD_TESTING})
set(_itk_build_shared ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS OFF) # Elastix does not support shared libs
# Building Python wheels, disable installation of elastix artifacts
if(SKBUILD)
option(ELASTIX_NO_INSTALL_RUNTIME_LIBRARIES "Do not install runtime libraries" ON)
option(ELASTIX_NO_INSTALL_EXECUTABLES "Do not install executables" ON)
option(ELASTIX_NO_INSTALL_DEVELOPMENT "Do not install development headers and static libraries" ON)
mark_as_advanced(ELASTIX_NO_INSTALL_EXECUTABLES ELASTIX_NO_INSTALL_RUNTIME_LIBRARIES ELASTIX_NO_INSTALL_DEVELOPMENT)
endif()
if(WASI OR EMSCRIPTEN)
option(ELASTIX_NO_INSTALL_EXECUTABLES "Do not install executables" ON)
endif()
set(elastix_GIT_REPOSITORY "https://github.com/SuperElastix/elastix.git")
# Upstream tag 5.3.1, 2026-03-17
set(elastix_GIT_TAG "ef34ca99d84c226d1bb72d534c8a201526a5c034")
FetchContent_Declare(
elx
GIT_REPOSITORY ${elastix_GIT_REPOSITORY}
GIT_TAG ${elastix_GIT_TAG})
FetchContent_GetProperties(elx)
if(NOT elx_POPULATED)
FetchContent_Populate(elx)
# Use CMake's FindOpenCL.cmake, which is backend agnostic
file(REMOVE ${elx_SOURCE_DIR}/CMake/FindOpenCL.cmake)
if(ELASTIX_USE_OPENCL)
find_package(OpenCL REQUIRED)
set(OPENCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIRS} CACHE PATH "OpenCL include directories")
set(OPENCL_LIBRARIES ${OpenCL_LIBRARIES} CACHE FILEPATH "OpenCL library")
endif()
add_subdirectory(${elx_SOURCE_DIR} ${elx_BINARY_DIR})
endif()
set(Elastix_DIR "${elx_BINARY_DIR}")
find_package(Elastix REQUIRED)
include_directories( ${ELASTIX_INCLUDE_DIRS} )
link_directories( ${ELASTIX_LIBRARY_DIRS} )
#include(${ELASTIX_USE_FILE})
if(ELASTIX_USE_OPENCL)
add_definitions(-DELASTIX_USE_OPENCL)
endif()
# Reset parameters for ITK remote module build
if (NOT WASI AND NOT EMSCRIPTEN)
set(BUILD_TESTING ${_itk_build_testing})
set(BUILD_SHARED_LIBS ${_itk_build_shared})
endif()
if(ITK_WRAP_PYTHON) # Python wrapping is enabled
get_property(multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(multi_config)
if(NOT (CMAKE_CONFIGURATION_TYPES STREQUAL "Release"))
message(WARNING "Python wrapping of ITKElastix is known not to work with RelWithDebInfo configuration. Release is recommended. Your CMAKE_CONFIGURATION_TYPES: ${CMAKE_CONFIGURATION_TYPES}")
endif()
else()
if(NOT (CMAKE_BUILD_TYPE STREQUAL "Release"))
message(WARNING "Python wrapping of ITKElastix is known not to work with RelWithDebInfo configuration. Release is recommended. Your CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
endif()
endif()
endif()
option(ITKELASTIX_BUILD_WASM_EXECUTABLES "Build WASM executables" OFF)
if(NOT ITK_SOURCE_DIR)
find_package(ITK REQUIRED)
list(APPEND CMAKE_MODULE_PATH ${ITK_CMAKE_DIR})
include(ITKModuleExternal)
if(WASI OR EMSCRIPTEN OR ITKELASTIX_BUILD_WASM_EXECUTABLES)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(wasm)
endif()
else()
set(ITK_DIR ${CMAKE_BINARY_DIR})
itk_module_impl()
endif()
# ITK version 6.0+ requires exported targets for used libraries
itk_module_target(elastix_lib NO_INSTALL)
itk_module_target(transformix_lib NO_INSTALL)
================================================
FILE: CTestConfig.cmake
================================================
set(CTEST_PROJECT_NAME "ITK")
set(CTEST_NIGHTLY_START_TIME "1:00:00 UTC")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "open.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=Insight")
set(CTEST_DROP_SITE_CDASH TRUE)
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
ITKElastix
==========
[](https://github.com/InsightSoftwareConsortium/ITKElastix/actions/workflows/wasm.yml)

[](https://pypi.python.org/pypi/itk-elastix)
[](https://mybinder.org/v2/gh/InsightSoftwareConsortium/ITKElastix/main?urlpath=lab/tree/examples%2FITK_Example01_SimpleRegistration.ipynb)
[](https://mybinder.org/v2/gh/InsightSoftwareConsortium/ITKElastix/main?urlpath=%2Fvoila%2Frender%2Fexamples%2FITK_Registration_App.ipynb)
[](https://github.com/InsightSoftwareConsortium/ITKElastix/blob/main/LICENSE)
[](https://zenodo.org/badge/latestdoi/207451937)
[](https://czi.co/EOSS)
Overview
--------
Provides an [ITK](https://www.itk.org) Python, JavaScript, and WebAssembly interface to [elastix](https://elastix.dev/), a toolbox for rigid and nonrigid registration of images.
elastix is open source software, based on the well-known [Insight Toolkit (ITK)](https://discourse.itk.org). The software consists of a collection of algorithms that are commonly used to solve (medical) image registration problems. The modular design of elastix allows the user to quickly configure, test, and compare different registration methods for a specific application.
[👨💻 **Live JavaScript API Demo** ✨](https://itk-wasm-elastix-app-js.on.fleek.co/ ':include :type=iframe width=100% height=800px')
Installation
------------
Install cross-platform native binary Python packages with [pip](https://pypi.org/project/pip/):
```sh
pip install itk-elastix
```
*Experimental* WebAssembly Python packages can be installed across platforms with:
```sh
pip install itkwasm-elastix
```
> **Note**
The API for the WebAssembly and native binary packages are slightly different. For the WebAssembly interface, see [the package's Sphinx documentation](https://py.docs.elastix.wasm.itk.eth.limo/). For the interface to the native binaries, see the *examples/* directory in this repository.
JavaScript / TypesScript packages cas be installed with
```sh
npm install @itk-wasm/elastix
```
Usage
-----
To register two images with the native Python binaries, traditionally called the fixed image and the moving image:
import itk
fixed_image = itk.imread('path/to/fixed_image.mha')
moving_image = itk.imread('path/to/moving_image.mha')
registered_image, params = itk.elastix_registration_method(fixed_image, moving_image)
Interactive examples and tutorial material can be found in the [examples](https://github.com/InsightSoftwareConsortium/ITKElastix/tree/main/examples) directory. Run the examples in free cloud compute containers [on MyBinder](https://mybinder.org/v2/gh/InsightSoftwareConsortium/ITKElastix/main?urlpath=lab/tree/examples%2FITK_Example01_SimpleRegistration.ipynb) or clone the repository and run the notebooks locally in [Jupyter Notebook or Jupyter Lab](https://jupyter.org/). Try out the *experimental* GPU packages [on Paperspace Gradient](https://www.paperspace.com/temmx3m64/notebook/prdfn7bsz).
ITKElastix can be used with both the [procedural](https://docs.python.org/3/howto/functional.html) and the [object oriented method](https://docs.python.org/3/howto/functional.html), as shown in the example notebooks. The procedural method is shorter, less explicit and currently slightly less functional than the object oriented method, however the execution time and output do not differ apart from possible differences due to the stochastic nature of the Elastix algorithm.
To find parameters that work well with specific datasets, see the [elastix Model Zoo](https://lkeb.ml/modelzoo/).
For a graphical user interface in a desktop application, see the [napari plugin](https://github.com/SuperElastix/elastix_napari).
Additional [documentation is available for the WebAssembly JavaScript bindings](https://js.docs.elastix.wasm.itk.eth.limo/) and [WebAssembly Python bindings](https://py.docs.elastix.wasm.itk.eth.limo/).
Acknowledgements
----------------
ITKElastix was developed in part with support from:
- [NIH NIMH BRAIN Initiative](https://braininitiative.nih.gov/) under award 1RF1MH126732.
- The [Essential Open Source Software for Science (EOSS)](https://czi.co/EOSS) program, Cycles 4 and 6, at [Chan Zuckerberg Initiative](https://chanzuckerberg.com/) under the awards [Open Source Image Registration: The elastix Toolbox](https://chanzuckerberg.com/eoss/proposals/open-source-image-registration-the-elastix-toolbox/).
The lead developers of elastix are [Stefan Klein](https://github.com/stefanklein) and [Marius Staring](https://github.com/mstaring).
This software was initially developed at the Image Sciences Institute, under supervision of Josien P.W. Pluim. Today, [many](https://github.com/SuperElastix/elastix/graphs/contributors) have
contributed to elastix.
If you use this software anywhere we would appreciate if you cite the following articles:
- K. Ntatsis, N. Dekker, V. Valk, T. Birdsong, D. Zukić, S. Klein, M Staring, M McCormick,
[\"itk-elastix: Medical image registration in Python\"](https://conference.scipy.org/proceedings/scipy2023/konstantinos_ntatsis.html),
Proceedings of the 22nd Python in Science Conference,
pp. 101 - 105, 2023, https://doi.org/10.25080/gerudo-f2bc6f59-00d.
- D.P. Shamonin, E.E. Bron, B.P.F. Lelieveldt, M. Smits, S. Klein
and M. Staring, \"Fast Parallel Image Registration on CPU and GPU
for Diagnostic Classification of Alzheimer's Disease\", Frontiers in
Neuroinformatics, vol. 7, no. 50, pp. 1-15, January 2014.
This ITK module is based on [SimpleElastix](https://simpleelastix.github.io/), created by [Kasper Marstal](https://github.com/kaspermarstal). For more information, see:
- Kasper Marstal, Floris Berendsen, Marius Staring and Stefan Klein,
\"SimpleElastix: A user-friendly, multi-lingual library for medical
image registration\", International Workshop on Biomedical Image
Registration (WBIR), Las Vegas, Nevada, USA, 2016
================================================
FILE: environment.yml
================================================
name: itkwasm-elastix
channels:
- conda-forge
dependencies:
- pytest
- python=3.11
- pip
- pip:
- hatch
- itkwasm-compare-images
- itkwasm-image-io
================================================
FILE: examples/1_NumPyArray.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Working with NumPy Array Images"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import itk\n",
"import numpy as np\n",
"import imageio\n",
"from itkwidgets import view, compare, checkerboard"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Images as NumPy arrays can be registered.\n",
"\n",
"Convert them to floating point arrays, then to ITK images for registration."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"numpy.ndarray"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fixed = imageio.imread(\"data/CT_2D_head_fixed.mha\")\n",
"fixed = np.asarray(fixed).astype(np.float32)\n",
"type(fixed)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"numpy.ndarray"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"moving = imageio.imread(\"data/CT_2D_head_moving.mha\")\n",
"moving = np.asarray(moving).astype(np.float32)\n",
"type(moving)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "71241595c02d4bdab4c5da75531373ad",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"AppLayout(children=(HBox(children=(Label(value='Link:'), Checkbox(value=False, description='cmap'), Checkbox(v\u2026"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"compare(fixed, moving, ui_collapsed=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Before registration, the moving image is not aligned with the fixed image."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "fbce1ccbcc51461195e41a6628ae3863",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Viewer(annotations=False, interpolation=False, rendered_image=<itk.itkImagePython.itkImageF2; p\u2026"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"checkerboard(fixed, moving, pattern=10)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Register!\n",
"registered, parameters = itk.elastix_registration_method(\n",
" itk.image_from_array(fixed), itk.image_from_array(moving))\n",
"type(registered)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "a53ed7e6f48c405582228821d5b58464",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"AppLayout(children=(HBox(children=(Label(value='Link:'), Checkbox(value=False, description='cmap'), Checkbox(v\u2026"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"compare(fixed, registered, ui_collapsed=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The registered moving image is aligned with the fixed image"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f43861b9188e47ee979b74c64b7e68d6",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Viewer(annotations=False, interpolation=False, rendered_image=<itk.itkImagePython.itkImageF2; p\u2026"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"checkerboard(fixed, registered, pattern=10)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example01_SimpleRegistration.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Simple Elastix"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Registration"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import itk\n",
"from itkwidgets import compare, checkerboard\n",
"import numpy as np"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Image registration** finds the *spatial transformation that aligns images in the presence of noise*."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In image registration, we typically identify the two images as the fixed and moving image. Our goal is to find the spatial transformation that makes the moving image align with the fixed image.\n",
"\n",
"First, let's load our **fixed image** and the image we will align to our fixed image, the **moving image**."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Load images with itk floats (itk.F). Necessary for elastix\n",
"fixed_image = itk.imread(\"data/CT_2D_head_fixed.mha\", itk.F)\n",
"moving_image = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For now we will use a default parametermap of elastix, for more info about parametermaps, see [example2](ITK_Example02_CustomOrMultipleParameterMaps.ipynb#section_id2)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"default_rigid_parameter_map = itk.ParameterObject.GetDefaultParameterMap(\"rigid\")\n",
"parameter_object = itk.ParameterObject.New(parameter_map=default_rigid_parameter_map)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Registration can either be done in one line with the registration function..."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image, moving_image, parameter_object=parameter_object, log_to_console=False\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an elastix image filter object. The result of these to methods should only differ due to the stochastic nature of elastix. \n",
"\n",
"The object oriented method below can be used when more explicit function calls are preferred."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Load Elastix Image Filter Object\n",
"elastix_object = itk.ElastixRegistrationMethod.New(fixed_image, moving_image)\n",
"# elastix_object.SetFixedImage(fixed_image)\n",
"# elastix_object.SetMovingImage(moving_image)\n",
"elastix_object.SetParameterObject(parameter_object)\n",
"\n",
"# Set additional options\n",
"elastix_object.SetLogToConsole(False)\n",
"\n",
"# Update filter object (required)\n",
"elastix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Registration\n",
"result_image = elastix_object.GetOutput()\n",
"result_transform_parameters = elastix_object.GetTransformParameterObject()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Save image with itk\n",
"itk.imwrite(result_image, \"exampleoutput/result_image.mha\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The output of the elastix algorithm is the registered (transformed) version of the moving image. The parameters of this transformation can also be obtained after registation."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example02_CustomOrMultipleParameterMaps.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Image Registration with Multiple and Custom Parameter Maps"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Registration"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import itk"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id='section_id2'></a>\n",
"We can run the registration with multiple stages, using the spatial transformation result from the current stage to initialize registration at the next stage.\n",
"\n",
"Typically, we start with a simple spatial transformation and advance to a more complex spatial transformation.\n",
"\n",
"The default, conservative, registration parameters progress from a *translation -> affine -> bspline* transformation, with 4 resolutions for each transformation type.\n",
"\n",
"When multiple resolutions are used, a multi-scale image pyramid is generated with downscaled versions of the image. Registration results at a lower resolution is used to initialize registration at a higher resolution.\n",
"This improves speed and robustness.\n",
"\n",
"The number of resolutions can be manually specified aswell.\n",
"\n",
"A default set of registration parameters are available for\n",
"\n",
"- *translation*\n",
"- *rigid*\n",
"- *affine*\n",
"- *bspline*\n",
"- *spline*\n",
"- *groupwise*\n",
"\n",
"transformations. More information on these transformation and on all possible parameter settings can be found in the [elastix manual](https://github.com/SuperElastix/elastix/releases/download/5.3.0/elastix-5.3.0-manual.pdf)."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ParameterObject (000001C71962FAD0)\n",
" RTTI typeinfo: class elastix::ParameterObject\n",
" Reference Count: 1\n",
" Modified Time: 69\n",
" Debug: Off\n",
" Object Name: \n",
" Observers: \n",
" none\n",
"ParameterMap 0: \n",
" (AutomaticParameterEstimation \"true\")\n",
" (AutomaticScalesEstimation \"true\")\n",
" (CheckNumberOfSamples \"true\")\n",
" (DefaultPixelValue 0)\n",
" (FinalBSplineInterpolationOrder 3)\n",
" (FixedImagePyramid \"FixedSmoothingImagePyramid\")\n",
" (ImageSampler \"RandomCoordinate\")\n",
" (Interpolator \"LinearInterpolator\")\n",
" (MaximumNumberOfIterations 256)\n",
" (MaximumNumberOfSamplingAttempts 8)\n",
" (Metric \"AdvancedMattesMutualInformation\")\n",
" (MovingImagePyramid \"MovingSmoothingImagePyramid\")\n",
" (NewSamplesEveryIteration \"true\")\n",
" (NumberOfResolutions 3)\n",
" (NumberOfSamplesForExactGradient 4096)\n",
" (NumberOfSpatialSamples 2048)\n",
" (Optimizer \"AdaptiveStochasticGradientDescent\")\n",
" (Registration \"MultiResolutionRegistration\")\n",
" (ResampleInterpolator \"FinalBSplineInterpolator\")\n",
" (Resampler \"DefaultResampler\")\n",
" (Transform \"EulerTransform\")\n",
" (WriteIterationInfo \"false\")\n",
" (WriteResultImage \"true\")\n",
"ParameterMap 1: \n",
" (AutomaticParameterEstimation \"true\")\n",
" (CheckNumberOfSamples \"true\")\n",
" (DefaultPixelValue 0)\n",
" (FinalBSplineInterpolationOrder 3)\n",
" (FinalGridSpacingInPhysicalUnits 20)\n",
" (FixedImagePyramid \"FixedSmoothingImagePyramid\")\n",
" (GridSpacingSchedule 1.9881 1.41 1)\n",
" (ImageSampler \"RandomCoordinate\")\n",
" (Interpolator \"LinearInterpolator\")\n",
" (MaximumNumberOfIterations 256)\n",
" (MaximumNumberOfSamplingAttempts 8)\n",
" (Metric \"AdvancedMattesMutualInformation\" \"TransformBendingEnergyPenalty\")\n",
" (Metric0Weight 1)\n",
" (Metric1Weight 1)\n",
" (MovingImagePyramid \"MovingSmoothingImagePyramid\")\n",
" (NewSamplesEveryIteration \"true\")\n",
" (NumberOfResolutions 3)\n",
" (NumberOfSamplesForExactGradient 4096)\n",
" (NumberOfSpatialSamples 2048)\n",
" (Optimizer \"AdaptiveStochasticGradientDescent\")\n",
" (Registration \"MultiMetricMultiResolutionRegistration\")\n",
" (ResampleInterpolator \"FinalBSplineInterpolator\")\n",
" (Resampler \"DefaultResampler\")\n",
" (Transform \"BSplineTransform\")\n",
" (WriteIterationInfo \"false\")\n",
" (WriteResultImage \"true\")\n",
"ParameterMap 2: \n",
" (BSplineInterpolationOrder 1)\n",
" (DefaultPixelValue 0)\n",
" (ErodeMask \"false\")\n",
" (FinalBSplineInterpolationOrder 3)\n",
" (FinalGridSpacingInPhysicalUnits 16)\n",
" (FixedImagePyramid \"FixedRecursiveImagePyramid\")\n",
" (FixedInternalImagePixelType \"float\")\n",
" (HowToCombineTransforms \"Compose\")\n",
" (ImageSampler \"Random\")\n",
" (Interpolator \"BSplineInterpolator\")\n",
" (MaximumNumberOfIterations 500)\n",
" (Metric \"AdvancedMattesMutualInformation\")\n",
" (MovingImagePyramid \"MovingRecursiveImagePyramid\")\n",
" (MovingInternalImagePixelType \"float\")\n",
" (NewSamplesEveryIteration \"true\")\n",
" (NumberOfHistogramBins 32)\n",
" (NumberOfResolutions 1)\n",
" (NumberOfSpatialSamples 2048)\n",
" (Optimizer \"AdaptiveStochasticGradientDescent\")\n",
" (Registration \"MultiResolutionRegistration\")\n",
" (ResampleInterpolator \"FinalBSplineInterpolator\")\n",
" (Resampler \"DefaultResampler\")\n",
" (ResultImagePixelType \"short\")\n",
" (Transform \"BSplineTransform\")\n",
" (UseDirectionCosines \"true\")\n",
" (WriteResultImage \"true\")\n",
"ParameterMap 3: \n",
" (AutomaticParameterEstimation \"true\")\n",
" (AutomaticScalesEstimation \"true\")\n",
" (CheckNumberOfSamples \"true\")\n",
" (DefaultPixelValue 0)\n",
" (FinalBSplineInterpolationOrder 3)\n",
" (FixedImagePyramid \"FixedSmoothingImagePyramid\")\n",
" (ImageSampler \"RandomCoordinate\")\n",
" (Interpolator \"LinearInterpolator\")\n",
" (MaximumNumberOfIterations 256)\n",
" (MaximumNumberOfSamplingAttempts 8)\n",
" (Metric \"AdvancedMattesMutualInformation\")\n",
" (MovingImagePyramid \"MovingSmoothingImagePyramid\")\n",
" (NewSamplesEveryIteration \"true\")\n",
" (NumberOfResolutions 4)\n",
" (NumberOfSamplesForExactGradient 4096)\n",
" (NumberOfSpatialSamples 2048)\n",
" (Optimizer \"AdaptiveStochasticGradientDescent\")\n",
" (Registration \"MultiResolutionRegistration\")\n",
" (ResampleInterpolator \"FinalBSplineInterpolator\")\n",
" (Resampler \"DefaultResampler\")\n",
" (Transform \"BSplineTransform\")\n",
" (WriteIterationInfo \"false\")\n",
" (WriteResultImage \"true\")\n",
"\n"
]
}
],
"source": [
"# Import Images\n",
"fixed_image = itk.imread(\"data/CT_2D_head_fixed.mha\", itk.F)\n",
"moving_image = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)\n",
"\n",
"# Import Default Parameter Map\n",
"parameter_object = itk.ParameterObject.New()\n",
"resolutions = 3\n",
"parameter_map_rigid = itk.ParameterObject.GetDefaultParameterMap(\"rigid\", 3)\n",
"parameter_object.AddParameterMap(parameter_map_rigid)\n",
"\n",
"# For the bspline default parameter map, an extra argument can be specified that define the final bspline grid spacing in physical space.\n",
"parameter_map_bspline = itk.ParameterObject.GetDefaultParameterMap(\n",
" \"bspline\", resolutions, 20.0\n",
")\n",
"parameter_object.AddParameterMap(parameter_map_bspline)\n",
"\n",
"\n",
"# .. and/or load custom parameter maps from .txt file\n",
"parameter_object.AddParameterFile(\"data/parameters_BSpline.txt\")\n",
"\n",
"# ... and/or load and customize more\n",
"parameter_map_custom = itk.ParameterObject.GetDefaultParameterMap(\"rigid\")\n",
"parameter_map_custom[\"Transform\"] = [\"BSplineTransform\"]\n",
"parameter_map_custom[\"Metric\"] = [\"AdvancedMattesMutualInformation\"]\n",
"parameter_object.AddParameterMap(parameter_map_custom)\n",
"\n",
"# ... or customize parameter maps afterwards\n",
"# here the 'NumberOfResolutions' parameter of the 2nd parameter map of the parameter_object is set to 1.\n",
"parameter_object.SetParameter(2, \"NumberOfResolutions\", \"1\")\n",
"\n",
"# here the 'DefaultPixelValue' of all parameter maps is in the parameter_object set to 0\n",
"parameter_object.SetParameter(\"DefaultPixelValue\", \"0\")\n",
"\n",
"# Remove a parameter\n",
"parameter_object.RemoveParameter(\"ResultImageFormat\")\n",
"\n",
"print(parameter_object)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The parameter object or the seperate parameter maps can be saved or serialized in several ways"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Save custom parameter map\n",
"itk.ParameterObject.WriteParameterFile(\n",
" parameter_map_custom, \"exampleoutput/parameters_custom.txt\"\n",
")\n",
"\n",
"# Or serialize each parameter map to a file.\n",
"for index in range(parameter_object.GetNumberOfParameterMaps()):\n",
" parameter_map = parameter_object.GetParameterMap(index)\n",
" itk.ParameterObject.WriteParameterFile(\n",
" parameter_map, \"exampleoutput/Parameters.{0}.txt\".format(index)\n",
" )"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ParameterObject (00000246C4B724A0)\n",
" RTTI typeinfo: class elastix::ParameterObject\n",
" Reference Count: 1\n",
" Modified Time: 61\n",
" Debug: Off\n",
" Object Name: \n",
" Observers: \n",
" none\n",
"ParameterMap 0: \n",
" (AutomaticParameterEstimation \"true\")\n",
" (AutomaticScalesEstimation \"true\")\n",
" (CheckNumberOfSamples \"true\")\n",
" (DefaultPixelValue 0)\n",
" (FinalBSplineInterpolationOrder 3)\n",
" (FixedImagePyramid \"FixedSmoothingImagePyramid\")\n",
" (ImageSampler \"RandomCoordinate\")\n",
" (Interpolator \"LinearInterpolator\")\n",
" (MaximumNumberOfIterations 256)\n",
" (MaximumNumberOfSamplingAttempts 8)\n",
" (Metric \"AdvancedMattesMutualInformation\")\n",
" (MovingImagePyramid \"MovingSmoothingImagePyramid\")\n",
" (NewSamplesEveryIteration \"true\")\n",
" (NumberOfResolutions 3)\n",
" (NumberOfSamplesForExactGradient 4096)\n",
" (NumberOfSpatialSamples 2048)\n",
" (Optimizer \"AdaptiveStochasticGradientDescent\")\n",
" (Registration \"MultiResolutionRegistration\")\n",
" (ResampleInterpolator \"FinalBSplineInterpolator\")\n",
" (Resampler \"DefaultResampler\")\n",
" (Transform \"EulerTransform\")\n",
" (WriteIterationInfo \"false\")\n",
" (WriteResultImage \"true\")\n",
"ParameterMap 1: \n",
" (AutomaticParameterEstimation \"true\")\n",
" (CheckNumberOfSamples \"true\")\n",
" (DefaultPixelValue 0)\n",
" (FinalBSplineInterpolationOrder 3)\n",
" (FinalGridSpacingInPhysicalUnits 20)\n",
" (FixedImagePyramid \"FixedSmoothingImagePyramid\")\n",
" (GridSpacingSchedule 1.9881 1.41 1)\n",
" (ImageSampler \"RandomCoordinate\")\n",
" (Interpolator \"LinearInterpolator\")\n",
" (MaximumNumberOfIterations 256)\n",
" (MaximumNumberOfSamplingAttempts 8)\n",
" (Metric \"AdvancedMattesMutualInformation\" \"TransformBendingEnergyPenalty\")\n",
" (Metric0Weight 1)\n",
" (Metric1Weight 1)\n",
" (MovingImagePyramid \"MovingSmoothingImagePyramid\")\n",
" (NewSamplesEveryIteration \"true\")\n",
" (NumberOfResolutions 3)\n",
" (NumberOfSamplesForExactGradient 4096)\n",
" (NumberOfSpatialSamples 2048)\n",
" (Optimizer \"AdaptiveStochasticGradientDescent\")\n",
" (Registration \"MultiMetricMultiResolutionRegistration\")\n",
" (ResampleInterpolator \"FinalBSplineInterpolator\")\n",
" (Resampler \"DefaultResampler\")\n",
" (Transform \"BSplineTransform\")\n",
" (WriteIterationInfo \"false\")\n",
" (WriteResultImage \"true\")\n",
"ParameterMap 2: \n",
" (BSplineInterpolationOrder 1)\n",
" (DefaultPixelValue 0)\n",
" (ErodeMask \"false\")\n",
" (FinalBSplineInterpolationOrder 3)\n",
" (FinalGridSpacingInPhysicalUnits 16)\n",
" (FixedImagePyramid \"FixedRecursiveImagePyramid\")\n",
" (FixedInternalImagePixelType \"float\")\n",
" (HowToCombineTransforms \"Compose\")\n",
" (ImageSampler \"Random\")\n",
" (Interpolator \"BSplineInterpolator\")\n",
" (MaximumNumberOfIterations 500)\n",
" (Metric \"AdvancedMattesMutualInformation\")\n",
" (MovingImagePyramid \"MovingRecursiveImagePyramid\")\n",
" (MovingInternalImagePixelType \"float\")\n",
" (NewSamplesEveryIteration \"true\")\n",
" (NumberOfHistogramBins 32)\n",
" (NumberOfResolutions 1)\n",
" (NumberOfSpatialSamples 2048)\n",
" (Optimizer \"AdaptiveStochasticGradientDescent\")\n",
" (Registration \"MultiResolutionRegistration\")\n",
" (ResampleInterpolator \"FinalBSplineInterpolator\")\n",
" (Resampler \"DefaultResampler\")\n",
" (ResultImagePixelType \"short\")\n",
" (Transform \"BSplineTransform\")\n",
" (UseDirectionCosines \"true\")\n",
" (WriteResultImage \"true\")\n",
"ParameterMap 3: \n",
" (AutomaticParameterEstimation \"true\")\n",
" (AutomaticScalesEstimation \"true\")\n",
" (CheckNumberOfSamples \"true\")\n",
" (DefaultPixelValue 0)\n",
" (FinalBSplineInterpolationOrder 3)\n",
" (FixedImagePyramid \"FixedSmoothingImagePyramid\")\n",
" (ImageSampler \"RandomCoordinate\")\n",
" (Interpolator \"LinearInterpolator\")\n",
" (MaximumNumberOfIterations 256)\n",
" (MaximumNumberOfSamplingAttempts 8)\n",
" (Metric \"AdvancedMattesMutualInformation\")\n",
" (MovingImagePyramid \"MovingSmoothingImagePyramid\")\n",
" (NewSamplesEveryIteration \"true\")\n",
" (NumberOfResolutions 4)\n",
" (NumberOfSamplesForExactGradient 4096)\n",
" (NumberOfSpatialSamples 2048)\n",
" (Optimizer \"AdaptiveStochasticGradientDescent\")\n",
" (Registration \"MultiResolutionRegistration\")\n",
" (ResampleInterpolator \"FinalBSplineInterpolator\")\n",
" (Resampler \"DefaultResampler\")\n",
" (Transform \"BSplineTransform\")\n",
" (WriteIterationInfo \"false\")\n",
" (WriteResultImage \"true\")\n",
"\n"
]
}
],
"source": [
"# To deserialize the parameters\n",
"parameter_files = [\"exampleoutput/Parameters.{0}.txt\".format(i) for i in range(4)]\n",
"parameter_object = itk.ParameterObject.New()\n",
"parameter_object.ReadParameterFiles(parameter_files)\n",
"print(parameter_object)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For more information on the available parameters and their meaning, see the [Elastix Parameters](https://elastix.dev/doxygen/parameter.html) documentation.\n",
"\n",
"A database of parameter sets that work well for specific types of data can be found on the [Elastix parameter modelzoo](https://lkeb.ml/modelzoo/), in sync with it's [Github repo](https://github.com/SuperElastix/ElastixModelZoo) where parameter files can be uploaded."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Registration can either be done in one line with the registration function..."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image, moving_image, parameter_object=parameter_object, log_to_console=False\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an elastix image filter object."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Load Elastix Image Filter Object\n",
"elastix_object = itk.ElastixRegistrationMethod.New(fixed_image, moving_image)\n",
"# elastix_object.SetFixedImage(fixed_image)\n",
"# elastix_object.SetMovingImage(moving_image)\n",
"elastix_object.SetParameterObject(parameter_object)\n",
"\n",
"# Set additional options\n",
"elastix_object.SetLogToConsole(False)\n",
"\n",
"# Update filter object (required)\n",
"elastix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Registration\n",
"result_image = elastix_object.GetOutput()\n",
"result_transform_parameters = elastix_object.GetTransformParameterObject()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "ITKElastix",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.11"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example03_Masked_3D_Registration.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. 3D Image Registration with Masks"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Registration"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Often, some content in the images may not correspond. For example, there may be background content or noisy areas. A mask defined on the fixed and/or moving image can be used to exclude these regions at a pixel level from the similarity metric computations. This improves the robustness of registration.\n",
"\n",
"A mask is a binary image with 1 meaning that a pixel is include in elastix' computation and a 0 meaning it's not.\n",
"\n",
"For more information, see Section 5.4, \"Masks\" of the [Elastix Manual](https://github.com/SuperElastix/elastix/releases/download/5.3.0/elastix-5.3.0-manual.pdf)."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import itk\n",
"from itkwidgets import compare, checkerboard, view"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The function calls in the 3D case to import and register the images is similar to the 2D case. Masks, usually binary images, are import with the itk library similar to the images. "
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Import Images\n",
"fixed_image = itk.imread(\"data/CT_3D_lung_fixed.mha\", itk.F)\n",
"moving_image = itk.imread(\"data/CT_3D_lung_moving.mha\", itk.F)\n",
"\n",
"# Import Custom Parameter Map\n",
"parameter_object = itk.ParameterObject.New()\n",
"parameter_object.AddParameterFile(\"data/parameters.3D.NC.affine.ASGD.001.txt\")\n",
"\n",
"# \"WriteResultImage\" needs to be set to \"true\" so that the image is resampled at the end of the registration\n",
"# and the result_image is populated properly\n",
"parameter_object.SetParameter(0, \"WriteResultImage\", \"true\")\n",
"\n",
"# Import Mask Images\n",
"fixed_mask = itk.imread(\"data/CT_3D_lung_fixed_mask.mha\", itk.UC)\n",
"moving_mask = itk.imread(\"data/CT_3D_lung_moving_mask.mha\", itk.UC)\n",
"\n",
"# Or Optionally Create Masks from scratch\n",
"\n",
"# MaskImageType = itk.Image[itk.UC, 2]\n",
"# fixed_mask = itk.binary_threshold_image_filter(fixed,\n",
"# lower_threshold=80.0,\n",
"# inside_value=1,\n",
"# ttype=(type(fixed), MaskImageType))\n",
"# moving_mask = itk.binary_threshold_image_filter(moving,\n",
"# lower_threshold=80.0,\n",
"# inside_value=1,\n",
"# ttype=(type(moving), MaskImageType))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Input Visualization\n",
"The images and their masks can be visualized with the itkwidget's view function. This can be useful to visually inspect the quality of the masks."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "9e0ed89550c043a29bef90625e1cb58e",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Viewer(geometries=[], gradient_opacity=0.22, interpolation=False, point_sets=[], rendered_image=<itk.itkImageP…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"view(fixed_image, label_image=fixed_mask)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "3e093036b3be428389dcebe081bb587b",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Viewer(geometries=[], gradient_opacity=0.22, interpolation=False, point_sets=[], rendered_image=<itk.itkImageP…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"view(moving_image, label_image=moving_mask)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Registration"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Registration can either be done in one line with the registration function..."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image,\n",
" moving_image,\n",
" parameter_object=parameter_object,\n",
" fixed_mask=fixed_mask,\n",
" moving_mask=moving_mask,\n",
" log_to_console=False,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an elastix image filter object."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Load Elastix Image Filter Object\n",
"# Fixed and moving image should be given to the Elastix method to ensure that\n",
"# the correct 3D class is initialized.\n",
"elastix_object = itk.ElastixRegistrationMethod.New(fixed_image, moving_image)\n",
"elastix_object.SetFixedMask(fixed_mask)\n",
"elastix_object.SetMovingMask(moving_mask)\n",
"elastix_object.SetParameterObject(parameter_object)\n",
"\n",
"# Set additional options\n",
"elastix_object.SetLogToConsole(False)\n",
"\n",
"# Update filter object (required)\n",
"elastix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Registration\n",
"result_image = elastix_object.GetOutput()\n",
"result_transform_parameters = elastix_object.GetTransformParameterObject()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Output Visualization\n",
"The results of the 3D image registration can also be visualized with widgets from the itkwidget library such as the checkerboard and compare widgets."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "94d279f136cc48b3983cc60458776d58",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Viewer(annotations=False, interpolation=False, rendered_image=<itk.itkImagePython.itkImageF3; p…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"checkerboard(fixed_image, result_image, pattern=5)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "b68308d4d978479789642fe885a49896",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"AppLayout(children=(HBox(children=(Label(value='Link:'), Checkbox(value=True, description='cmap'), Checkbox(va…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"compare(\n",
" fixed_image, result_image, label_image=[fixed_image, result_image], link_cmap=True\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example04_InitialTransformAndMultiThreading.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. Image Registration with initial transform and/or multiple threads"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this notebook 2 other options of the elastix algorithm are shown: initial transformation and multithreading.\n",
"They're shown together just to reduce the number of example notebooks and \n",
"thus can be used independently as well as in combination with whichever other functionality\n",
"of the elastix algorithm. \n",
"\n",
"Initial transforms are transformations that are done on the moving image before the registration is started.\n",
"\n",
"Multithreading spreaks for itself and can be used in similar fashion in the transformix algorithm.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Registration"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"import itk"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Import Images\n",
"fixed_image = itk.imread(\"data/CT_2D_head_fixed.mha\", itk.F)\n",
"moving_image = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)\n",
"\n",
"# Import Default Parameter Map\n",
"parameter_map_rigid = itk.ParameterObject.GetDefaultParameterMap(\"rigid\")\n",
"parameter_object = itk.ParameterObject.New(parameter_map=parameter_map_rigid)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Registration can either be done in one line with the registration function..."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function with initial transfrom and number of threads\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image,\n",
" moving_image,\n",
" parameter_object=parameter_object,\n",
" initial_transform_parameter_file_name=\"data/TransformParameters.0.txt\",\n",
" number_of_threads=4,\n",
" log_to_console=False,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an elastix image filter object."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# Load Elastix Image Filter Object with initial transfrom and number of threads\n",
"elastix_object = itk.ElastixRegistrationMethod.New(fixed_image, moving_image)\n",
"# elastix_object.SetFixedImage(fixed_image)\n",
"# elastix_object.SetMovingImage(moving_image)\n",
"elastix_object.SetParameterObject(parameter_object)\n",
"elastix_object.SetInitialTransformParameterFileName(\"data/TransformParameters.0.txt\")\n",
"elastix_object.SetNumberOfThreads(4)\n",
"\n",
"# Set additional options\n",
"elastix_object.SetLogToConsole(False)\n",
"\n",
"# Update filter object (required)\n",
"elastix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Registration\n",
"result_image = elastix_object.GetOutput()\n",
"result_transform_parameters = elastix_object.GetTransformParameterObject()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Pointing from a transform parameter file to the path of a second initial transform parameter file is supported from the 0.7.0 release of ITKElastix."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example05_PointRegistration.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Point Registration"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Point-based registration allows us to help the registration via pre-defined sets of corresponding points. The 'CorrespondingPointsEuclideanDistanceMetric' minimises the distance of between a points on the fixed image and corresponding points on the moving image. The metric can be used to help in a difficult registration task by taking into account positions are known to correspond. Think of it as a way of embedding expert knowledge in the registration procedure. We can manually or automatically select points via centroids of segmentations for example. Anything is possible.\n",
"Point sets should always be given to elastix with their corresponding image."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Registration"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import itk\n",
"import numpy as np\n",
"from itkwidgets import compare, checkerboard, view"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In order for 3D registration to work with a point set, the 'CorrespondingPointsEuclideanDistanceMetric', should be set as metric. For the 3D case, this means that the metric should be a multimetric with the first metric of type AdvancedImageToImageMetric and the second the 'CorrespondingPointsEuclideanDistanceMetric'. The Registration parameter should therefore be set to 'MultiMetricMultiResolutionRegistration', to allow a multimetric parameter."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Import Images\n",
"fixed_image = itk.imread(\"data/CT_3D_lung_fixed.mha\", itk.F)\n",
"moving_image = itk.imread(\"data/CT_3D_lung_moving.mha\", itk.F)\n",
"\n",
"fixed_point_set = np.loadtxt(\n",
" \"data/CT_3D_lung_fixed_point_set_corrected.txt\", skiprows=2, delimiter=\" \"\n",
")\n",
"moving_point_set = np.loadtxt(\n",
" \"data/CT_3D_lung_moving_point_set_corrected.txt\", skiprows=2, delimiter=\" \"\n",
")\n",
"\n",
"# Import and adjust Parameter Map\n",
"parameter_object = itk.ParameterObject.New()\n",
"parameter_map_rigid = itk.ParameterObject.GetDefaultParameterMap(\"rigid\")\n",
"parameter_map_rigid[\"Registration\"] = [\"MultiMetricMultiResolutionRegistration\"]\n",
"original_metric = parameter_map_rigid[\"Metric\"]\n",
"parameter_map_rigid[\"Metric\"] = [\n",
" original_metric[0],\n",
" \"CorrespondingPointsEuclideanDistanceMetric\",\n",
"]\n",
"parameter_object.AddParameterMap(parameter_map_rigid)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The point sets can be visualized and analysed with the itkwidgets package. Currently the point set visualization layer is put on top of the 3D image, which makes the slice view show all 'passed' points as well, this will change in future versions of the itkwidgets. (Changing the point set size and the gradient opacity of the image aids the visualization of the point sets in the 3D image)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "4b85bb6d559348c5affec2dcdfcf6a3b",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Viewer(geometries=[], gradient_opacity=0.22, point_set_colors=array([[0.8392157, 0. , 0. ]], dtype…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"view(fixed_image, point_sets=[fixed_point_set])"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "bf24816ea3ec41b693d371fee1841a63",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Viewer(geometries=[], gradient_opacity=0.22, point_set_colors=array([[0.8392157, 0. , 0. ]], dtype…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"view(moving_image, point_sets=[moving_point_set])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With regards to the elastix function, the point sets do not need to be initialized first, so their file name + path can be given directly to elastix. Future version of ITKElastix will support initialization of point sets and passing these to elastix, just like the point set was initialized for the visualization with the itkwidgets.\n",
"\n",
"Registration can either be done in one line with the registration function..."
]
},
{
"cell_type": "code",
"execution_count": 128,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image,\n",
" moving_image,\n",
" fixed_point_set_file_name=\"data/CT_3D_lung_fixed_point_set_corrected.txt\",\n",
" moving_point_set_file_name=\"data/CT_3D_lung_moving_point_set_corrected.txt\",\n",
" log_to_console=False,\n",
" parameter_object=parameter_object,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an elastix image filter object."
]
},
{
"cell_type": "code",
"execution_count": 111,
"metadata": {},
"outputs": [],
"source": [
"# Load Elastix Image Filter Object\n",
"# Fixed and moving image should be given to the Elastix method to ensure that\n",
"# the correct 3D class is initialized.\n",
"elastix_object = itk.ElastixRegistrationMethod.New(fixed_image, moving_image)\n",
"elastix_object.SetFixedPointSetFileName(\"data/CT_3D_lung_fixed_point_set_corrected.txt\")\n",
"elastix_object.SetMovingPointSetFileName(\n",
" \"data/CT_3D_lung_moving_point_set_corrected.txt\"\n",
")\n",
"elastix_object.SetParameterObject(parameter_object)\n",
"elastix_object.SetLogToConsole(False)\n",
"\n",
"# Update filter object (required)\n",
"elastix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Registration\n",
"result_image = elastix_object.GetOutput()\n",
"result_transform_parameters = elastix_object.GetTransformParameterObject()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example06_GroupwiseRegistration.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. Groupwise Image Registration"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Groupwise registration methods try to mitigate uncertainties associated with any one image by simultaneously registering all images in a population. This incorporates all image information in registration process and eliminates bias towards a chosen reference frame. The method described here uses a 3D (2D+time) free-form B-spline deformation model and a similarity metric that minimizes variance of intensities under the constraint that the average deformation over images is zero. This constraint defines a true mean frame of reference that lie in the center of the population without having to calculate it explicitly.\n",
"\n",
"The method can take into account temporal smoothness of the deformations and a cyclic transform in the time dimension. This may be appropriate if it is known a priori that the anatomical motion has a cyclic nature e.g. in cases of cardiac or respiratory motion."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Registration"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import itk"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Load folder containing images.\n",
"images = itk.imread(\"data/CT_2D_plus_time.nii\", itk.F)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Create Groupwise Parameter Object\n",
"groupwise_parameter_map = itk.ParameterObject.GetDefaultParameterMap(\"groupwise\")\n",
"parameter_object = itk.ParameterObject.New(parameter_map=groupwise_parameter_map)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Registration can either be done in one line with the registration function..."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function\n",
"# both fixed and moving image should be set with the vector_itk to prevent elastix from throwing errors\n",
"\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" images, images, parameter_object=parameter_object, log_to_console=True\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an elastix image filter object."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Load Elastix Image Filter Object\n",
"# Fixed and moving image should be given to the Elastix method to ensure that\n",
"# the correct 3D class is initialized.\n",
"# Both fixed and moving image should be set with the vector_itk to prevent elastix from throwing errors\n",
"\n",
"elastix_object = itk.ElastixRegistrationMethod.New(images, images)\n",
"elastix_object.SetParameterObject(parameter_object)\n",
"\n",
"# Set additional options\n",
"elastix_object.SetLogToConsole(False)\n",
"\n",
"# Update filter object (required)\n",
"elastix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Registration\n",
"result_image = elastix_object.GetOutput()\n",
"result_transform_parameters = elastix_object.GetTransformParameterObject()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.11"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example07_MultimetricMultiImageRegistration.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7. Registration with multiple metrics and with multi-spectral images."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Multimetric Registration"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import itk"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ParameterObject (000001852EB86E00)\n",
" RTTI typeinfo: class elastix::ParameterObject\n",
" Reference Count: 1\n",
" Modified Time: 55\n",
" Debug: Off\n",
" Object Name: \n",
" Observers: \n",
" none\n",
"ParameterMap 0: \n",
" (AutomaticScalesEstimation \"true\")\n",
" (AutomaticTransformInitialization \"true\")\n",
" (BSplineInterpolationOrder 1)\n",
" (DefaultPixelValue 0)\n",
" (ErodeMask \"false\")\n",
" (FinalBSplineInterpolationOrder 3)\n",
" (FixedImagePyramid \"FixedSmoothingImagePyramid\" \"FixedSmoothingImagePyramid\")\n",
" (FixedInternalImagePixelType \"float\")\n",
" (HowToCombineTransforms \"Compose\")\n",
" (ImageSampler \"RandomCoordinate\" \"RandomCoordinate\")\n",
" (Interpolator \"BSplineInterpolator\" \"BSplineInterpolator\")\n",
" (MaximumNumberOfIterations 250)\n",
" (Metric \"AdvancedMattesMutualInformation\" \"AdvancedMeanSquares\")\n",
" (Metric0Weight 0.125)\n",
" (Metric1Weight 0.125)\n",
" (MovingImagePyramid \"MovingSmoothingImagePyramid\" \"MovingSmoothingImagePyramid\")\n",
" (MovingInternalImagePixelType \"float\")\n",
" (NewSamplesEveryIteration \"true\")\n",
" (NumberOfHistogramBins 32)\n",
" (NumberOfResolutions 4)\n",
" (NumberOfSpatialSamples 2048)\n",
" (Optimizer \"AdaptiveStochasticGradientDescent\")\n",
" (Registration \"MultiMetricMultiResolutionRegistration\")\n",
" (ResampleInterpolator \"FinalBSplineInterpolator\")\n",
" (Resampler \"DefaultResampler\")\n",
" (ResultImageFormat \"mhd\")\n",
" (ResultImagePixelType \"short\")\n",
" (Transform \"BSplineTransform\")\n",
" (UseDirectionCosines \"true\")\n",
" (WriteResultImage \"true\")\n",
"\n"
]
}
],
"source": [
"# Import Images\n",
"fixed_image = itk.imread(\"data/CT_2D_head_fixed.mha\", itk.F)\n",
"moving_image = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)\n",
"\n",
"# Import Multimetric Parameter Map (see elastix documentation,\n",
"# KNNGraphAlphaMutualInformation is not supported yet by ITKElastix)\n",
"parameter_object = itk.ParameterObject.New()\n",
"parameter_object.AddParameterFile(\"data/parameters_Bspline_Multimetric.txt\")\n",
"print(parameter_object)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Registration can either be done in one line with the registration function..."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image, moving_image, parameter_object=parameter_object, log_to_console=True\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an elastix image filter object."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Load Elastix Image Filter Object\n",
"elastix_object = itk.ElastixRegistrationMethod.New(fixed_image, moving_image)\n",
"elastix_object.SetParameterObject(parameter_object)\n",
"\n",
"# Set additional options\n",
"elastix_object.SetLogToConsole(False)\n",
"\n",
"# Update filter object (required)\n",
"elastix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Registration\n",
"result_image = elastix_object.GetOutput()\n",
"result_transform_parameters = elastix_object.GetTransformParameterObject()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Multi-spectral image registration"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Import Images of multiple spectra\n",
"# Images of actual different spectra should be used here, for now same images are used.\n",
"fixed_image_spectrum1 = itk.imread(\"data/CT_2D_head_fixed.mha\", itk.F)\n",
"moving_image_spectrum1 = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)\n",
"fixed_image_spectrum2 = itk.imread(\"data/CT_2D_head_fixed.mha\", itk.F)\n",
"moving_image_spectrum2 = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)\n",
"\n",
"# Import Parameter Map\n",
"parameter_object = itk.ParameterObject.New()\n",
"parameter_object.AddParameterFile(\"data/parameters_BSpline.txt\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Multi-spectral registration can only be done with the object-oriented method in ITKElastix"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Load Elastix Image Filter Object\n",
"elastix_object = itk.ElastixRegistrationMethod.New(\n",
" fixed_image_spectrum1, moving_image_spectrum1\n",
")\n",
"# elastix_object.SetFixedImage(fixed_image_spectrum1)\n",
"elastix_object.AddFixedImage(fixed_image_spectrum2)\n",
"\n",
"# elastix_object.SetMovingImage(moving_image_spectrum1)\n",
"elastix_object.AddMovingImage(moving_image_spectrum2)\n",
"\n",
"elastix_object.SetParameterObject(parameter_object)\n",
"\n",
"# Set additional options\n",
"elastix_object.SetLogToConsole(False)\n",
"\n",
"# Update filter object (required)\n",
"elastix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Registration\n",
"result_image = elastix_object.GetOutput()\n",
"result_transform_parameters = elastix_object.GetTransformParameterObject()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example08_SimpleTransformix.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8. Simple Transformix"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"After image registrations it is often useful to apply the transformation as found by the registration to another image. Maybe you want to apply the transformation to an original (larger) image to gain resolution. Or maybe you need the transformation to apply it to a label image (segmentation). Transformix is an image filter that was developed together with elastix, that can be used to do these transformations.\n",
"\n",
"A spatial transformation is defined as a mapping from the fixed image domain to the moving image domain. More information on the precise definition of the transform can be found in the [elastix manual](https://github.com/SuperElastix/elastix/releases/download/5.3.0/elastix-5.3.0-manual.pdf). Transformix can be used to apply this mapping not only to images, but also to masks (binary images) and point sets see [example 9](ITK_Example09_PointSetAndMaskTransformation.ipynb#section_id10).\n",
"\n",
"As an alternative, see the [itk resampling example](ITK_Example13_ITKResampling.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Elastix"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import itk\n",
"from itkwidgets import compare, checkerboard"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Import Images\n",
"fixed_image = itk.imread(\"data/CT_2D_head_fixed.mha\", itk.F)\n",
"moving_image = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)\n",
"\n",
"# Import Default Parameter Map\n",
"parameter_map_rigid = itk.ParameterObject.GetDefaultParameterMap(\"rigid\")\n",
"parameter_object = itk.ParameterObject.New(parameter_map=parameter_map_rigid)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Registration with the registration function..."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image, moving_image, parameter_object=parameter_object\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Transformix\n",
"The transform parameters that elastix outputs can be given to transformix as input for the transformations. The output transform parameters from elastix are mappings from the fixed image to the moving image domain. Transformix therefore uses a backwards mapping to obtain a registered version of the moving image (moving -> fixed domain). "
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Import Image to transform\n",
"# In this example the same moving image is used, that was used for elastix,\n",
"# this however will result in the same image as was already given by the\n",
"# first elastix registration.\n",
"moving_image_transformix = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Transformation can either be done in one line with the transformix function..."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"result_image_transformix = itk.transformix_filter(\n",
" moving_image, result_transform_parameters\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an transformix image filter object similar to the elastix algorithm."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Load Transformix Object\n",
"transformix_object = itk.TransformixFilter.New(moving_image_transformix)\n",
"transformix_object.SetTransformParameterObject(result_transform_parameters)\n",
"\n",
"# Update object (required)\n",
"transformix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Transformation\n",
"result_image_transformix = transformix_object.GetOutput()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Visualization\n",
"The results of the image transform can be visualized with widgets from the itkwidget library such as the checkerboard and compare widgets."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "d857fe306c1848a8802af23ebfb415e8",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"VBox(children=(Viewer(annotations=False, interpolation=False, rendered_image=<itk.itkImagePython.itkImageF2; p…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"checkerboard(fixed_image, result_image_transformix, pattern=5)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "039f95f8fd05433986ca7cd0e952e1fc",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"AppLayout(children=(HBox(children=(Label(value='Link:'), Checkbox(value=True, description='cmap'), Checkbox(va…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"compare(fixed_image, result_image_transformix, link_cmap=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example09_PointSetAndMaskTransformation.ipynb
================================================
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## 9. Point set and Mask Transformation"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"<a id='section_id10'></a>\n",
"Transformix can be used to transform point sets and mask images as well. Masks can be seen as images so the registration of masks is done in similar fashion as the registration of a moving image.\n",
"When transforming an image or mask (defined in the moving image domain), it is transformed to the fixed image domain. This is useful for example when one needs to deform a segmentation from the moving image to the fixed image, to obtain an estimate of a segmentation in the fixed image. When transforming a point set, this happens the other way around: from the fixed image domain to the moving image domain. This is useful for example when you want to know where a point maps to.\n",
"Point sets therefor need not be transformed with the backwards mapping protocol, but can instead be transformed with regular forward transformation (fixed -> moving).\n",
"Transforming point sets can be used to get the regions of interest (ROI) in the moving image, based on ROI of the fixed image."
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Elastix"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import itk\n",
"import numpy as np\n",
"from itkwidgets import compare, checkerboard, view"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Import Images\n",
"fixed_image = itk.imread(\"data/CT_3D_lung_fixed.mha\", itk.F)\n",
"moving_image = itk.imread(\"data/CT_3D_lung_moving.mha\", itk.F)\n",
"\n",
"# Import Default Parameter Map\n",
"parameter_object = itk.ParameterObject.New()\n",
"parameter_map_rigid = itk.ParameterObject.GetDefaultParameterMap(\"rigid\")\n",
"parameter_object.AddParameterMap(parameter_map_rigid)\n",
"parameter_map_affine = itk.ParameterObject.GetDefaultParameterMap(\"affine\")\n",
"parameter_object.AddParameterMap(parameter_map_affine)\n",
"parameter_map_bspline = itk.ParameterObject.GetDefaultParameterMap(\"bspline\")\n",
"parameter_object.AddParameterMap(parameter_map_bspline)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Registration with the registration function..."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image, moving_image, parameter_object=parameter_object, log_to_console=True\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Mask Transformation"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Import Mask\n",
"# Note: Version v0.17.0 and onwards supports various image types for elastix and transformix functions/objects\n",
"moving_mask = itk.imread(\"data/CT_3D_lung_moving_mask.mha\", itk.UC)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Mask image is a binary image, therefore the FinalBSplineInterpolationOrder should be 0\n",
"result_transform_parameters.SetParameter(\"FinalBSplineInterpolationOrder\", \"0\")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Transformation of a mask is similar to the transformation of an image and can either be done in one line with the transformix function..."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Procedural interface of transformix filter\n",
"result_moving_mask = itk.transformix_filter(moving_mask, result_transform_parameters)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an transformix image filter object."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Load Transformix Object, initialize with 3D Mask.\n",
"transformix_object = itk.TransformixFilter.New(moving_mask)\n",
"\n",
"transformix_object.SetTransformParameterObject(result_transform_parameters)\n",
"\n",
"# Update object (required)\n",
"transformix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Transformation\n",
"result_moving_mask = transformix_object.GetOutput()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Segmentation Transformation Evaluation"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"The result of a segmentation transformation can be evaluated by means of, for example, the dice loss. The dice loss is the proportion of the 2 segmentations that overlap. In the example above the masks used were segmentations of the images. (This is offcourse not always the case, masks could also hide artifacts, in which case they're not (only) image segmentations). The dice loss of the segmentation transformation can therefore be calculated with the dice loss of the 2 masks."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# In case of boolaen segmentation, the dice loss is equal to 2 x dot product of the flattened arrays,\n",
"# divided by the total volume of both masks.\n",
"def dice_loss(y_true, y_pred):\n",
" y_true = y_true.flatten()\n",
" y_pred = y_pred.flatten()\n",
" intersection = y_true.dot(y_pred)\n",
" union = sum(y_true) + sum(y_pred)\n",
" dice = 2 * intersection / union\n",
" return dice"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"# Import groundtruth segmentation\n",
"fixed_mask = itk.imread(\"data/CT_3D_lung_fixed_mask.mha\", itk.UC)\n",
"\n",
"# Cast itk images to numpy arrays and round result image to boolean array.\n",
"fixed_mask_np = np.asarray(fixed_mask)\n",
"result_mask_np = np.asarray(result_moving_mask).round().astype(int)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dice loss: 0.9862246731348647\n"
]
}
],
"source": [
"print(\"Dice loss:\", dice_loss(fixed_mask_np, result_mask_np))"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "c76e48b027c84e37963cf1e02ee8a702",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"AppLayout(children=(HBox(children=(Label(value='Link:'), Checkbox(value=False, description='cmap'), Checkbox(v…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"compare(fixed_mask, result_moving_mask)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"### Point Set Transformation"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"# Procedural interface of transformix filter\n",
"result_point_set = itk.transformix_pointset(\n",
" moving_image,\n",
" result_transform_parameters,\n",
" fixed_point_set_file_name=\"data/CT_3D_lung_fixed_point_set_corrected.txt\",\n",
" output_directory=\"./exampleoutput\",\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an transformix image filter object."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"# Load Transformix Object\n",
"transformix_object = itk.TransformixFilter.New(moving_image)\n",
"transformix_object.SetFixedPointSetFileName(\n",
" \"data/CT_3D_lung_fixed_point_set_corrected.txt\"\n",
")\n",
"transformix_object.SetTransformParameterObject(result_transform_parameters)\n",
"transformix_object.SetLogToConsole(True)\n",
"transformix_object.SetOutputDirectory(\"./exampleoutput/\")\n",
"\n",
"# Update object (required)\n",
"transformix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Transformation\n",
"# -- Bug? -- Output is saved as .txt file in outputdirectory.\n",
"# The .GetOutput() function outputs an empty image.\n",
"output_transformix = transformix_object.GetOutput()\n",
"result_point_set = np.loadtxt(\"exampleoutput/outputpoints.txt\", dtype=\"str\")[\n",
" :, 30:33\n",
"].astype(\"float64\")"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "3a044dd051e04f2f92d3dae77639590e",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Viewer(geometries=[], gradient_opacity=0.22, point_set_colors=array([[0.8392157, 0. , 0. ]], dtype…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"view(moving_image, point_sets=[result_point_set])"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example10_Transformix_Jacobian.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 10. Transformix: Spatial Jacobian calculations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With the transformix algorithm the spatial jacobian and the determinant of the spatial jacobian of the transformation can be calculated.\n",
"Especially the determinant of the spatial Jacobian, which identifies the amount of local\n",
"compression or expansion and can be useful, for example in lung ventilation studies."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Elastix"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"import itk\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Import Images\n",
"fixed_image = itk.imread(\"data/CT_2D_head_fixed.mha\", itk.F)\n",
"moving_image = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)\n",
"\n",
"# Import Default Parameter Map\n",
"parameter_map_rigid = itk.ParameterObject.GetDefaultParameterMap(\"rigid\")\n",
"parameter_object = itk.ParameterObject.New(parameter_map=parameter_map_rigid)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Registration with the registration function.\n",
"The output directory has to be specified, \n",
"otherwise elastix will not save the transformparameter file as .txt file."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function and specify output directory\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image,\n",
" moving_image,\n",
" parameter_object=parameter_object,\n",
" output_directory=\"exampleoutput/\",\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Transformix Jacobian Calculation"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"# Import Image to transform, transformix is transforming from moving -> fixed;\n",
"# for this example the exact same moving image is used, this however is normally not\n",
"# very usefull since the elastix algorithm already transformed this image.\n",
"moving_image_transformix = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The calculation of the Jacobian matrix and it's determinant can be done in one line..."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# Calculate Jacobian matrix and it's determinant in a tuple\n",
"jacobians = itk.transformix_jacobian(\n",
" moving_image_transformix, result_transform_parameters\n",
")\n",
"\n",
"# Casting tuple to two numpy matrices for further calculations.\n",
"spatial_jacobian = np.asarray(jacobians[0]).astype(np.float32)\n",
"det_spatial_jacobian = np.asarray(jacobians[1]).astype(np.float32)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an transformix image filter object, calculating the jacobian and reading the jacobian from Disk IO."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Load Transformix Object\n",
"transformix_object = itk.TransformixFilter.New(moving_image_transformix)\n",
"transformix_object.SetTransformParameterObject(result_transform_parameters)\n",
"\n",
"# Set advanced options\n",
"transformix_object.SetComputeSpatialJacobian(True)\n",
"transformix_object.SetComputeDeterminantOfSpatialJacobian(True)\n",
"\n",
"# Set output directory for spatial jacobian and its determinant,\n",
"# default directory is current directory.\n",
"transformix_object.SetOutputDirectory(\"exampleoutput/\")\n",
"\n",
"# Update object (required)\n",
"transformix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Transformation\n",
"result_image_transformix = transformix_object.GetOutput()\n",
"\n",
"# Load Jacobian from Disk IO and cast to numpy matrices\n",
"spatial_jacobian = itk.imread(\"exampleoutput/fullSpatialJacobian.nii\", itk.F)\n",
"spatial_jacobian = np.asarray(spatial_jacobian).astype(np.float32)\n",
"\n",
"det_spatial_jacobian = itk.imread(\"exampleoutput/spatialJacobian.nii\", itk.F)\n",
"det_spatial_jacobian = np.asarray(det_spatial_jacobian).astype(np.float32)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Inspect the deformation field by looking at the determinant of the Jacobian of Tµ(x). Values smaller\n",
"than 1 indicate local compression, values larger than 1 indicate local expansion, and 1 means volume\n",
"preservation. The measure is quantitative: a value of 1.1 means a 10% increase in volume. If this\n",
"value deviates substantially from 1, you may be worried (but maybe not if this is what you expect for\n",
"your application). In case it is negative you have “foldings” in your transformation, and you definitely\n",
"should be worried. For more information see [elastix manual](https://github.com/SuperElastix/elastix/releases/download/5.3.0/elastix-5.3.0-manual.pdf)."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Number of foldings in transformation: 0\n"
]
}
],
"source": [
"print(\"Number of foldings in transformation:\", np.sum(det_spatial_jacobian < 0))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
================================================
FILE: examples/ITK_Example11_Transformix_DeformationField.ipynb
================================================
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 11. Transformix: Deformation Field and it's inverse"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With the transformix algorithm the deformation field of the transformation, including it's inverse can be calculated.\n",
"The deformation field is a vector image where each voxel contains the displacement vector in physical coordinates."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Elastix"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import itk"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# Import Images\n",
"fixed_image = itk.imread(\"data/CT_2D_head_fixed.mha\", itk.F)\n",
"moving_image = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)\n",
"\n",
"# Import Default Parameter Map\n",
"parameter_object = itk.ParameterObject.New()\n",
"parameter_map_rigid = itk.ParameterObject.GetDefaultParameterMap(\"rigid\")\n",
"parameter_map_bspline = itk.ParameterObject.GetDefaultParameterMap(\"bspline\")\n",
"\n",
"parameter_object.AddParameterMap(parameter_map_rigid)\n",
"parameter_object.AddParameterMap(parameter_map_bspline)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Registration with the registration function.\n",
"The output directory has to be specified, \n",
"otherwise elastix will not save the transformparameter file as .txt file."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# Call registration function and specify output directory\n",
"result_image, result_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image,\n",
" moving_image,\n",
" parameter_object=parameter_object,\n",
" output_directory=\"exampleoutput/\",\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Transformix Deformation Field calculation"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"# Import Image to transform, transformix is transforming from moving -> fixed;\n",
"# for this example the exact same moving image is used, this however is normally not\n",
"# very usefull since the elastix algorithm already transformed this image.\n",
"moving_image_transformix = itk.imread(\"data/CT_2D_head_moving.mha\", itk.F)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The deformation field can either be calculation in one line..."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"deformation_field = itk.transformix_deformation_field(\n",
" moving_image_transformix, result_transform_parameters\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
".. or by initiating an transformix image filter object."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# Load Transformix Object\n",
"transformix_object = itk.TransformixFilter.New(moving_image_transformix)\n",
"transformix_object.SetTransformParameterObject(result_transform_parameters)\n",
"\n",
"# Set advanced options\n",
"transformix_object.SetComputeDeformationField(True)\n",
"\n",
"# Set output directory for spatial jacobian and its determinant,\n",
"# default directory is current directory.\n",
"transformix_object.SetOutputDirectory(\"exampleoutput/\")\n",
"\n",
"# Update object (required)\n",
"transformix_object.UpdateLargestPossibleRegion()\n",
"\n",
"# Results of Transformation\n",
"result_image_transformix = transformix_object.GetOutput()\n",
"deformation_field = transformix_object.GetOutputDeformationField()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Deformation Field Inversion"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The DisplacementMagnitudePenalty is a cost function that penalises ||Tµ(x) − x||2. You can use this\n",
"to invert transforms, by setting the transform to be inverted as an initial transform (using -t0), setting\n",
"(HowToCombineTransforms \"Compose\"), and running elastix with this metric, using the original fixed\n",
"image set both as fixed (-f) and moving (-m) image. After that you can manually set the initial transform\n",
"in the last parameter file to \"NoInitialTransform\", and voila, you have the inverse transform! Strictly\n",
"speaking, you should then also change the Size/Spacing/Origin/Index/Direction settings to match that of\n",
"the moving image.\n",
"Note that inverting a transformation becomes conceptually very similar to performing an image registration\n",
"in this way. Consequently, the same choices are relevant: optimisation algorithm, multiresolution etc...\n",
"With Transformix the inverted transform can then be used to calculate the inversion of the deformation field, just like Transformix normally calculates the deformation field from a transform."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"# Import Default Parameter Map and adjust parameters\n",
"parameter_object = itk.ParameterObject.New()\n",
"# parameter_map_rigid = itk.ParameterObject.GetDefaultParameterMap('rigid')\n",
"# parameter_map_bspline = itk.ParameterObject.GetDefaultParameterMap('rigid')\n",
"parameter_map_bspline[\"HowToCombineTransforms\"] = [\"Compose\"]\n",
"parameter_map_rigid[\"HowToCombineTransforms\"] = [\"Compose\"]\n",
"parameter_object.AddParameterMap(parameter_map_rigid)\n",
"parameter_object.AddParameterMap(parameter_map_bspline)\n",
"\n",
"# Call registration function with transform parameters of normal elastix run as initial transform\n",
"# on fixed image to fixed image registration. In ITKElastix there is not option to pass the result_transform_parameters\n",
"# as a python object yet, the initial transform can only be passed as a .txt file to initial_transform_parameter_file_name.\n",
"# Elastix also writes the transformparameter file to a .txt file if an output directory is specified.\n",
"# Make sure to give the correct TransformParameterFile.txt to elastix if multiple parameter maps are used.\n",
"inverse_image, inverse_transform_parameters = itk.elastix_registration_method(\n",
" fixed_image,\n",
" fixed_image,\n",
" parameter_object=parameter_object,\n",
" initial_transform_parameter_file_name=\"exampleoutput/TransformParameters.1.txt\",\n",
")\n",
"\n",
"# Adjust inverse transform parameters object\n",
"inverse_transform_parameters.SetParameter(\n",
" 0, \"InitialTransformParametersFileName\", \"NoInitialTransform\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"# Use inverse transform parameters to calculate inverse deformation field\n",
"# Setting the original fixed image for inverse transformation should give the moving image as result\n",
"# but since we're focussed on obtaining the inverse deformation field, setting this image is trivial.\n",
"inverse_deformation_field = itk.transformix_deformation_field(\n",
" fixed_image, inverse_transform_parameters\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Visualization of the deformation field and its inverse."
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
gitextract_mgec5cpq/
├── .binder/
│ ├── postBuild
│ └── requirements.txt
├── .clang-format
├── .gitattributes
├── .github/
│ └── workflows/
│ ├── build-test-package.yml
│ ├── clang-format-linter.yml
│ └── wasm.yml
├── .gitignore
├── .jupyter/
│ └── jupyter_notebook_config.py
├── CMakeLists.txt
├── CTestConfig.cmake
├── LICENSE
├── README.md
├── environment.yml
├── examples/
│ ├── 1_NumPyArray.ipynb
│ ├── ITK_Example01_SimpleRegistration.ipynb
│ ├── ITK_Example02_CustomOrMultipleParameterMaps.ipynb
│ ├── ITK_Example03_Masked_3D_Registration.ipynb
│ ├── ITK_Example04_InitialTransformAndMultiThreading.ipynb
│ ├── ITK_Example05_PointRegistration.ipynb
│ ├── ITK_Example06_GroupwiseRegistration.ipynb
│ ├── ITK_Example07_MultimetricMultiImageRegistration.ipynb
│ ├── ITK_Example08_SimpleTransformix.ipynb
│ ├── ITK_Example09_PointSetAndMaskTransformation.ipynb
│ ├── ITK_Example10_Transformix_Jacobian.ipynb
│ ├── ITK_Example11_Transformix_DeformationField.ipynb
│ ├── ITK_Example12_DifferentSizeTransformation.ipynb
│ ├── ITK_Example13_ITKResampling.ipynb
│ ├── ITK_Example14_WorldCoordinatesExplanation_Napari.ipynb
│ ├── ITK_Example15_Transformix_image_TranslationTransform.ipynb
│ ├── ITK_Example16_Transformix_mesh_TranslationTransform.ipynb
│ ├── ITK_Example17_MONAIWithPreregistration.ipynb
│ ├── ITK_Example18_MONAI_affine_Elastix_nonlinear.ipynb
│ ├── ITK_Example20_PixelTypes.ipynb
│ ├── ITK_Example21_ConstrainedRegistration.ipynb
│ ├── ITK_Example22_ConvertToITKTransform.ipynb
│ ├── ITK_Example_RegistrationWithCorrespondingPointsInMemory.ipynb
│ ├── ITK_Example_TomlFileFormatForParameterFiles.ipynb
│ ├── ITK_Registration_App.ipynb
│ ├── ITK_UnitTestExample1_RigidRegistration.ipynb
│ ├── ITK_UnitTestExample2_AffineRegistration.ipynb
│ ├── ITK_UnitTestExample3_BsplineRegistration.ipynb
│ ├── ITK_UnitTestExample4_MaskedRegistration.ipynb
│ ├── ITK_UnitTestExample5_GroupwiseRegistration.ipynb
│ ├── ITK_UnitTestExample6_PointSetTransformation.ipynb
│ ├── ITK_UnitTestExample7_SizeTransformation.ipynb
│ ├── data/
│ │ ├── CT_2D_head_fixed.mha
│ │ ├── CT_2D_head_fixed_mask.mha
│ │ ├── CT_2D_head_moving.mha
│ │ ├── CT_2D_head_moving_mask.mha
│ │ ├── CT_2D_plus_time.nii
│ │ ├── CT_3D_lung_fixed.mha
│ │ ├── CT_3D_lung_fixed_mask.mha
│ │ ├── CT_3D_lung_fixed_point_set.txt
│ │ ├── CT_3D_lung_fixed_point_set_corrected.txt
│ │ ├── CT_3D_lung_moving.mha
│ │ ├── CT_3D_lung_moving_mask.mha
│ │ ├── CT_3D_lung_moving_point_set.txt
│ │ ├── CT_3D_lung_moving_point_set_corrected.txt
│ │ ├── TransformParameters.0.txt
│ │ ├── TransformParameters.1.txt
│ │ ├── fixed_point_set_test.txt
│ │ ├── lung_sem/
│ │ │ └── ParameterFile.txt
│ │ ├── parameters.3D.NC.affine.ASGD.001.txt
│ │ ├── parameters_Affine.txt
│ │ ├── parameters_BSpline.txt
│ │ ├── parameters_Bspline_Multimetric.txt
│ │ └── parameters_Rigid.txt
│ ├── exampleoutput/
│ │ ├── Parameters.0.txt
│ │ ├── Parameters.1.txt
│ │ ├── Parameters.2.txt
│ │ ├── Parameters.3.txt
│ │ ├── TransformParameters.0.txt
│ │ ├── TransformParameters.1.txt
│ │ ├── fullSpatialJacobian.nii
│ │ ├── itk_composite_transform.h5
│ │ ├── outputpoints.txt
│ │ ├── parameters_custom.txt
│ │ ├── result_image.mha
│ │ └── spatialJacobian.nii
│ ├── exampleoutput_unittests/
│ │ └── outputpoints.txt
│ └── requirements.txt
├── itk-module.cmake
├── itk_wasm_env.bash
├── package.json
├── pixi.toml
├── pnpm-workspace.yaml
├── pyproject.toml
├── test/
│ ├── Baseline/
│ │ ├── CT_2D_head_test.mha.sha512
│ │ ├── CT_3D_lung_test.mha.sha512
│ │ └── itkElastixRegistrationMethodTestOutput.mha.sha512
│ ├── CMakeLists.txt
│ ├── Input/
│ │ ├── CT_2D_head_fixed.mha.sha512
│ │ ├── CT_2D_head_fixed_mask.mha.sha512
│ │ ├── CT_2D_head_moving.mha.sha512
│ │ ├── CT_2D_head_moving_mask.mha.sha512
│ │ ├── CT_3D_lung_fixed.mha.sha512
│ │ ├── CT_3D_lung_fixed_mask.mha.sha512
│ │ ├── CT_3D_lung_fixed_small.mha.sha512
│ │ ├── CT_3D_lung_moving.mha.sha512
│ │ ├── CT_3D_lung_moving_mask.mha.sha512
│ │ ├── parameters.3D.NC.bspline.ASGD.001.txt
│ │ ├── parameters_BSpline.txt
│ │ ├── parameters_Rigid.txt
│ │ └── transformparameters.3DCT_lung.affine.txt
│ └── itkElastixRegistrationMethodTest.cxx
├── wasm/
│ ├── CMakeLists.txt
│ ├── default-parameter-map.cxx
│ ├── elastix-wasm.cxx
│ ├── python/
│ │ ├── itkwasm-elastix/
│ │ │ ├── .gitattributes
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── docs/
│ │ │ │ ├── Makefile
│ │ │ │ ├── conf.py
│ │ │ │ ├── index.md
│ │ │ │ ├── make.bat
│ │ │ │ └── requirements.txt
│ │ │ ├── itkwasm_elastix/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _version.py
│ │ │ │ ├── default_parameter_map.py
│ │ │ │ ├── default_parameter_map_async.py
│ │ │ │ ├── elastix.py
│ │ │ │ ├── elastix_async.py
│ │ │ │ ├── read_parameter_files.py
│ │ │ │ ├── read_parameter_files_async.py
│ │ │ │ ├── write_parameter_files.py
│ │ │ │ └── write_parameter_files_async.py
│ │ │ ├── pyproject.toml
│ │ │ └── tests/
│ │ │ ├── __init__.py
│ │ │ ├── fixtures.py
│ │ │ ├── test_default_parameter_map.py
│ │ │ ├── test_elastix.py
│ │ │ ├── test_itkwasm_elastix.py
│ │ │ ├── test_read_parameter_files.py
│ │ │ ├── test_write_parameter_files.py
│ │ │ └── test_write_parameter_files_async.py
│ │ ├── itkwasm-elastix-emscripten/
│ │ │ ├── .gitattributes
│ │ │ ├── .gitignore
│ │ │ ├── README.md
│ │ │ ├── itkwasm_elastix_emscripten/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── _version.py
│ │ │ │ ├── default_parameter_map_async.py
│ │ │ │ ├── elastix_async.py
│ │ │ │ ├── js_package.py
│ │ │ │ ├── read_parameter_files_async.py
│ │ │ │ └── write_parameter_files_async.py
│ │ │ ├── pyproject.toml
│ │ │ ├── test/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── fixtures.py
│ │ │ │ ├── test_itkwasm_elastix.py
│ │ │ │ └── test_write_parameter_files_async.py
│ │ │ └── tests/
│ │ │ ├── __init__.py
│ │ │ ├── fixtures.py
│ │ │ ├── test_default_parameter_map_async.py
│ │ │ ├── test_elastix_async.py
│ │ │ ├── test_read_parameter_files_async.py
│ │ │ └── test_write_parameter_files_async.py
│ │ └── itkwasm-elastix-wasi/
│ │ ├── .gitattributes
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── itkwasm_elastix_wasi/
│ │ │ ├── __init__.py
│ │ │ ├── _version.py
│ │ │ ├── default_parameter_map.py
│ │ │ ├── elastix.py
│ │ │ ├── read_parameter_files.py
│ │ │ ├── wasm_modules/
│ │ │ │ ├── default-parameter-map.wasi.wasm
│ │ │ │ ├── elastix.wasi.wasm
│ │ │ │ ├── read-parameter-file.wasi.wasm
│ │ │ │ ├── read-parameter-files.wasi.wasm
│ │ │ │ └── write-parameter-files.wasi.wasm
│ │ │ └── write_parameter_files.py
│ │ ├── pyproject.toml
│ │ └── tests/
│ │ ├── __init__.py
│ │ ├── common.py
│ │ ├── test_default_parameter_map.py
│ │ ├── test_elastix.py
│ │ ├── test_elastix_wasm.py
│ │ ├── test_read_parameter_files.py
│ │ └── test_write_parameter_files.py
│ ├── read-parameter-files.cxx
│ ├── typescript/
│ │ ├── .gitignore
│ │ ├── .nojekll
│ │ ├── .npmignore
│ │ ├── README.md
│ │ ├── build/
│ │ │ ├── rollup.browser.config.js
│ │ │ └── rollup.node.config.js
│ │ ├── index.html
│ │ ├── package.json
│ │ ├── playwright.config.ts
│ │ ├── src/
│ │ │ ├── default-parameter-map-node-options.ts
│ │ │ ├── default-parameter-map-node-result.ts
│ │ │ ├── default-parameter-map-node.ts
│ │ │ ├── default-parameter-map-options.ts
│ │ │ ├── default-parameter-map-result.ts
│ │ │ ├── default-parameter-map.ts
│ │ │ ├── default-web-worker.ts
│ │ │ ├── elastix-node-options.ts
│ │ │ ├── elastix-node-result.ts
│ │ │ ├── elastix-node.ts
│ │ │ ├── elastix-options.ts
│ │ │ ├── elastix-result.ts
│ │ │ ├── elastix.ts
│ │ │ ├── index-all.ts
│ │ │ ├── index-common.ts
│ │ │ ├── index-node-only.ts
│ │ │ ├── index-node.ts
│ │ │ ├── index-only.ts
│ │ │ ├── index-worker-embedded.min.ts
│ │ │ ├── index-worker-embedded.ts
│ │ │ ├── index.ts
│ │ │ ├── itkConfig.js
│ │ │ ├── pipeline-worker-url.ts
│ │ │ ├── pipelines-base-url.ts
│ │ │ ├── read-parameter-files-node-options.ts
│ │ │ ├── read-parameter-files-node-result.ts
│ │ │ ├── read-parameter-files-node.ts
│ │ │ ├── read-parameter-files-options.ts
│ │ │ ├── read-parameter-files-result.ts
│ │ │ ├── read-parameter-files.ts
│ │ │ ├── version.ts
│ │ │ ├── write-parameter-files-node-result.ts
│ │ │ ├── write-parameter-files-node.ts
│ │ │ ├── write-parameter-files-options.ts
│ │ │ ├── write-parameter-files-result.ts
│ │ │ └── write-parameter-files.ts
│ │ ├── test/
│ │ │ ├── browser/
│ │ │ │ ├── common.ts
│ │ │ │ ├── default-parameter-map.spec.ts
│ │ │ │ ├── read-parameter-files.spec.ts
│ │ │ │ └── write-parameter-files.spec.ts
│ │ │ └── node/
│ │ │ ├── default-parameter-map-test.js
│ │ │ ├── elastix-test.js
│ │ │ ├── read-parameter-files-test.js
│ │ │ └── write-parameter-files-test.js
│ │ ├── tsconfig.json
│ │ └── vite.config.js
│ └── write-parameter-files.cxx
└── wrapping/
├── CMakeLists.txt
├── dockcross-manylinux-build-module-wheels-opencl.sh
├── dockcross-manylinux-download-cache.sh
├── elxParameterObject.wrap
├── itkElastixRegistrationMethod.wrap
├── itkTransformixFilter.wrap
├── stdParameterMap.i
├── test/
│ ├── CMakeLists.txt
│ ├── test_elx_parameter_object_dict.py
│ ├── test_itk_elastix_registration_method.py
│ ├── test_itk_elastix_registration_method_dict.py
│ └── test_itk_transformix_filter.py
└── transformix_extras.py
SYMBOL INDEX (103 symbols across 69 files)
FILE: test/itkElastixRegistrationMethodTest.cxx
class ShowProgress (line 29) | class ShowProgress : public itk::Command
method Execute (line 34) | void
method Execute (line 40) | void
function itkElastixRegistrationMethodTest (line 57) | int
FILE: wasm/default-parameter-map.cxx
function main (line 26) | int
FILE: wasm/elastix-wasm.cxx
class PipelineFunctor (line 41) | class PipelineFunctor
function main (line 290) | int
FILE: wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/default_parameter_map_async.py
function default_parameter_map_async (line 18) | async def default_parameter_map_async(
FILE: wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/elastix_async.py
function elastix_async (line 20) | async def elastix_async(
FILE: wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/read_parameter_files_async.py
function read_parameter_files_async (line 19) | async def read_parameter_files_async(
FILE: wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/write_parameter_files_async.py
function write_parameter_files_async (line 19) | async def write_parameter_files_async(
FILE: wasm/python/itkwasm-elastix-emscripten/test/fixtures.py
function package_wheel (line 12) | def package_wheel():
function input_data (line 16) | def input_data():
FILE: wasm/python/itkwasm-elastix-emscripten/test/test_itkwasm_elastix.py
function package_wheel (line 12) | def package_wheel():
function test_example (line 16) | async def test_example(selenium, package_wheel):
FILE: wasm/python/itkwasm-elastix-emscripten/test/test_write_parameter_files_async.py
function test_write_parameter_files_async (line 10) | async def test_write_parameter_files_async(selenium, package_wheel, inpu...
FILE: wasm/python/itkwasm-elastix-emscripten/tests/fixtures.py
function package_wheel (line 13) | def package_wheel():
function input_data (line 17) | def input_data():
FILE: wasm/python/itkwasm-elastix-emscripten/tests/test_default_parameter_map_async.py
function test_default_parameter_map_async (line 12) | async def test_default_parameter_map_async(selenium, package_wheel):
FILE: wasm/python/itkwasm-elastix-emscripten/tests/test_elastix_async.py
function test_elastix_async (line 12) | async def test_elastix_async(selenium, package_wheel):
FILE: wasm/python/itkwasm-elastix-emscripten/tests/test_read_parameter_files_async.py
function test_read_parameter_files_async (line 12) | async def test_read_parameter_files_async(selenium, package_wheel):
FILE: wasm/python/itkwasm-elastix-emscripten/tests/test_write_parameter_files_async.py
function test_write_parameter_files_async (line 12) | async def test_write_parameter_files_async(selenium, package_wheel):
FILE: wasm/python/itkwasm-elastix-wasi/itkwasm_elastix_wasi/default_parameter_map.py
function default_parameter_map (line 18) | def default_parameter_map(
FILE: wasm/python/itkwasm-elastix-wasi/itkwasm_elastix_wasi/elastix.py
function elastix (line 20) | def elastix(
FILE: wasm/python/itkwasm-elastix-wasi/itkwasm_elastix_wasi/read_parameter_files.py
function read_parameter_files (line 19) | def read_parameter_files(
FILE: wasm/python/itkwasm-elastix-wasi/itkwasm_elastix_wasi/write_parameter_files.py
function write_parameter_files (line 19) | def write_parameter_files(
FILE: wasm/python/itkwasm-elastix-wasi/tests/test_default_parameter_map.py
function test_default_parameter_map (line 7) | def test_default_parameter_map():
FILE: wasm/python/itkwasm-elastix-wasi/tests/test_elastix.py
function test_elastix (line 7) | def test_elastix():
FILE: wasm/python/itkwasm-elastix-wasi/tests/test_elastix_wasm.py
function test_elastix_wasm (line 12) | def test_elastix_wasm():
FILE: wasm/python/itkwasm-elastix-wasi/tests/test_read_parameter_files.py
function test_read_parameter_files (line 7) | def test_read_parameter_files():
FILE: wasm/python/itkwasm-elastix-wasi/tests/test_write_parameter_files.py
function test_write_parameter_files (line 8) | def test_write_parameter_files():
FILE: wasm/python/itkwasm-elastix/itkwasm_elastix/default_parameter_map.py
function default_parameter_map (line 10) | def default_parameter_map(
FILE: wasm/python/itkwasm-elastix/itkwasm_elastix/default_parameter_map_async.py
function default_parameter_map_async (line 10) | async def default_parameter_map_async(
FILE: wasm/python/itkwasm-elastix/itkwasm_elastix/elastix.py
function elastix (line 12) | def elastix(
FILE: wasm/python/itkwasm-elastix/itkwasm_elastix/elastix_async.py
function elastix_async (line 12) | async def elastix_async(
FILE: wasm/python/itkwasm-elastix/itkwasm_elastix/read_parameter_files.py
function read_parameter_files (line 11) | def read_parameter_files(
FILE: wasm/python/itkwasm-elastix/itkwasm_elastix/read_parameter_files_async.py
function read_parameter_files_async (line 11) | async def read_parameter_files_async(
FILE: wasm/python/itkwasm-elastix/itkwasm_elastix/write_parameter_files.py
function write_parameter_files (line 11) | def write_parameter_files(
FILE: wasm/python/itkwasm-elastix/itkwasm_elastix/write_parameter_files_async.py
function write_parameter_files_async (line 11) | async def write_parameter_files_async(
FILE: wasm/python/itkwasm-elastix/tests/fixtures.py
function package_wheel (line 12) | def package_wheel():
function input_data (line 16) | def input_data():
FILE: wasm/python/itkwasm-elastix/tests/test_default_parameter_map.py
function test_default_parameter_map (line 12) | async def test_default_parameter_map(selenium, package_wheel, emscripten...
FILE: wasm/python/itkwasm-elastix/tests/test_elastix.py
function test_elastix (line 12) | async def test_elastix(selenium, package_wheel, emscripten_package_wheel):
FILE: wasm/python/itkwasm-elastix/tests/test_itkwasm_elastix.py
function package_wheel (line 12) | def package_wheel():
function test_example (line 16) | async def test_example(selenium, package_wheel):
FILE: wasm/python/itkwasm-elastix/tests/test_read_parameter_files.py
function test_read_parameter_files (line 12) | async def test_read_parameter_files(selenium, package_wheel, emscripten_...
FILE: wasm/python/itkwasm-elastix/tests/test_write_parameter_files.py
function test_write_parameter_files (line 8) | def test_write_parameter_files():
FILE: wasm/python/itkwasm-elastix/tests/test_write_parameter_files_async.py
function test_write_parameter_files_async (line 10) | async def test_write_parameter_files_async(selenium, package_wheel, inpu...
FILE: wasm/read-parameter-files.cxx
function main (line 26) | int
FILE: wasm/typescript/src/default-parameter-map-node-options.ts
type DefaultParameterMapNodeOptions (line 3) | interface DefaultParameterMapNodeOptions {
FILE: wasm/typescript/src/default-parameter-map-node-result.ts
type DefaultParameterMapNodeResult (line 5) | interface DefaultParameterMapNodeResult {
FILE: wasm/typescript/src/default-parameter-map-node.ts
function defaultParameterMapNode (line 25) | async function defaultParameterMapNode(
FILE: wasm/typescript/src/default-parameter-map-options.ts
type DefaultParameterMapOptions (line 5) | interface DefaultParameterMapOptions extends WorkerPoolFunctionOption {
FILE: wasm/typescript/src/default-parameter-map-result.ts
type DefaultParameterMapResult (line 5) | interface DefaultParameterMapResult extends WorkerPoolFunctionResult {
FILE: wasm/typescript/src/default-parameter-map.ts
function defaultParameterMap (line 27) | async function defaultParameterMap(
FILE: wasm/typescript/src/default-web-worker.ts
function createNewWorker (line 8) | async function createNewWorker() {
function setDefaultWebWorker (line 14) | function setDefaultWebWorker (webWorker: Worker | null): void {
function getDefaultWebWorker (line 18) | async function getDefaultWebWorker (): Promise<Worker> {
FILE: wasm/typescript/src/elastix-node-options.ts
type ElastixNodeOptions (line 5) | interface ElastixNodeOptions {
FILE: wasm/typescript/src/elastix-node-result.ts
type ElastixNodeResult (line 5) | interface ElastixNodeResult {
FILE: wasm/typescript/src/elastix-node.ts
function elastixNode (line 27) | async function elastixNode(
FILE: wasm/typescript/src/elastix-options.ts
type ElastixOptions (line 5) | interface ElastixOptions extends WorkerPoolFunctionOption {
FILE: wasm/typescript/src/elastix-result.ts
type ElastixResult (line 5) | interface ElastixResult extends WorkerPoolFunctionResult {
FILE: wasm/typescript/src/elastix.ts
function elastix (line 30) | async function elastix(
FILE: wasm/typescript/src/pipeline-worker-url.ts
function setPipelineWorkerUrl (line 7) | function setPipelineWorkerUrl (workerUrl: string | URL | null): void {
function getPipelineWorkerUrl (line 11) | function getPipelineWorkerUrl (): string | URL | null {
FILE: wasm/typescript/src/pipelines-base-url.ts
function setPipelinesBaseUrl (line 7) | function setPipelinesBaseUrl (baseUrl: string | URL): void {
function getPipelinesBaseUrl (line 11) | function getPipelinesBaseUrl (): string | URL {
FILE: wasm/typescript/src/read-parameter-files-node-options.ts
type ReadParameterFilesNodeOptions (line 5) | interface ReadParameterFilesNodeOptions {
FILE: wasm/typescript/src/read-parameter-files-node-result.ts
type ReadParameterFilesNodeResult (line 5) | interface ReadParameterFilesNodeResult {
FILE: wasm/typescript/src/read-parameter-files-node.ts
function readParameterFilesNode (line 24) | async function readParameterFilesNode(
FILE: wasm/typescript/src/read-parameter-files-options.ts
type ReadParameterFilesOptions (line 5) | interface ReadParameterFilesOptions extends WorkerPoolFunctionOption {
FILE: wasm/typescript/src/read-parameter-files-result.ts
type ReadParameterFilesResult (line 5) | interface ReadParameterFilesResult extends WorkerPoolFunctionResult {
FILE: wasm/typescript/src/read-parameter-files.ts
function readParameterFiles (line 27) | async function readParameterFiles(
FILE: wasm/typescript/src/write-parameter-files-node-result.ts
type WriteParameterFilesNodeResult (line 3) | interface WriteParameterFilesNodeResult {
FILE: wasm/typescript/src/write-parameter-files-node.ts
function writeParameterFilesNode (line 24) | async function writeParameterFilesNode(
FILE: wasm/typescript/src/write-parameter-files-options.ts
type WriteParameterFilesOptions (line 5) | interface WriteParameterFilesOptions extends WorkerPoolFunctionOption {
FILE: wasm/typescript/src/write-parameter-files-result.ts
type WriteParameterFilesResult (line 5) | interface WriteParameterFilesResult extends WorkerPoolFunctionResult {
FILE: wasm/typescript/src/write-parameter-files.ts
function writeParameterFiles (line 29) | async function writeParameterFiles(
FILE: wasm/write-parameter-files.cxx
function main (line 28) | int
FILE: wrapping/test/test_elx_parameter_object_dict.py
function test_convert_to_parameter_value (line 22) | def test_convert_to_parameter_value():
function test_convert_to_parameter_map (line 30) | def test_convert_to_parameter_map():
function test_dict_to_parameter_object_single_dict (line 48) | def test_dict_to_parameter_object_single_dict():
function test_dict_to_parameter_object_list_of_dicts (line 63) | def test_dict_to_parameter_object_list_of_dicts():
function test_parameter_object_new_with_converted_map (line 77) | def test_parameter_object_new_with_converted_map():
function test_convert_to_parameter_map_idempotent (line 89) | def test_convert_to_parameter_map_idempotent():
FILE: wrapping/transformix_extras.py
function convert_to_parameter_value (line 6) | def convert_to_parameter_value(value):
function convert_to_parameter_map (line 19) | def convert_to_parameter_map(d):
function dict_to_parameter_object (line 37) | def dict_to_parameter_object(d):
function convert_to_parameter_value_init_docstring (line 62) | def convert_to_parameter_value_init_docstring():
function convert_to_parameter_map_init_docstring (line 67) | def convert_to_parameter_map_init_docstring():
function dict_to_parameter_object_init_docstring (line 72) | def dict_to_parameter_object_init_docstring():
function _preprocess_parameter_args (line 76) | def _preprocess_parameter_args(args, kwargs, parameter_keys=None):
function elastix_registration_method (line 111) | def elastix_registration_method(*args, **kwargs):
function elastix_registration_method_init_docstring (line 130) | def elastix_registration_method_init_docstring():
function transformix_filter (line 134) | def transformix_filter(*args, **kwargs):
function transformix_filter_init_docstring (line 149) | def transformix_filter_init_docstring():
function transformix_deformation_field (line 153) | def transformix_deformation_field(*args, **kwargs):
function transformix_deformation_field_init_docstring (line 162) | def transformix_deformation_field_init_docstring():
function transformix_jacobian (line 166) | def transformix_jacobian(*args, **kwargs):
function transformix_jacobian_init_docstring (line 188) | def transformix_jacobian_init_docstring():
function transformix_pointset (line 192) | def transformix_pointset(*args, **kwargs):
function transformix_pointset_init_docstring (line 215) | def transformix_pointset_init_docstring():
Condensed preview — 249 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,430K chars).
[
{
"path": ".binder/postBuild",
"chars": 272,
"preview": "#!/bin/bash\n\nconda install -c conda-forge nodejs\njupyter labextension install @jupyter-widgets/jupyterlab-manager@2.0.0 "
},
{
"path": ".binder/requirements.txt",
"chars": 200,
"preview": "itk-elastix>=0.25.1\nitkwidgets>=0.32.0\njupyterlab>=2.2.0\nimageio\nipywidgets>=7.5.1\nipympl>=0.5.7\nnumpy\ntorch>=2.0\nmonai>"
},
{
"path": ".clang-format",
"chars": 5238,
"preview": "## This config file is only relevant for clang-format version 8.0.0\n##\n## Examples of each format style can be found on "
},
{
"path": ".gitattributes",
"chars": 520,
"preview": "# Custom attribute to mark sources as using our C++/C code style.\n[attr]our-c-style whitespace=tab-in-indent,no-lf-at-e"
},
{
"path": ".github/workflows/build-test-package.yml",
"chars": 1052,
"preview": "name: Build\n\non:\n push:\n branches:\n - main\n tags:\n - 'v*'\n pull_request:\n branches:\n - main\n\nj"
},
{
"path": ".github/workflows/clang-format-linter.yml",
"chars": 242,
"preview": "name: clang-format linter\n\non: [push,pull_request]\n\njobs:\n lint:\n runs-on: ubuntu-latest\n\n steps:\n - uses: act"
},
{
"path": ".github/workflows/wasm.yml",
"chars": 1094,
"preview": "name: WebAssembly\n\non:\n push:\n branches:\n - main\n tags:\n - '*'\n pull_request:\n branches:\n - m"
},
{
"path": ".gitignore",
"chars": 542,
"preview": "ITK-cp27-cp27m-manylinux1_x64\nITK-cp27-cp27mu-manylinux1_x64\nITK-cp35-cp35m-manylinux1_x64\nITK-cp36-cp36m-manylinux1_x64"
},
{
"path": ".jupyter/jupyter_notebook_config.py",
"chars": 257,
"preview": "# Configuration file for jupyter-notebook.\n\n## Supply overrides for the tornado.web.Application that the Jupyter noteboo"
},
{
"path": "CMakeLists.txt",
"chars": 4538,
"preview": "cmake_minimum_required(VERSION 3.16.3)\nproject(Elastix)\n\nif(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 17)\n # Su"
},
{
"path": "CTestConfig.cmake",
"chars": 230,
"preview": "set(CTEST_PROJECT_NAME \"ITK\")\nset(CTEST_NIGHTLY_START_TIME \"1:00:00 UTC\")\n\nset(CTEST_DROP_METHOD \"http\")\nset(CTEST_DROP_"
},
{
"path": "LICENSE",
"chars": 11360,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 8883,
"preview": "ITKElastix\n==========\n\n[\n(NumberOfParameters 722)\n(TransformParameters -2.950718 -3.545671 -3.421660 -3.067611 -2."
},
{
"path": "examples/data/TransformParameters.1.txt",
"chars": 8104,
"preview": "(Transform \"BSplineTransform\")\n(NumberOfParameters 722)\n(TransformParameters -2.950718 -3.545671 -3.421660 -3.067611 -2."
},
{
"path": "examples/data/fixed_point_set_test.txt",
"chars": 37,
"preview": "point\n5\n25 25\n25 75\n75 75\n75 25\n50 50"
},
{
"path": "examples/data/lung_sem/ParameterFile.txt",
"chars": 1576,
"preview": "(FixedInternalImagePixelType \"float\")\n(MovingInternalImagePixelType \"float\")\n\n// (UseDirectionCosines \"true\")\n\n(Registra"
},
{
"path": "examples/data/parameters.3D.NC.affine.ASGD.001.txt",
"chars": 2113,
"preview": "// This parameter file has kind of realistic values.\n// In most other parameter files for testing, the number of samples"
},
{
"path": "examples/data/parameters_Affine.txt",
"chars": 6101,
"preview": "// Example parameter file for affine registration\n// C-style comments: //\n\n// The internal pixel type, used for internal"
},
{
"path": "examples/data/parameters_BSpline.txt",
"chars": 6843,
"preview": "// Example parameter file for B-spline registration\n// C-style comments: //\n\n// The internal pixel type, used for intern"
},
{
"path": "examples/data/parameters_Bspline_Multimetric.txt",
"chars": 6291,
"preview": "// Example parameter file for affine registration\n// C-style comments: //\n\n// The internal pixel type, used for internal"
},
{
"path": "examples/data/parameters_Rigid.txt",
"chars": 6088,
"preview": "// Example parameter file for rotation registration\n// C-style comments: //\n\n// The internal pixel type, used for intern"
},
{
"path": "examples/exampleoutput/Parameters.0.txt",
"chars": 826,
"preview": "(AutomaticParameterEstimation \"true\")\n(AutomaticScalesEstimation \"true\")\n(CheckNumberOfSamples \"true\")\n(DefaultPixelValu"
},
{
"path": "examples/exampleoutput/Parameters.1.txt",
"chars": 965,
"preview": "(AutomaticParameterEstimation \"true\")\n(CheckNumberOfSamples \"true\")\n(DefaultPixelValue 0)\n(FinalBSplineInterpolationOrde"
},
{
"path": "examples/exampleoutput/Parameters.2.txt",
"chars": 898,
"preview": "(BSplineInterpolationOrder 1)\n(DefaultPixelValue 0)\n(ErodeMask \"false\")\n(FinalBSplineInterpolationOrder 3)\n(FinalGridSpa"
},
{
"path": "examples/exampleoutput/Parameters.3.txt",
"chars": 828,
"preview": "(AutomaticParameterEstimation \"true\")\n(AutomaticScalesEstimation \"true\")\n(CheckNumberOfSamples \"true\")\n(DefaultPixelValu"
},
{
"path": "examples/exampleoutput/TransformParameters.0.txt",
"chars": 957,
"preview": "(Transform \"EulerTransform\")\n(NumberOfParameters 3)\n(TransformParameters -0.001020 -0.954586 -0.005754)\n(InitialTransfor"
},
{
"path": "examples/exampleoutput/TransformParameters.1.txt",
"chars": 17135,
"preview": "(Transform \"BSplineTransform\")\n(NumberOfParameters 1682)\n(TransformParameters -0.000626 0.005453 0.012955 0.018906 0.015"
},
{
"path": "examples/exampleoutput/outputpoints.txt",
"chars": 26639,
"preview": "Point\t0\t; InputIndex = [ 86 83 92 ]\t; InputPoint = [ -36.351000 -36.974000 -1204.500000 ]\t; OutputIndexFixed = [ 83 76 1"
},
{
"path": "examples/exampleoutput/parameters_custom.txt",
"chars": 854,
"preview": "(AutomaticParameterEstimation \"true\")\n(AutomaticScalesEstimation \"true\")\n(CheckNumberOfSamples \"true\")\n(DefaultPixelValu"
},
{
"path": "examples/exampleoutput_unittests/outputpoints.txt",
"chars": 1079,
"preview": "Point\t0\t; InputIndex = [ 25 25 ]\t; InputPoint = [ 25.000000 25.000000 ]\t; OutputIndexFixed = [ 1 10 ]\t; OutputPoint = [ "
},
{
"path": "examples/requirements.txt",
"chars": 156,
"preview": "itk-elastix>=0.25.1\nitkwidgets>=0.32.0\njupyterlab>=2.2.0\nimageio\nipywidgets>=7.5.1\nipympl>=0.5.7\nnumpy\ntorch>=2.0\nmonai>"
},
{
"path": "itk-module.cmake",
"chars": 870,
"preview": "# the top-level README is used for describing this module, just\n# re-used it for documentation here\nget_filename_compone"
},
{
"path": "itk_wasm_env.bash",
"chars": 2179,
"preview": "#!/usr/bin/env bash\n\nfunction die() {\n echo \"$1\"\n exit 1\n}\n\nexport ITK_WASM_DESCRIPTION=${ITK_WASM_DESCRIPTION:-$("
},
{
"path": "package.json",
"chars": 1215,
"preview": "{\n \"name\": \"itk-elastix-build\",\n \"version\": \"0.1.0\",\n \"description\": \"npm scripts to generate itk-wasm artifacts.\",\n "
},
{
"path": "pixi.toml",
"chars": 6568,
"preview": "[project]\nname = \"@itk-wasm/elastix\"\nversion = \"1.0.0\"\nauthors = [\"Matt McCormick <matt.mccormick@kitware.com>\"]\nchannel"
},
{
"path": "pnpm-workspace.yaml",
"chars": 32,
"preview": "packages:\n - 'wasm/typescript'\n"
},
{
"path": "pyproject.toml",
"chars": 3959,
"preview": "[build-system]\nrequires = [\"scikit-build-core\"]\nbuild-backend = \"scikit_build_core.build\"\n\n[project]\nname = \"itk-elastix"
},
{
"path": "test/Baseline/CT_2D_head_test.mha.sha512",
"chars": 129,
"preview": "30a9466f952eacbc246eeb9f351795e32f43bb37197df83374b91348e1ec96b73e2f2b9dc994df14c231587cfe5f0a95bfb80f7c72ea6dd7801fe8c4"
},
{
"path": "test/Baseline/CT_3D_lung_test.mha.sha512",
"chars": 129,
"preview": "98c6553957f81f63e61fbfb36d2cd4a06ede7b2f8a347c6e9dafcf1d7fb16b5de9b3d4dbfd2f49970507a9c9d5795063a9cae32abe31c0192463a30c"
},
{
"path": "test/Baseline/itkElastixRegistrationMethodTestOutput.mha.sha512",
"chars": 129,
"preview": "6c872ea58c9c6e0b477c607c2dbc84a402943ab6fb11bd68627dd884628c58164a0e2fc30c47d3fe608479f86131a5a6dbb3cbc1805e0894a7dbf559"
},
{
"path": "test/CMakeLists.txt",
"chars": 660,
"preview": "itk_module_test()\n\nset(ElastixTests\n itkElastixRegistrationMethodTest.cxx\n )\n\nCreateTestDriver(Elastix \"${Elastix-Test"
},
{
"path": "test/Input/CT_2D_head_fixed.mha.sha512",
"chars": 129,
"preview": "61ace3c1f2be81ec716a552d7c3de5876035527a47ab0c4aface07e9f8735e28463c532f3ee6789cf976d6a024f191dce9a1f9f2b35517e98903c25b"
},
{
"path": "test/Input/CT_2D_head_fixed_mask.mha.sha512",
"chars": 129,
"preview": "e3db5b01ffd6d1a4f1f399d635f7a71006dc3154c4da958b7ecbd465ac0c75329b13b2888bb7984e81f5c7da518d3e80bd7d4e5d8a5fd3843d6a867d"
},
{
"path": "test/Input/CT_2D_head_moving.mha.sha512",
"chars": 129,
"preview": "3fe1df7ff5abdad70bec56a3cfc4095090e01a883706c57c174eedf7881acac174806b7a9ab31fe9b627e0215594371bb846a1b703e6006d949e1cce"
},
{
"path": "test/Input/CT_2D_head_moving_mask.mha.sha512",
"chars": 129,
"preview": "6c83e9a5117a3fec44602aa9a5869f1546fad3fef045d3de3bab8fe0686df70dc5fb532a1b4b287a34951ad719fc46c03a87af474c6057afd1805600"
},
{
"path": "test/Input/CT_3D_lung_fixed.mha.sha512",
"chars": 129,
"preview": "75f630aafc86005f9837fd41843cd304c1b415131eb9915873a31d0c654feb308a654176a7b39e0cdb50707502c22a4a94c220c7f0c1faec69c2734b"
},
{
"path": "test/Input/CT_3D_lung_fixed_mask.mha.sha512",
"chars": 129,
"preview": "55e68413897c53b490f59a7332790c9826a72b296c4042a905ba4433873c341c8f8acdd1feb0af4a3ad7c3ed21ddf220f03eeb848e2ddc62ae5a9695"
},
{
"path": "test/Input/CT_3D_lung_fixed_small.mha.sha512",
"chars": 129,
"preview": "98233a721050af7d757327bdff7bd721cded419f3db9ad865b5fb3d039f3fe0eda52600074d54f49e313fc8eefde4bb05968f5def03debdfb58a3a33"
},
{
"path": "test/Input/CT_3D_lung_moving.mha.sha512",
"chars": 129,
"preview": "680a3057f9db8eedcfc1598b8b7597fe14ae21d4a95314ccc1844928e761496ee47e7f90a07307b681b65a2ecf0d63d027e038831ebc034bcfaec59d"
},
{
"path": "test/Input/CT_3D_lung_moving_mask.mha.sha512",
"chars": 129,
"preview": "de18b27af77a099f48534d4340f91477c8b8246689e0ec54549aebd3b37b3cf9a0ea23f8083d472ff42c361ddd27bd24a1858df52bab3ab96208f8ec"
},
{
"path": "test/Input/parameters.3D.NC.bspline.ASGD.001.txt",
"chars": 2264,
"preview": "// This parameter file has kind of realistic values.\n// In most other parameter files for testing, the number of samples"
},
{
"path": "test/Input/parameters_BSpline.txt",
"chars": 6843,
"preview": "// Example parameter file for B-spline registration\n// C-style comments: //\n\n// The internal pixel type, used for intern"
},
{
"path": "test/Input/parameters_Rigid.txt",
"chars": 6088,
"preview": "// Example parameter file for rotation registration\n// C-style comments: //\n\n// The internal pixel type, used for intern"
},
{
"path": "test/Input/transformparameters.3DCT_lung.affine.txt",
"chars": 1123,
"preview": "(Transform \"AffineTransform\")\n(NumberOfParameters 12)\n(TransformParameters 1.036712 -0.007980 -0.008800 0.021786 1.05413"
},
{
"path": "test/itkElastixRegistrationMethodTest.cxx",
"chars": 5469,
"preview": "/*=========================================================================\n *\n * Copyright NumFOCUS\n *\n * Licensed un"
},
{
"path": "wasm/CMakeLists.txt",
"chars": 4648,
"preview": "cmake_minimum_required(VERSION 3.16)\nproject(ElastixWasm)\n\nset(CMAKE_CXX_STANDARD 17)\n\nif(EMSCRIPTEN)\n set(io_component"
},
{
"path": "wasm/default-parameter-map.cxx",
"chars": 2974,
"preview": "/*=========================================================================\n *\n * Copyright NumFOCUS\n *\n * Licensed un"
},
{
"path": "wasm/elastix-wasm.cxx",
"chars": 12719,
"preview": "/*=========================================================================\n *\n * Copyright NumFOCUS\n *\n * Licensed un"
},
{
"path": "wasm/python/itkwasm-elastix/.gitattributes",
"chars": 86,
"preview": "# GitHub syntax highlighting\npixi.lock linguist-language=YAML linguist-generated=true\n"
},
{
"path": "wasm/python/itkwasm-elastix/.gitignore",
"chars": 37,
"preview": "# pixi environments\n.pixi\n*.egg-info\n"
},
{
"path": "wasm/python/itkwasm-elastix/README.md",
"chars": 308,
"preview": "# itkwasm-elastix\n\n[](https://badge.fury.io/py/itkwasm-elas"
},
{
"path": "wasm/python/itkwasm-elastix/docs/Makefile",
"chars": 634,
"preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line, and also\n# from the "
},
{
"path": "wasm/python/itkwasm-elastix/docs/conf.py",
"chars": 1551,
"preview": "# Configuration file for the Sphinx documentation builder.\n#\n# For the full list of built-in configuration values, see t"
},
{
"path": "wasm/python/itkwasm-elastix/docs/index.md",
"chars": 683,
"preview": "itkwasm-elastix\n=======\n\n> A toolbox for rigid and nonrigid registration of images.\n\n[:\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix/tests/test_default_parameter_map.py",
"chars": 589,
"preview": "import pytest\nimport sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix/tests/test_elastix.py",
"chars": 561,
"preview": "import pytest\nimport sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix/tests/test_itkwasm_elastix.py",
"chars": 539,
"preview": "import pytest\nimport sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix/tests/test_read_parameter_files.py",
"chars": 587,
"preview": "import pytest\nimport sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix/tests/test_write_parameter_files.py",
"chars": 773,
"preview": "from pathlib import Path\nimport json\n\nimport pytest\n\nfrom itkwasm_elastix_wasi import write_parameter_files\n\ndef test_wr"
},
{
"path": "wasm/python/itkwasm-elastix/tests/test_write_parameter_files_async.py",
"chars": 1162,
"preview": "import sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_module_level=T"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/.gitattributes",
"chars": 86,
"preview": "# GitHub syntax highlighting\npixi.lock linguist-language=YAML linguist-generated=true\n"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/.gitignore",
"chars": 53,
"preview": "# pixi environments\n.pixi\n*.egg-info\npyodide.tar.bz2\n"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/README.md",
"chars": 616,
"preview": "# itkwasm-elastix-emscripten\n\n[](https://badge.f"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/__init__.py",
"chars": 457,
"preview": "# Generated file. To retain edits, remove this comment.\n\n\"\"\"itkwasm-elastix-emscripten: A toolbox for rigid and nonrigid"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/_version.py",
"chars": 22,
"preview": "__version__ = \"0.3.1\"\n"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/default_parameter_map_async.py",
"chars": 1867,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom pathlib import Path\nimport os\nfrom typing import Dict, Tup"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/elastix_async.py",
"chars": 2539,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom pathlib import Path\nimport os\nfrom typing import Dict, Tup"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/js_package.py",
"chars": 268365,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom itkwasm.pyodide import JsPackageConfig, JsPackage\n\nfrom ._"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/read_parameter_files_async.py",
"chars": 1416,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom pathlib import Path\nimport os\nfrom typing import Dict, Tup"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/itkwasm_elastix_emscripten/write_parameter_files_async.py",
"chars": 1503,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom pathlib import Path\nimport os\nfrom typing import Dict, Tup"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/pyproject.toml",
"chars": 3028,
"preview": "[build-system]\nrequires = [\"hatchling\", \"hatch-vcs\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"itkwasm-elasti"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/test/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/test/fixtures.py",
"chars": 752,
"preview": "import pytest\nimport sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/test/test_itkwasm_elastix.py",
"chars": 561,
"preview": "import pytest\nimport sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/test/test_write_parameter_files_async.py",
"chars": 1173,
"preview": "import sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_module_level=T"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/tests/fixtures.py",
"chars": 719,
"preview": "import pytest\nimport sys\nimport glob\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Pyt"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/tests/test_default_parameter_map_async.py",
"chars": 507,
"preview": "import pytest\nimport sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/tests/test_elastix_async.py",
"chars": 479,
"preview": "import pytest\nimport sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/tests/test_read_parameter_files_async.py",
"chars": 505,
"preview": "import pytest\nimport sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix-emscripten/tests/test_write_parameter_files_async.py",
"chars": 507,
"preview": "import pytest\nimport sys\n\nif sys.version_info < (3,10):\n pytest.skip(\"Skipping pyodide tests on older Python\", allow_"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/.gitattributes",
"chars": 86,
"preview": "# GitHub syntax highlighting\npixi.lock linguist-language=YAML linguist-generated=true\n"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/.gitignore",
"chars": 37,
"preview": "# pixi environments\n.pixi\n*.egg-info\n"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/README.md",
"chars": 598,
"preview": "# itkwasm-elastix-wasi\n\n[](https://badge.fury.io/py/it"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/itkwasm_elastix_wasi/__init__.py",
"chars": 397,
"preview": "# Generated file. To retain edits, remove this comment.\n\n\"\"\"itkwasm-elastix-wasi: A toolbox for rigid and nonrigid regis"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/itkwasm_elastix_wasi/_version.py",
"chars": 22,
"preview": "__version__ = \"0.3.1\"\n"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/itkwasm_elastix_wasi/default_parameter_map.py",
"chars": 1943,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom pathlib import Path, PurePosixPath\nimport os\nfrom typing i"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/itkwasm_elastix_wasi/elastix.py",
"chars": 3504,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom pathlib import Path, PurePosixPath\nimport os\nfrom typing i"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/itkwasm_elastix_wasi/read_parameter_files.py",
"chars": 1725,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom pathlib import Path, PurePosixPath\nimport os\nfrom typing i"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/itkwasm_elastix_wasi/write_parameter_files.py",
"chars": 1773,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom pathlib import Path, PurePosixPath\nimport os\nfrom typing i"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/pyproject.toml",
"chars": 1720,
"preview": "[build-system]\nrequires = [\"hatchling\", \"hatch-vcs\"]\nbuild-backend = \"hatchling.build\"\n\n[project]\nname = \"itkwasm-elasti"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "wasm/python/itkwasm-elastix-wasi/tests/common.py",
"chars": 363,
"preview": "from pathlib import Path\n\ntest_input_path = Path(__file__).parent / \"..\" / \"..\" / \"..\" / \"test\" / \"data\" / \"input\"\ntest_"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/tests/test_default_parameter_map.py",
"chars": 211,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom itkwasm_elastix_wasi import default_parameter_map\n\nfrom .c"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/tests/test_elastix.py",
"chars": 183,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom itkwasm_elastix_wasi import elastix\n\nfrom .common import t"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/tests/test_elastix_wasm.py",
"chars": 1836,
"preview": "from pathlib import Path\nfrom dataclasses import asdict\nimport json\n\nimport pytest\n\nfrom itkwasm_compare_images import c"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/tests/test_read_parameter_files.py",
"chars": 209,
"preview": "# Generated file. To retain edits, remove this comment.\n\nfrom itkwasm_elastix_wasi import read_parameter_files\n\nfrom .co"
},
{
"path": "wasm/python/itkwasm-elastix-wasi/tests/test_write_parameter_files.py",
"chars": 773,
"preview": "from pathlib import Path\nimport json\n\nimport pytest\n\nfrom itkwasm_elastix_wasi import write_parameter_files\n\ndef test_wr"
},
{
"path": "wasm/read-parameter-files.cxx",
"chars": 2915,
"preview": "/*=========================================================================\n *\n * Copyright NumFOCUS\n *\n * Licensed un"
},
{
"path": "wasm/typescript/.gitignore",
"chars": 73,
"preview": "demo-app/\ntest/browser-demo-app/public/\nplaywright-report/\ntest-results/\n"
},
{
"path": "wasm/typescript/.nojekll",
"chars": 0,
"preview": ""
},
{
"path": "wasm/typescript/.npmignore",
"chars": 44,
"preview": "node_modules\n.DS_Store\ntest\ncypress\ndemo-app"
},
{
"path": "wasm/typescript/README.md",
"chars": 13886,
"preview": "# @itk-wasm/elastix\n\n[](https://www.npmjs.com/package/@i"
},
{
"path": "wasm/typescript/build/rollup.browser.config.js",
"chars": 1362,
"preview": "import { nodeResolve } from '@rollup/plugin-node-resolve'\nimport copy from 'rollup-plugin-copy'\nimport typescript from '"
},
{
"path": "wasm/typescript/build/rollup.node.config.js",
"chars": 771,
"preview": "import { nodeResolve } from '@rollup/plugin-node-resolve'\nimport typescript from '@rollup/plugin-typescript'\nimport comm"
},
{
"path": "wasm/typescript/index.html",
"chars": 2038,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>@itk-wasm/elastix</title>\n <meta http-equiv=\""
},
{
"path": "wasm/typescript/package.json",
"chars": 2026,
"preview": "{\n \"name\": \"@itk-wasm/elastix\",\n \"version\": \"0.4.0\",\n \"description\": \"A toolbox for rigid and nonrigid registration o"
},
{
"path": "wasm/typescript/playwright.config.ts",
"chars": 2141,
"preview": "import { defineConfig, devices } from \"@playwright/test\";\n\n/**\n * @see https://playwright.dev/docs/test-configuration\n *"
},
{
"path": "wasm/typescript/src/default-parameter-map-node-options.ts",
"chars": 337,
"preview": "// Generated file. To retain edits, remove this comment.\n\ninterface DefaultParameterMapNodeOptions {\n /** Number of mul"
},
{
"path": "wasm/typescript/src/default-parameter-map-node-result.ts",
"chars": 269,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { JsonCompatible } from 'itk-wasm'\n\ninterface DefaultPa"
},
{
"path": "wasm/typescript/src/default-parameter-map-node.ts",
"chars": 1922,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport {\n JsonCompatible,\n InterfaceTypes,\n PipelineOutput,"
},
{
"path": "wasm/typescript/src/default-parameter-map-options.ts",
"chars": 415,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { WorkerPoolFunctionOption } from 'itk-wasm'\n\ninterface"
},
{
"path": "wasm/typescript/src/default-parameter-map-result.ts",
"chars": 320,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { JsonCompatible, WorkerPoolFunctionResult } from 'itk-"
},
{
"path": "wasm/typescript/src/default-parameter-map.ts",
"chars": 2261,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport {\n JsonCompatible,\n InterfaceTypes,\n PipelineOutput,"
},
{
"path": "wasm/typescript/src/default-web-worker.ts",
"chars": 1159,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { getDefaultWebWorker as itkWasmGetDefaultWebWorker, cr"
},
{
"path": "wasm/typescript/src/elastix-node-options.ts",
"chars": 546,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { Image,BinaryFile,JsonCompatible } from 'itk-wasm'\n\nin"
},
{
"path": "wasm/typescript/src/elastix-node-result.ts",
"chars": 376,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { Image, JsonCompatible } from 'itk-wasm'\n\ninterface El"
},
{
"path": "wasm/typescript/src/elastix-node.ts",
"chars": 2999,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport {\n JsonCompatible,\n Image,\n InterfaceTypes,\n Pipeli"
},
{
"path": "wasm/typescript/src/elastix-options.ts",
"chars": 597,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { Image,BinaryFile,JsonCompatible, WorkerPoolFunctionOp"
},
{
"path": "wasm/typescript/src/elastix-result.ts",
"chars": 464,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { Image, BinaryFile, JsonCompatible, WorkerPoolFunction"
},
{
"path": "wasm/typescript/src/elastix.ts",
"chars": 3774,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport {\n JsonCompatible,\n Image,\n BinaryFile,\n InterfaceT"
},
{
"path": "wasm/typescript/src/index-all.ts",
"chars": 161,
"preview": "// Generated file. To retain edits, remove this comment.\n\nexport * from './index-common.js'\nexport * from './index-only."
},
{
"path": "wasm/typescript/src/index-common.ts",
"chars": 194,
"preview": "// Generated file. To retain edits, remove this comment.\n\nexport { default as version } from './version.js'\n\nexport type"
},
{
"path": "wasm/typescript/src/index-node-only.ts",
"chars": 1282,
"preview": "// Generated file. To retain edits, remove this comment.\n\n\n\nimport DefaultParameterMapNodeResult from './default-paramet"
},
{
"path": "wasm/typescript/src/index-node.ts",
"chars": 129,
"preview": "// Generated file. To retain edits, remove this comment.\n\nexport * from './index-common.js'\nexport * from './index-node-"
},
{
"path": "wasm/typescript/src/index-only.ts",
"chars": 1380,
"preview": "// Generated file. To retain edits, remove this comment.\n\nexport * from './pipelines-base-url.js'\nexport * from './pipel"
},
{
"path": "wasm/typescript/src/index-worker-embedded.min.ts",
"chars": 304,
"preview": "import { setPipelineWorkerUrl } from './index.js'\n// TypeScript might complain about implicit 'any' here\n// @ts-ignore\ni"
},
{
"path": "wasm/typescript/src/index-worker-embedded.ts",
"chars": 310,
"preview": "import { setPipelineWorkerUrl } from './index.js'\n// TypeScript might complain about implicit 'any' here\n// @ts-ignore\ni"
},
{
"path": "wasm/typescript/src/index.ts",
"chars": 124,
"preview": "// Generated file. To retain edits, remove this comment.\n\nexport * from './index-common.js'\nexport * from './index-only."
},
{
"path": "wasm/typescript/src/itkConfig.js",
"chars": 321,
"preview": "import version from 'itk-wasm'\n\nconst itkConfig = {\n // Use the worker bundled by vite or webpack\n pipelineWorkerUrl: "
},
{
"path": "wasm/typescript/src/pipeline-worker-url.ts",
"chars": 680,
"preview": "import { getPipelineWorkerUrl as itkWasmGetPipelineWorkerUrl } from 'itk-wasm'\n\nlet pipelineWorkerUrl: string | URL | nu"
},
{
"path": "wasm/typescript/src/pipelines-base-url.ts",
"chars": 728,
"preview": "import { getPipelinesBaseUrl as itkWasmGetPipelinesBaseUrl } from 'itk-wasm'\nimport packageJson from '../package.json'\n\n"
},
{
"path": "wasm/typescript/src/read-parameter-files-node-options.ts",
"chars": 268,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { TextFile } from 'itk-wasm'\n\ninterface ReadParameterFi"
},
{
"path": "wasm/typescript/src/read-parameter-files-node-result.ts",
"chars": 273,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { JsonCompatible } from 'itk-wasm'\n\ninterface ReadParam"
},
{
"path": "wasm/typescript/src/read-parameter-files-node.ts",
"chars": 1916,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport {\n JsonCompatible,\n InterfaceTypes,\n PipelineOutput,"
},
{
"path": "wasm/typescript/src/read-parameter-files-options.ts",
"chars": 319,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { TextFile, WorkerPoolFunctionOption } from 'itk-wasm'\n"
},
{
"path": "wasm/typescript/src/read-parameter-files-result.ts",
"chars": 324,
"preview": "// Generated file. To retain edits, remove this comment.\n\nimport { JsonCompatible, WorkerPoolFunctionResult } from 'itk-"
}
]
// ... and 49 more files (download for full content)
About this extraction
This page contains the full source code of the InsightSoftwareConsortium/ITKElastix GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 249 files (33.3 MB), approximately 1.4M tokens, and a symbol index with 103 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.