simulate
This commit is contained in:
@@ -396,8 +396,8 @@ EXPORT_DESTINATIONS = ["local", "remote"]
|
|||||||
|
|
||||||
|
|
||||||
TRACKER_TUBE_AXIS = "vertical"
|
TRACKER_TUBE_AXIS = "vertical"
|
||||||
TRACKER_MIN_AREA = 20 # surface min planaire
|
TRACKER_MIN_AREA = 8 # surface min planaire px x px
|
||||||
TRACKER_MAX_AREA_RATIO = 0.05 # 5% de la frame = surface max acceptable
|
TRACKER_MAX_AREA_RATIO = 0.1 # 5% de la frame = surface max acceptable
|
||||||
TRACKER_MAX_PLANARIANS = 3
|
TRACKER_MAX_PLANARIANS = 3
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ class MultiWellManager:
|
|||||||
|
|
||||||
|
|
||||||
#def _grid_scanning_capture(self, uuid, duration):
|
#def _grid_scanning_capture(self, uuid, duration):
|
||||||
def _grid_scanning_capture(self, experiment, well_position):
|
def _grid_scanning_capture(self, experiment, well_position, simulate=False):
|
||||||
well = well_position.well
|
well = well_position.well
|
||||||
multiwell = experiment.multiwell
|
multiwell = experiment.multiwell
|
||||||
|
|
||||||
@@ -134,12 +134,15 @@ class MultiWellManager:
|
|||||||
uuid = f'{self.process.data.session}-{multiwell.position}-{well.name}'
|
uuid = f'{self.process.data.session}-{multiwell.position}-{well.name}'
|
||||||
## start recording
|
## start recording
|
||||||
self.process.data.uuid = uuid
|
self.process.data.uuid = uuid
|
||||||
self.process.data.record = True
|
if not simulate:
|
||||||
|
self.process.data.record = True
|
||||||
|
|
||||||
start = time.monotonic()
|
start = time.monotonic()
|
||||||
while not self.stop_playing.is_set():
|
while not self.stop_playing.is_set():
|
||||||
if time.monotonic() - start > multiwell.duration:
|
if time.monotonic() - start > multiwell.duration:
|
||||||
break
|
break
|
||||||
self.cnc_controller.wait_for(1.0)
|
self.cnc_controller.wait_for(1.0)
|
||||||
|
|
||||||
self.process.data.record = False
|
self.process.data.record = False
|
||||||
self.process.data.uuid = None
|
self.process.data.uuid = None
|
||||||
|
|
||||||
@@ -148,7 +151,7 @@ class MultiWellManager:
|
|||||||
self.process._send(scan_state=msg)
|
self.process._send(scan_state=msg)
|
||||||
|
|
||||||
|
|
||||||
def _grid_scanning(self, experiment, xnext=0, ynext=0):
|
def _grid_scanning(self, experiment, xnext=0, ynext=0, simulate=False):
|
||||||
multiwell = experiment.multiwell
|
multiwell = experiment.multiwell
|
||||||
wells = models.WellPosition.objects.filter(multiwell_id=multiwell.id).order_by('order').all()
|
wells = models.WellPosition.objects.filter(multiwell_id=multiwell.id).order_by('order').all()
|
||||||
cam = self.process.cam
|
cam = self.process.cam
|
||||||
@@ -159,10 +162,7 @@ class MultiWellManager:
|
|||||||
if self.stop_playing.is_set():
|
if self.stop_playing.is_set():
|
||||||
break
|
break
|
||||||
self.cnc_controller.move_to(wl.x, wl.y, feed=wl.multiwell.feed)
|
self.cnc_controller.move_to(wl.x, wl.y, feed=wl.multiwell.feed)
|
||||||
|
self._grid_scanning_capture(experiment, wl, simulate=simulate)
|
||||||
#uuid = f'{self.process.data.session}-{multiwell.position}-{wl.well.name}'
|
|
||||||
#self._grid_scanning_capture(uuid, multiwell.duration)
|
|
||||||
self._grid_scanning_capture(experiment, wl)
|
|
||||||
|
|
||||||
## change file
|
## change file
|
||||||
if self.process.conf.capture_type == 'file':
|
if self.process.conf.capture_type == 'file':
|
||||||
@@ -172,7 +172,7 @@ class MultiWellManager:
|
|||||||
self.cnc_controller.move_to(xnext, ynext, feed=multiwell.feed*2)
|
self.cnc_controller.move_to(xnext, ynext, feed=multiwell.feed*2)
|
||||||
|
|
||||||
|
|
||||||
def _start_scanning(self, session, experiments):
|
def _start_scanning(self, session, experiments, simulate=False):
|
||||||
self.process.cam._aligner.debug = False
|
self.process.cam._aligner.debug = False
|
||||||
xynext = []
|
xynext = []
|
||||||
for obs in experiments:
|
for obs in experiments:
|
||||||
@@ -189,7 +189,7 @@ class MultiWellManager:
|
|||||||
obs.save()
|
obs.save()
|
||||||
xnext, ynext = xynext[pos]
|
xnext, ynext = xynext[pos]
|
||||||
pos +=1
|
pos +=1
|
||||||
self._grid_scanning(obs, xnext=xnext, ynext=ynext)
|
self._grid_scanning(obs, xnext=xnext, ynext=ynext, simulate=simulate)
|
||||||
obs.finished = timezone.now()
|
obs.finished = timezone.now()
|
||||||
obs.save()
|
obs.save()
|
||||||
|
|
||||||
@@ -197,10 +197,12 @@ class MultiWellManager:
|
|||||||
if self.stop_playing.is_set():
|
if self.stop_playing.is_set():
|
||||||
msg = f"Session {session.name} abandonnée à {session.finished} après {session.finished - started} secondes."
|
msg = f"Session {session.name} abandonnée à {session.finished} après {session.finished - started} secondes."
|
||||||
else:
|
else:
|
||||||
session.active = False
|
if not simulate:
|
||||||
if session.scanning_task:
|
session.active = False
|
||||||
session.scanning_task.enabled = False
|
if session.scanning_task:
|
||||||
session.save()
|
session.scanning_task.enabled = False
|
||||||
|
session.save()
|
||||||
|
|
||||||
msg = f"Session {session.name} terminée à {session.finished} après {session.finished - started} secondes."
|
msg = f"Session {session.name} terminée à {session.finished} après {session.finished - started} secondes."
|
||||||
logger.info(msg)
|
logger.info(msg)
|
||||||
self.process._send(scan_state=msg)
|
self.process._send(scan_state=msg)
|
||||||
@@ -214,13 +216,13 @@ class MultiWellManager:
|
|||||||
self.process.cam._aligner.debug = False
|
self.process.cam._aligner.debug = False
|
||||||
|
|
||||||
|
|
||||||
def scanning(self, sid):
|
def scanning(self, sid, simulate=False):
|
||||||
try:
|
try:
|
||||||
if self.scan_thread:
|
if self.scan_thread:
|
||||||
return
|
return
|
||||||
session = models.Session.objects.get(pk=sid)
|
session = models.Session.objects.get(pk=sid)
|
||||||
experiments = models.SessionExperiment.experiment_by_session(sid)
|
experiments = models.SessionExperiment.experiment_by_session(sid)
|
||||||
self.scan_thread = Thread(target=self._start_scanning, args=(session, experiments, ), daemon=True).start()
|
self.scan_thread = Thread(target=self._start_scanning, args=(session, experiments, simulate, ), daemon=True).start()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("MultiWellManager::scan error", e)
|
print("MultiWellManager::scan error", e)
|
||||||
|
|
||||||
@@ -258,7 +260,7 @@ class MultiWellManager:
|
|||||||
self.stop_playing = Event()
|
self.stop_playing = Event()
|
||||||
cam = self.process.cam
|
cam = self.process.cam
|
||||||
cam._aligner.set_tube_diameter(self.multiwell.diameter)
|
cam._aligner.set_tube_diameter(self.multiwell.diameter)
|
||||||
duration = self.duration if not auto else settings.CALIBRATION_AUTO_DURATION
|
duration = self.duration if not auto else settings.CALIBRATION_AUTO_DURATION
|
||||||
try:
|
try:
|
||||||
start_test = time.monotonic()
|
start_test = time.monotonic()
|
||||||
for wl in self.well_iterator:
|
for wl in self.well_iterator:
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ class ScannerProcess(Task):
|
|||||||
if self.data.play:
|
if self.data.play:
|
||||||
try:
|
try:
|
||||||
jpeg=base64.b64encode(jpeg_bytes).decode()
|
jpeg=base64.b64encode(jpeg_bytes).decode()
|
||||||
logger.warning(f"{jpeg[:100]}")
|
#logger.warning(f"{jpeg[:100]}")
|
||||||
self._send(ts=ts.timestamp(), jpeg=jpeg, frame_count=frame_count)
|
self._send(ts=ts.timestamp(), jpeg=jpeg, frame_count=frame_count)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"----_on_frame: {e}")
|
logger.error(f"----_on_frame: {e}")
|
||||||
@@ -289,6 +289,8 @@ class ScannerProcess(Task):
|
|||||||
while not self.stop_event.is_set():
|
while not self.stop_event.is_set():
|
||||||
try:
|
try:
|
||||||
(uuid, ts, frame, metrics, frame_count) = self.record_queue.get()
|
(uuid, ts, frame, metrics, frame_count) = self.record_queue.get()
|
||||||
|
|
||||||
|
|
||||||
labels = dict(fps=self.video_fps, session=self.data.session, detected="1" if metrics.get("detected") else "0")
|
labels = dict(fps=self.video_fps, session=self.data.session, detected="1" if metrics.get("detected") else "0")
|
||||||
|
|
||||||
if metrics.get("detected"):
|
if metrics.get("detected"):
|
||||||
@@ -345,16 +347,16 @@ class ScannerProcess(Task):
|
|||||||
self.cam._active_median = False
|
self.cam._active_median = False
|
||||||
self.grbl.go_origin(feed=self.manager.feed)
|
self.grbl.go_origin(feed=self.manager.feed)
|
||||||
|
|
||||||
elif topic == 'scan':
|
elif topic == 'scan' or topic == 'simulate':
|
||||||
|
|
||||||
logger.info(f"==== Scan {cmd}")
|
logger.info(f"==== Scan {cmd}")
|
||||||
sid = cmd.get("session", '0')
|
sid = cmd.get("session", '0')
|
||||||
if sid == "0":
|
if sid == "0":
|
||||||
self._send(state='error', msg=str(_('La session est nulle!...')))
|
self._send(state='error', msg=str(_('La session est nulle!...')))
|
||||||
else:
|
else:
|
||||||
self.cam._active_median = False
|
self.cam._active_median = False
|
||||||
self.manager.scanning(sid)
|
self.manager.scanning(sid, simulate=(topic=='simulate'))
|
||||||
|
self._send(state=topic, msg=str(_('Balayage démarré...')))
|
||||||
|
|
||||||
elif cmd["type"]=="calibrate":
|
elif cmd["type"]=="calibrate":
|
||||||
topic = cmd.get("topic")
|
topic = cmd.get("topic")
|
||||||
value = cmd.get("value")
|
value = cmd.get("value")
|
||||||
|
|||||||
@@ -104,22 +104,24 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<a href="{% url 'scanner:main' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
<a href="{% url 'scanner:scanning' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
||||||
<i class="fa-solid fa-film w3-text-green w3-xlarge""></i> {% trans "Balayage multi-puits" %}
|
<i class="fa-solid fa-film w3-text-green w3-xlarge""></i> {% trans "Balayage multi-puits" %}
|
||||||
</a>
|
</a>
|
||||||
<a href="{% url 'planarian:experiment-list' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
{% if conf.tracking %}
|
||||||
|
<a href="{% url 'planarian:experiment-list' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
||||||
<i class="fa-solid fa-vials w3-text-lime w3-xlarge"></i> {% trans "Préparation des expériences" %}
|
<i class="fa-solid fa-vials w3-text-lime w3-xlarge"></i> {% trans "Préparation des expériences" %}
|
||||||
</a>
|
</a>
|
||||||
|
{% endif %}
|
||||||
<a href="{% url 'scanner:images' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
<a href="{% url 'scanner:images' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
||||||
<i class="fa-regular fa-images w3-text-cyan w3-xlarge" w3-xlarge""></i> {% trans "Gestionnaire d'images" %}
|
<i class="fa-regular fa-images w3-text-cyan w3-xlarge" w3-xlarge""></i> {% trans "Gestionnaire d'images" %}
|
||||||
</a>
|
</a>
|
||||||
<a href="{% url 'scanner:replay' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
<a href="{% url 'scanner:replay' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
||||||
<i class="fa-solid fa-podcast w3-text-ambe w3-xlarge"r"></i> {% trans "Redifusion vidéos" %}
|
<i class="fa-solid fa-podcast w3-text-ambe w3-xlarge"r"></i> {% trans "Redifusion vidéos" %}
|
||||||
</a>
|
</a>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
|
|
||||||
|
|||||||
+31
-22
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
{% block styles %}
|
{% block styles %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<link href="/static/scanner/css/main.css" rel="stylesheet">
|
<link href="/static/scanner/css/scanning.css" rel="stylesheet">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block columns %}{% endblock %}
|
{% block columns %}{% endblock %}
|
||||||
|
|
||||||
@@ -25,26 +25,34 @@
|
|||||||
<div class="w3-col w3-padding"><span id="_uuid"></span></div>
|
<div class="w3-col w3-padding"><span id="_uuid"></span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="w3-row w3-row-padding">
|
||||||
<div class="w3-col">
|
<div class="w3-half">
|
||||||
<button id="_median" class="w3-button w3-dark-xlight w3-round-large w3-padding-small w3-block">
|
<button id="_median" class="w3-button w3-dark-xlight w3-round-large w3-block">
|
||||||
{% trans 'Axes' %} <br><i class="fa-solid fa-crosshairs w3-text-amber w3-xlarge"></i>
|
{% trans 'Axes' %} <br><i class="fa-solid fa-crosshairs w3-text-amber w3-xlarge"></i>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="w3-half">
|
||||||
|
<button id="_crop" class="w3-button w3-dark-xlight w3-round-large w3-block">
|
||||||
|
{% trans 'Recadrer' %}<br><i class="fa-solid fa-crop w3-text-amber w3-xlarge"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w3-col">
|
<div class="w3-row w3-row-padding">
|
||||||
<button id="_crop" class="w3-button w3-dark-xlight w3-round-large w3-padding-top w3-margin-top w3-block">
|
<div class="w3-twothird">
|
||||||
{% trans 'Recadrer' %}<br><i class="fa-solid fa-crop w3-text-amber w3-xlarge"></i>
|
<button id="_scan" class="w3-button w3-light-blue w3-round-large w3-margin-top w3-block">
|
||||||
</button>
|
{% trans 'Lancer' %}<br>{% trans 'le balayage' %}<br><i class="fa-solid fa-circle-check w3-text-blue w3-xlarge"></i>
|
||||||
</div>
|
</button>
|
||||||
<div class="w3-col">
|
</div>
|
||||||
<button id="_scan" class="w3-button w3-dark-xlight w3-round-large w3-margin-top w3-block">
|
<div class="w3-third">
|
||||||
{% trans 'Lancer le balayage' %}<br><i class="fa-solid fa-circle-check w3-text-orange w3-xlarge"></i>
|
<button id="_scan" class="w3-button w3-dark-xlight w3-round-large w3-margin-top w3-block">
|
||||||
</button>
|
{% trans 'Simuler' %}<br>{% trans 'le balayage' %}<br><i class="fa-solid fa-triangle-exclamation w3-text-orange w3-xlarge"></i>
|
||||||
</div>
|
</button>
|
||||||
<div class="w3-col">
|
</div>
|
||||||
<button id="_halt" class="w3-button w3-red w3-round-large w3-margin-top w3-block">
|
<div class="w3-col">
|
||||||
{% trans 'ARRET' %}<br><i class="fa-solid fa-hand w3-xlarge"></i>
|
<button id="_halt" class="w3-button w3-red w3-round-large w3-margin-top w3-block">
|
||||||
</button>
|
{% trans 'ARRET' %}<br><i class="fa-solid fa-hand w3-xlarge"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w3-col">
|
<div class="w3-col">
|
||||||
<div class="w3-margin-top w3-padding w3-small">
|
<div class="w3-margin-top w3-padding w3-small">
|
||||||
@@ -85,10 +93,11 @@
|
|||||||
axial_pos : sId("_axial_pos"),
|
axial_pos : sId("_axial_pos"),
|
||||||
area_px : sId("_area_px"),
|
area_px : sId("_area_px"),
|
||||||
frame_count : sId("_count"),
|
frame_count : sId("_count"),
|
||||||
scan_state: sId("_scan_state")
|
scan_state : sId("_scan_state"),
|
||||||
|
simulate : sId("_simulate")
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<script src="/static/scanner/js/main.js"></script>
|
<script src="/static/scanner/js/scanning.js"></script>
|
||||||
<script>
|
<script>
|
||||||
const manager = new ScannerManager(container, options);
|
const manager = new ScannerManager(container, options);
|
||||||
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
||||||
@@ -14,7 +14,7 @@ urlpatterns = [
|
|||||||
path('logs/worker', views.supervisor_worker, name='logs_worker'),
|
path('logs/worker', views.supervisor_worker, name='logs_worker'),
|
||||||
path('logs/scheduler', views.supervisor_scheduler, name='logs_scheduler'),
|
path('logs/scheduler', views.supervisor_scheduler, name='logs_scheduler'),
|
||||||
|
|
||||||
path('main/', views.main_view, name='main'),
|
path('scanning/', views.scanning_view, name='scanning'),
|
||||||
path('images/', views.images_view, name='images'),
|
path('images/', views.images_view, name='images'),
|
||||||
path('replay/', views.replay_view, name='replay'),
|
path('replay/', views.replay_view, name='replay'),
|
||||||
path('api/stats/', views.stats_view, name='api_stats'),
|
path('api/stats/', views.stats_view, name='api_stats'),
|
||||||
|
|||||||
@@ -75,14 +75,14 @@ def supervisor_scheduler(request):
|
|||||||
|
|
||||||
## Mainboard
|
## Mainboard
|
||||||
@login_required
|
@login_required
|
||||||
def main_view(request):
|
def scanning_view(request):
|
||||||
ctx = dict(
|
ctx = dict(
|
||||||
ws_route=settings.SCANNER_WEBSOCKET_ROUTE,
|
ws_route=settings.SCANNER_WEBSOCKET_ROUTE,
|
||||||
columns=1,
|
columns=1,
|
||||||
sessions=models.Session.objects.filter(active=True).all(),
|
sessions=models.Session.objects.filter(active=True).all(),
|
||||||
choice_title=_("Balayage multi-puits")
|
choice_title=_("Balayage multi-puits")
|
||||||
)
|
)
|
||||||
return render(request, "scanner/main.html", context=global_context(request, **ctx))
|
return render(request, "scanner/scanning.html", context=global_context(request, **ctx))
|
||||||
|
|
||||||
## Calibration
|
## Calibration
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
Reference in New Issue
Block a user