sitk_registration_sys/
lib.rs

1//! This crate does two things:
2//! - find an affine transform or translation that transforms one image into the other
3//! - use bspline or nearest neighbor interpolation to apply a transformation to an image
4//!
5//! To do this, [SimpleITK](https://github.com/SimpleITK/SimpleITK), which is written in
6//! C++, is used. An adapter library is created using [autocxx](https://crates.io/crates/autocxx)
7//! to expose the required functionality in SimpleITK. Because of this, compilation of this crate
8//! requires quite some time, several GB of memory, up to 50 GB of hard disk space, as well as
9//! cmake, a C++ compiler, llvm and git. Use at your own risk!
10//!
11//! # Examples
12//! ## Registration
13//! ```
14//! use ndarray::Array2;
15//! use sitk_registration_sys::registration::{AffineTransform, julia_image};
16//!
17//! let j = julia_image(0f32, 0f32).unwrap();
18//! let shape = j.shape();
19//! let origin = [
20//!     ((shape[1] - 1) as f64) / 2f64,
21//!     ((shape[0] - 1) as f64) / 2f64,
22//! ];
23//! let s = AffineTransform::new([1.2, 0., 0., 1., 5., 7.], origin, [shape[0], shape[1]]);
24//! let k: Array2<_> = s.transform_image_bspline(j.view()).unwrap().into();
25//! let t = AffineTransform::register_affine(j.view(), k.view()).unwrap().inverse().unwrap();
26//! let d = (t.matrix() - s.matrix()).powi(2).sum();
27//! assert!(d < 0.025, "d: {}, t: {:?}", d, t.parameters);
28//! ```
29//!
30//! ## Interpolation
31//! ```
32//! use ndarray::Array2;
33//! use sitk_registration_sys::registration::{AffineTransform, julia_image};
34//!
35//! let j = julia_image(-120f32, 10f32).unwrap();
36//! let k = julia_image(0f32, 0f32).unwrap();
37//! let shape = j.shape();
38//! let origin = [
39//!     ((shape[1] - 1) as f64) / 2f64,
40//!     ((shape[0] - 1) as f64) / 2f64,
41//! ];
42//! let transform = AffineTransform::new([1., 0., 0., 1., 120., -10.], origin, [shape[0], shape[1]]);
43//! let n: Array2<_> = transform.transform_image_bspline(j.view()).unwrap().into();
44//! let d = (k.mapv(|x| x as f64) - n.mapv(|x| x as f64)).powi(2).sum();
45//! assert!(d <= (shape[0] * shape[1]) as f64);
46//! ```
47
48extern crate link_cplusplus;
49pub mod registration;
50
51/// The bindings generated by [autocxx](https://google.github.io/autocxx).
52/// Everything in here is unsafe.
53pub use ffi::itk::simple;
54
55use autocxx::prelude::*;
56
57include_cpp! {
58    #include "sitkAdditionalProcedures.h"
59    #include "sitkAffineTransform.h"
60    #include "sitkElastixImageFilter.h"
61    #include "sitkInterpolator.h"
62    #include "sitkImage.h"
63    #include "sitkTransform.h"
64    safety!(unsafe)
65    generate!("itk::simple::AffineTransform")
66    generate!("itk::simple::ElastixImageFilter")
67    generate!("itk::simple::InterpolatorEnum")
68    generate!("itk::simple::Image")
69    generate!("itk::simple::Resample")
70    generate!("itk::simple::Transform")
71    opaque!("itk::simple::ElastixImageFilter")  // deleted constructor
72}
73
74/// Manually generated bindings for some things that autocxx does not understand.
75#[cxx::bridge]
76pub mod ffi_extra {
77    unsafe extern "C++" {
78        include!("ffi_extra.h");
79
80        #[namespace = "itk::simple"]
81        type ElastixImageFilter = crate::ffi::itk::simple::ElastixImageFilter;
82        type ParameterMap;
83
84        fn new_parameter_map() -> UniquePtr<ParameterMap>;
85        fn insert(self: Pin<&mut ParameterMap>, key: &CxxString, value: &CxxVector<CxxString>);
86        fn keys(self: &ParameterMap) -> UniquePtr<CxxVector<CxxString>>;
87        fn get(self: &ParameterMap, key: &CxxString) -> UniquePtr<CxxVector<CxxString>>;
88
89        fn get_transform_parameter_map(
90            tfilter: &mut ElastixImageFilter,
91            index: u32,
92        ) -> UniquePtr<ParameterMap>;
93
94        fn get_default_parameter_map(kind: &CxxString) -> UniquePtr<ParameterMap>;
95
96        fn set_parameter_map(
97            tfilter: &mut ElastixImageFilter,
98            parameter_map: &UniquePtr<ParameterMap>,
99        );
100    }
101}