Skip to content

segmenter: Introduce live segmentation#854

Open
babo989 wants to merge 45 commits intomainfrom
feat/live-segmentation-with-acquisition-fixes
Open

segmenter: Introduce live segmentation#854
babo989 wants to merge 45 commits intomainfrom
feat/live-segmentation-with-acquisition-fixes

Conversation

@babo989
Copy link
Collaborator

@babo989 babo989 commented Feb 2, 2026

Summary

Add real-time segmentation preview during acquisition with fixes for pump synchronization issues.

Features

  • Live segmentation with blur metrics and object detection preview

Bug Fixes

  • Prevent retained MQTT messages from skipping pump cycles
  • Acquisition lock prevents UI pump controls from interrupting
  • fsync ensures images are fully written before announcing via MQTT

tpollina and others added 15 commits November 30, 2025 21:41
Add real-time segmentation preview during image acquisition with robust synchronization to prevent race conditions and interference.

Features:
- Live segmentation with blur metrics and object detection preview
- Real-time feedback during acquisition

Fixes:
- Prevent retained MQTT "Done" messages from skipping pump cycles
- Tag acquisition pump commands with from_acquisition flag
- Acquisition lock prevents UI pump controls from interfering
- fsync ensures file is written before announcing via MQTT
- File stability check before reading captured images
@sonnyp sonnyp changed the base branch from update-dashboard to main February 3, 2026 17:15
Copy link
Collaborator

@sonnyp sonnyp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks awesome.

I see a couple of improvements to be made but we can do that incrementally after it is merged.

The only things I would like us to fix before merging are

  • regressions compared to what we have now
  • potential API breaks for clients

Please add a segmenter/testlive.js file next to segmenter/test.js to trigger/test live segmentation.


pump_started = False
# FIX: Track acquisition state to prevent UI commands from interrupting acquisition
acquisition_in_progress = False
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something I wanted to have as well 👍

However it doesn't belong in the controller. controllers should only concern themselves with providing a simple hardware API.

Ideally we have a backend app handling "business logic". Until then we can do that logic in the node-red frontend. WDYT?

Comment on lines +416 to +423
# FIX: Only process Done if we are actually waiting for pump to finish
# This prevents retained/stale Done messages from triggering early return
if not self._waiting_for_pump:
loguru.logger.debug(
f"Ignoring pump Done (not waiting for pump): {self._mqtt.msg['payload']}"
)
self._mqtt.read_message()
continue
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I introduced the retained messages. Can you elaborate on what the issue is? Maybe with a sequence of pseudo events.

Comment on lines +136 to +139
# FIX: Use fsync on specific file to ensure write completes before MQTT publish
# os.sync() is system-wide and async - doesn't guarantee this file is written
with open(capture_path, "rb") as f:
os.fsync(f.fileno())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# FIX: Use fsync on specific file to ensure write completes before MQTT publish
# os.sync() is system-wide and async - doesn't guarantee this file is written
with open(capture_path, "rb") as f:
os.fsync(f.fileno())
# Use fsync to ensure write completes before MQTT publish
with open(capture_path, "rb") as f:
os.fsync(f.fileno())

makes sense

I'm going to benchmark this as part of https://github.com/fairscope/PlanktoScope3/issues/375 to measure impact but I agree we should do this anyway

at least until we optimize sequence of events and start capturing n+1 before n finished writing

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os.fsync(f.fileno()) end us being slightly faster than os.sync

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +1 to +17
# Copyright (C) 2021 Romain Bazile
#
# This file is part of the PlanktoScope software.
#
# PlanktoScope is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PlanktoScope is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PlanktoScope. If not, see <http://www.gnu.org/licenses/>.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Copyright (C) 2021 Romain Bazile
#
# This file is part of the PlanktoScope software.
#
# PlanktoScope is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PlanktoScope is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PlanktoScope. If not, see <http://www.gnu.org/licenses/>.

Copyright / license headers are not useful (also the attribution is wrong :D )

You retain copyright over what you write. The license is already specified globally.

Comment on lines +57 to +58
IMG_BASE = "/home/pi/data/img"
OBJECTS_BASE = "/home/pi/data/objects"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recently introduced PLANKTOSCOPE_DATA_PATH to allow running the segmenter outside of a PlanktoScope

can you use the same logic as 1f84f2e#diff-059c3e4c6af9c25ca8f0562bb9887799bd0ffefe21b49f175fdd8c494d5bb0b6 ?

# Paths for visualization output
IMG_BASE = "/home/pi/data/img"
OBJECTS_BASE = "/home/pi/data/objects"
LIVE_STATS_FILE = "/tmp/live_seg_stats.json"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +53 to +54
# Hardware config path (same as used by controller)
HARDWARE_CONFIG_PATH = "/home/pi/PlanktoScope/hardware.json"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will prevent the segmenter from being run outside of a PlanktoScope

It looks like this is only needed to read process_pixel_fixed.

Can the live segmenter use the same mechanism as the current segmenter instead?

We have process_min_ESD that is given by the frontend and we use scikit equivalent_diameter_area

Search for __process_min_ESD in https://github.com/PlanktoScope/PlanktoScope/blob/cf9169bb302c686dffc5aa8b5c2883c2e08766b9/segmenter/planktoscope/segmenter/__init__.py

ESD is not an accurate name for it (since we don't process spherical objects) but I kept it for backward compatibility. We can rename it later.

"className": "",
"x": 800,
"y": 180,
"y": 200,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert unrelated changes (flows.json)

@sonnyp sonnyp changed the title feat: Live segmentation with acquisition synchronization fixes segmenter: Introduce live segmentation Feb 4, 2026
sonnyp added a commit that referenced this pull request Feb 9, 2026
Based on suggestion from @babo989 at
#854

---

Co-authored-by: Adam <aglarson@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants