Add test that stack checking agrees with at least 80% of manual labels
This commit is contained in:
parent
9149121d4b
commit
92e5541267
2 changed files with 123 additions and 0 deletions
43
tests/unit_tests/data/sharpness_test_cases.json
Normal file
43
tests/unit_tests/data/sharpness_test_cases.json
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
[
|
||||||
|
{"sharpnesses": [100000, 300000, 500000, 300000, 100000], "label": "success"},
|
||||||
|
{"sharpnesses": [100000, 200000, 400000, 600000, 400000, 200000, 100000], "label": "success"},
|
||||||
|
{"sharpnesses": [100000, 200000, 300000, 400000, 500000], "label": "continue"},
|
||||||
|
{"sharpnesses": [500000, 400000, 300000, 200000, 100000], "label": "restart"},
|
||||||
|
{"sharpnesses": [100000, 200000, 300000, 200000, 100000, 50000], "label": ["success"]},
|
||||||
|
{"sharpnesses": [0, 100000, 200000, 300000, 400000, 500000], "label": "continue"},
|
||||||
|
{"sharpnesses": [500000, 500000, 500000, 500000, 500000], "label": "continue"},
|
||||||
|
{"sharpnesses": [100000, 200000, 300000, 300000, 200000, 100000], "label": ["success"]},
|
||||||
|
{"sharpnesses": [100000, 200000, 300000, 400000, 400000, 300000, 200000], "label": ["success", "continue"]},
|
||||||
|
{"sharpnesses": [100000, 300000, 500000, 500000, 500000, 300000, 100000], "label": ["success", "continue"]},
|
||||||
|
{"sharpnesses": [100000, 300000, 500000, 400000, 500000, 300000, 100000], "label": ["continue", "success"]},
|
||||||
|
{"sharpnesses": [100000, 400000, 600000, 500000, 300000, 200000, 100000], "label": "success"},
|
||||||
|
{"sharpnesses": [100000, 200000, 500000, 700000, 600000, 300000, 100000], "label": "success"},
|
||||||
|
{"sharpnesses": [100000, 200000, 300000, 500000, 700000, 600000, 400000], "label": ["success", "continue"]},
|
||||||
|
{"sharpnesses": [700000, 600000, 500000, 400000, 300000, 200000, 100000, 0], "label": "restart"},
|
||||||
|
{"sharpnesses": [100000, 300000, 600000, 900000, 600000, 300000, 200000, 100000], "label": "success"},
|
||||||
|
{"sharpnesses": [100000, 200000, 400000, 800000, 900000, 800000, 400000, 200000], "label": "success"},
|
||||||
|
{"sharpnesses": [100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000], "label": "continue"},
|
||||||
|
{"sharpnesses": [800000, 700000, 600000, 500000, 400000, 300000, 200000, 100000], "label": "restart"},
|
||||||
|
{"sharpnesses": [100000, 200000, 300000, 400000, 400000, 400000, 300000, 200000], "label": ["success", "continue"]},
|
||||||
|
{"sharpnesses": [100000, 200000, 300000, 500000, 500000, 500000, 500000, 500000], "label": "continue"},
|
||||||
|
{"sharpnesses": [500000, 500000, 500000, 500000, 500000, 400000, 300000, 200000], "label": "restart"},
|
||||||
|
{"sharpnesses": [100000, 200000, 300000, 600000, 900000, 600000, 300000, 200000, 100000], "label": "success"},
|
||||||
|
{"sharpnesses": [100000, 200000, 400000, 700000, 1000000, 900000, 700000, 400000, 200000], "label": "success"},
|
||||||
|
{"sharpnesses": [100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000], "label": "continue"},
|
||||||
|
{"sharpnesses": [900000, 800000, 700000, 600000, 500000, 400000, 300000, 200000, 100000], "label": "restart"},
|
||||||
|
{"sharpnesses": [100000, 200000, 1000000, 200000, 1000000, 200000, 100000], "label": "continue"},
|
||||||
|
{"sharpnesses": [100000, 500000, 100000, 500000, 100000, 500000, 100000], "label": ["restart", "continue"]},
|
||||||
|
{"sharpnesses": [300000, 300000, 300000, 300000, 300000, 300000, 300000], "label": "continue"},
|
||||||
|
{"sharpnesses": [500000, 600000, 800000, 1100000, 1500000, 1100000, 800000, 600000, 500000], "label": "success"},
|
||||||
|
{"sharpnesses": [1000000, 1100000, 1300000, 1600000, 2000000, 1600000, 1300000, 1100000, 1000000], "label": "success"},
|
||||||
|
{"sharpnesses": [2000000, 1800000, 1500000, 1200000, 1000000, 900000, 800000, 700000, 600000], "label": "restart"},
|
||||||
|
{"sharpnesses": [600000, 700000, 800000, 900000, 1100000, 1300000, 1500000, 1700000, 1800000], "label": "continue"},
|
||||||
|
{"sharpnesses": [500000, 700000, 1000000, 1400000, 1800000, 1700000, 1400000, 1000000, 700000], "label": "success"},
|
||||||
|
{"sharpnesses": [500000, 600000, 900000, 1300000, 1800000, 1900000, 1700000, 1300000, 900000], "label": "success"},
|
||||||
|
{"sharpnesses": [500000, 500000, 500000, 500000, 600000, 900000, 600000, 500000, 500000], "label": ["success"]},
|
||||||
|
{"sharpnesses": [500000, 500000, 500000, 500000, 500000, 600000, 900000, 600000, 500000], "label": ["success", "continue"]},
|
||||||
|
{"sharpnesses": [500000, 500000, 500000, 500000, 500000, 500000, 600000, 900000, 600000], "label": "continue"},
|
||||||
|
{"sharpnesses": [100000, 100000, 100000, 100000, 200000, 500000, 200000, 100000, 100000], "label": ["success"]},
|
||||||
|
{"sharpnesses": [100000, 100000, 100000, 100000, 100000, 200000, 500000, 200000, 100000], "label": ["success", "continue"]},
|
||||||
|
{"sharpnesses": [100000, 100000, 100000, 100000, 100000, 100000, 200000, 500000, 200000], "label": "continue"}
|
||||||
|
]
|
||||||
80
tests/unit_tests/test_stack_examples.py
Normal file
80
tests/unit_tests/test_stack_examples.py
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
"""Unit tests for validating stack classification logic in AutofocusThing.
|
||||||
|
|
||||||
|
This module tests whether the `check_stack_result` method correctly classifies
|
||||||
|
z-stack sharpness profiles into "success", "continue", or "restart" categories
|
||||||
|
based on predefined test cases.
|
||||||
|
|
||||||
|
Sharpness profiles are loaded from a JSON file and converted into mock capture
|
||||||
|
objects to simulate real camera captures.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from labthings_fastapi.testing import create_thing_without_server
|
||||||
|
|
||||||
|
from openflexure_microscope_server.things.autofocus import AutofocusThing
|
||||||
|
|
||||||
|
|
||||||
|
class MockCapture:
|
||||||
|
"""Simple mock object representing a captured image.
|
||||||
|
|
||||||
|
This class mimics the minimal interface required by
|
||||||
|
`check_stack_result` by adding the `sharpness` and `buffer_id`
|
||||||
|
attributes.
|
||||||
|
|
||||||
|
:param sharpness: The sharpness value associated with the image.
|
||||||
|
:param buffer_id: A unique identifier for the image buffer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, sharpness, buffer_id):
|
||||||
|
"""Give each capture a sharpness and buffer_id."""
|
||||||
|
self.sharpness = sharpness
|
||||||
|
self.buffer_id = buffer_id
|
||||||
|
|
||||||
|
|
||||||
|
def make_captures(sharpness_list):
|
||||||
|
"""Convert a list of sharpness values into mock capture objects.
|
||||||
|
|
||||||
|
:param sharpness_list: A list of numeric sharpness values.
|
||||||
|
:returns: A list of MockCapture instances with sequential buffer IDs.
|
||||||
|
"""
|
||||||
|
return [MockCapture(s, i) for i, s in enumerate(sharpness_list)]
|
||||||
|
|
||||||
|
|
||||||
|
def test_stack_labelling():
|
||||||
|
"""Test stack classification accuracy against labelled sharpness cases.
|
||||||
|
|
||||||
|
This test loads predefined sharpness profiles and their expected labels
|
||||||
|
from a JSON file, converts them into mock capture objects, and evaluates
|
||||||
|
the classification returned by `check_stack_result`.
|
||||||
|
|
||||||
|
The test asserts that at least 90% of cases are correctly classified.
|
||||||
|
|
||||||
|
Expected labels may be a single value or a list of acceptable values.
|
||||||
|
"""
|
||||||
|
autofocus_thing = create_thing_without_server(AutofocusThing, mock_all_slots=True)
|
||||||
|
with open(r"tests\unit_tests\data\sharpness_test_cases.json") as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
success = 0
|
||||||
|
total = len(data)
|
||||||
|
|
||||||
|
for _i, case in enumerate(data):
|
||||||
|
sharpnesses = case["sharpnesses"]
|
||||||
|
expected = case["label"]
|
||||||
|
|
||||||
|
# Allow multiple acceptable labels
|
||||||
|
if not isinstance(expected, list):
|
||||||
|
expected = [expected]
|
||||||
|
|
||||||
|
# Convert to capture objects
|
||||||
|
captures = make_captures(sharpnesses)
|
||||||
|
|
||||||
|
# Call the method under test
|
||||||
|
result, _ = autofocus_thing.check_stack_result(
|
||||||
|
captures, check_turning_points=False
|
||||||
|
)
|
||||||
|
if result in expected:
|
||||||
|
success += 1
|
||||||
|
|
||||||
|
assert success > 0.8 * total
|
||||||
Loading…
Add table
Add a link
Reference in a new issue