"""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 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")