Files
PlanarianScanner/CONTEXT.md
T
denis defolie c6145f250b readme&context
2026-07-10 10:02:20 +02:00

9.8 KiB
Raw Blame History

PlanarianScanner — Contexte technique

Système d'imagerie automatisé pour le suivi comportemental de planaires (Platyhelminthes). Développé par dd@linuxtarn.org pour le Laboratoire de Biologie, Université Champollion, Albi.


Matériel cible

Composant Détail
Carte Raspberry Pi 4
Caméra ArduCam haute définition (Picamera2)
Motorisation Bras CNC L2544 piloté en GRBL via port série
Grille 4 plaques multi-puits de 6×4 = 96 puits (Ø 16 mm)
Réseau LAN — export Samba (CIFS) / rsync SSH

Stack technique

Couche Technologie
Backend Django 5.1 + Django Channels (WebSocket)
Serveur ASGI Daphne
Broker/cache Redis
Tâches async Celery + django-celery-beat (one-shot via ClockedSchedule)
Vision OpenCV (headless) + Picamera2
Stockage frames ReductStore (base time série haute performance)
BDD MariaDB (prod) — sqlite3 (dev)
Export distant Samba client (CIFS) / rsync
Plateforme Raspberry Pi 4, Debian 64-bit Trixie
Python 3.13 — venv dans .venv/

Structure du dépôt

PlanarianScanner/
├── etc/                        # Scripts d'installation et configs système
│   ├── 1-install-sys.sh        # Dépendances système
│   ├── 2-cargo-reductstore-install.sh  # Build ReductStore (~15 min sur RPi4)
│   ├── 3-install-samba-client.sh
│   ├── 4-install_mariadb.sh
│   ├── 5-install_adminer.sh
│   ├── 6-install_django_app.sh # Init Django (migrations, fixtures, collectstatic)
│   ├── db/                     # Fixtures JSON initiales (configuration, multiwell, well)
│   ├── requirements.txt
│   ├── scanner_service.conf    # Supervisor : Django + Celery workers
│   ├── reductstore_service.conf
│   └── nginx_service.conf
├── datas/                      # Données hors Django (gitignored)
│   ├── medias/                 # Images et vidéos capturées
│   ├── exports/csv/            # Exports CSV EthoVision
│   ├── remote/exports/         # Dossier cible des transferts distants
│   └── backup/mariadb/         # Sauvegardes MariaDB
├── assets/                     # Logo, screenshots
├── test_tube_scanner/          # Racine du projet Django
│   ├── home/                   # Package projet (settings, urls, wsgi, asgi, celery)
│   ├── scanner/                # App scanner (CNC, multi-puits, sessions, exports)
│   ├── planarian/              # App suivi planaires (métriques, export CSV)
│   ├── modules/                # Modules partagés (capture, GRBL, tracker, metrics…)
│   ├── manage.py
│   ├── run-server.sh
│   ├── run-workers.sh
│   ├── planarian_sim.py        # Simulateur standalone (CLI)
│   └── .env / .env.example
└── browser.py                  # Ouverture navigateur local (utilitaire)

Applications Django

scanner — Pilotage CNC et acquisition

Modèles principaux :

Modèle Rôle
Configuration Config globale active (caméra, GRBL, tracking, calibration)
MultiWell Plaque multi-puits (position HG/HD/BG/BD, grille 6×4, pas XY, crop_radius)
Well Puit individuel (nom Ai..Di)
WellPosition Position XY mm d'un puit dans un MultiWell + px_per_mm (calibration optique caméra)
VideoPlate Vidéo plaque entière associée à un MultiWell — champs : px_per_mm (échelle vidéo ~15 px/mm), x_origin_mm / y_origin_mm (origine CNC stable, indépendante de la calibration)
Experiment Session de capture sur un MultiWell (durée, début/fin)
Session Groupe d'expériences avec planification (ClockedSchedule one-shot)
SessionExperiment Liaison Session ↔ Experiment
ExperimentWell Liaison Experiment ↔ Well (puits actifs)

Signaux Django :

  • post_save(MultiWell) → génère automatiquement les WellPosition en serpentin
  • post_save(Session) → crée les PeriodicTask Celery Beat (export + scanning)
  • post_delete(Session) → supprime les PeriodicTask associées

Tâches Celery (scanner/tasks.py, scanner/export_tasks.py) :

  • run_scanning(session_id) — parcours serpentin des puits (GRBL + capture)
  • run_session_exports(session_id) — génération ZIP JPEG + MP4 + transfert distant

planarian — Suivi multi-individus et métriques

Modèle ExperimentConfig : paramètres de tracking par puit (px_per_mm, fps, seuils).


Modules partagés (modules/)

