Test axonométrique du 27/09 : pipeline de fabrication et prototype

pipeline/axo : extraction du Rhino, recalage sur la planche (1:640), maisons,
arbres (positions réelles des blocs, couleurs de la planche), scène en mètres,
sols depuis le PDF Illustrator vectoriel (calques pilotés), bulles de la page 15,
planche de l'eau nettoyée. prototypes/axo-test : la page de test et son assembleur.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jules Nény
2026-09-27 16:46:14 +02:00
co-authored by Claude Opus 5.5
parent a9e0143536
commit 731531dbe2
17 changed files with 1334 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
"""08 — La planche du réseau hydrique alternatif, nettoyée de ses textes, pour le zoom « cycle de l'eau ».
Source : le PDF d'impression du concours Habiter Demain 2020 (page 6, dessins à 417 dpi),
identique au pixel près à la page 13 de la présentation TMIP 2024 (décalage mesuré : 0).
Les blocs de texte sont effacés : en dégradé dans la bande haute (le fond y passe du blanc au crème),
en aplat clair ailleurs. Les numéros d'étape deviennent des points actifs de la page web.
Si Jules fournit les originaux sans texte, remplacer cette étape par eux.
Usage : python 08_planche_eau.py <concours_IMPRESSION.pdf>
Sorties : eau_crop.jpg (2422 x 1290), eau_crop.json (points actifs et trajets, repère 100 dpi recadré)
"""
import sys, json, subprocess
import numpy as np
from PIL import Image
from scipy.ndimage import median_filter
subprocess.run(["pdftoppm", "-f", "6", "-l", "6", "-r", "150", "-png", sys.argv[1], "c6_150"], check=True)
im = np.asarray(Image.open("c6_150-06.png").convert("RGB")).astype(np.float32); k = 1.5
haut = [(55,28,1210,118),(85,443,305,543),(205,452,640,462),(632,452,642,532),(950,430,1113,572),(1118,428,1342,567)]
bas = [(958,568,968,652),(958,645,1182,655),(1226,560,1236,640),(78,722,248,818),(222,724,325,736),(88,925,282,1098),(230,932,495,944),
(578,936,752,952),(578,954,803,1118),(897,938,995,952),(915,954,1098,1118),(751,896,763,936),(915,905,926,938),
(1438,493,1620,752),(1410,657,1442,667),(1445,745,1622,962),(1355,752,1450,762),(1445,980,1615,1078),(1275,868,1462,878),(1453,868,1463,992),
(1158,978,1372,1090),(1165,948,1175,986),(480,1112,1220,1152),(1520,1100,1615,1145)]
for x0, y0, x1, y1 in haut:
X0, Y0, X1, Y1 = int(x0 * k), int(y0 * k), int(x1 * k), int(y1 * k)
h = median_filter(np.median(im[max(0, Y0 - 5):Y0, X0:X1], axis=0), size=(41, 1))
b = median_filter(np.median(im[Y1:Y1 + 5, X0:X1], axis=0), size=(41, 1))
t = np.linspace(0, 1, Y1 - Y0)[:, None, None]; im[Y0:Y1, X0:X1] = h[None] * (1 - t) + b[None] * t
for x0, y0, x1, y1 in bas:
X0, Y0, X1, Y1 = int(x0 * k), int(y0 * k), int(x1 * k), int(y1 * k)
a = np.concatenate([im[max(0, Y0 - 8):Y0, X0:X1].reshape(-1, 3), im[Y1:Y1 + 8, X0:X1].reshape(-1, 3), im[Y0:Y1, max(0, X0 - 8):X0].reshape(-1, 3), im[Y0:Y1, X1:X1 + 8].reshape(-1, 3)])
clair = a[a.mean(1) > 228]; im[Y0:Y1, X0:X1] = np.median(clair if len(clair) > 20 else a, axis=0)
Image.fromarray(np.clip(im, 0, 255).astype(np.uint8)).crop((30, 195, 2452, 1485)).save("eau_crop.jpg", quality=78, optimize=True, progressive=True)
pts = {"h1": (430, 790), "h2": (610, 850), "h3": (637, 612), "h4": (840, 660), "h5": (855, 800), "h6": (1130, 700), "h7": (1215, 790), "h8": (1378, 625),
"h9": (1320, 780), "h10": (1255, 880), "h11": (1105, 875), "h1b": (630, 300), "h5b": (1025, 372)}
flux = {"usees": [(592,822),(640,872),(700,925),(760,948),(830,950),(885,935),(940,895),(1000,850),(1050,805),(1090,765)], "pluie": [(585,748),(630,750),(690,758)]}
off = (20, 130)
json.dump({"W": 1615, "H": 860, "pts": {n: [x - off[0], y - off[1]] for n, (x, y) in pts.items()}, "flux": {n: [[x - off[0], y - off[1]] for x, y in l] for n, l in flux.items()}}, open("eau_crop.json", "w"))
print("planche de l'eau écrite")