- remove ndim field
- add hashing
This commit is contained in:
1 parent
7eb39a2fbf
commit
5c580dc80f
3 files changed
+242
-81
No files matched your search
@@ -336,7 +336,7 @@ fn main() -> Result<(), Error> {
|
|||||||
|
|
||||||
| Module | Contents |
|
| Module | Contents |
|
||||||
|----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|----------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `image_registration::transform` | `Transform`, the affine transform type: construction (`new`, `new_with_center`, `from_translation`, `from_scaling`, `from_rotation`), algebra (`inverse`, `with_translation`, `with_scaling`, `with_rotation`, `with_rotation_around`, `Mul`), coordinate transforms (`transform_point`, `transform_points`, `matrix`, `dmatrix`), resampling (`interpolate`, `interpolate_par`), registration (`register`, `register_debug`, `register_affine`, `register_translation`), serialization (`to_file`, `from_file`), plus the free function `transform_point` and a blas-free `matrix_inverse`. |
|
| `image_registration::transform` | `Transform`, the affine transform type: construction (`new`, `new_with_center`, `from_translation`, `from_scaling`, `from_rotation`), algebra (`inverse`, `add_translation`, `add_scaling`, `with_rotation`, `with_rotation_around`, `Mul`), coordinate transforms (`transform_point`, `transform_points`, `matrix`, `dmatrix`), resampling (`interpolate`, `interpolate_par`), registration (`register`, `register_debug`, `register_affine`, `register_translation`), serialization (`to_file`, `from_file`), plus the free function `transform_point` and a blas-free `matrix_inverse`. |
|
||||||
| `image_registration::register` | `Registration`, `RegistrationStep`, `RegistrationResult`, `Optimizer` (LBFGS/ASGD). |
|
| `image_registration::register` | `Registration`, `RegistrationStep`, `RegistrationResult`, `Optimizer` (LBFGS/ASGD). |
|
||||||
| `image_registration::metric` | `MattesMetric` (Mattes mutual information with analytic gradient), `SamplingArg` (Fixed/FixedAt/Random), `Sigma` (None/Absolute/Relative), `FixedMu`. |
|
| `image_registration::metric` | `MattesMetric` (Mattes mutual information with analytic gradient), `SamplingArg` (Fixed/FixedAt/Random), `Sigma` (None/Absolute/Relative), `FixedMu`. |
|
||||||
| `image_registration::bspline` | `BSpline<N, D>` B-spline interpolation of arbitrary order, `BSplineTrait`, `BSplineMem`, Parzen kernel helpers. |
|
| `image_registration::bspline` | `BSpline<N, D>` B-spline interpolation of arbitrary order, `BSplineTrait`, `BSplineMem`, Parzen kernel helpers. |
|
||||||
|
|||||||
@@ -17,4 +17,6 @@ pub enum Error {
|
|||||||
FixedMuLength(usize, usize),
|
FixedMuLength(usize, usize),
|
||||||
#[error("expected initial guess length of {0}, got {1}")]
|
#[error("expected initial guess length of {0}, got {1}")]
|
||||||
InitialGuessLength(usize, usize),
|
InitialGuessLength(usize, usize),
|
||||||
|
#[error("interpolation order {0} is not implemented")]
|
||||||
|
InterpolationNotImplemented(usize),
|
||||||
}
|
}
|
||||||
+239
-80
@@ -8,6 +8,7 @@ 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::hash::{Hash, Hasher};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::{Add, Div, Mul, Sub};
|
use std::ops::{Add, Div, Mul, Sub};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -110,13 +111,11 @@ struct TransformS {
|
|||||||
|
|
||||||
impl<D: Dimension> From<TransformS> for Transform<D> {
|
impl<D: Dimension> From<TransformS> for Transform<D> {
|
||||||
fn from(t: TransformS) -> Self {
|
fn from(t: TransformS) -> Self {
|
||||||
let ndim = t.shape.len();
|
|
||||||
Self {
|
Self {
|
||||||
parameters: t.parameters,
|
parameters: t.parameters,
|
||||||
dparameters: t.dparameters,
|
dparameters: t.dparameters,
|
||||||
center: t.center,
|
center: t.center,
|
||||||
shape: t.shape,
|
shape: t.shape,
|
||||||
ndim,
|
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,8 +135,6 @@ pub struct Transform<D: Dimension = Ix2> {
|
|||||||
/// the shape of images for which this transform is meant
|
/// the shape of images for which this transform is meant
|
||||||
pub shape: Vec<usize>,
|
pub shape: Vec<usize>,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
ndim: usize,
|
|
||||||
#[serde(skip)]
|
|
||||||
dimension: PhantomData<D>,
|
dimension: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,22 +171,21 @@ impl<D: Dimension> Mul<&Transform<D>> for &Transform<D> {
|
|||||||
let dm = self.dmatrix().dot(&rhs.matrix()) + self.matrix().dot(&rhs.dmatrix());
|
let dm = self.dmatrix().dot(&rhs.matrix()) + self.matrix().dot(&rhs.dmatrix());
|
||||||
Self::Output {
|
Self::Output {
|
||||||
parameters: m
|
parameters: m
|
||||||
.slice(s![..self.ndim, ..self.ndim])
|
.slice(s![..self.ndim(), ..self.ndim()])
|
||||||
.flatten()
|
.flatten()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(m.slice(s![..self.ndim, self.ndim]).iter())
|
.chain(m.slice(s![..self.ndim(), self.ndim()]).iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
dparameters: dm
|
dparameters: dm
|
||||||
.slice(s![..self.ndim, ..])
|
.slice(s![..self.ndim(), ..])
|
||||||
.flatten()
|
.flatten()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(dm.slice(s![..self.ndim, ..]).iter())
|
.chain(dm.slice(s![..self.ndim(), ..]).iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
center: self.center.clone(),
|
center: self.center.clone(),
|
||||||
shape: self.shape.clone(),
|
shape: self.shape.clone(),
|
||||||
ndim: self.ndim,
|
|
||||||
dimension: self.dimension,
|
dimension: self.dimension,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,22 +223,21 @@ impl<D: Dimension> Add<&Transform<D>> for &Transform<D> {
|
|||||||
let dm = (self.dmatrix().powi(2) + rhs.matrix().powi(2)).sqrt();
|
let dm = (self.dmatrix().powi(2) + rhs.matrix().powi(2)).sqrt();
|
||||||
Self::Output {
|
Self::Output {
|
||||||
parameters: m
|
parameters: m
|
||||||
.slice(s![..self.ndim, ..self.ndim])
|
.slice(s![..self.ndim(), ..self.ndim()])
|
||||||
.flatten()
|
.flatten()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(m.slice(s![..self.ndim, self.ndim]).iter())
|
.chain(m.slice(s![..self.ndim(), self.ndim()]).iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
dparameters: dm
|
dparameters: dm
|
||||||
.slice(s![..self.ndim, ..])
|
.slice(s![..self.ndim(), ..])
|
||||||
.flatten()
|
.flatten()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(dm.slice(s![..self.ndim, ..]).iter())
|
.chain(dm.slice(s![..self.ndim(), ..]).iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
center: self.center.clone(),
|
center: self.center.clone(),
|
||||||
shape: self.shape.clone(),
|
shape: self.shape.clone(),
|
||||||
ndim: self.ndim,
|
|
||||||
dimension: self.dimension,
|
dimension: self.dimension,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -280,22 +275,21 @@ impl<D: Dimension> Sub<&Transform<D>> for &Transform<D> {
|
|||||||
let dm = (self.dmatrix().powi(2) + rhs.matrix().powi(2)).sqrt();
|
let dm = (self.dmatrix().powi(2) + rhs.matrix().powi(2)).sqrt();
|
||||||
Self::Output {
|
Self::Output {
|
||||||
parameters: m
|
parameters: m
|
||||||
.slice(s![..self.ndim, ..self.ndim])
|
.slice(s![..self.ndim(), ..self.ndim()])
|
||||||
.flatten()
|
.flatten()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(m.slice(s![..self.ndim, self.ndim]).iter())
|
.chain(m.slice(s![..self.ndim(), self.ndim()]).iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
dparameters: dm
|
dparameters: dm
|
||||||
.slice(s![..self.ndim, ..])
|
.slice(s![..self.ndim(), ..])
|
||||||
.flatten()
|
.flatten()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(dm.slice(s![..self.ndim, ..]).iter())
|
.chain(dm.slice(s![..self.ndim(), ..]).iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
center: self.center.clone(),
|
center: self.center.clone(),
|
||||||
shape: self.shape.clone(),
|
shape: self.shape.clone(),
|
||||||
ndim: self.ndim,
|
|
||||||
dimension: self.dimension,
|
dimension: self.dimension,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,22 +327,21 @@ impl<D: Dimension> Mul<f64> for &Transform<D> {
|
|||||||
let dm = self.dmatrix() * rhs;
|
let dm = self.dmatrix() * rhs;
|
||||||
Self::Output {
|
Self::Output {
|
||||||
parameters: m
|
parameters: m
|
||||||
.slice(s![..self.ndim, ..self.ndim])
|
.slice(s![..self.ndim(), ..self.ndim()])
|
||||||
.flatten()
|
.flatten()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(m.slice(s![..self.ndim, self.ndim]).iter())
|
.chain(m.slice(s![..self.ndim(), self.ndim()]).iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
dparameters: dm
|
dparameters: dm
|
||||||
.slice(s![..self.ndim, ..])
|
.slice(s![..self.ndim(), ..])
|
||||||
.flatten()
|
.flatten()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(dm.slice(s![..self.ndim, ..]).iter())
|
.chain(dm.slice(s![..self.ndim(), ..]).iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
center: self.center.clone(),
|
center: self.center.clone(),
|
||||||
shape: self.shape.clone(),
|
shape: self.shape.clone(),
|
||||||
ndim: self.ndim,
|
|
||||||
dimension: self.dimension,
|
dimension: self.dimension,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -370,22 +363,21 @@ impl<D: Dimension> Div<f64> for &Transform<D> {
|
|||||||
let dm = self.dmatrix() / rhs;
|
let dm = self.dmatrix() / rhs;
|
||||||
Self::Output {
|
Self::Output {
|
||||||
parameters: m
|
parameters: m
|
||||||
.slice(s![..self.ndim, ..self.ndim])
|
.slice(s![..self.ndim(), ..self.ndim()])
|
||||||
.flatten()
|
.flatten()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(m.slice(s![..self.ndim, self.ndim]).iter())
|
.chain(m.slice(s![..self.ndim(), self.ndim()]).iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
dparameters: dm
|
dparameters: dm
|
||||||
.slice(s![..self.ndim, ..])
|
.slice(s![..self.ndim(), ..])
|
||||||
.flatten()
|
.flatten()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(dm.slice(s![..self.ndim, ..]).iter())
|
.chain(dm.slice(s![..self.ndim(), ..]).iter())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
center: self.center.clone(),
|
center: self.center.clone(),
|
||||||
shape: self.shape.clone(),
|
shape: self.shape.clone(),
|
||||||
ndim: self.ndim,
|
|
||||||
dimension: self.dimension,
|
dimension: self.dimension,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -393,6 +385,19 @@ impl<D: Dimension> Div<f64> for &Transform<D> {
|
|||||||
|
|
||||||
impl<D: Dimension> Eq for Transform<D> {}
|
impl<D: Dimension> Eq for Transform<D> {}
|
||||||
|
|
||||||
|
impl<D: Dimension> Hash for Transform<D> {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
for values in [&self.parameters, &self.dparameters, &self.center] {
|
||||||
|
values.len().hash(state);
|
||||||
|
for v in values {
|
||||||
|
let v = if *v == 0.0 { 0.0 } else { *v };
|
||||||
|
v.to_bits().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.shape.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<D: Dimension> Default for Transform<D> {
|
impl<D: Dimension> Default for Transform<D> {
|
||||||
/// the unit transform
|
/// the unit transform
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@@ -407,7 +412,6 @@ impl<D: Dimension> Default for Transform<D> {
|
|||||||
dparameters: vec![0f64; ndim * ndim + ndim],
|
dparameters: vec![0f64; ndim * ndim + ndim],
|
||||||
center: vec![0f64; ndim],
|
center: vec![0f64; ndim],
|
||||||
shape: vec![0usize; ndim],
|
shape: vec![0usize; ndim],
|
||||||
ndim,
|
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -429,7 +433,6 @@ impl<D: Dimension> Transform<D> {
|
|||||||
dparameters: vec![0.0; ndim * ndim + ndim],
|
dparameters: vec![0.0; ndim * ndim + ndim],
|
||||||
center,
|
center,
|
||||||
shape,
|
shape,
|
||||||
ndim,
|
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,7 +451,6 @@ impl<D: Dimension> Transform<D> {
|
|||||||
dparameters: vec![0.0; ndim * ndim + ndim],
|
dparameters: vec![0.0; ndim * ndim + ndim],
|
||||||
center,
|
center,
|
||||||
shape,
|
shape,
|
||||||
ndim,
|
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -548,7 +550,6 @@ impl<D: Dimension> Transform<D> {
|
|||||||
dparameters: vec![0f64; ndim * ndim + ndim],
|
dparameters: vec![0f64; ndim * ndim + ndim],
|
||||||
center: vec![0f64; ndim],
|
center: vec![0f64; ndim],
|
||||||
shape: vec![0usize; ndim],
|
shape: vec![0usize; ndim],
|
||||||
ndim,
|
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -581,19 +582,79 @@ impl<D: Dimension> Transform<D> {
|
|||||||
dparameters: vec![0f64; ndim * ndim + ndim],
|
dparameters: vec![0f64; ndim * ndim + ndim],
|
||||||
center: vec![0f64; ndim],
|
center: vec![0f64; ndim],
|
||||||
shape: vec![0usize; ndim],
|
shape: vec![0usize; ndim],
|
||||||
ndim,
|
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// replace the transform by a scaling
|
||||||
|
pub fn as_scaling(&self, scaling: &[f64]) -> Self {
|
||||||
|
let ndim = if let Some(ndim) = D::NDIM {
|
||||||
|
ndim
|
||||||
|
} else {
|
||||||
|
scaling.len()
|
||||||
|
};
|
||||||
|
debug_assert_eq!(scaling.len(), ndim);
|
||||||
|
let mut parameters = vec![0.0; ndim * ndim + ndim];
|
||||||
|
parameters[ndim * ndim + ndim - 1] = 1.0;
|
||||||
|
for (p, s) in parameters
|
||||||
|
.iter_mut()
|
||||||
|
.step_by(ndim + 1)
|
||||||
|
.zip_eq(scaling.iter())
|
||||||
|
{
|
||||||
|
*p = *s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
parameters,
|
||||||
|
dparameters: vec![0f64; ndim * ndim + ndim],
|
||||||
|
center: self.center.clone(),
|
||||||
|
shape: self.shape.clone(),
|
||||||
|
dimension: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// scale self
|
||||||
|
pub fn add_scaling(&self, scaling: &[f64]) -> Self {
|
||||||
|
Self::from_scaling(scaling) * self
|
||||||
|
}
|
||||||
|
|
||||||
/// add a translation to self
|
/// add a translation to self
|
||||||
pub fn with_translation(&self, translation: &[f64]) -> Self {
|
pub fn with_translation(&self, translation: &[f64]) -> Self {
|
||||||
Self::from_translation(translation) * self
|
Self::from_translation(translation) * self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// scale self
|
/// replace the transform by a translation
|
||||||
pub fn with_scaling(&self, scaling: &[f64]) -> Self {
|
pub fn as_translation(&self, translation: &[f64]) -> Self {
|
||||||
Self::from_scaling(scaling) * self
|
let ndim = if let Some(ndim) = D::NDIM {
|
||||||
|
ndim
|
||||||
|
} else {
|
||||||
|
translation.len()
|
||||||
|
};
|
||||||
|
debug_assert_eq!(translation.len(), ndim);
|
||||||
|
let mut parameters = vec![0.0; ndim * ndim + ndim];
|
||||||
|
for i in 0..ndim {
|
||||||
|
parameters[(ndim + 1) * i] = 1.0;
|
||||||
|
}
|
||||||
|
for (p, t) in parameters
|
||||||
|
.iter_mut()
|
||||||
|
.skip(ndim * ndim)
|
||||||
|
.zip_eq(translation.iter())
|
||||||
|
{
|
||||||
|
*p = *t;
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
parameters,
|
||||||
|
dparameters: vec![0f64; ndim * ndim + ndim],
|
||||||
|
center: self.center.clone(),
|
||||||
|
shape: self.shape.clone(),
|
||||||
|
dimension: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// add a translation to self
|
||||||
|
pub fn add_translation(&self, translation: &[f64]) -> Self {
|
||||||
|
Self::from_translation(translation) * self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_center(mut self, center: Vec<f64>) -> Self {
|
pub fn with_center(mut self, center: Vec<f64>) -> Self {
|
||||||
@@ -620,8 +681,8 @@ impl<D: Dimension> Transform<D> {
|
|||||||
|
|
||||||
/// true if transform does nothing
|
/// true if transform does nothing
|
||||||
pub fn is_unity(&self) -> bool {
|
pub fn is_unity(&self) -> bool {
|
||||||
let n = self.ndim * self.ndim;
|
let n = self.ndim() * self.ndim();
|
||||||
let m = self.ndim + 1;
|
let m = self.ndim() + 1;
|
||||||
self.parameters
|
self.parameters
|
||||||
.iter()
|
.iter()
|
||||||
.take(n)
|
.take(n)
|
||||||
@@ -667,17 +728,17 @@ impl<D: Dimension> Transform<D> {
|
|||||||
|
|
||||||
/// get the matrix defining the transform
|
/// get the matrix defining the transform
|
||||||
pub fn matrix(&self) -> Array2<f64> {
|
pub fn matrix(&self) -> Array2<f64> {
|
||||||
let n = self.ndim * self.ndim;
|
let n = self.ndim() * self.ndim();
|
||||||
let mut matrix = Array2::eye(self.ndim + 1);
|
let mut matrix = Array2::eye(self.ndim() + 1);
|
||||||
for (m, p) in matrix
|
for (m, p) in matrix
|
||||||
.slice_mut(s![..self.ndim, ..self.ndim])
|
.slice_mut(s![..self.ndim(), ..self.ndim()])
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip_eq(self.parameters.iter().take(n))
|
.zip_eq(self.parameters.iter().take(n))
|
||||||
{
|
{
|
||||||
*m = *p;
|
*m = *p;
|
||||||
}
|
}
|
||||||
for (m, p) in matrix
|
for (m, p) in matrix
|
||||||
.slice_mut(s![..self.ndim, self.ndim])
|
.slice_mut(s![..self.ndim(), self.ndim()])
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip_eq(self.parameters.iter().skip(n))
|
.zip_eq(self.parameters.iter().skip(n))
|
||||||
{
|
{
|
||||||
@@ -688,17 +749,17 @@ impl<D: Dimension> Transform<D> {
|
|||||||
|
|
||||||
/// get the matrix describing the error of the transform
|
/// get the matrix describing the error of the transform
|
||||||
pub fn dmatrix(&self) -> Array2<f64> {
|
pub fn dmatrix(&self) -> Array2<f64> {
|
||||||
let n = self.ndim * self.ndim;
|
let n = self.ndim() * self.ndim();
|
||||||
let mut matrix = Array2::zeros([self.ndim + 1, self.ndim + 1]);
|
let mut matrix = Array2::zeros([self.ndim() + 1, self.ndim() + 1]);
|
||||||
for (m, p) in matrix
|
for (m, p) in matrix
|
||||||
.slice_mut(s![..self.ndim, ..self.ndim])
|
.slice_mut(s![..self.ndim(), ..self.ndim()])
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip_eq(self.dparameters.iter().take(n))
|
.zip_eq(self.dparameters.iter().take(n))
|
||||||
{
|
{
|
||||||
*m = *p;
|
*m = *p;
|
||||||
}
|
}
|
||||||
for (m, p) in matrix
|
for (m, p) in matrix
|
||||||
.slice_mut(s![..self.ndim, self.ndim])
|
.slice_mut(s![..self.ndim(), self.ndim()])
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip_eq(self.dparameters.iter().skip(n))
|
.zip_eq(self.dparameters.iter().skip(n))
|
||||||
{
|
{
|
||||||
@@ -719,39 +780,39 @@ impl<D: Dimension> Transform<D> {
|
|||||||
|
|
||||||
pub fn with_matrix(mut self, matrix: ArrayView2<f64>) -> Self {
|
pub fn with_matrix(mut self, matrix: ArrayView2<f64>) -> Self {
|
||||||
let mut parameters = matrix
|
let mut parameters = matrix
|
||||||
.slice(s![..self.ndim, ..self.ndim])
|
.slice(s![..self.ndim(), ..self.ndim()])
|
||||||
.flatten()
|
.flatten()
|
||||||
.to_vec();
|
.to_vec();
|
||||||
parameters.extend(matrix.slice(s![..self.ndim, self.ndim]).to_vec());
|
parameters.extend(matrix.slice(s![..self.ndim(), self.ndim()]).to_vec());
|
||||||
self.parameters = parameters;
|
self.parameters = parameters;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_matrix(&mut self, matrix: ArrayView2<f64>) {
|
pub fn set_matrix(&mut self, matrix: ArrayView2<f64>) {
|
||||||
let mut parameters = matrix
|
let mut parameters = matrix
|
||||||
.slice(s![..self.ndim, ..self.ndim])
|
.slice(s![..self.ndim(), ..self.ndim()])
|
||||||
.flatten()
|
.flatten()
|
||||||
.to_vec();
|
.to_vec();
|
||||||
parameters.extend(matrix.slice(s![..self.ndim, self.ndim]).to_vec());
|
parameters.extend(matrix.slice(s![..self.ndim(), self.ndim()]).to_vec());
|
||||||
self.parameters = parameters;
|
self.parameters = parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_dmatrix(mut self, dmatrix: ArrayView2<f64>) -> Self {
|
pub fn with_dmatrix(mut self, dmatrix: ArrayView2<f64>) -> Self {
|
||||||
let mut dparameters = dmatrix
|
let mut dparameters = dmatrix
|
||||||
.slice(s![..self.ndim, ..self.ndim])
|
.slice(s![..self.ndim(), ..self.ndim()])
|
||||||
.flatten()
|
.flatten()
|
||||||
.to_vec();
|
.to_vec();
|
||||||
dparameters.extend(dmatrix.slice(s![..self.ndim, self.ndim]).to_vec());
|
dparameters.extend(dmatrix.slice(s![..self.ndim(), self.ndim()]).to_vec());
|
||||||
self.dparameters = dparameters;
|
self.dparameters = dparameters;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_dmatrix(&mut self, dmatrix: ArrayView2<f64>) {
|
pub fn set_dmatrix(&mut self, dmatrix: ArrayView2<f64>) {
|
||||||
let mut dparameters = dmatrix
|
let mut dparameters = dmatrix
|
||||||
.slice(s![..self.ndim, ..self.ndim])
|
.slice(s![..self.ndim(), ..self.ndim()])
|
||||||
.flatten()
|
.flatten()
|
||||||
.to_vec();
|
.to_vec();
|
||||||
dparameters.extend(dmatrix.slice(s![..self.ndim, self.ndim]).to_vec());
|
dparameters.extend(dmatrix.slice(s![..self.ndim(), self.ndim()]).to_vec());
|
||||||
self.dparameters = dparameters;
|
self.dparameters = dparameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -760,18 +821,17 @@ impl<D: Dimension> Transform<D> {
|
|||||||
let matrix = self.matrix();
|
let matrix = self.matrix();
|
||||||
let inverse = matrix_inverse(matrix);
|
let inverse = matrix_inverse(matrix);
|
||||||
let parameters = inverse
|
let parameters = inverse
|
||||||
.slice(s![..self.ndim, ..self.ndim])
|
.slice(s![..self.ndim(), ..self.ndim()])
|
||||||
.iter()
|
.iter()
|
||||||
.chain(inverse.slice(s![..self.ndim, self.ndim]))
|
.chain(inverse.slice(s![..self.ndim(), self.ndim()]))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
parameters,
|
parameters,
|
||||||
dparameters: vec![0f64; self.ndim * self.ndim + self.ndim],
|
dparameters: vec![0f64; self.ndim() * self.ndim() + self.ndim()],
|
||||||
center: self.center.clone(),
|
center: self.center.clone(),
|
||||||
shape: self.shape.clone(),
|
shape: self.shape.clone(),
|
||||||
ndim: self.ndim,
|
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -815,9 +875,55 @@ impl<D: Dimension> Transform<D> {
|
|||||||
bspline.interpolate_par(self)
|
bspline.interpolate_par(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn interpolate_order<'a, T, A>(
|
||||||
|
&self,
|
||||||
|
image: A,
|
||||||
|
order: usize,
|
||||||
|
) -> Result<Array<f64, D>, Error>
|
||||||
|
where
|
||||||
|
A: AsArray<'a, T, D>,
|
||||||
|
D: Dimension,
|
||||||
|
T: 'a + Clone + AsPrimitive<f64>,
|
||||||
|
{
|
||||||
|
match order {
|
||||||
|
0 => Ok(self.interpolate::<0, _, _>(image)?),
|
||||||
|
1 => Ok(self.interpolate::<1, _, _>(image)?),
|
||||||
|
2 => Ok(self.interpolate::<2, _, _>(image)?),
|
||||||
|
3 => Ok(self.interpolate::<3, _, _>(image)?),
|
||||||
|
4 => Ok(self.interpolate::<4, _, _>(image)?),
|
||||||
|
5 => Ok(self.interpolate::<5, _, _>(image)?),
|
||||||
|
_ => Err(Error::InterpolationNotImplemented(order)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interpolate_par_order<'a, T, A>(
|
||||||
|
&self,
|
||||||
|
image: A,
|
||||||
|
order: usize,
|
||||||
|
) -> Result<Array<f64, D>, Error>
|
||||||
|
where
|
||||||
|
A: AsArray<'a, T, D>,
|
||||||
|
D: Dimension,
|
||||||
|
T: 'a + Clone + AsPrimitive<f64>,
|
||||||
|
{
|
||||||
|
match order {
|
||||||
|
0 => Ok(self.interpolate_par::<0, _, _>(image)?),
|
||||||
|
1 => Ok(self.interpolate_par::<1, _, _>(image)?),
|
||||||
|
2 => Ok(self.interpolate_par::<2, _, _>(image)?),
|
||||||
|
3 => Ok(self.interpolate_par::<3, _, _>(image)?),
|
||||||
|
4 => Ok(self.interpolate_par::<4, _, _>(image)?),
|
||||||
|
5 => Ok(self.interpolate_par::<5, _, _>(image)?),
|
||||||
|
_ => Err(Error::InterpolationNotImplemented(order)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// the number of dimensions in the view
|
/// the number of dimensions in the view
|
||||||
pub fn ndim(&self) -> usize {
|
pub fn ndim(&self) -> usize {
|
||||||
if let Some(d) = D::NDIM { d } else { self.ndim }
|
if let Some(d) = D::NDIM {
|
||||||
|
d
|
||||||
|
} else {
|
||||||
|
self.center.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_dimensionality<D2: Dimension>(self) -> Result<Transform<D2>, Error> {
|
pub fn into_dimensionality<D2: Dimension>(self) -> Result<Transform<D2>, Error> {
|
||||||
@@ -828,7 +934,6 @@ impl<D: Dimension> Transform<D> {
|
|||||||
dparameters: self.dparameters,
|
dparameters: self.dparameters,
|
||||||
center: self.center,
|
center: self.center,
|
||||||
shape: self.shape,
|
shape: self.shape,
|
||||||
ndim: self.ndim,
|
|
||||||
dimension: Default::default(),
|
dimension: Default::default(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -840,7 +945,6 @@ impl<D: Dimension> Transform<D> {
|
|||||||
dparameters: self.dparameters,
|
dparameters: self.dparameters,
|
||||||
center: self.center,
|
center: self.center,
|
||||||
shape: self.shape,
|
shape: self.shape,
|
||||||
ndim: self.ndim,
|
|
||||||
dimension: Default::default(),
|
dimension: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -852,7 +956,44 @@ impl<D: Dimension> Transform<D> {
|
|||||||
dparameters: self.dparameters,
|
dparameters: self.dparameters,
|
||||||
center: self.center,
|
center: self.center,
|
||||||
shape: self.shape,
|
shape: self.shape,
|
||||||
ndim: self.ndim,
|
dimension: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parameters_unit(ndim: usize) -> Vec<f64> {
|
||||||
|
let mut p = vec![0.0; ndim * (ndim + 1)];
|
||||||
|
for i in 0..ndim {
|
||||||
|
p[i * (ndim + 1)] = 1.0;
|
||||||
|
}
|
||||||
|
p
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_dimension(&self, axis: usize, size: usize) -> Transform<D::Larger> {
|
||||||
|
let ndim = self.ndim() + 1;
|
||||||
|
let mut parameters = Self::parameters_unit(ndim);
|
||||||
|
let mut dparameters = Self::parameters_unit(ndim);
|
||||||
|
let mut j = 0;
|
||||||
|
for p in &self.parameters {
|
||||||
|
if j == axis * ndim {
|
||||||
|
j += ndim;
|
||||||
|
}
|
||||||
|
if j % ndim == axis {
|
||||||
|
j += 1;
|
||||||
|
}
|
||||||
|
parameters[j] = *p;
|
||||||
|
dparameters[j] = *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut center = self.center.clone();
|
||||||
|
center.insert(axis, ((size as f64) - 1.0) / 2.0);
|
||||||
|
let mut shape = self.shape.clone();
|
||||||
|
shape.insert(axis, size);
|
||||||
|
|
||||||
|
Transform {
|
||||||
|
parameters,
|
||||||
|
dparameters,
|
||||||
|
center,
|
||||||
|
shape,
|
||||||
dimension: Default::default(),
|
dimension: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -873,7 +1014,6 @@ impl Transform<Ix2> {
|
|||||||
dparameters: vec![0f64; 6],
|
dparameters: vec![0f64; 6],
|
||||||
center: center.to_vec(),
|
center: center.to_vec(),
|
||||||
shape: vec![0usize; 2],
|
shape: vec![0usize; 2],
|
||||||
ndim: 2,
|
|
||||||
dimension: PhantomData,
|
dimension: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -893,13 +1033,13 @@ impl Transform<Ix2> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::matrix_inverse;
|
use super::matrix_inverse;
|
||||||
use crate::julia_image;
|
use crate::julia_image;
|
||||||
|
use crate::transform::File;
|
||||||
use crate::transform::Transform;
|
use crate::transform::Transform;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use ndarray::{Array2, Ix2, array, s};
|
use ndarray::{Array2, Ix2, array, s};
|
||||||
use num::traits::FloatConst;
|
use num::traits::FloatConst;
|
||||||
use std::fs::File;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use tiff::decoder::{Decoder, DecodingResult};
|
use tiff::decoder::{Decoder, DecodingSampleBuffer};
|
||||||
use tiff::tags::Tag;
|
use tiff::tags::Tag;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1521,23 +1661,42 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_tiff<P: AsRef<Path>>(path: P) -> Result<Array2<f64>, Box<dyn std::error::Error>> {
|
fn read_tiff<P: AsRef<Path>>(path: P) -> Result<Array2<f64>, Box<dyn std::error::Error>> {
|
||||||
let mut reader = Decoder::new(File::open(path)?)?;
|
let mut reader = Decoder::open(File::open(path)?)?;
|
||||||
reader.seek_to_image(0)?;
|
reader.seek_to_image(0)?;
|
||||||
let bytes = match reader.read_image()? {
|
let bytes = match reader.read_image()? {
|
||||||
DecodingResult::U8(data) => data.into_iter().map(|i| i as f64).collect::<Vec<_>>(),
|
DecodingSampleBuffer::U8(data) => {
|
||||||
DecodingResult::U16(data) => data.into_iter().map(|i| i as f64).collect::<Vec<_>>(),
|
data.into_iter().map(|i| i as f64).collect::<Vec<_>>()
|
||||||
DecodingResult::U32(data) => data.into_iter().map(|i| i as f64).collect::<Vec<_>>(),
|
}
|
||||||
DecodingResult::U64(data) => data.into_iter().map(|i| i as f64).collect::<Vec<_>>(),
|
DecodingSampleBuffer::U16(data) => {
|
||||||
DecodingResult::I8(data) => data.into_iter().map(|i| i as f64).collect::<Vec<_>>(),
|
data.into_iter().map(|i| i as f64).collect::<Vec<_>>()
|
||||||
DecodingResult::I16(data) => data.into_iter().map(|i| i as f64).collect::<Vec<_>>(),
|
}
|
||||||
DecodingResult::I32(data) => data.into_iter().map(|i| i as f64).collect::<Vec<_>>(),
|
DecodingSampleBuffer::U32(data) => {
|
||||||
DecodingResult::I64(data) => data.into_iter().map(|i| i as f64).collect::<Vec<_>>(),
|
data.into_iter().map(|i| i as f64).collect::<Vec<_>>()
|
||||||
DecodingResult::F16(data) => data.into_iter().map(f64::from).collect::<Vec<_>>(),
|
}
|
||||||
DecodingResult::F32(data) => data.into_iter().map(|i| i as f64).collect::<Vec<_>>(),
|
DecodingSampleBuffer::U64(data) => {
|
||||||
DecodingResult::F64(data) => data,
|
data.into_iter().map(|i| i as f64).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
DecodingSampleBuffer::I8(data) => {
|
||||||
|
data.into_iter().map(|i| i as f64).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
DecodingSampleBuffer::I16(data) => {
|
||||||
|
data.into_iter().map(|i| i as f64).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
DecodingSampleBuffer::I32(data) => {
|
||||||
|
data.into_iter().map(|i| i as f64).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
DecodingSampleBuffer::I64(data) => {
|
||||||
|
data.into_iter().map(|i| i as f64).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
DecodingSampleBuffer::F16(data) => data.into_iter().map(f64::from).collect::<Vec<_>>(),
|
||||||
|
DecodingSampleBuffer::F32(data) => {
|
||||||
|
data.into_iter().map(|i| i as f64).collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
DecodingSampleBuffer::F64(data) => data,
|
||||||
};
|
};
|
||||||
let width = reader.get_tag(Tag::ImageWidth)?.into_u32()? as usize;
|
let mut ifd = reader.current_ifd();
|
||||||
let height = reader.get_tag(Tag::ImageLength)?.into_u32()? as usize;
|
let width = ifd.get_tag(Tag::ImageWidth)?.into_u32()? as usize;
|
||||||
|
let height = ifd.get_tag(Tag::ImageLength)?.into_u32()? as usize;
|
||||||
Ok(Array2::from_shape_vec((width, height), bytes)?)
|
Ok(Array2::from_shape_vec((width, height), bytes)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user