Skip to content

Commit

Permalink
Merge pull request #974 from AFM-SPM/SylviaWhittle/curvature
Browse files Browse the repository at this point in the history
Add basic curvature
  • Loading branch information
SylviaWhittle authored Nov 21, 2024
2 parents 550bfb0 + b368847 commit 42a764e
Show file tree
Hide file tree
Showing 15 changed files with 1,196 additions and 38 deletions.
421 changes: 421 additions & 0 deletions tests/measure/test_curvature.py

Large diffs are not rendered by default.

Binary file added tests/resources/img/test_plot_curvatures.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/resources/process_scan_topostats_file_regtest.topostats
Binary file not shown.
Binary file not shown.
Binary file not shown.
149 changes: 149 additions & 0 deletions tests/test_plottingfuncs.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,155 @@ def test_dilate_binary_image(binary_image: np.ndarray, dilation_iterations: int,
rng = np.random.default_rng()


@pytest.mark.mpl_image_compare(baseline_dir="resources/img/")
def test_plot_curvatures(tmp_path: Path) -> None:
"""Test plotting of curvatures."""
image = np.array(
[
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2],
[0.1, 0.2, 1.1, 1.1, 1.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2],
[0.1, 0.2, 1.1, 0.2, 1.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2],
[0.1, 0.2, 1.1, 1.1, 1.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 1.2, 1.1, 1.1, 1.1, 1.1, 0.2, 0.1],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 1.1, 1.1, 0.2, 0.1, 1.2, 1.1, 0.2],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 1.1, 0.2, 0.1, 0.2, 0.1, 1.1, 0.1],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 1.1, 0.1, 0.2, 0.1, 0.2, 1.1, 0.2],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 0.1, 1.1, 0.1, 0.2, 0.1, 1.1, 0.1],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 0.1, 0.1, 0.2, 1.1, 1.1, 1.1, 1.1, 0.1, 0.2],
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1],
]
)

cropped_images = {
"grain_0": {
"original_image": np.array(
[
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.2, 0.1, 0.2, 0.1, 0.2, 0.0],
[0.0, 0.2, 1.1, 1.1, 1.1, 0.2, 0.0],
[0.0, 0.2, 1.1, 0.2, 1.1, 0.2, 0.0],
[0.0, 0.2, 1.1, 1.1, 1.1, 0.2, 0.0],
[0.0, 0.2, 0.1, 0.2, 0.1, 0.2, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
]
),
"bbox": [1, 1, 5, 5],
"pad_width": 1,
},
"grain_1": {
"original_image": np.array(
[
[0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2],
[0.2, 1.2, 1.1, 1.1, 1.1, 1.1, 0.2, 0.1],
[0.1, 1.1, 1.1, 0.2, 0.1, 1.2, 1.1, 0.2],
[0.2, 1.1, 0.2, 0.1, 0.2, 0.1, 1.1, 0.1],
[0.1, 1.1, 0.1, 0.2, 0.1, 0.2, 1.1, 0.2],
[0.2, 0.1, 1.1, 0.1, 0.2, 0.1, 1.1, 0.1],
[0.1, 0.2, 1.1, 1.1, 1.1, 1.1, 0.1, 0.2],
[0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1],
]
),
"bbox": [8, 8, 15, 15],
"pad_width": 0,
},
}

grains_curvture_stats_dict = {
"grain_0": {"mol_0": np.array([0.2, 0.0, 0.2, 0.0, 0.2, 0.0, 0.2, 0.0])},
"grain_1": {
"mol_0": np.array(
[
0.1,
0.2,
0.1,
0.2,
0.1,
0.2,
0.1,
0.2,
0.1,
0.2,
0.1,
0.2,
0.1,
0.2,
0.1,
0.2,
0.1,
0.2,
]
)
},
}

