From 3f870d7462d207362e65377c8310fde1b2ed28d9 Mon Sep 17 00:00:00 2001 From: denis defolie Date: Tue, 28 Apr 2026 17:41:07 +0200 Subject: [PATCH] constants --- README.md | 35 +++++++++++++++++++ test_tube_scanner/home/settings.py | 1 + test_tube_scanner/planarian/models.py | 7 ++-- test_tube_scanner/scanner/constants.py | 47 ++++++++++++++++++++++++++ test_tube_scanner/scanner/process.py | 4 ++- test_tube_scanner/scanner/views.py | 32 +++--------------- 6 files changed, 95 insertions(+), 31 deletions(-) create mode 100644 test_tube_scanner/scanner/constants.py diff --git a/README.md b/README.md index defd618..a2963fc 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,41 @@ d'analyse distantes. - Interface administration Django (sqlite3 ou mariadb ou postgresql) - Suivi de progression des tâches longues par polling +## Planaire simulation de mouvement aléatoire + +Supporte plusieurs planaires avec paramètres configurables via arguments CLI. +Export CSV par planaire compatible EthoVision XT. + +Seuils EthoVision par défaut (configurables en arguments) : + +- Immobile : déplacement < 0.2 mm/s +- Mobile : 0.2 à 1.5 mm/s +- Très mobile : > 1.5 mm/s + +- EthoVision CSV frames CSV summary +- ========== ========== =========== +- movedCenter-pointTotalmm total_distance_mm movedCenter_pointTotal_mm +- VelocityCenter-pointMeanmm/s velocity_mm_s velocity_mean_mm_s +- MovementMoving moving, duration_moving_s movement_moving_duration_s +- MovementNot Moving duration_stopped_s movement_not_moving_duration_s +- ImmobileFrequency / Duration mobility_state mobility_immobile_frequency/duration_s +- MobileFrequency / Duration mobility_state mobility_mobile_frequency/duration_s +- Highly mobileFrequency / Duration mobility_state mobility_highly_mobile_frequency/duration_s + + +Métriques calculées : + - Distance totale parcourue (mm) → movedCenter-pointTotalmm + - Vitesse instantanée (mm/s) → VelocityCenter-pointMeanmm/s + - Durée cumulée en mouvement (s) → MovementMoving + - Durée cumulée à l'arrêt (s) → MovementNot Moving + - Fréquence et durée par état de mobilité → Mobility state (EthoVision) + - Distance à la paroi (mm) → thigmotactisme + +Comportements simulés : + - Thigmotactisme : attraction vers la paroi (--thigmotaxis) + - Phototactisme : fuite de la lumière (--photo-mode, --photo-strength) + - Chimiotactisme : attraction vers une source de nourriture (--chemo-strength) + - Inter-individus : évitement de contact, agrégation, répulsion chimique --- ## Architecture diff --git a/test_tube_scanner/home/settings.py b/test_tube_scanner/home/settings.py index 8fd1d94..4ab3a33 100644 --- a/test_tube_scanner/home/settings.py +++ b/test_tube_scanner/home/settings.py @@ -401,3 +401,4 @@ TRACKER_MIN_AREA = 200 CALIBRATION_AUTO_DURATION = 45.0 CALIBRATION_AUTO_TIMEOUT = 2.5 + diff --git a/test_tube_scanner/planarian/models.py b/test_tube_scanner/planarian/models.py index ed2a7fd..ede3498 100644 --- a/test_tube_scanner/planarian/models.py +++ b/test_tube_scanner/planarian/models.py @@ -3,10 +3,11 @@ from django.db import models from django.dispatch import receiver from django.db.models.signals import post_save - +from django.conf import settings from django.utils.translation import gettext_lazy as _ from django.contrib.auth.models import User -from scanner.models import Experiment, Well, WellPosition, Configuration +from scanner.models import Experiment, Well, WellPosition +from scanner.constants import ScannerConstants class ExperimentConfig(models.Model): """ @@ -155,7 +156,7 @@ def create_well_position(sender, instance, created, **kwargs): active_well = WellPosition.active_well(instance.multiwel, instance.well) instance.px_per_mm = active_well.px_per_mm instance.well_radius_mm = instance.experiment.multiwell.diameter / 2 - conf = Configuration.active_config() + conf = ScannerConstants().get() instance.fps = conf.video_frame_rate instance.save() diff --git a/test_tube_scanner/scanner/constants.py b/test_tube_scanner/scanner/constants.py new file mode 100644 index 0000000..163a6cd --- /dev/null +++ b/test_tube_scanner/scanner/constants.py @@ -0,0 +1,47 @@ +''' +Created on 28 avr. 2026 + +@author: denis +''' +from dataclasses import dataclass, asdict +from .models import Configuration + +@dataclass +class DefaultConfig: + """Constantes par défaut - utilisées en cas de problème BD""" + sidebar_width: str = "25%" + default_grid_columns: int = 3 + opencv_fourcc_format: str = 'mp4v' + opencv_video_type: str = 'mp4' + grbl_xmax: float = 350.0 + grbl_ymax: float = 250.0 + capture_type: str = 'rpi' + webcam_device_index: int = 2 + image_quality: int = 90 + video_jpeg_quality: int = 90 + video_frame_rate: int = 5.0 + video_width_capture: int = 2028 + video_height_capture: int = 1520 + calibration_crop_radius: int = 500 + calibration_default_multiwell: str = 'HD' + calibration_default_feed: int = 1000 + calibration_default_step: float = 1.0 + calibration_default_duration: float = 3.0 + tracking: bool = False + + +class ScannerConstants: + + def __init__(self): + self.conf = DefaultConfig() + d = asdict(self.conf) + v = d.keys() + lst = Configuration.objects.filter(active=True).values(*v) + if lst: + values = lst[0] + self.conf = DefaultConfig(**values) + + def get(self): + return self.conf + + \ No newline at end of file diff --git a/test_tube_scanner/scanner/process.py b/test_tube_scanner/scanner/process.py index 7d0b90a..f46dee5 100644 --- a/test_tube_scanner/scanner/process.py +++ b/test_tube_scanner/scanner/process.py @@ -26,8 +26,10 @@ from modules import reductstore, grbl, utils ## camera devices from modules.circular_crop import CircularCrop, CropStrategy from .multiwell import MultiWellManager +from .constants import ScannerConstants from . import models + @dataclass class ProcessData: play: bool = True @@ -160,7 +162,7 @@ class ScannerProcess(Task): def start(self, *args, **kwargs): try: - self.conf = models.Configuration.objects.filter(active=True).first() + self.conf = ScannerConstants().get() self.use_tracking = self.conf.tracking self.video_quality = self.conf.video_jpeg_quality diff --git a/test_tube_scanner/scanner/views.py b/test_tube_scanner/scanner/views.py index 9fa61aa..7100e3a 100644 --- a/test_tube_scanner/scanner/views.py +++ b/test_tube_scanner/scanner/views.py @@ -11,39 +11,15 @@ from django.conf import settings from reduct.time import unix_timestamp_to_iso from modules.system_stats import get_cached_stats, start_background_updater from modules import reductstore -from dataclasses import dataclass from .tasks import download_video, export_all_images, export_all_videos from .process import CameraRecordManager, cameraDB from . import models +from .constants import ScannerConstants -@dataclass -class DefaultConfig: - sidebar_width: str = "25%" - default_grid_columns: int = 3 - opencv_fourcc_format: str = 'mp4v' - opencv_video_type: str = 'mp4' - grbl_xmax: float = 350.0 - grbl_ymax: float = 250.0 - capture_type: str = 'rpi' - webcam_device_index: int = 2 - image_quality: int = 90 - video_jpeg_quality: int = 90 - video_frame_rate: int = 5.0 - video_width_capture: int = 2028 - video_height_capture: int = 1520 - calibration_crop_radius: int = 500 - calibration_default_multiwell: str = 'HD' - calibration_default_feed: int = 1000 - calibration_default_step: float = 1.0 - calibration_default_duration: float = 3.0 - tracking: bool = False - - -default_conf = DefaultConfig() record_manager = CameraRecordManager(cameraDB) start_background_updater() - + @require_GET def stats_view(request): @@ -58,7 +34,9 @@ def stats_view(request): def global_context(request, **ctx): default_multiwell = models.MultiWell.objects.filter(default=True).first() - conf = models.Configuration.active_config() or default_conf + conf = ScannerConstants().get() + + print(conf, type(conf)) return dict( app_title=settings.APP_TITLE, app_sub_title=settings.APP_SUB_TITLE,