trombinoscope 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trombinoscope-0.1.0/.gitignore +38 -0
- trombinoscope-0.1.0/CHANGELOG.md +141 -0
- trombinoscope-0.1.0/CREDITS.md +99 -0
- trombinoscope-0.1.0/LICENSE +21 -0
- trombinoscope-0.1.0/PKG-INFO +216 -0
- trombinoscope-0.1.0/README.md +179 -0
- trombinoscope-0.1.0/docs/DOC.md +491 -0
- trombinoscope-0.1.0/docs/color.md +269 -0
- trombinoscope-0.1.0/docs/improvements.md +166 -0
- trombinoscope-0.1.0/docs/legacy-review.md +295 -0
- trombinoscope-0.1.0/docs/prior-art.md +287 -0
- trombinoscope-0.1.0/examples/trombi_mp_sqlite.py +270 -0
- trombinoscope-0.1.0/pyproject.toml +125 -0
- trombinoscope-0.1.0/scripts/check_no_photos.py +71 -0
- trombinoscope-0.1.0/scripts/color_bench.py +233 -0
- trombinoscope-0.1.0/scripts/fetch_samples.py +201 -0
- trombinoscope-0.1.0/scripts/make_placeholder.py +52 -0
- trombinoscope-0.1.0/src/trombinoscope/__init__.py +96 -0
- trombinoscope-0.1.0/src/trombinoscope/__main__.py +8 -0
- trombinoscope-0.1.0/src/trombinoscope/assets/models/face_detection_yunet_2023mar.onnx +0 -0
- trombinoscope-0.1.0/src/trombinoscope/assets/placeholder.png +0 -0
- trombinoscope-0.1.0/src/trombinoscope/cli.py +251 -0
- trombinoscope-0.1.0/src/trombinoscope/color.py +479 -0
- trombinoscope-0.1.0/src/trombinoscope/detection.py +236 -0
- trombinoscope-0.1.0/src/trombinoscope/framing.py +130 -0
- trombinoscope-0.1.0/src/trombinoscope/imageio.py +192 -0
- trombinoscope-0.1.0/src/trombinoscope/log.py +62 -0
- trombinoscope-0.1.0/src/trombinoscope/models.py +345 -0
- trombinoscope-0.1.0/src/trombinoscope/pdf/__init__.py +13 -0
- trombinoscope-0.1.0/src/trombinoscope/pdf/canvas.py +232 -0
- trombinoscope-0.1.0/src/trombinoscope/pdf/grid.py +334 -0
- trombinoscope-0.1.0/src/trombinoscope/pipeline.py +220 -0
- trombinoscope-0.1.0/src/trombinoscope/roster.py +219 -0
- trombinoscope-0.1.0/tests/__init__.py +0 -0
- trombinoscope-0.1.0/tests/conftest.py +185 -0
- trombinoscope-0.1.0/tests/test_cli.py +229 -0
- trombinoscope-0.1.0/tests/test_color.py +383 -0
- trombinoscope-0.1.0/tests/test_detection.py +148 -0
- trombinoscope-0.1.0/tests/test_framing.py +200 -0
- trombinoscope-0.1.0/tests/test_grid.py +265 -0
- trombinoscope-0.1.0/tests/test_imageio.py +150 -0
- trombinoscope-0.1.0/tests/test_models.py +162 -0
- trombinoscope-0.1.0/tests/test_pipeline.py +222 -0
- trombinoscope-0.1.0/tests/test_roster.py +235 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Photographies : le dépôt n'en contient aucune, et ne doit jamais en contenir.
|
|
2
|
+
# Les tests d'intégration les téléchargent via scripts/fetch_samples.py.
|
|
3
|
+
tests/data/portraits/
|
|
4
|
+
*.jpg
|
|
5
|
+
*.jpeg
|
|
6
|
+
*.heic
|
|
7
|
+
*.heif
|
|
8
|
+
# Exception : la silhouette de remplacement, dessinée par scripts/make_placeholder.py
|
|
9
|
+
!src/trombinoscope/assets/placeholder.png
|
|
10
|
+
|
|
11
|
+
# Sorties de travail
|
|
12
|
+
artifacts/
|
|
13
|
+
portraits/
|
|
14
|
+
detections/
|
|
15
|
+
*.pdf
|
|
16
|
+
|
|
17
|
+
# Python
|
|
18
|
+
__pycache__/
|
|
19
|
+
*.py[cod]
|
|
20
|
+
*.egg-info/
|
|
21
|
+
build/
|
|
22
|
+
dist/
|
|
23
|
+
.venv/
|
|
24
|
+
venv/
|
|
25
|
+
|
|
26
|
+
# Outils
|
|
27
|
+
.pytest_cache/
|
|
28
|
+
.ruff_cache/
|
|
29
|
+
.mypy_cache/
|
|
30
|
+
.coverage
|
|
31
|
+
coverage.xml
|
|
32
|
+
htmlcov/
|
|
33
|
+
|
|
34
|
+
# Systèmes
|
|
35
|
+
.DS_Store
|
|
36
|
+
Thumbs.db
|
|
37
|
+
.vscode/
|
|
38
|
+
.idea/
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Journal des modifications
|
|
2
|
+
|
|
3
|
+
Le format suit [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/) et le
|
|
4
|
+
versionnage sémantique.
|
|
5
|
+
|
|
6
|
+
## [Non publié]
|
|
7
|
+
|
|
8
|
+
## [0.1.0]
|
|
9
|
+
|
|
10
|
+
Première version publique. C'est la réécriture d'un module personnel de 2020,
|
|
11
|
+
jamais publié, qui produisait les trombinoscopes d'une classe préparatoire.
|
|
12
|
+
|
|
13
|
+
### Ajouté
|
|
14
|
+
|
|
15
|
+
- Interface en ligne de commande `trombinoscope` avec trois sous-commandes :
|
|
16
|
+
`build`, `inspect` et `template`.
|
|
17
|
+
- `BatchColorHarmonizer` : harmonisation colorimétrique **à l'échelle du lot**,
|
|
18
|
+
en deux passes, vers l'illuminant et la luminance médians de la séance. C'est
|
|
19
|
+
la seule fonction que les bibliothèques de correction couleur existantes ne
|
|
20
|
+
fournissent pas — elles travaillent toutes image par image. Sur une séance
|
|
21
|
+
simulée, la dispersion chromatique chute de 78 %.
|
|
22
|
+
- Estimateurs d'illuminant `GrayWorldEstimator`, `ShadesOfGrayEstimator`
|
|
23
|
+
(défaut, `p = 6`) et `WhitePatchEstimator`, calculés **en lumière linéaire**.
|
|
24
|
+
- `LuminanceMatcher` : normalisation d'exposition par correction gamma, mesurée
|
|
25
|
+
sur le visage et non sur l'image entière.
|
|
26
|
+
- Paramètre `strength` pour atténuer la correction de teinte.
|
|
27
|
+
- `PortraitFramer` : recadrage à proportion de visage constante, et redressement
|
|
28
|
+
optionnel de la ligne des yeux (`align_eyes`).
|
|
29
|
+
- Détection par YuNet, avec les cinq points caractéristiques. Le détecteur est un
|
|
30
|
+
protocole injectable.
|
|
31
|
+
- `RosterLoader` : lecture CSV et JSON, séparateur détecté, en-têtes reconnus
|
|
32
|
+
sans tenir compte de la casse ni des accents, colonnes inconnues ignorées.
|
|
33
|
+
- `load_sqlite` : liste chargée depuis une requête SQLite libre, base ouverte en
|
|
34
|
+
lecture seule, colonnes nommées avec `AS` pour traduire un schéma métier.
|
|
35
|
+
- `GridConfig.title_top` et `title_skip` se comptent en **hauteurs de ligne**
|
|
36
|
+
(multiples de `font_size`) et non en millimètres, de sorte que l'espacement du
|
|
37
|
+
titre suive sa taille. `PdfCanvas.draw_paragraph` tient désormais compte des
|
|
38
|
+
`spaceBefore` / `spaceAfter` du style, comme un flowable ReportLab.
|
|
39
|
+
- `GridConfig.annotation_layout`, `badge_corner`, `badge_inset`, `logo_position`,
|
|
40
|
+
`logo_width`, `logo_margin` et `logo_offset` : placement des annotations
|
|
41
|
+
pivotées, de l'étoile et du logo. Le logo se pose par défaut en haut à droite,
|
|
42
|
+
et l'étoile est centrée sur le coin de la photo.
|
|
43
|
+
- `examples/trombi_mp_sqlite.py` : reproduction d'un trombinoscope de classe
|
|
44
|
+
préparatoire depuis sa base SQLite, avec la mise en page historique.
|
|
45
|
+
- `BuildReport` : rapport structuré des personnes sans photo, photos sans
|
|
46
|
+
personne, photos sans visage et photos à plusieurs visages.
|
|
47
|
+
- `GridPaginator` : pagination testable indépendamment de ReportLab.
|
|
48
|
+
- Lecture des fichiers HEIC via l'extra `[heic]`.
|
|
49
|
+
- 322 tests, dont l'essentiel tourne sur des images synthétiques et un détecteur
|
|
50
|
+
bouchon : ni réseau, ni modèle, ni photographie. Intégration continue sur
|
|
51
|
+
Linux, macOS et Windows, en Python 3.11 à 3.14.
|
|
52
|
+
- Documentation : [étude colorimétrique](docs/color.md), [état de l'art et étude
|
|
53
|
+
d'originalité](docs/prior-art.md), [pistes d'amélioration](docs/improvements.md),
|
|
54
|
+
[revue du module de 2020](docs/legacy-review.md).
|
|
55
|
+
|
|
56
|
+
### Corrigé
|
|
57
|
+
|
|
58
|
+
Défauts de la version 2020. L'analyse détaillée, extraits de code à l'appui, est
|
|
59
|
+
dans [docs/legacy-review.md](docs/legacy-review.md) ; le code source, lui, ne
|
|
60
|
+
commente que ce qu'il fait.
|
|
61
|
+
|
|
62
|
+
- **La correction colorimétrique était inopérante.**
|
|
63
|
+
`cv2.convertScaleAbs(image, alpha, beta)` place `alpha` en position `dst` et
|
|
64
|
+
`beta` en position `alpha` — la signature réelle est
|
|
65
|
+
`convertScaleAbs(src, dst, alpha, beta)`. Le gain calculé n'était jamais
|
|
66
|
+
appliqué et les images ressortaient saturées. Un test de non-régression
|
|
67
|
+
verrouille l'appel nommé. Détail dans [docs/color.md](docs/color.md).
|
|
68
|
+
- **L'appariement se décalait silencieusement.** Une photo sur laquelle aucun
|
|
69
|
+
visage n'était trouvé faisait `continue` sans avancer l'indice de la personne :
|
|
70
|
+
toutes les suivantes changeaient de photo. L'appariement est désormais résolu
|
|
71
|
+
avant toute détection.
|
|
72
|
+
- **Les annotations se retrouvaient sous les mauvaises photos** quand la dernière
|
|
73
|
+
ligne était centrée : placement et annotations recalculaient l'indice de la
|
|
74
|
+
personne de deux façons incompatibles. Une `IndexError` était même possible sur
|
|
75
|
+
une dernière ligne incomplète.
|
|
76
|
+
- **`UnboundLocalError`** lorsque les groupes étaient affichés sans étiquettes :
|
|
77
|
+
la coordonnée `x` n'était calculée que dans la branche des étiquettes.
|
|
78
|
+
- **Exception sur les cadrages débordant** de la photo source, par recollage
|
|
79
|
+
manuel de tranches de tableau.
|
|
80
|
+
- **Division par zéro** de l'étalement d'histogramme sur une image uniforme.
|
|
81
|
+
- **Étalement calculé sur l'image entière**, donc sur le fond plutôt que sur le
|
|
82
|
+
sujet.
|
|
83
|
+
- **Chemins non-ASCII** : `cv2.imread` et `cv2.imwrite` échouent silencieusement
|
|
84
|
+
sous Windows ; la lecture et l'écriture passent par `imdecode` / `imencode`.
|
|
85
|
+
- **`os.system` avec un chemin concaténé** dans l'ouverture du PDF : un espace ou
|
|
86
|
+
une apostrophe cassait la commande.
|
|
87
|
+
- **Sensibilité à la casse du système de fichiers** devinée en écrivant un
|
|
88
|
+
fichier temporaire dans le dossier de l'utilisateur, avec un cache partagé
|
|
89
|
+
entre tous les dossiers.
|
|
90
|
+
- **Déduplication en O(n²)** par `os.path.samefile`.
|
|
91
|
+
|
|
92
|
+
### Modifié
|
|
93
|
+
|
|
94
|
+
- **Modèle de détection** : SSD ResNet-10 Caffe (10 Mo) remplacé par YuNet ONNX
|
|
95
|
+
(227 Ko), qui fournit en plus les points caractéristiques. L'arborescence
|
|
96
|
+
d'origine transportait 142 Mo de modèles, dont 132 Mo jamais chargés par le
|
|
97
|
+
code — le prédicteur 68 points de dlib et un fichier PyTorch. `readNetFromCaffe`
|
|
98
|
+
a par ailleurs disparu d'OpenCV 5 : l'ancienne approche n'était plus viable.
|
|
99
|
+
- **`Eleve` devient `Person`.** Les champs de prépa française (`cube`, `LV1`,
|
|
100
|
+
`LV2`, `option`, `groupe`, `groupecolle`) laissent place à deux listes libres
|
|
101
|
+
d'étiquettes, qui couvrent le cas d'origine sans imposer son vocabulaire. Table
|
|
102
|
+
de correspondance dans [docs/DOC.md](docs/DOC.md), section 10.
|
|
103
|
+
- **`trombinoscope/logging.py` devient `trombinoscope/log.py`** et s'appuie sur
|
|
104
|
+
la bibliothèque standard. L'ancien nom masquait `logging` pour tout import
|
|
105
|
+
absolu depuis l'intérieur du paquet.
|
|
106
|
+
- **`warning()` ne bloque plus sur `input()`.** La pause interactive devient un
|
|
107
|
+
choix explicite de l'appelant, désactivé par défaut.
|
|
108
|
+
- **Aucun modèle n'est chargé à l'import.** Le réseau était construit au niveau
|
|
109
|
+
module : un simple `import trombinoscope` le payait, et échouait si le fichier
|
|
110
|
+
manquait, même pour n'utiliser que la mise en page.
|
|
111
|
+
- **`pkg_resources` remplacé par `importlib.resources`** — le premier a disparu
|
|
112
|
+
de Python 3.12.
|
|
113
|
+
- **Le module local `pdf_maker` (412 lignes, non publié) est réduit** à ce dont
|
|
114
|
+
le trombinoscope a besoin. La grille est dessinée directement sur le canevas
|
|
115
|
+
plutôt qu'avec des tableaux ReportLab imbriqués, ce qui rend la position des
|
|
116
|
+
annotations traçable.
|
|
117
|
+
- **Dépendance `opencv-python-headless`** plutôt que `opencv-python` : aucune
|
|
118
|
+
bibliothèque graphique système requise.
|
|
119
|
+
- **L'étalement d'histogramme est désactivé par défaut.** Une fois son bug
|
|
120
|
+
corrigé, la mesure montre qu'il dégrade la cohérence du lot.
|
|
121
|
+
- **La rotation de redressement des yeux** utilisait l'opposé de l'inclinaison,
|
|
122
|
+
ce qui l'aurait doublée au lieu de la corriger. Détecté par un test lors de la
|
|
123
|
+
réécriture ; la fonctionnalité n'avait jamais été branchée dans la version
|
|
124
|
+
d'origine.
|
|
125
|
+
|
|
126
|
+
### Supprimé
|
|
127
|
+
|
|
128
|
+
- Toutes les photographies personnelles : portraits d'élèves, PDF de
|
|
129
|
+
trombinoscopes nominatifs, logo d'établissement. Le dépôt ne contient plus
|
|
130
|
+
aucune image de personne, et la CI vérifie qu'il n'en apparaît ni dans le dépôt
|
|
131
|
+
ni dans la roue. Les tests d'intégration téléchargent à la demande des
|
|
132
|
+
portraits sous licence libre — voir [CREDITS.md](CREDITS.md).
|
|
133
|
+
- `FaceAligner` et le prédicteur 68 points de dlib (95 Mo), jamais utilisés : le
|
|
134
|
+
redressement se fait maintenant avec les points de YuNet, dans la même
|
|
135
|
+
transformation affine que le recadrage.
|
|
136
|
+
- Le fichier `HR18-300W.pth` (37 Mo), auquel aucun code ne faisait référence.
|
|
137
|
+
- Le cache `photos.pkl` écrit dans le dossier de l'utilisateur.
|
|
138
|
+
- Le guide ReportLab en PDF (548 Ko) versionné dans l'arborescence.
|
|
139
|
+
|
|
140
|
+
[Non publié]: https://github.com/antnardo/trombinoscope/compare/v0.1.0...HEAD
|
|
141
|
+
[0.1.0]: https://github.com/antnardo/trombinoscope/releases/tag/v0.1.0
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Crédits et licences des composants tiers
|
|
2
|
+
|
|
3
|
+
## Embarqué dans la distribution
|
|
4
|
+
|
|
5
|
+
### Modèle de détection YuNet
|
|
6
|
+
|
|
7
|
+
`src/trombinoscope/assets/models/face_detection_yunet_2023mar.onnx` — 227 Ko.
|
|
8
|
+
|
|
9
|
+
- Source : [OpenCV Zoo](https://github.com/opencv/opencv_zoo/tree/main/models/face_detection_yunet)
|
|
10
|
+
- Auteurs : Wei Wu, Weiyuan Peng, Shiqi Yu
|
|
11
|
+
- Licence : MIT
|
|
12
|
+
- Empreinte SHA-256 : `8f2383e4dd3cfbb4553ea8718107fc0423210dc964f9f4280604804ed2552fa4`
|
|
13
|
+
|
|
14
|
+
La licence MIT du dépôt OpenCV Zoo couvre les poids comme le code, ce qui autorise
|
|
15
|
+
la redistribution dans une roue PyPI — contrairement, par exemple, aux poids
|
|
16
|
+
d'InsightFace ou de MODNet, réservés à un usage non commercial. Voir
|
|
17
|
+
[docs/improvements.md](docs/improvements.md), section 1.2.
|
|
18
|
+
|
|
19
|
+
### Silhouette de remplacement
|
|
20
|
+
|
|
21
|
+
`src/trombinoscope/assets/placeholder.png` est **dessinée par
|
|
22
|
+
`scripts/make_placeholder.py`**, pas téléchargée. C'est la seule façon d'être
|
|
23
|
+
certain qu'aucune œuvre tierce — et surtout aucun portrait de personne réelle —
|
|
24
|
+
ne se retrouve dans la distribution. Pour la régénérer :
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
uv run python scripts/make_placeholder.py
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Dépendances d'exécution
|
|
31
|
+
|
|
32
|
+
| Paquet | Licence |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| [NumPy](https://numpy.org/) | BSD-3-Clause |
|
|
35
|
+
| [opencv-python-headless](https://github.com/opencv/opencv-python) | Apache-2.0 (OpenCV), MIT (l'empaquetage) |
|
|
36
|
+
| [Pillow](https://python-pillow.org/) | MIT-CMU |
|
|
37
|
+
| [ReportLab](https://www.reportlab.com/) | BSD-3-Clause |
|
|
38
|
+
| [pillow-heif](https://github.com/bigcat88/pillow_heif) *(extra `heic`)* | BSD-3-Clause / LGPL-3.0 pour libheif |
|
|
39
|
+
|
|
40
|
+
## Images de test
|
|
41
|
+
|
|
42
|
+
**Aucune de ces images n'est versionnée ni distribuée.** Elles sont téléchargées
|
|
43
|
+
à la demande par `scripts/fetch_samples.py`, dans `tests/data/portraits/`, un
|
|
44
|
+
dossier ignoré par git. Les tests unitaires — l'essentiel de la couverture —
|
|
45
|
+
n'en ont pas besoin et fonctionnent sur des images synthétiques.
|
|
46
|
+
|
|
47
|
+
Toutes proviennent de [Wikimedia Commons](https://commons.wikimedia.org/) et sont
|
|
48
|
+
sous licence libre. L'attribution ci-dessous est fournie parce que c'est correct
|
|
49
|
+
de le faire, et parce que trois d'entre elles l'exigent.
|
|
50
|
+
|
|
51
|
+
| Fichier local | Sujet | Licence | Auteur |
|
|
52
|
+
| --- | --- | --- | --- |
|
|
53
|
+
| `01-hopper.jpg` | Grace Hopper | Domaine public | James S. Davis, U.S. Navy |
|
|
54
|
+
| `02-johnson.jpg` | Katherine Johnson | Domaine public | NASA |
|
|
55
|
+
| `03-perlman.jpg` | Radia Perlman | Domaine public | Scientist-100 (Wikipédia anglophone) |
|
|
56
|
+
| `04-hamilton.jpg` | Margaret Hamilton | CC BY-SA 3.0 | Daphne Weld Nichols |
|
|
57
|
+
| `05-liskov.jpg` | Barbara Liskov | CC BY-SA 3.0 | Kenneth C. Zirkel |
|
|
58
|
+
| `06-vanrossum.jpg` | Guido van Rossum | CC BY-SA 4.0 | Daniel Stroud |
|
|
59
|
+
| `07-knuth.jpg` | Donald Knuth | CC BY-SA 2.5 | Jacob Appelbaum |
|
|
60
|
+
| `08-kay.jpg` | Alan Kay | CC BY 2.0 | Marcin Wichary |
|
|
61
|
+
|
|
62
|
+
Le manifeste écrit à côté des fichiers (`MANIFEST.json`) reprend ces informations
|
|
63
|
+
avec l'URL de la page Commons et l'empreinte SHA-256 de chaque téléchargement.
|
|
64
|
+
|
|
65
|
+
Note sur le partage à l'identique : les clauses SA des licences CC BY-SA
|
|
66
|
+
s'appliquent à la **distribution** d'œuvres dérivées. Les portraits recadrés
|
|
67
|
+
produits par les tests vivent dans un dossier temporaire et ne sont jamais
|
|
68
|
+
publiés ; aucune obligation de partage n'est donc déclenchée. Si vous
|
|
69
|
+
redistribuez ces images ou des dérivés, les clauses s'appliquent pleinement.
|
|
70
|
+
|
|
71
|
+
## Travaux antérieurs
|
|
72
|
+
|
|
73
|
+
Le paquet ne reprend le code d'aucun projet tiers, mais il s'appuie sur des idées
|
|
74
|
+
et des algorithmes publiés. L'[étude d'originalité](docs/prior-art.md) est
|
|
75
|
+
détaillée ; les dettes principales :
|
|
76
|
+
|
|
77
|
+
- **Shades of Gray** — G. Finlayson et E. Trezzi, *Shades of Gray and Colour
|
|
78
|
+
Constancy*, Color Imaging Conference, 2004. L'estimateur d'illuminant par
|
|
79
|
+
défaut est une implémentation directe de cet article.
|
|
80
|
+
- **Correction de von Kries** — J. von Kries, 1902, pour la correction diagonale
|
|
81
|
+
par gains indépendants par canal.
|
|
82
|
+
- **Retinex / white patch** — E. Land, *The Retinex Theory of Color Vision*,
|
|
83
|
+
Scientific American, 1977.
|
|
84
|
+
- **YuNet** — W. Wu, W. Peng, S. Yu, *YuNet: A Tiny Millisecond-level Face
|
|
85
|
+
Detector*, Machine Intelligence Research, 2023.
|
|
86
|
+
- **[autocrop](https://github.com/leblancfg/autocrop)** (MIT) — le recadrage à
|
|
87
|
+
proportion de visage constante (`--facePercent`) y préexiste. Aucun code n'en
|
|
88
|
+
est repris, mais l'idée n'est pas de nous.
|
|
89
|
+
- **[WhosWho](https://framagit.org/Yvan-Masson/WhosWho)** (GPL-3.0) — le
|
|
90
|
+
concurrent libre le plus abouti, et une référence utile pour ce qu'un
|
|
91
|
+
générateur de trombinoscope doit savoir faire.
|
|
92
|
+
|
|
93
|
+
## Historique
|
|
94
|
+
|
|
95
|
+
Ce paquet est la réécriture d'un module personnel non publié, écrit en 2020 pour
|
|
96
|
+
produire les trombinoscopes d'une classe préparatoire. La structure du pipeline,
|
|
97
|
+
la logique de dernière ligne centrée et les annotations pivotées en viennent
|
|
98
|
+
directement. Le reste — modèle de détection, module colorimétrique, découpage en
|
|
99
|
+
modules, tests, CLI — a été refait. Voir [CHANGELOG.md](CHANGELOG.md).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 antnardo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: trombinoscope
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Génère un trombinoscope PDF prêt à imprimer depuis un dossier de photos brutes et une liste de personnes.
|
|
5
|
+
Project-URL: Homepage, https://github.com/antnardo/trombinoscope
|
|
6
|
+
Project-URL: Documentation, https://github.com/antnardo/trombinoscope/blob/main/docs/DOC.md
|
|
7
|
+
Project-URL: Repository, https://github.com/antnardo/trombinoscope
|
|
8
|
+
Project-URL: Issues, https://github.com/antnardo/trombinoscope/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/antnardo/trombinoscope/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: antnardo <antnardo@users.noreply.github.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: face-detection,opencv,pdf,portrait,reportlab,trombinoscope,white-balance,yearbook
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Education
|
|
17
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Natural Language :: French
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
26
|
+
Classifier: Topic :: Multimedia :: Graphics :: Capture
|
|
27
|
+
Classifier: Topic :: Printing
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.11
|
|
30
|
+
Requires-Dist: numpy>=1.24
|
|
31
|
+
Requires-Dist: opencv-python-headless>=4.8
|
|
32
|
+
Requires-Dist: pillow>=10.0
|
|
33
|
+
Requires-Dist: reportlab>=4.0
|
|
34
|
+
Provides-Extra: heic
|
|
35
|
+
Requires-Dist: pillow-heif>=0.15; extra == 'heic'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# trombinoscope
|
|
39
|
+
|
|
40
|
+
[](https://github.com/antnardo/trombinoscope/actions/workflows/ci.yml)
|
|
41
|
+
[](https://pypi.org/project/trombinoscope/)
|
|
42
|
+
[](https://pypi.org/project/trombinoscope/)
|
|
43
|
+
[](LICENSE)
|
|
44
|
+
|
|
45
|
+
Un dossier de photos brutes, une liste CSV, un PDF prêt à imprimer.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install trombinoscope
|
|
49
|
+
trombinoscope build photos/ classe.csv -o trombinoscope.pdf
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Le paquet détecte le visage sur chaque photo, recadre au même endroit et à la
|
|
53
|
+
même taille pour tout le monde, homogénéise les couleurs **à l'échelle du lot**,
|
|
54
|
+
puis compose une grille paginée.
|
|
55
|
+
|
|
56
|
+
## Ce qu'il fait
|
|
57
|
+
|
|
58
|
+
- **Recadrage à proportion de visage constante.** Que la photo ait été prise à
|
|
59
|
+
deux mètres ou à cinquante centimètres, le visage occupe la même fraction du
|
|
60
|
+
cadre. C'est ce qui rend une planche regardable.
|
|
61
|
+
- **Homogénéisation colorimétrique du lot.** Chaque portrait est ramené vers
|
|
62
|
+
l'illuminant et la luminance *médians de la séance*, pas vers un gris neutre
|
|
63
|
+
arbitraire. Sur une séance dont la balance des blancs dérive, la dispersion
|
|
64
|
+
chromatique chute de 78 %. C'est la seule chose que ce paquet fait et que les
|
|
65
|
+
bibliothèques de correction couleur existantes ne font pas — elles travaillent
|
|
66
|
+
toutes image par image. Voir [docs/color.md](docs/color.md).
|
|
67
|
+
- **Appariement positionnel.** Les photos triées par nom de fichier suivent
|
|
68
|
+
l'ordre de la liste. Aucun renommage manuel.
|
|
69
|
+
- **Mise en page soignée.** Pagination automatique, dernière ligne centrée,
|
|
70
|
+
étiquettes pivotées dans les gouttières, silhouette de remplacement pour les
|
|
71
|
+
absents.
|
|
72
|
+
- **Aucune dépendance système.** Ni LaTeX, ni LibreOffice, ni ImageMagick : que
|
|
73
|
+
des roues Python. Installable en conteneur et en CI.
|
|
74
|
+
- **Détecteur léger et remplaçable.** YuNet en ONNX, 227 Ko, embarqué dans la
|
|
75
|
+
roue. Le détecteur est un protocole : branchez le vôtre si vous préférez.
|
|
76
|
+
|
|
77
|
+
## Ce qu'il ne fait pas
|
|
78
|
+
|
|
79
|
+
Il ne fait **pas de reconnaissance faciale**. Il détecte qu'il y a un visage et
|
|
80
|
+
où, jamais qui c'est. C'est une frontière volontaire.
|
|
81
|
+
|
|
82
|
+
Il ne ramène **pas les carnations vers une teinte de référence** : cela
|
|
83
|
+
reviendrait à modifier la couleur de peau des personnes photographiées. Seul
|
|
84
|
+
l'illuminant — une propriété de l'éclairage — est estimé.
|
|
85
|
+
|
|
86
|
+
## Démarrage
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# 1. Un modèle de liste, pour voir le format attendu
|
|
90
|
+
trombinoscope template classe.csv
|
|
91
|
+
|
|
92
|
+
# 2. Vérifier la détection avant de tout lancer
|
|
93
|
+
trombinoscope inspect photos/ -o detections/
|
|
94
|
+
|
|
95
|
+
# 3. Produire le PDF
|
|
96
|
+
trombinoscope build photos/ classe.csv -o trombi.pdf \
|
|
97
|
+
--title "MP2 — 2026-2027" --columns 6 --align-eyes
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Le fichier de liste :
|
|
101
|
+
|
|
102
|
+
```csv
|
|
103
|
+
nom,prenom,tags,groupes,badge
|
|
104
|
+
HOPPER,Grace,Maths;LV2 ALL,Gr1;Tr3,1
|
|
105
|
+
JOHNSON,Katherine,Info,Gr2;Tr1,
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Seule la colonne `nom` est obligatoire. `tags` s'affiche dans la gouttière
|
|
109
|
+
gauche, `groupes` dans la gouttière droite, `badge` place une étoile en coin.
|
|
110
|
+
Les en-têtes sont reconnus sans tenir compte de la casse ni des accents, et les
|
|
111
|
+
colonnes inconnues sont ignorées : donnez directement votre export d'ENT.
|
|
112
|
+
|
|
113
|
+
### Depuis Python
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from trombinoscope import BuildOptions, TrombinoscopeBuilder, FramingConfig, GridConfig
|
|
117
|
+
|
|
118
|
+
options = BuildOptions(
|
|
119
|
+
title="Promotion 2026",
|
|
120
|
+
absent=("DUPONT",), # dans la liste, mais pas photographié
|
|
121
|
+
face_choice={"MARTIN": 1}, # deux visages sur sa photo : prendre le second
|
|
122
|
+
framing=FramingConfig(face_ratio=0.5, align_eyes=True),
|
|
123
|
+
grid=GridConfig(columns=6, landscape=True),
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
report = TrombinoscopeBuilder(options).build("photos/", "classe.csv", "trombi.pdf")
|
|
127
|
+
print(report.summary())
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`build` renvoie toujours un `BuildReport` : personnes sans photo, photos sans
|
|
131
|
+
personne, photos sans visage détecté, photos à plusieurs visages. Rien n'est
|
|
132
|
+
avalé silencieusement.
|
|
133
|
+
|
|
134
|
+
Les briques s'utilisent aussi séparément — `PortraitFramer` pour recadrer sans
|
|
135
|
+
produire de PDF, `BatchColorHarmonizer` pour harmoniser un lot d'images
|
|
136
|
+
quelconques, `GridPaginator` pour la mise en page seule.
|
|
137
|
+
|
|
138
|
+
La liste peut aussi venir d'une base SQLite, via une requête libre dont les
|
|
139
|
+
colonnes sont nommées avec `AS` :
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from trombinoscope import load_sqlite
|
|
143
|
+
|
|
144
|
+
people = load_sqlite("base.db", "SELECT nom, prenom, redoublant AS badge FROM eleves ORDER BY nom")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Voir [`examples/`](examples/) pour un script complet branché sur une base réelle.
|
|
148
|
+
|
|
149
|
+
## Quand utiliser autre chose
|
|
150
|
+
|
|
151
|
+
Ce paquet occupe une case étroite. L'[étude d'originalité](docs/prior-art.md) est
|
|
152
|
+
détaillée et n'édulcore rien ; en résumé :
|
|
153
|
+
|
|
154
|
+
| Votre besoin | Préférez |
|
|
155
|
+
| --- | --- |
|
|
156
|
+
| Une interface graphique, sans écrire de code | [WhosWho](https://framagit.org/Yvan-Masson/WhosWho) |
|
|
157
|
+
| Vos photos sont déjà dans PRONOTE | Le trombinoscope de PRONOTE |
|
|
158
|
+
| Seulement recadrer des portraits sur le visage | [autocrop](https://github.com/leblancfg/autocrop) |
|
|
159
|
+
| Des photos d'identité aux normes, fond détouré | [HivisionIDPhotos](https://github.com/Zeyi-Lin/HivisionIDPhotos) |
|
|
160
|
+
| Une planche image en une ligne de shell | `montage` d'ImageMagick |
|
|
161
|
+
| **Un PDF reproductible depuis un script ou une CI** | **`trombinoscope`** |
|
|
162
|
+
|
|
163
|
+
[WhosWho](https://framagit.org/Yvan-Masson/WhosWho) mérite d'être mentionné
|
|
164
|
+
d'emblée : c'est un logiciel libre, vivant, qui couvre l'essentiel du même
|
|
165
|
+
besoin. Si une application de bureau vous convient, utilisez-la. Les différences
|
|
166
|
+
réelles sont l'absence d'harmonisation colorimétrique inter-photos de son côté,
|
|
167
|
+
et l'absence d'interface graphique du nôtre.
|
|
168
|
+
|
|
169
|
+
## Documentation
|
|
170
|
+
|
|
171
|
+
- [DOC.md](docs/DOC.md) — référence complète : options, API, formats, recettes
|
|
172
|
+
- [color.md](docs/color.md) — l'étude colorimétrique, mesures à l'appui
|
|
173
|
+
- [prior-art.md](docs/prior-art.md) — état de l'art et étude d'originalité
|
|
174
|
+
- [improvements.md](docs/improvements.md) — pistes examinées et décisions
|
|
175
|
+
- [legacy-review.md](docs/legacy-review.md) — revue du module de 2020 dont ce
|
|
176
|
+
paquet est issu, et ce que la réécriture en a tiré
|
|
177
|
+
- [CREDITS.md](CREDITS.md) — modèles, images et travaux réutilisés
|
|
178
|
+
|
|
179
|
+
## Installation
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
pip install trombinoscope # cœur
|
|
183
|
+
pip install 'trombinoscope[heic]' # + lecture des .heic de l'iPhone
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Python 3.11 et suivants, testé sur Linux, macOS et Windows.
|
|
187
|
+
|
|
188
|
+
La dépendance OpenCV est `opencv-python-headless` : aucune bibliothèque
|
|
189
|
+
graphique système n'est requise. Si votre environnement contient déjà
|
|
190
|
+
`opencv-python`, installez avec `--no-deps` pour éviter que les deux
|
|
191
|
+
distributions ne se disputent le module `cv2`.
|
|
192
|
+
|
|
193
|
+
## Développement
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
git clone https://github.com/antnardo/trombinoscope
|
|
197
|
+
cd trombinoscope
|
|
198
|
+
uv sync --group dev
|
|
199
|
+
|
|
200
|
+
uv run pytest -m "not integration" # rapide, sans réseau
|
|
201
|
+
uv run ruff format src tests scripts
|
|
202
|
+
uv run ruff check src tests scripts
|
|
203
|
+
|
|
204
|
+
uv run python scripts/fetch_samples.py # portraits d'exemple, non versionnés
|
|
205
|
+
uv run pytest -m integration
|
|
206
|
+
uv run python scripts/color_bench.py --output artifacts
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Le dépôt ne contient **aucune photographie**. Les portraits utilisés par les
|
|
210
|
+
tests d'intégration sont téléchargés à la demande depuis Wikimedia Commons et la
|
|
211
|
+
CI vérifie qu'aucun fichier image n'apparaît ni dans le dépôt ni dans la roue.
|
|
212
|
+
|
|
213
|
+
## Licence
|
|
214
|
+
|
|
215
|
+
MIT — voir [LICENSE](LICENSE). Les composants tiers embarqués ou téléchargés ont
|
|
216
|
+
leurs propres licences, toutes recensées dans [CREDITS.md](CREDITS.md).
|