Skip to content

Commit

Permalink
testing compute operations
Browse files Browse the repository at this point in the history
  • Loading branch information
ashmeigh committed Feb 29, 2024
1 parent 88fe6ad commit af1bdce
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 48 deletions.
11 changes: 4 additions & 7 deletions mantidimaging/core/operations/circular_mask/circular_mask.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,8 @@ class CircularMaskFilter(BaseFilter):
filter_name = "Circular Mask"
link_histograms = True

@classmethod
def filter_func(cls,
data: ImageStack,
circular_mask_ratio=0.95,
circular_mask_value=0.,
progress=None) -> ImageStack:
@staticmethod
def filter_func(data: ImageStack, circular_mask_ratio=0.95, circular_mask_value=0., progress=None) -> ImageStack:
"""
:param data: Input data as a 3D numpy.ndarray
:param circular_mask_ratio: The ratio to the full image.
Expand All @@ -47,7 +43,8 @@ def filter_func(cls,

params = {'circular_mask_ratio': circular_mask_ratio, 'circular_mask_value': circular_mask_value}

ps.run_compute_func(cls.compute_function, data.data.shape[0], [data.shared_array], params, progress)
ps.run_compute_func(CircularMaskFilter.compute_function, data.data.shape[0], [data.shared_array], params,
progress)

return data

Expand Down
46 changes: 30 additions & 16 deletions mantidimaging/core/operations/crop_coords/crop_coords.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
from __future__ import annotations

from functools import partial
from typing import Union, Optional, List, TYPE_CHECKING
from typing import Union, Optional, List, TYPE_CHECKING, Dict, Any

import numpy as np

from mantidimaging.core.parallel import shared as ps
from mantidimaging import helper as h
from mantidimaging.core.parallel import utility as pu, shared as ps
from mantidimaging.core.operations.base_filter import BaseFilter, FilterGroup
from mantidimaging.core.utility.sensible_roi import SensibleROI
from mantidimaging.gui.utility.qt_helpers import Type
Expand All @@ -31,9 +32,8 @@ class CropCoordinatesFilter(BaseFilter):
filter_name = "Crop Coordinates"
link_histograms = True

@classmethod
def filter_func(cls,
images: ImageStack,
@staticmethod
def filter_func(images: ImageStack,
region_of_interest: Optional[Union[List[int], List[float], SensibleROI]] = None,
progress=None) -> ImageStack:
"""Execute the Crop Coordinates by Region of Interest filter. This does
Expand All @@ -55,25 +55,39 @@ def filter_func(cls,
"""

if region_of_interest is None:
region_of_interest = [0, 0, 50, 50] # Default ROI
# ROI is correct (SensibleROI or list of coords)
region_of_interest = SensibleROI.from_list([0, 0, 50, 50])
if isinstance(region_of_interest, list):
roi = region_of_interest
else:
roi = [region_of_interest.left, region_of_interest.top, region_of_interest.right, region_of_interest.bottom]
region_of_interest = SensibleROI.from_list(region_of_interest)

assert isinstance(region_of_interest, SensibleROI)

params = {'roi': roi}
ps.run_compute_func(cls.compute_function, images.data.shape[0], images.shared_array, params, progress)
h.check_data_stack(images)

sample = images.data
shape = (sample.shape[0], region_of_interest.height, region_of_interest.width)
if any((s < 0 for s in shape)):
raise ValueError("It seems the Region of Interest is outside of the current image dimensions.\n"
"This can happen on the image preview right after a previous Crop Coordinates.")

output = pu.create_array(shape, images.dtype)
params = {'sample': sample, 'roi': region_of_interest, 'output': output.array}
ps.run_compute_func(CropCoordinatesFilter.compute_function, sample.shape[0], images.shared_array, params,
progress)
images.shared_array = output
return images

@staticmethod
def compute_function(i: int, array: np.ndarray, params: dict):
def compute_function(i: int, array: np.ndarray, params: Dict[str, Any]):
_ = array
sample = params['sample']
roi = params['roi']
# Crop ROI
array[i] = array[i, roi[1]:roi[3], roi[0]:roi[2]]
output = params['output']
if isinstance(roi, SensibleROI):
left, top, right, bottom = roi.left, roi.top, roi.right, roi.bottom
else:
left, top, right, bottom = roi[0], roi[1], roi[2], roi[3]
output[i] = sample[i, top:bottom, left:right]

@staticmethod
def register_gui(form, on_change, view):
from mantidimaging.gui.utility import add_property_to_form
label, roi_field = add_property_to_form("ROI",
Expand Down
6 changes: 3 additions & 3 deletions mantidimaging/core/operations/divide/divide.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ class DivideFilter(BaseFilter):
filter_name = "Divide"
link_histograms = True

@classmethod
def filter_func(cls, images: ImageStack, value: Union[int, float] = 0, unit="micron", progress=None) -> ImageStack:
@staticmethod
def filter_func(images: ImageStack, value: Union[int, float] = 0, unit="micron", progress=None) -> ImageStack:
"""
:param value: The division value.
:param unit: The unit of the divisor.
Expand All @@ -47,7 +47,7 @@ def filter_func(cls, images: ImageStack, value: Union[int, float] = 0, unit="mic
value *= conversion_factor

params = {'value': value}
ps.run_compute_func(cls.compute_function, images.data.shape[0], images.shared_array, params, progress)
ps.run_compute_func(DivideFilter.compute_function, images.data.shape[0], images.shared_array, params, progress)

return images

Expand Down
12 changes: 4 additions & 8 deletions mantidimaging/core/operations/nan_removal/nan_removal.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,8 @@ class NaNRemovalFilter(BaseFilter):

MODES = ["Constant", "Median"]

@classmethod
def filter_func(cls,
images: ImageStack,
replace_value: float = 0.0,
mode_value: str = "Constant",
progress=None) -> ImageStack:
@staticmethod
def filter_func(data, replace_value=None, mode_value="Constant", progress=None) -> ImageStack:
"""
:param data: The input data.
:param mode_value: Values to replace NaNs with. One of ["Constant", "Median"]
Expand All @@ -54,9 +50,9 @@ def filter_func(cls,
"""

params = {'replace_value': replace_value, 'mode_value': mode_value}
ps.run_compute_func(cls.compute_function, images.data.shape[0], images.shared_array, params, progress)
ps.run_compute_func(NaNRemovalFilter.compute_function, data.data.shape[0], data.shared_array, params, progress)

return images
return data

@staticmethod
def compute_function(i: int, array: np.ndarray, params: dict):
Expand Down
39 changes: 30 additions & 9 deletions mantidimaging/core/operations/rebin/rebin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
from __future__ import annotations

from functools import partial
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, List

import numpy as np
from skimage.transform import resize

from mantidimaging.core.operations.base_filter import BaseFilter
from mantidimaging.core.parallel import shared as ps
from mantidimaging.core.parallel import utility as pu, shared as ps
from mantidimaging.gui.utility import add_property_to_form
from mantidimaging.gui.utility.qt_helpers import Type

Expand All @@ -30,8 +30,8 @@ class RebinFilter(BaseFilter):
filter_name = "Rebin"
link_histograms = True

@classmethod
def filter_func(cls, images: ImageStack, rebin_param=0.5, mode=None, progress=None) -> ImageStack:
@staticmethod
def filter_func(images: ImageStack, rebin_param=0.5, mode=None, progress=None) -> ImageStack:
"""
:param images: Sample data which is to be processed. Expects radiograms
:param rebin_param: int, float or tuple
Expand All @@ -43,7 +43,6 @@ def filter_func(cls, images: ImageStack, rebin_param=0.5, mode=None, progress=No
:return: The processed 3D numpy.ndarray
"""
# Validate rebin_param
if isinstance(rebin_param, tuple):
new_shape = rebin_param
elif isinstance(rebin_param, (int, float)):
Expand All @@ -52,16 +51,21 @@ def filter_func(cls, images: ImageStack, rebin_param=0.5, mode=None, progress=No
else:
raise ValueError("Invalid type for rebin_param")

params = {'new_shape': new_shape, 'mode': mode}
ps.run_compute_func(cls.compute_function, images.data.shape[0], images.shared_array, params, progress)
output = _create_reshaped_array(images, rebin_param)

params = {'new_shape': new_shape, 'mode': mode}
ps.run_compute_func(RebinFilter.compute_function, images.data.shape[0], [images.shared_array, output], params,
progress)
images.shared_array = output
return images

@staticmethod
def compute_function(i: int, array: np.ndarray, params: dict):
def compute_function(i: int, arrays: List[np.ndarray], params: dict):
array = arrays[0]
output = arrays[1]
new_shape = params['new_shape']
mode = params['mode']
array[i] = resize(array[i], output_shape=new_shape, mode=mode, preserve_range=True)
output[i] = resize(array[i], output_shape=new_shape, mode=mode, preserve_range=True)

@staticmethod
def register_gui(form, on_change, view):
Expand Down Expand Up @@ -142,5 +146,22 @@ def execute_wrapper(rebin_to_dimensions_radio=None,
return partial(RebinFilter.filter_func, mode=mode_field.currentText(), rebin_param=params)


def _create_reshaped_array(images, rebin_param):
old_shape = images.data.shape
num_images = old_shape[0]

# use SciPy's calculation to find the expected dimensions
# int to avoid visible deprecation warning
if isinstance(rebin_param, tuple):
expected_dimy = int(rebin_param[0])
expected_dimx = int(rebin_param[1])
else:
expected_dimy = int(rebin_param * old_shape[1])
expected_dimx = int(rebin_param * old_shape[2])

shape = (num_images, expected_dimy, expected_dimx)
return pu.create_array(shape, images.dtype)


def modes():
return ["constant", "edge", "wrap", "reflect", "symmetric"]
4 changes: 2 additions & 2 deletions scripts/operations_tests/operations_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
from mantidimaging.core.io.loader import loader # noqa: E402
from mantidimaging.core.operations.loader import load_filter_packages # noqa: E402

LOAD_SAMPLE = (Path.home() / "mantidimaging-data" / "ISIS" / "IMAT" / "IMAT00010675" / "Tomo" /
"IMAT_Flower_Tomo_000000.tif")
LOAD_SAMPLE = ("C:/Users/44770/Downloads/mantidimaging-data-small "
"(2)/mantidimaging-data-small/ISIS/IMAT/IMAT00010675/Tomo/IMAT_Flower_Tomo_000000.tif")

if path := os.getenv("MANTIDIMAGING_APPROVAL_TESTS_DIR"):
SAVE_DIR = Path(path)
Expand Down
45 changes: 42 additions & 3 deletions scripts/operations_tests/test_cases.json
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,10 @@
}
]
},
"Ring Removal": {
"params": {"center_mode": "image center"},
"Ring Removal": {
"params": {
"center_mode": "image center"
},
"source_data": "flower128",
"cases": [
{
Expand All @@ -235,5 +237,42 @@
}
}
]
},
"Rebin": {
"params": {
"rebin_param": 0.5,
"mode": "reflect"
},
"source_data": "flower128",
"cases": [
{
"test_name": "rebin_by_factor_0.5",
"params": {
"rebin_param": 0.5
}
},
{
"test_name": "rebin_to_dimensions_100x100",
"params": {
"rebin_param": [
100,
100
]
}
}
]
},
"Divide": {
"params": {},
"source_data": "flower128",
"cases": [
{
"test_name": "divide_by_non_zero_value",
"params": {
"value": 1.5,
"unit": "micron"
}
}
]
}
}
}

0 comments on commit af1bdce

Please sign in to comment.