all_grain_smoothed_data = {
"grain_0": {
"mol_0": {
"spline_coords": np.array(
[
[2.5, 2.5],
[2.5, 3.5],
[2.5, 4.5],
[3.5, 4.5],
[4.5, 4.5],
[4.5, 3.5],
[4.5, 2.5],
[3.5, 2.5],
]
),
},
},
"grain_1": {
"mol_0": {
"spline_coords": np.array(
[
[1.5, 1.5],
[1.5, 2.5],
[1.5, 3.5],
[1.5, 4.5],
[1.5, 5.5],
[2.5, 5.5],
[2.5, 6.5],
[3.5, 6.5],
[4.5, 6.5],
[5.5, 6.5],
[6.5, 5.5],
[6.5, 4.5],
[6.5, 3.5],
[6.5, 2.5],
[5.5, 2.5],
[4.5, 1.5],
[3.5, 1.5],
[2.5, 1.5],
],
)
}
},
}

fig, _ = Images(
np.array([[0, 0], [0, 0]]),
output_dir=tmp_path,
filename="Curvature",
image_type="non-binary",
savefig_dpi=200,
core_set=True,
).plot_curvatures(
image=image,
cropped_images=cropped_images,
grains_curvature_stats_dict=grains_curvture_stats_dict,
all_grain_smoothed_data=all_grain_smoothed_data,
colourmap_normalisation_bounds=[-0.2, 0.2],
)

return fig


