Merge branch 'stitching-two' into 'v3'

Stitch 2 images

See merge request openflexure/openflexure-microscope-server!630
This commit is contained in:
Joe Knapper 2026-06-30 17:31:00 +00:00
commit f35ad17449
4 changed files with 18 additions and 9 deletions

View file

@ -406,9 +406,8 @@ class SmartScanThing(OFMThing):
if self._preview_stitcher is None: if self._preview_stitcher is None:
# This scan can't stitch. # This scan can't stitch.
return return
# Assume 4 images means at least one offset in x and y, making the stitching # Begin stitching once two images are captured
# well constrained. if self.scan_data.image_count >= 2 and not self._preview_stitcher.running:
if self.scan_data.image_count > 3 and not self._preview_stitcher.running:
self._preview_stitcher.start() self._preview_stitcher.start()
@_scan_running @_scan_running
@ -543,8 +542,8 @@ class SmartScanThing(OFMThing):
@_scan_running @_scan_running
def _perform_final_stitch(self) -> None: def _perform_final_stitch(self) -> None:
"""Update the scan zip and perform final stitch of the data.""" """Update the scan zip and perform final stitch of the data."""
if self.scan_data.image_count <= 3: if self.scan_data.image_count <= 1:
self.logger.info("Not performing a stitch as 3 or fewer images taken") self.logger.info("Not performing a stitch as not enough images captured")
return return
self.ongoing_scan.zip_files() self.ongoing_scan.zip_files()
@ -758,6 +757,6 @@ class SmartScanThing(OFMThing):
# Use the scan list (the data read by the gallery) to find any scans that # Use the scan list (the data read by the gallery) to find any scans that
# need stitching. # need stitching.
for scan in self.get_data_for_gallery(): for scan in self.get_data_for_gallery():
if scan.dzi is None: if scan.dzi is None and scan.number_of_images >= 2:
self.logger.info(f"Stitching {scan.name}") self.logger.info(f"Stitching {scan.name}")
self.stitch_scan(scan_name=scan.name) self.stitch_scan(scan_name=scan.name)

View file

@ -333,10 +333,19 @@ def test_stitch_all_scans_continues_after_error(mocker, caplog, smart_scan_thing
mocker.Mock(name="scan1", dzi=None), mocker.Mock(name="scan1", dzi=None),
mocker.Mock(name="scan2", dzi=None), mocker.Mock(name="scan2", dzi=None),
mocker.Mock(name="scan3", dzi=None), mocker.Mock(name="scan3", dzi=None),
mocker.Mock(name="scan4", dzi=None),
] ]
scans[0].name = "scan1" scans[0].name = "scan1"
scans[1].name = "scan2" scans[1].name = "scan2"
scans[2].name = "scan3" scans[2].name = "scan3"
scans[3].name = "scan4"
# stitch_all skips any scans with less than 2 images, without logging
scans[0].number_of_images = 10
scans[1].number_of_images = 10
scans[2].number_of_images = 1
scans[3].number_of_images = 10
mocker.patch.object( mocker.patch.object(
smart_scan_thing, smart_scan_thing,
@ -373,9 +382,10 @@ def test_stitch_all_scans_continues_after_error(mocker, caplog, smart_scan_thing
messages = [r.message for r in caplog.records] messages = [r.message for r in caplog.records]
# scan3 is not logged as there is only 1 image so it is ignored by ``stitch_all_scans``
assert messages == [ assert messages == [
"Stitching scan1", "Stitching scan1",
"Stitching scan2", "Stitching scan2",
"Stitching failed: test_message", "Stitching failed: test_message",
"Stitching scan3", "Stitching scan4",
] ]

View file

@ -62,7 +62,7 @@
<li>Duration: {{ formatDuration(itemData.duration) }}</li> <li>Duration: {{ formatDuration(itemData.duration) }}</li>
</ul> </ul>
<ul> <ul>
<li v-if="itemData.number_of_images < 3" class="warning-msg"> <li v-if="itemData.number_of_images < 2" class="warning-msg">
Not enough images to stitch Not enough images to stitch
</li> </li>
<li v-else-if="!itemData.dzi && itemData.stitch_available" class="alert-msg"> <li v-else-if="!itemData.dzi && itemData.stitch_available" class="alert-msg">

View file

@ -219,7 +219,7 @@ export default {
return; return;
} }
all_items.forEach((item) => { all_items.forEach((item) => {
item.can_stitch = !item.stitch_available && item.number_of_images > 3; item.can_stitch = !item.stitch_available && item.number_of_images > 1;
}); });
all_items.sort((a, b) => { all_items.sort((a, b) => {
return b.created - a.created; return b.created - a.created;