Module Rôle
grbl.py Pilotage CNC via port série (G-code, homing, déplacement XY)
grbl_simulator.py Simulateur GRBL pour dev sans matériel
capture_interface.py Interface abstraite de capture — crop circulaire, edge enhance, debug overlay, tracking
picamera2_capture.py Capture ArduCam via Picamera2
webcam_capture.py Capture webcam via OpenCV
videofile_capture.py Lecture fichier vidéo (test/sim)
videoplate_capture.py Capture par crop dynamique dans une vidéo plaque entière — position GRBL → région extraite, hot swap vidéo, plein cadre à l'origine
planarian_tracker.py Tracking multi-individus : MOG2 + algorithme hongrois (scipy)
planarian_metrics.py Métriques par frame et summary (mobilité, thigmo, photo, chemo, social)
tube_aligner.py Détection HoughCircles + CLAHE, calibration optique, plage rayon configurable (set_radius_range)
circular_crop.py Découpe circulaire des images de puit
reductstore.py Interface ReductStore (stockage/lecture frames time série)
system_stats.py Stats système (CPU, RAM, disque — affichage dashboard)

Métriques de tracking

Par frame : velocity, distance, moving, mobility_state, dist_to_wall_mm, near_wall, dist_to_light_mm, heading_to_light_deg, fleeing_light, dist_to_food_mm, heading_to_food_deg, approaching_food, in_food_zone, nearest_neighbour_mm, in_avoid_zone, in_aggreg_zone, chem_repulsion_level.

Summary : totaux et pourcentages EthoVision-compatibles pour mobilité, thigmotactisme, phototactisme, chimiotactisme, interactions sociales.

Export CSV compatible EthoVision XT.


Configuration runtime

Fichier .env (python-decouple) dans test_tube_scanner/ :

SECRET_KEY, DEBUG, DOMAIN_SERVER, ALLOWED_HOSTS, CSRF_TRUSTED_ORIGINS
APP_DATAS          # chemin relatif vers datas/ (ex: ../datas)
DJANGO_APP         # nom de l'app (home)
REDIS_URL          # ex: redis://localhost:6379/0
REDUCTSTORE_URL    # ex: http://localhost:8383
DB_*               # MariaDB credentials

Démarrage des services

Tous gérés par Supervisor :

# Interface web Supervisor
http://root:toor@<ip>:9001

# CLI
sudo supervisorctl start|stop|restart reductstore
sudo supervisorctl start|stop|restart test_tube:*

En dev :

cd test_tube_scanner
./manage.py runserver 0.0.0.0:8000
# Workers Celery séparés :
./run-workers.sh

Accès réseau : ajouter <ip-rpi4> scanner.local dans /etc/hosts des clients.


Simulateur standalone

test_tube_scanner/planarian_sim.py — simulation CLI d'une arène circulaire (Ø 16 mm, 500×500 px), export CSV EthoVision par planaire.

python3 planarian_sim.py --count 5 --thigmotaxis 0.4
python3 planarian_sim.py --count 5 --photo-mode fixed --photo-x 0.2 --photo-y 0.2 --photo-strength 0.6

test_tube_scanner/make_videos.sh — génération de 24 vidéos de simulation (une par puit).


Mode capture vidéo plaque (capture_type == 'video')

Alternative à la caméra ArduCam : une vidéo de la plaque entière enregistrée une fois, rejouée en boucle pendant les scans. Adapté aux labos sans Raspberry Pi ou pour tests hors matériel.

Flux

VideoPlateCapture.capture_frame()
  → lit la frame courante de la vidéo
  → extrait un carré 2r×2r centré sur (GRBL_x, GRBL_y) converti en pixels
  → si GRBL à (0,0) : retourne la frame entière (vue plaque)
  → sinon          : retourne le crop du puit courant
→ process_frame()
  → edge_enhance (optionnel, CLAHE + Canny overlay vert)
  → TubeAligner.detect_tube() (optionnel, debug HoughCircles)
  → crop circulaire (optionnel)

Calibration vidéo

  • VideoPlate.px_per_mm : échelle de la vidéo (~15 px/mm) — différent de WellPosition.px_per_mm (~50 px/mm, optique caméra)
  • VideoPlate.x_origin_mm / y_origin_mm : position CNC correspondant au pixel (0,0) de la vidéo — stable, jamais modifiée par la calibration des puits
  • MultiWell.crop_radius : rayon du crop en pixels — contrôle la taille de la vue par puit

Contrôles calibration UI (boutons)

Bouton Action
Debug Active TubeAligner.debug — détection HoughCircles en continu
Overlay Affiche/masque les annotations de détection sans couper la détection
Contours Active edge enhance (CLAHE + Canny overlay vert) sur la frame propre
Recadrer Active le crop circulaire + navigue vers la position Base (mode vidéo)

TubeAligner.set_radius_range(min_ratio, max_ratio)

Ajuste la plage de recherche HoughCircles en fraction de min(w,h) :

  • Mode caméra : 0.260.37 (tube occupe ~30% du champ)
  • Mode vidéo : 0.380.47 (puit remplit le crop, ratio ~0.430.50)

Déploiement réseau isolé (labo sans internet)

GitHub ←→ Portable (internet) ←→ Routeur OpenWrt ←→ Machine labo (SSH)

Mise à jour sans internet :

# Sur la machine labo (une fois)
git config receive.denyCurrentBranch updateInstead

# Sur le portable — ajouter le labo comme remote
git remote add labo ssh://user@<ip-labo>/chemin/PlanarianScanner

# Workflow répétable
git pull origin video-plate-calibration   # portable ← GitHub
git push labo video-plate-calibration     # labo ← portable

Licence

GPL-3.0