@pytest.mark.parametrize(
("masked_array", "axes_colorbar", "region_properties"),
[(rng.random((10, 10)), True, None), (None, True, None), (None, False, True)],
Expand Down
85 changes: 57 additions & 28 deletions tests/test_processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def test_process_scan_below(regtest, tmp_path, process_scan_config: dict, load_s
nodestats_config=process_scan_config["nodestats"],
ordered_tracing_config=process_scan_config["ordered_tracing"],
splining_config=process_scan_config["splining"],
curvature_config=process_scan_config["curvature"],
plotting_config=process_scan_config["plotting"],
output_dir=tmp_path,
)
Expand Down Expand Up @@ -76,6 +77,7 @@ def test_process_scan_below_height_profiles(tmp_path, process_scan_config: dict,
nodestats_config=process_scan_config["nodestats"],
ordered_tracing_config=process_scan_config["ordered_tracing"],
splining_config=process_scan_config["splining"],
curvature_config=process_scan_config["curvature"],
plotting_config=process_scan_config["plotting"],
output_dir=tmp_path,
)
Expand Down Expand Up @@ -110,6 +112,7 @@ def test_process_scan_above(regtest, tmp_path, process_scan_config: dict, load_s
nodestats_config=process_scan_config["nodestats"],
ordered_tracing_config=process_scan_config["ordered_tracing"],
splining_config=process_scan_config["splining"],
curvature_config=process_scan_config["curvature"],
plotting_config=process_scan_config["plotting"],
output_dir=tmp_path,
)
Expand All @@ -136,6 +139,7 @@ def test_process_scan_above_height_profiles(tmp_path, process_scan_config: dict,
nodestats_config=process_scan_config["nodestats"],
ordered_tracing_config=process_scan_config["ordered_tracing"],
splining_config=process_scan_config["splining"],
curvature_config=process_scan_config["curvature"],
plotting_config=process_scan_config["plotting"],
output_dir=tmp_path,
)
Expand Down Expand Up @@ -172,6 +176,7 @@ def test_process_scan_both(regtest, tmp_path, process_scan_config: dict, load_sc
nodestats_config=process_scan_config["nodestats"],
ordered_tracing_config=process_scan_config["ordered_tracing"],
splining_config=process_scan_config["splining"],
curvature_config=process_scan_config["curvature"],
plotting_config=process_scan_config["plotting"],
output_dir=tmp_path,
)
Expand Down Expand Up @@ -226,6 +231,7 @@ def test_save_cropped_grains(
nodestats_config=process_scan_config["nodestats"],
ordered_tracing_config=process_scan_config["ordered_tracing"],
splining_config=process_scan_config["splining"],
curvature_config=process_scan_config["curvature"],
plotting_config=process_scan_config["plotting"],
output_dir=tmp_path,
)
Expand Down Expand Up @@ -274,6 +280,7 @@ def test_save_format(process_scan_config: dict, load_scan_data: LoadScans, tmp_p
nodestats_config=process_scan_config["nodestats"],
ordered_tracing_config=process_scan_config["ordered_tracing"],
splining_config=process_scan_config["splining"],
curvature_config=process_scan_config["curvature"],
plotting_config=process_scan_config["plotting"],
output_dir=tmp_path,
)
Expand Down Expand Up @@ -558,58 +565,76 @@ def test_check_run_steps(
"nodestats_run",
"ordered_tracing_run",
"splining_run",
"curvature_run",
"log_msg1",
"log_msg2",
),
[
pytest.param(
False,
False,
False,
False,
False,
False,
False,
False, # Filters
False, # Grains
False, # Grainstats
False, # Disordered tracing
False, # Nodestats
False, # Ordered tracing
False, # Splining
False, # Curvature
"You have not included running the initial filter stage.",
"Please check your configuration file.",
id="All stages are disabled",
),
pytest.param(
True,
False,
False,
False,
False,
False,
False,
True, # Filters
False, # Grains
False, # Grainstats
False, # Disordered tracing
False, # Nodestats
False, # Ordered tracing
False, # Splining
False, # Curvature
"Detection of grains disabled, GrainStats will not be run.",
"",
id="Only filtering enabled",
),
pytest.param(
True,
True,
False,
False,
False,
False,
False,
True, # Filters
True, # Grains
False, # Grainstats
False, # Disordered tracing
False, # Nodestats
False, # Ordered tracing
False, # Splining
False, # Curvature
"Calculation of grainstats disabled, returning empty dataframe and empty height_profiles.",
"",
id="Filtering and Grain enabled",
),
pytest.param(
True,
True,
True,
False,
False,
False,
False,
True, # Filter
True, # Grains
True, # Grainstats
False, # Disordered Tracing
False, # Nodestats
False, # Ordered tracing
False, # Splining
False, # Curvature
"Processing grain",
"Calculation of Disordered Tracing disabled, returning empty dictionary.",
id="Filtering, Grain and GrainStats enabled",
),
pytest.param(
True, # Filter
True, # Grains
True, # Grainstats
True, # Disordered Tracing
True, # Nodestats
True, # Ordered tracing
True, # Splining
False, # Curvature
"Processing grain",
"Calculation of Curvature Stats disabled, returning None.",
id="All stages enabled",
),
# @ns-rse 2024-09-13 : Parameters need updating so test is performed.
# pytest.param(
# True,
Expand All @@ -633,6 +658,7 @@ def test_process_stages(
nodestats_run: bool,
ordered_tracing_run: bool,
splining_run: bool,
curvature_run: bool,
log_msg1: str,
log_msg2: str,
caplog,
Expand All @@ -652,6 +678,7 @@ def test_process_stages(
process_scan_config["nodestats"]["run"] = nodestats_run
process_scan_config["ordered_tracing"]["run"] = ordered_tracing_run
process_scan_config["splining"]["run"] = splining_run
process_scan_config["curvature"]["run"] = curvature_run
_, _, _, _, _, _ = process_scan(
topostats_object=img_dic["minicircle_small"],
base_dir=BASE_DIR,
Expand All @@ -662,6 +689,7 @@ def test_process_stages(
nodestats_config=process_scan_config["nodestats"],
ordered_tracing_config=process_scan_config["ordered_tracing"],
splining_config=process_scan_config["splining"],
curvature_config=process_scan_config["curvature"],
plotting_config=process_scan_config["plotting"],
output_dir=tmp_path,
)
Expand All @@ -685,6 +713,7 @@ def test_process_scan_no_grains(process_scan_config: dict, load_scan_data: LoadS
nodestats_config=process_scan_config["nodestats"],
ordered_tracing_config=process_scan_config["ordered_tracing"],
splining_config=process_scan_config["splining"],
curvature_config=process_scan_config["curvature"],
plotting_config=process_scan_config["plotting"],
output_dir=tmp_path,
)
Expand Down
3 changes: 3 additions & 0 deletions topostats/default_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ splining:
spline_linear_smoothing: 5.0 # The amount of smoothing to apply to linear features.
spline_circular_smoothing: 5.0 # The amount of smoothing to apply to circular features.
spline_degree: 3 # The polynomial degree of the spline.
curvature:
run: true # Options : true, false
colourmap_normalisation_bounds: [-0.5, 0.5] # Radians per nm to normalise the colourmap to.
plotting:
run: true # Options : true, false
style: topostats.mplstyle # Options : topostats.mplstyle or path to a matplotlibrc params file
Expand Down
Loading

0 comments on commit 42a764e

Please sign in to comment.