Skip to content

Commit 4d897f9

Browse files
committed
Migrate unit tests from cdl to sigima_ (finished image tests)
1 parent 3bc1e20 commit 4d897f9

16 files changed

Lines changed: 259 additions & 150 deletions

cdl/plugins/cdl_testdata.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def create_peak2d_image(self) -> None:
8383
param = test_data.PeakDataParam.create(size=max(obj.data.shape))
8484
self.imagepanel.processor.update_param_defaults(param)
8585
if param.edit(self.main):
86-
obj.data = test_data.get_peak2d_data(param)
86+
obj.data, _coords = test_data.get_peak2d_data(param)
8787
self.proxy.add_object(obj)
8888

8989
def create_sincos_image(self) -> None:

cdl/tests/features/images/imagebgdlg_unit_test.py renamed to cdl/tests/features/images/background_dialog_test.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from __future__ import annotations
1212

13+
import numpy as np
1314
from guidata.qthelpers import exec_dialog, qt_app_context
1415

1516
import sigima_.computation.image as sigima_image
@@ -21,8 +22,27 @@
2122
from sigima_.tests.data import create_noisygauss_image
2223

2324

24-
def test_image_background_dialog() -> None:
25-
"""Image background dialog test."""
25+
def test_image_background_selection() -> None:
26+
"""Image background selection test."""
27+
with qt_app_context():
28+
img = create_noisygauss_image()
29+
dlg = ImageBackgroundDialog(img)
30+
dlg.resize(640, 480)
31+
dlg.setObjectName(dlg.objectName() + "_00") # to avoid timestamp suffix
32+
with execenv.context(delay=200):
33+
# For more details about the why of the delay, see the comment in
34+
# cdl\tests\features\image\offset_correction_unit_test.py
35+
exec_dialog(dlg)
36+
execenv.print(f"background: {dlg.get_background()}")
37+
execenv.print(f"rect coords: {dlg.get_rect_coords()}")
38+
# Check background value:
39+
x0, y0, x1, y1 = dlg.get_rect_coords()
40+
ix0, iy0, ix1, iy1 = dlg.imageitem.get_closest_index_rect(x0, y0, x1, y1)
41+
assert np.isclose(img.data[iy0:iy1, ix0:ix1].mean(), dlg.get_background())
42+
43+
44+
def test_image_offset_correction_with_background_dialog() -> None:
45+
"""Image offset correction interactive test using the background dialog."""
2646
with qt_app_context():
2747
i1 = create_noisygauss_image()
2848
dlg = ImageBackgroundDialog(i1)
@@ -51,4 +71,5 @@ def test_image_background_dialog() -> None:
5171

5272

5373
if __name__ == "__main__":
54-
test_image_background_dialog()
74+
test_image_background_selection()
75+
test_image_offset_correction_with_background_dialog()

cdl/tests/features/images/peak2d_unit_test.py

Lines changed: 0 additions & 42 deletions
This file was deleted.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2+
3+
"""
4+
Profile extraction unit test
5+
"""
6+
7+
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
8+
# guitest: show
9+
10+
from guidata.qthelpers import exec_dialog, qt_app_context
11+
12+
import sigima_.param
13+
from cdl.env import execenv
14+
from cdl.gui.profiledialog import ProfileExtractionDialog
15+
from sigima_.tests.data import create_noisygauss_image
16+
17+
18+
def test_profile_unit():
19+
"""Run profile extraction test"""
20+
with qt_app_context():
21+
obj = create_noisygauss_image(center=(0.0, 0.0), add_annotations=False)
22+
for mode in ("line", "segment", "rectangle"):
23+
for initial_param in (True, False):
24+
if initial_param:
25+
if mode == "line":
26+
param = sigima_.param.LineProfileParam.create(row=100, col=200)
27+
elif mode == "segment":
28+
param = sigima_.param.SegmentProfileParam.create(
29+
row1=10, col1=20, row2=200, col2=300
30+
)
31+
else:
32+
param = sigima_.param.AverageProfileParam.create(
33+
row1=10, col1=20, row2=200, col2=300
34+
)
35+
else:
36+
if mode == "line":
37+
param = sigima_.param.LineProfileParam()
38+
elif mode == "segment":
39+
param = sigima_.param.SegmentProfileParam()
40+
else:
41+
param = sigima_.param.AverageProfileParam()
42+
execenv.print("-" * 80)
43+
execenv.print(f"Testing mode: {mode} - initial_param: {initial_param}")
44+
dialog = ProfileExtractionDialog(
45+
mode, param, add_initial_shape=initial_param
46+
)
47+
dialog.set_obj(obj)
48+
if initial_param:
49+
dialog.edit_values()
50+
ok = exec_dialog(dialog)
51+
execenv.print(f"Returned code: {ok}")
52+
execenv.print(f"Param: {param}")
53+
54+
55+
if __name__ == "__main__":
56+
test_profile_unit()

