-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
516 additions
and
352 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from numpy.typing import NDArray | ||
import numpy as np | ||
from pydantic import BaseModel | ||
from math import pi | ||
|
||
|
||
class AngleSearchRange(BaseModel): | ||
max_angle: float | None = None # Maximum +/- deflection angle to rotate images when searching for the best control point alignment, if None, a full circle is searched at step-size intervals | ||
angle_step_size: float = 3 # Number of degrees to step between search angles | ||
|
||
@property | ||
def angle_range(self) -> NDArray[float]: | ||
if self.max_angle is None: | ||
angles = np.arange(start=-180, stop=180, step=self.angle_step_size) | ||
else: | ||
angles = np.arange(start=-self.max_angle, | ||
stop=self.max_angle + self.angle_step_size, | ||
step=self.angle_step_size) # numpy.linspace(-7.5, 7.5, 11) | ||
|
||
angles = np.union1d(angles, [0]) | ||
return angles | ||
|
||
def __iter__(self): | ||
return iter(self.angle_range) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
from numpy.typing import NDArray | ||
import numpy as np | ||
from typing import NamedTuple, Sequence, Iterable | ||
from pydantic import BaseModel | ||
from nornir_imageregistration.settings.angle_range import AngleSearchRange | ||
|
||
|
||
class StosBruteSettings(BaseModel): | ||
"""Encodes the settings required or used to invoke StosBrute""" | ||
angles: AngleSearchRange | Sequence[float] | None = None | ||
min_overlap: float = 0.75 # The minimum amount of overlap we require in the images. Higher values reduce false positives but may not register offset images | ||
source_image_scale_factors: tuple[float] | None = None | ||
"""Amount to scale the warped image before attempting registration, | ||
this handles cases where multiple scopes are used with slightly differnt magnification values """ | ||
|
||
larget_dimension: int | None = None # The input images should be scaled so the largest image dimension is equal to this value, default is 1024. None means use the actual image size | ||
try_flipped: bool = False # If True the algorithm will test the flipped version of the source image too | ||
|
||
def __init__(self, | ||
angles: AngleSearchRange | Sequence[float] | None = None, | ||
min_overlap: float = 0.75, | ||
source_image_scale_factors: NDArray[float] | None = None, | ||
larget_dimension: int | None = 1024, | ||
try_flipped: bool = False): | ||
""" | ||
:param angles: Angles to search for the best control point alignment or None if all angles should be searched | ||
:param min_overlap: Minimum amount of overlap we require to consider a registration to be valiud | ||
:param source_image_scale_factors: Amount to scale the warped image before attempting registration, this handles cases where multiple scopes are used with slightly differnt magnification values | ||
:param larget_dimension: The input images should be scaled so the largest image dimension is equal to this value, default is 1024. None means use the actual image size | ||
:param try_flipped: If True the algorithm will test the flipped version of the source image too | ||
""" | ||
super().__init__() | ||
self.angles = angles | ||
self.min_overlap = min_overlap | ||
self.larget_dimension = larget_dimension | ||
self.try_flipped = try_flipped | ||
|
||
self.source_image_scale_factors = source_image_scale_factors | ||
|
||
if self.source_image_scale_factors is None: | ||
pass | ||
elif isinstance(source_image_scale_factors, np.ndarray): | ||
self.source_image_scale_factors = source_image_scale_factors | ||
elif hasattr(source_image_scale_factors, '__iter__'): | ||
self.source_image_scale_factors = np.array(source_image_scale_factors, float) | ||
else: | ||
self.source_image_scale_factors = np.array([source_image_scale_factors, source_image_scale_factors], float) | ||
|
||
def angle_range_defined(self) -> bool: | ||
return self.angles is not None | ||
|
||
@property | ||
def angle_range(self) -> NDArray[float]: | ||
""":return: The range of angles to search for the best control point alignment or None if all angles should be searched""" | ||
if self.angles is None: | ||
return np.array(range(-178, 182, 2), float) | ||
|
||
if isinstance(self.angles, np.ndarray): | ||
return self.angles | ||
elif isinstance(self.angles, AngleSearchRange): | ||
return self.angles.angle_range | ||
elif isinstance(self.angles, Iterable): | ||
return np.array(list(self.angles), float) | ||
|
||
raise ValueError(f"Unexpected type for self.angle_search_settings: {self.angles.__class__}") | ||
|
||
@property | ||
def source_image_scaling_required(self) -> bool: | ||
if self.source_image_scale_factors is None: | ||
return False | ||
|
||
return np.any(self.source_image_scale_factors != 1) |
Oops, something went wrong.