- more arithmetics for Transform

This commit is contained in:
w.pomp
2026-09-15 13:41:55 +02:00
parent 1563352d42
commit ef9e257f75
4 changed files with 287 additions and 4 deletions
+4
View File
@@ -798,6 +798,8 @@ where
} }
/// eq 2.8 The L2 Polynomial Spline Pyramid, Unser et al. 1993 /// eq 2.8 The L2 Polynomial Spline Pyramid, Unser et al. 1993
/// may be used for future improvements
#[expect(dead_code)]
fn u<'a, A, B>(m: usize, z: A) -> Array<Complex<f64>, B> fn u<'a, A, B>(m: usize, z: A) -> Array<Complex<f64>, B>
where where
A: AsArray<'a, Complex<f64>, B>, A: AsArray<'a, Complex<f64>, B>,
@@ -816,6 +818,8 @@ where
} }
/// table III The L2 Polynomial Spline Pyramid, Unser et al. 1993 /// table III The L2 Polynomial Spline Pyramid, Unser et al. 1993
/// may be used for future improvements
#[expect(dead_code)]
pub(crate) fn reduction_filter(shape: &[usize]) -> Result<Array<Complex<f64>, D>, Error> { pub(crate) fn reduction_filter(shape: &[usize]) -> Result<Array<Complex<f64>, D>, Error> {
let mut filter: Array<Complex<f64>, D> = ArrayD::ones(shape).into_dimensionality()?; let mut filter: Array<Complex<f64>, D> = ArrayD::ones(shape).into_dimensionality()?;
for (i, &s) in shape.iter().enumerate() { for (i, &s) in shape.iter().enumerate() {
+3
View File
@@ -10,4 +10,7 @@ pub enum Error {
ShapeError(#[from] ndarray::ShapeError), ShapeError(#[from] ndarray::ShapeError),
#[error("number of dimensions is not defined")] #[error("number of dimensions is not defined")]
NumberOfDimensionsNotDefined, NumberOfDimensionsNotDefined,
/// the dimensionality of the data does not match
#[error("dimensionality mismatch: {0} != {0}")]
DimensionalityMismatch(usize, usize),
} }
+1 -1
View File
@@ -75,7 +75,7 @@ impl FixedMu {
/// first_bin, last_bin: center of bin /// first_bin, last_bin: center of bin
/// n_bins >= 2 /// n_bins >= 2
#[allow(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
fn parzen( fn parzen(
alpha: f64, alpha: f64,
dalpha: &[f64], dalpha: &[f64],
+279 -3
View File
@@ -3,13 +3,13 @@ use crate::error::Error;
use crate::metric::FixedMu; use crate::metric::FixedMu;
use crate::register::{Registration, RegistrationResult, RegistrationStep}; use crate::register::{Registration, RegistrationResult, RegistrationStep};
use itertools::Itertools; use itertools::Itertools;
use ndarray::{Array, Array2, ArrayD, AsArray, Dimension, Ix2, s}; use ndarray::{Array, Array2, ArrayD, ArrayView2, AsArray, Dimension, Ix2, IxDyn, s};
use num::cast::AsPrimitive; use num::cast::AsPrimitive;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_yaml::{from_reader, to_writer}; use serde_yaml::{from_reader, to_writer};
use std::fs::File; use std::fs::File;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::Mul; use std::ops::{Add, Div, Mul, Sub};
use std::path::PathBuf; use std::path::PathBuf;
/// get coordinates resulting from transforming input coordinates, coordinate must have N /// get coordinates resulting from transforming input coordinates, coordinate must have N
@@ -143,7 +143,7 @@ impl<D: Dimension> Mul<Transform<D>> for &Transform<D> {
impl<D: Dimension> Mul<&Transform<D>> for &Transform<D> { impl<D: Dimension> Mul<&Transform<D>> for &Transform<D> {
type Output = Transform<D>; type Output = Transform<D>;
#[allow(clippy::suspicious_arithmetic_impl)] #[expect(clippy::suspicious_arithmetic_impl)]
fn mul(self, rhs: &Transform<D>) -> Self::Output { fn mul(self, rhs: &Transform<D>) -> Self::Output {
let m = self.matrix().dot(&rhs.matrix()); let m = self.matrix().dot(&rhs.matrix());
let dm = self.dmatrix().dot(&rhs.matrix()) + self.matrix().dot(&rhs.dmatrix()); let dm = self.dmatrix().dot(&rhs.matrix()) + self.matrix().dot(&rhs.dmatrix());
@@ -170,6 +170,202 @@ impl<D: Dimension> Mul<&Transform<D>> for &Transform<D> {
} }
} }
impl<D: Dimension> Add for Transform<D> {
type Output = Transform<D>;
fn add(self, rhs: Self) -> Self::Output {
&self + &rhs
}
}
impl<D: Dimension> Add<&Transform<D>> for Transform<D> {
type Output = Transform<D>;
fn add(self, rhs: &Transform<D>) -> Self::Output {
&self + rhs
}
}
impl<D: Dimension> Add<Transform<D>> for &Transform<D> {
type Output = Transform<D>;
fn add(self, rhs: Transform<D>) -> Self::Output {
self + &rhs
}
}
impl<D: Dimension> Add<&Transform<D>> for &Transform<D> {
type Output = Transform<D>;
fn add(self, rhs: &Transform<D>) -> Self::Output {
let m = self.matrix() + &rhs.matrix();
let dm = (self.dmatrix().powi(2) + rhs.matrix().powi(2)).sqrt();
Self::Output {
parameters: m
.slice(s![..self.ndim, ..self.ndim])
.flatten()
.iter()
.chain(m.slice(s![..self.ndim, self.ndim]).iter())
.cloned()
.collect(),
dparameters: dm
.slice(s![..self.ndim, ..])
.flatten()
.iter()
.chain(dm.slice(s![..self.ndim, ..]).iter())
.cloned()
.collect(),
center: self.center.clone(),
shape: self.shape.clone(),
ndim: self.ndim,
dimension: self.dimension,
}
}
}
impl<D: Dimension> Sub for Transform<D> {
type Output = Transform<D>;
fn sub(self, rhs: Self) -> Self::Output {
&self - &rhs
}
}
impl<D: Dimension> Sub<&Transform<D>> for Transform<D> {
type Output = Transform<D>;
fn sub(self, rhs: &Transform<D>) -> Self::Output {
&self - rhs
}
}
impl<D: Dimension> Sub<Transform<D>> for &Transform<D> {
type Output = Transform<D>;
fn sub(self, rhs: Transform<D>) -> Self::Output {
self - &rhs
}
}
impl<D: Dimension> Sub<&Transform<D>> for &Transform<D> {
type Output = Transform<D>;
fn sub(self, rhs: &Transform<D>) -> Self::Output {
let m = self.matrix() - &rhs.matrix();
let dm = (self.dmatrix().powi(2) + rhs.matrix().powi(2)).sqrt();
Self::Output {
parameters: m
.slice(s![..self.ndim, ..self.ndim])
.flatten()
.iter()
.chain(m.slice(s![..self.ndim, self.ndim]).iter())
.cloned()
.collect(),
dparameters: dm
.slice(s![..self.ndim, ..])
.flatten()
.iter()
.chain(dm.slice(s![..self.ndim, ..]).iter())
.cloned()
.collect(),
center: self.center.clone(),
shape: self.shape.clone(),
ndim: self.ndim,
dimension: self.dimension,
}
}
}
impl<D: Dimension> Mul<Transform<D>> for f64 {
type Output = Transform<D>;
fn mul(self, rhs: Transform<D>) -> Self::Output {
rhs * self
}
}
impl<D: Dimension> Mul<&Transform<D>> for f64 {
type Output = Transform<D>;
fn mul(self, rhs: &Transform<D>) -> Self::Output {
rhs * self
}
}
impl<D: Dimension> Mul<f64> for Transform<D> {
type Output = Transform<D>;
fn mul(self, rhs: f64) -> Self::Output {
&self * rhs
}
}
impl<D: Dimension> Mul<f64> for &Transform<D> {
type Output = Transform<D>;
fn mul(self, rhs: f64) -> Self::Output {
let m = self.matrix() * rhs;
let dm = self.dmatrix() * rhs;
Self::Output {
parameters: m
.slice(s![..self.ndim, ..self.ndim])
.flatten()
.iter()
.chain(m.slice(s![..self.ndim, self.ndim]).iter())
.cloned()
.collect(),
dparameters: dm
.slice(s![..self.ndim, ..])
.flatten()
.iter()
.chain(dm.slice(s![..self.ndim, ..]).iter())
.cloned()
.collect(),
center: self.center.clone(),
shape: self.shape.clone(),
ndim: self.ndim,
dimension: self.dimension,
}
}
}
impl<D: Dimension> Div<f64> for Transform<D> {
type Output = Transform<D>;
fn div(self, rhs: f64) -> Self::Output {
&self / rhs
}
}
impl<D: Dimension> Div<f64> for &Transform<D> {
type Output = Transform<D>;
fn div(self, rhs: f64) -> Self::Output {
let m = self.matrix() / rhs;
let dm = self.dmatrix() / rhs;
Self::Output {
parameters: m
.slice(s![..self.ndim, ..self.ndim])
.flatten()
.iter()
.chain(m.slice(s![..self.ndim, self.ndim]).iter())
.cloned()
.collect(),
dparameters: dm
.slice(s![..self.ndim, ..])
.flatten()
.iter()
.chain(dm.slice(s![..self.ndim, ..]).iter())
.cloned()
.collect(),
center: self.center.clone(),
shape: self.shape.clone(),
ndim: self.ndim,
dimension: self.dimension,
}
}
}
impl<D: Dimension> Eq for Transform<D> {} impl<D: Dimension> Eq for Transform<D> {}
impl<D: Dimension> Default for Transform<D> { impl<D: Dimension> Default for Transform<D> {
@@ -481,6 +677,44 @@ impl<D: Dimension> Transform<D> {
matrix matrix
} }
pub fn with_matrix(mut self, matrix: ArrayView2<f64>) -> Self {
let mut parameters = matrix
.slice(s![..self.ndim, ..self.ndim])
.flatten()
.to_vec();
parameters.extend(matrix.slice(s![..self.ndim, self.ndim]).to_vec());
self.parameters = parameters;
self
}
pub fn set_matrix(&mut self, matrix: ArrayView2<f64>) {
let mut parameters = matrix
.slice(s![..self.ndim, ..self.ndim])
.flatten()
.to_vec();
parameters.extend(matrix.slice(s![..self.ndim, self.ndim]).to_vec());
self.parameters = parameters;
}
pub fn with_dmatrix(mut self, dmatrix: ArrayView2<f64>) -> Self {
let mut dparameters = dmatrix
.slice(s![..self.ndim, ..self.ndim])
.flatten()
.to_vec();
dparameters.extend(dmatrix.slice(s![..self.ndim, self.ndim]).to_vec());
self.dparameters = dparameters;
self
}
pub fn set_dmatrix(&mut self, dmatrix: ArrayView2<f64>) {
let mut dparameters = dmatrix
.slice(s![..self.ndim, ..self.ndim])
.flatten()
.to_vec();
dparameters.extend(dmatrix.slice(s![..self.ndim, self.ndim]).to_vec());
self.dparameters = dparameters;
}
/// get the inverse transform /// get the inverse transform
pub fn inverse(&self) -> Result<Self, Error> { pub fn inverse(&self) -> Result<Self, Error> {
let matrix = self.matrix(); let matrix = self.matrix();
@@ -540,6 +774,48 @@ impl<D: Dimension> Transform<D> {
let bspline = BSpline::<B, _>::new(&image); let bspline = BSpline::<B, _>::new(&image);
bspline.interpolate_par(self) bspline.interpolate_par(self)
} }
/// the number of dimensions in the view
pub fn ndim(&self) -> usize {
if let Some(d) = D::NDIM { d } else { self.ndim }
}
pub fn into_dimensionality<D2: Dimension>(self) -> Result<Transform<D2>, Error> {
if let Some(d) = D2::NDIM {
if d == self.ndim() {
Ok(Transform {
parameters: self.parameters,
dparameters: self.dparameters,
center: self.center,
shape: self.shape,
ndim: self.ndim,
dimension: Default::default(),
})
} else {
Err(Error::DimensionalityMismatch(d, self.ndim()))
}
} else {
Ok(Transform {
parameters: self.parameters,
dparameters: self.dparameters,
center: self.center,
shape: self.shape,
ndim: self.ndim,
dimension: Default::default(),
})
}
}
pub fn into_dyn(self) -> Transform<IxDyn> {
Transform {
parameters: self.parameters,
dparameters: self.dparameters,
center: self.center,
shape: self.shape,
ndim: self.ndim,
dimension: Default::default(),
}
}
} }
impl Transform<Ix2> { impl Transform<Ix2> {