cdl/tests/features/images/select_background_unit_test.py

Lines changed: 0 additions & 38 deletions
This file was deleted.

cdl/tests/sigima_tests/images/contour_unit_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,12 @@ def find_contours(data):
5757
@pytest.mark.gui
5858
def test_contour_interactive():
5959
"""2D peak detection test"""
60+
data, _coords = get_peak2d_data()
6061
# pylint: disable=import-outside-toplevel
6162
from guidata.qthelpers import qt_app_context
6263

6364
with qt_app_context():
64-
find_contours(get_peak2d_data())
65+
find_contours(data)
6566

6667

6768
if __name__ == "__main__":

cdl/tests/sigima_tests/images/hough_circle_unit_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,12 @@ def __exec_hough_circle_test(data):
5656
@pytest.mark.gui
5757
def test_hough_circle():
5858
"""2D peak detection test"""
59+
data, _coords = get_peak2d_data(multi=False)
5960
# pylint: disable=import-outside-toplevel
6061
from guidata.qthelpers import qt_app_context
6162

6263
with qt_app_context():
63-
__exec_hough_circle_test(get_peak2d_data(multi=False))
64+
__exec_hough_circle_test(data)
6465

6566

6667
if __name__ == "__main__":

cdl/tests/features/images/peak2d_limits_unit.py renamed to cdl/tests/sigima_tests/images/peak2d_limits_unit_test.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,28 @@
55
"""
66

77
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
8-
# guitest: skip
98

10-
from guidata.qthelpers import qt_app_context
9+
import pytest
1110

12-
from cdl.env import execenv
13-
from cdl.tests.features.images.peak2d_unit_test import exec_image_peak_detection_func
11+
from cdl.tests.sigima_tests.images.peak2d_unit_test import (
12+
exec_image_peak_detection_func,
13+
)
1414
from sigima_.algorithms.image import get_2d_peaks_coords
15+
from sigima_.env import execenv
1516
from sigima_.tests.data import get_peak2d_data
1617

1718

18-
def peak2d_limit_test():
19+
@pytest.mark.skip(reason="Limit testing, not required for automated testing")
20+
def test_peak2d_limit():
1921
"""2D peak detection test"""
22+
# pylint: disable=import-outside-toplevel
23+
from guidata.qthelpers import qt_app_context
24+
2025
with qt_app_context():
2126
execenv.print("Testing peak detection algorithm with random generated data:")
2227
for idx in range(100):
2328
execenv.print(f" Iteration #{idx:02d}: ", end="")
24-
generated_data = get_peak2d_data(multi=True)
29+
generated_data, _coords = get_peak2d_data(multi=True)
2530
coords = get_2d_peaks_coords(generated_data)
2631
if coords.shape[0] != 4:
2732
execenv.print(f"KO - {coords.shape[0]}/4 peaks were detected")
@@ -33,4 +38,4 @@ def peak2d_limit_test():
3338

3439

3540
if __name__ == "__main__":
36-
peak2d_limit_test()
41+
test_peak2d_limit()
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2+
3+
"""
4+
Image peak detection test
5+
"""
6+
7+
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
8+
# pylint: disable=duplicate-code
9+
10+
from __future__ import annotations
11+
12+
import time
13+
14+
import numpy as np
15+
import pytest
16+
17+
import sigima_.computation.image as sigima_image
18+
import sigima_.obj
19+
import sigima_.param
20+
from sigima_.algorithms.image import get_2d_peaks_coords
21+
from sigima_.env import execenv
22+
from sigima_.tests.data import get_peak2d_data
23+
from sigima_.tests.helpers import check_array_result
24+
from sigima_.tests.vistools import view_image_items
25+
26+
27+
def exec_image_peak_detection_func(data: np.ndarray) -> np.ndarray:
28+
"""Execute image peak detection function
29+
30+
Args:
31+
data: 2D image data
32+
33+
Returns:
34+
2D array of peak coordinates
35+
"""
36+
t0 = time.time()
37+
coords = get_2d_peaks_coords(data)
38+
dt = time.time() - t0
39+
execenv.print(f"Calculation time: {int(dt * 1e3):d} ms")
40+
execenv.print(f" => {coords.tolist()}")
41+
return coords
42+
43+
44+
def view_image_peak_detection(data: np.ndarray, coords: np.ndarray) -> None:
45+
"""View image peak detection results
46+
47+
Args:
48+
data: 2D image data
49+
coords: Coordinates of detected peaks (shape: (n, 2))
50+
"""
51+
from plotpy.builder import make # pylint: disable=import-outside-toplevel
52+
53+
execenv.print("Peak detection results:")
54+
items = [make.image(data, interpolation="linear", colormap="hsv")]
55+
for x, y in coords:
56+
items.append(make.marker((x, y)))
57+
view_image_items(
58+
items, name=view_image_peak_detection.__name__, title="Peak Detection"
59+
)
60+
61+
62+
def test_peak2d_unit():
63+
"""2D peak detection unit test"""
64+
data, coords_expected = get_peak2d_data(multi=False)
65+
coords = exec_image_peak_detection_func(data)
66+
assert coords.shape == coords_expected.shape, (
67+
f"Expected {coords_expected.shape[0]} peaks, got {coords.shape[0]}"
68+
)
69+
# Absolute tolerance is set to 2 pixels, as coordinates are in pixel units
70+
# and the algorithm may detect peaks at slightly different pixel locations
71+
check_array_result("Peak coords (alg.)", coords, coords_expected, atol=2, sort=True)
72+
73+
74+
@pytest.mark.validation
75+
def test_image_peak_detection():
76+
"""2D peak detection unit test"""
77+
data, coords_expected = get_peak2d_data(multi=False)
78+
obj = sigima_.obj.create_image("peak2d_unit_test", data=data)
79+
param = sigima_.param.Peak2DDetectionParam()
80+
df = sigima_image.peak_detection(obj, param).to_dataframe()
81+
coords = df.to_numpy(int)
82+
assert coords.shape == coords_expected.shape, (
83+
f"Expected {coords_expected.shape[0]} peaks, got {coords.shape[0]}"
84+
)
85+
# Absolute tolerance is set to 2 pixels, as coordinates are in pixel units
86+
# and the algorithm may detect peaks at slightly different pixel locations
87+
check_array_result(
88+
"Peak coords (comp.)", coords, coords_expected, atol=2, sort=True
89+
)
90+
91+
92+
@pytest.mark.gui
93+
def test_peak2d_interactive():
94+
"""2D peak detection interactive test"""
95+
data, _coords = get_peak2d_data(multi=False)
96+
coords = exec_image_peak_detection_func(data)
97+
98+
# pylint: disable=import-outside-toplevel
99+
from guidata.qthelpers import qt_app_context
100+
101+
with qt_app_context():
102+
view_image_peak_detection(data, coords)
103+
104+
105+
if __name__ == "__main__":
106+
test_peak2d_unit()
107+
test_image_peak_detection()
108+
test_peak2d_interactive()

cdl/tests/features/images/processing_unit_test.py renamed to cdl/tests/sigima_tests/images/processing_unit_test.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737

3838
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
3939
# pylint: disable=duplicate-code
40-
# guitest: show
4140

4241
from __future__ import annotations
4342

0 commit comments

Comments
 (0)