Cet article présente les mathématiques de la reconstruction des hautes lumières d’Ansel : la conception originale des guided laplacians de 2021, dont les idées générales n’avaient jamais été qu’esquissées sur le forum pixls.us,1 et la transposition harmonique, la méthode qui l’a remplacée après qu’une étude sur vérité terrain a mis au jour un bug de récupération de la magnitude.2 Il est organisé de sorte que chaque lecteur trouve sa section : les résultats et l’Intuition & contexte de chaque méthode ne demandent aucune mathématique ; les développeurs trouveront les sous-sections Implémentation & optimisations et l’étude de performance ; les
conclusions théoriques et
l’annexe cimetière sont écrites pour être
réutilisables en dehors de la photographie ; et
comment ce travail a réellement été mené documente le protocole de recherche homme–machine qui le sous-tend.
Résumé
Lorsqu’un capteur d’appareil photo sature, les trois canaux de couleur ne s’écrêtent pas au même moment, si bien qu’une haute lumière brûlée dérive en couleur, généralement vers le magenta. Cet article documente de bout en bout la reconstruction des hautes lumières d’Ansel, et dans l’ordre où elle s’est déroulée : les guided laplacians originaux de 2021 (transfert du détail des ondelettes à travers un filtre guidé, jamais entièrement couché sur le papier auparavant), l’étude sur vérité terrain qui a mis au jour son bug de magnitude, et la méthode qui l’a remplacée — la transposition harmonique, qui conserve le modèle local de colour-line du filtre guidé mais transporte ses coefficients à travers la zone brûlée sous forme de champs diffusés lisses pilotés par la structure des canaux survivants, débiaise le rolloff de saturation du capteur avant l’ajustement, et confie chaque bande de fréquence et chaque classe de pixels à l’estimateur qui y est mesurablement le meilleur. Chaque décision de conception est étayée par un chiffre sur un banc d’essai public, et les échecs sont documentés avec le même soin que les succès, y compris deux résultats que nous pensons être généraux : l’énergie de couture au passage de relais entre deux estimateurs quelconques est égale au désaccord des estimateurs et ne peut pas être atténuée par pondération, et la validité d’une colour-line au plus profond d’une zone brûlée est indécidable à partir des données qui l’entourent.34
Le problème
La dominante magenta
Un capteur numérique est une matrice de photosites, chacun recouvert d’un filtre coloré d’une matrice de filtres colorés (CFA) : la matrice de Bayer (2×2 de R, G, G, B) ou le X-Trans de Fuji (6×6). Chaque photosite est un puits de potentiel qui se remplit de photo-électrons pendant l’exposition et sature à une capacité fixe. Comme la capacité du puits est une propriété du silicium, les trois couleurs saturent à peu près à la même valeur de code raw.
Le piège est la balance des blancs. Un sujet gris neutre ne produit pas des signaux raw égaux dans les trois canaux : les transmissions de la CFA, la sensibilité spectrale du capteur et l’illuminant de la scène diffèrent tous d’un canal à l’autre. Pour rendre un tel sujet comme neutre, le logiciel de développement raw multiplie chaque canal par un coefficient de balance des blancs : typiquement le canal vert est laissé proche de $1$ tandis que le rouge et le bleu sont multipliés vers le haut par $1.5$ à $2$.
Suivons maintenant une haute lumière neutre à mesure qu’elle s’éclaircit. Au niveau du capteur, il n’y a rien de propre à chaque canal dans la saturation : les trois signaux raw grimpent vers un plafond commun partagé — le puits plein — et s’écrêtent à peu près à la même valeur. Le magenta est fabriqué ensuite, par les gains de la balance des blancs : multiplier chaque canal change à la fois sa pente en montant et le niveau auquel son plateau écrêté se pose. Le vert (gain $\approx 1$) plafonne là où le capteur l’a laissé ; le bleu et le rouge sont poussés vers le haut par leurs gains et plafonnent au-dessus. Passé la saturation, les ratios enregistrés ne sont plus neutres — le rouge et le bleu dépassent le vert, et la haute lumière « blanche » se lit comme du magenta. (Sur des sujets réels, les canaux s’écrêtent tout de même en séquence — la couleur propre du sujet et les sensibilités par canal décalent les débuts, ce qui explique pourquoi des pixels partiellement écrêtés existent et portent des guides survivants — mais le magenta d’un neutre brûlé est l’œuvre des gains, non de seuils propres à chaque canal.)
Note
Il s’agit d’un artefact purement mécanique et colorimétrique de l’appareil de capture. Il n’y a aucun magenta dans la scène. Toute reconstruction qui travaille dans un espace colorimétrique après dématriçage se bat déjà contre une erreur de teinte qu’un algorithme de dématriçage aura étalée sur les pixels voisins. Reconstruire avant dématriçage, tant que les données sont encore une mosaïque propre par canal, est tout l’intérêt de la méthode guided-laplacian.La valeur à laquelle un canal est déclaré écrêté n’est pas le maximum numérique mais un seuil propre à chaque canal, dérivé du point blanc raw :
où $\text{white}_c$ est le processed_maximum du module pour le canal $c$ (le niveau de blanc raw par canal ayant survécu aux étapes antérieures du pipeline) et clip est un facteur de sécurité utilisateur autour de $1$. La marge de $0.995$ garde les photosites presque saturés (dont la réponse est déjà devenue non linéaire près du haut du puits) hors de l’ensemble « valide ».2
Corrections plus simples
Le module d’Ansel propose trois modes de reconstruction moins coûteux avant celui des guided-laplacian, et il vaut la peine de les énoncer car ils cadrent ce que la méthode coûteuse apporte :
- Clip écrase simplement chaque canal au seuil commun $\texttt{clip}\times\min_c \text{white}_c$ (les mêmes niveaux de blanc, sans la marge de $0.995$). Pas de magenta, mais chaque région écrêtée devient une tache blanche plate et sans texture.
- Reconstruct in LCh convertit chaque bloc de Bayer en un triplet luminance/chroma/teinte, redimensionne la chroma des blocs écrêtés pour l’accorder à la luminance non écrêtée, puis reconvertit. Elle supprime la dérive de teinte mais ne peut pas inventer de texture.2
- Reconstruct color (inpaint) propage les ratios de couleur depuis les pixels non écrêtés voisins le long des lignes et des colonnes, en utilisant la mise à jour de ratio à décroissance exponentielle de l’algorithme de Magic Lantern. Elle est rapide et directionnelle mais unidimensionnelle et facilement trompée par les contours complexes.2
Le mode guided laplacians est le seul qui restaure à la fois la texture et la magnitude d’une région écrêtée, en empruntant aux canaux qui ont survécu le long de la colour-line locale.
Darktable en amont livre deux modes de reconstruction qu’Ansel ne reprend pas, et ils constituent une comparaison instructive car ils partent d’une hypothèse différente sur ce qu’est une haute lumière brûlée. Tous deux ont été développés par les équipes G’mic et Darktable et tous deux travaillent, comme notre méthode, sur la mosaïque raw : chaque canal de couleur est d’abord approché partout à partir de son voisinage de 3×3 photosites, donnant une image par canal grossière mais en pleine résolution.
Inpaint opposed repose sur une observation empirique : pour un canal écrêté, la moyenne des deux autres canaux (la moyenne « opposée », calculée dans l’espace en racine cubique pour comprimer la plage dynamique) est une bonne estimation de la valeur manquante dans la grande majorité des images. Le mécanisme est en conséquence simple : remplacer chaque valeur écrêtée par cette moyenne opposée, puis ajouter un décalage de chrominance global, mesuré sur les pixels morphologiquement les plus proches des zones écrêtées, pour absorber la dominante de couleur globale. Ses modes d’échec documentés sont les scènes où une relation fixe ne peut pas tenir : éclairage mixte, balance des blancs éloignée de l’hypothèse du pipeline, ou plusieurs sources lumineuses de couleurs différentes alimentant différentes hautes lumières.
Segmentation based affine le même estimateur de base par une adaptation spatiale. Les pixels écrêtés de chaque canal sont remplis par diffusion (flood-fill) en segments connexes (éventuellement fusionnés par une fermeture morphologique, le réglage « combine ») ; pour chaque segment, l’algorithme cherche sur sa bordure non écrêtée le meilleur pixel candidat (noté par l’écart-type local et la médiane dans une fenêtre 5×5) et transplante la pseudo-chrominance de ce candidat (le canal moins la moyenne opposée, à nouveau dans l’espace en racine cubique) sur tout le segment. S’il n’existe aucun candidat convaincant, il se rabat sur une moyenne à l’échelle du segment avec une correction de chrominance. Là où tous les canaux s’écrêtent, une passe « rebuild » séparée extrapole une surface de luminance à partir des gradients de bordure, contrôlée par une transformée de distance — le cousin le plus proche, dans tout ce paysage, de notre dôme biharmonique. Les hypothèses sont donc : une chrominance représentative par segment (meilleure qu’une par image, mais toujours plate à l’intérieur d’un segment), une texture héritée de ce que portent les canaux survivants, et une extrapolation de gradient là où rien n’a survécu.
Les deux sont des tentatives désespérées de remplir la zone endommagée avec quelque chose de plausible, mais promeuvent des surfaces colorées plates à la mauvaise magnitude.
Premiers principes
La méthode est un assemblage de quatre idées. Deux d’entre elles (les Laplaciens discrets et la pyramide B-spline à-trous) sont partagées textuellement avec diffuse or sharpen et ne sont que résumées ici. Les deux autres, le filtre guidé et la diffusion de chrominance, portent la reconstruction et sont dérivées intégralement.
Gradients et Laplaciens
Pour une image discrète $u(i,j)$, le gradient mesure la pente locale,
et le Laplacien mesure la courbure locale : à quel point un pixel s’écarte de la moyenne de ses voisins,
Le Laplacien est ici le cheval de trait car il isole la texture comme oscillation autour d’une moyenne locale (il est nul sur les régions plates et ne répond qu’au contraste local) et parce qu’il est linéaire : surexposer ou sous-exposer l’image ne fait que le redimensionner (une propriété sur laquelle nous nous appuyons plus bas). Isoler la texture de cette façon est ce qui nous permet de la transplanter entre canaux sans traîner avec elle la luminosité absolue du guide ; la différence de magnitude globale entre un canal écrêté et son guide est absorbée par la pente du filtre guidé, non par le Laplacien lui-même. Ansel utilise le pochoir à 9 points à symétrie de rotation de Oono & Puri
dont l’erreur angulaire est bien plus petite que celle de la croix naïve à 5 points, si bien que la diffusion ne privilégie pas les axes de la grille de pixels.567
La pyramide B-spline à-trous
Pour agir sur des structures de tailles multiples, l’image est découpée en bandes de fréquence en la floutant de façon répétée avec le noyau B-spline cardinal séparable
une approximation compacte d’une gaussienne de paramètre $\sigma_B \approx 1.0554$.8 À l’échelle $s$ les taps sont écartés d’un pas de $2^s$ pixels (« à-trous »), si bien que le même petit noyau atteint toujours plus loin sans jamais croître en coût. En notant $G_s$ les images passe-bas successives (progressivement floutées) et $H_s$ les bandes de détail,
l’image est exactement la somme de ses bandes, $u = \sum_{s=0}^{n-1} H_s + G_{n-1}$. Une bande de détail $H_s$ est une différence de gaussiennes, qui est elle-même une approximation à l’échelle d’un Laplacien-de-gaussienne — si bien que « filtrer la bande $H_s$ » et « appliquer un Laplacien à l’échelle $s$ » sont deux vues de la même opération. La dérivation complète, y compris la façon dont le rayon gaussien équivalent croît selon
est donnée dans l’article compagnon sur diffuse or sharpen.29
Note
Deux produits de cette pyramide sont utilisés ci-dessous. Le passe-bas $G_s$ est une moyenne pondérée locale à l’échelle $s$ — exactement la moyenne locale dont le filtre guidé a besoin, sur toute une échelle de tailles de fenêtres. La bande de détail $H_s$ est un Laplacien mis à l’échelle, l’opérateur que la solution de repli par diffusion de chrominance intègre. La reconstruction proprement dite travaille sur les $G_s$ (qui portent la magnitude de la couleur) ; la solution de repli travaille sur les $H_s$.Le filtre guidé
Le filtre guidé de He, Sun et Tang est le moteur qui emprunte de la texture depuis un bon canal vers un canal écrêté.3 Supposons que nous voulions produire une image de sortie $q$ qui reste fidèle à une certaine cible $p$ mais porte les contours et la texture d’un guide $I$. Supposons qu’à l’intérieur de toute petite fenêtre $\omega_k$ autour du pixel $k$, la sortie soit une fonction affine du guide :
Cette unique hypothèse, une colour-line locale, est tout le modèle. Elle dit qu’à l’intérieur d’un petit patch, le canal que nous reconstruisons n’est qu’une copie mise à l’échelle et décalée du guide. C’est le même a priori qui sous-tend le dématriçage inter-canaux, le désembuage, le détourage (matting) d’image et la colorisation : les surfaces naturelles tracent des colour-lines (localement, leurs canaux sont reliés affinement) parce que la plupart des contours sont des changements de réflectance qui redimensionnent tous les canaux ensemble.10 Sous une application affine, $\nabla q = a_k \nabla I$, si bien que $q$ hérite de chaque contour de $I$, simplement redimensionné par $a_k$.
Nous ajustons $(a_k, b_k)$ par moindres carrés, en gardant $a_k$ petit pour éviter d’amplifier le bruit (un terme de régularisation ridge $\varepsilon a_k^2$) :
En annulant les dérivées, on obtient la forme fermée qui apparaît, presque textuellement, dans le code :
La covariance au numérateur (une mesure de combien le guide et la cible montent et descendent ensemble) est la clé : là où ils bougent ensemble, $a_k \to 1$ et la texture du guide est copiée à travers ; là où le guide est plat ($\operatorname{var} \to 0$), $a_k \to 0$ et la sortie se rabat sur la moyenne locale $\bar p$. Le paramètre de régularisation ridge $\varepsilon$ fixe l’échelle en dessous de laquelle les variations sont traitées comme du bruit et lissées plutôt que transférées.
Note
Le filtre guidé de He comporte une deuxième étape (moyenner les coefficients par fenêtre $(a_k, b_k)$ sur toutes les fenêtres couvrant un pixel) qui empêche la sortie d’avoir un aspect en blocs. L’implémentation réécrite obtient le même lissage gratuitement en calculant les statistiques de fenêtre avec un noyau lisse (une gaussienne) plutôt qu’une boîte dure : des fenêtres lisses qui se chevauchent font de $a$ et $b$ des champs variant en douceur, si bien que $a,I + b$ est déjà exempt d’artefacts sans passe de moyennage séparée. Ce n’est pas un détail cosmétique : rejouer le même ajustement avec une fenêtre en boîte dure de support comparable laisse des stries alignées sur les axes et des plateaux en marches visibles partout où la structure de l’image traverse une frontière de fenêtre, et coûte environ un tiers d’erreur en plus sur la scène de contours du banc d’essai. Le code de 2021, quant à lui, utilisait une boîte dure $3\times3$ sans aucun moyennage — il s’en tirait parce que la fenêtre fait trois pixels de large et que la diffusion itérée lisse tout ce qu’elle laisse derrière elle.[^impl]La diffusion comme inpainting de couleur
Remplir la couleur d’un trou est un problème différent de remplir sa texture. La couleur d’un trou devrait varier en douceur et s’accorder à son pourtour ; elle ne devrait pas porter de détail haute fréquence (une texture fine variant rapidement) qui lui soit propre. Le formalisme naturel est l’énergie de Dirichlet, la quantité totale de variation que contient l’image, grande là où elle ondule et nulle là où elle est constante :
dont le minimiseur sur le trou $\Omega$, avec les pixels environnants comme condition aux limites, est la fonction harmonique satisfaisant $\Delta u = 0$.
(Notation, utilisée tout au long de l’article : $\lVert v \rVert$ est la norme euclidienne d’un vecteur — pour le gradient, $\lVert \nabla u \rVert = \sqrt{(\partial_x u)^2 + (\partial_y u)^2}$, la magnitude de la pente locale ; $\lvert s \rvert$ est la valeur absolue d’un scalaire ; et $\langle \cdot \rangle$ — les crochets angulaires — est la moyenne de la quantité encadrée sur les pixels de la région.) La descente de gradient de cette énergie est précisément l’équation de la chaleur
c’est-à-dire la diffusion isotrope, isotrope signifiant aveugle à la direction, se répandant également dans toutes les directions. La faire tourner répand la couleur de la frontière vers l’intérieur jusqu’à ce que le trou soit rempli par une surface lisse et sans courbure. C’est le même modèle d’inpainting par transfert de chaleur anisotrope de Qin et al. qu’Ansel utilise déjà pour diffuse or sharpen, restreint ici à son cas isotrope.4 Nous l’appliquerons non pas aux pixels mais aux ratios de couleur, de sorte que seule la chrominance soit lissée tandis que la luminance reconstruite est laissée intacte.
Piloter la diffusion : l’extension anisotrope. L’énergie de Dirichlet ci-dessus traite chaque direction également ; elle est isotrope. Elle se généralise en une forme pondérée,
où le tenseur de diffusion $D$ est une petite matrice symétrique définie à chaque pixel, dont le rôle est de re-pondérer les directions : conductance pleine le long de l’un de ses vecteurs propres, conductance amortie le long de l’autre. Minimiser cette énergie résout $\mathrm{div}(D\,\nabla u) = 0$ (son équation d’Euler–Lagrange), et avec $D$ égal à l’identité partout, elle se réduit exactement au cas isotrope ci-dessus. Tout l’intérêt de cette machinerie est le pilotage : choisir la direction forte le long des isophotes de l’image (les lignes de luminosité constante) et la direction amortie en travers, et la diffusion lisse une quantité le long de la structure de l’image tout en refusant de la porter à travers les contours.
Discrétiser ceci en toute sécurité demande une précaution. En écrivant le tenseur $D = \begin{pmatrix} a & b \ b & c \end{pmatrix}$ (moyenné entre chaque pixel et son voisin, avec le terme croisé borné à $|b| \leq \min(a, c)$), la divergence $\operatorname{div}(D\,\nabla u)$ devient une somme sur les huit voisins avec des poids
le pochoir préservant la non-négativité de Weickert : la borne garantit que chaque poids est non négatif, si bien que la relaxation ancrée $u_0 \leftarrow \sum_k w_k u_k / \sum_k w_k$ remplace chaque inconnue par une combinaison convexe de ses voisins. C’est le principe du maximum discret — les valeurs résolues ne peuvent jamais sortir de la plage des ancres, peu importe la force avec laquelle le tenseur pilote — et c’est ce qui rend la diffusion anisotrope sûre à exécuter sur des données qui doivent rester physiques. La méthode livrée utilise cette machinerie à deux endroits : le transport des coefficients de colour-line à travers la zone brûlée (étape 3 de l’algorithme, où le tenseur mélange en outre le pilotage par isophote et par gradient selon une probabilité de contour mesurée), et la chrominance des cœurs entièrement écrêtés (étape 8), où les couleurs doivent suivre la structure de la luminance récupérée et ne jamais déborder à travers elle.
Inpainting biharmonique
L’inpainting harmonique est le bon outil pour un signal qui devrait devenir plat à l’intérieur du trou : une chrominance lisse. C’est le mauvais outil pour un signal qui était encore en train de monter quand le capteur l’a écrêté : la magnitude d’une haute lumière brûlée continuait de grimper, et la remplir à plat ($\Delta u = 0$) laisse un disque mat là où un dôme brillant devrait être. Pour porter la pente environnante vers l’intérieur au lieu de l’effacer, pénalisez le fléchissement du signal plutôt que son gradient : minimisez l’énergie de plaque mince (biharmonique)
dont l’équation d’Euler–Lagrange (la condition que tout minimiseur de l’énergie doit satisfaire) est l’équation biharmonique $\Delta^2 u = 0$. Là où la solution harmonique force $\Delta u = 0$ (une surface minimale plate), la solution biharmonique rend $\Delta u$ lui-même harmonique : la courbure au pourtour est portée vers l’intérieur, si bien que le gradient montant de la frontière est extrapolé en un dôme (une spline de plaque mince). C’est la contrepartie d’ordre supérieur, étendant le gradient, de la diffusion, dans le même esprit où diffuse or sharpen inverse le signe du Laplacien pour affûter plutôt que lisser. Nous la résolvons comme un système linéaire creux direct sur le trou, et l’utilisons plus bas pour reconstruire la magnitude d’un canal écrêté à partir de son propre pourtour valide partout où aucun canal corrélé n’a survécu pour le guider.7
La méthode de 2021 : guided laplacians
Avant de suivre l’évolution de la méthode, cette section documente la conception originale, telle qu’elle a été livrée en 2021 et telle qu’elle est encore livrée aujourd’hui — conception inchangée, bien qu’elle partage un correctif mesuré de collecte de bordure avec le nouveau pipeline (documenté avec les raffinements harmoniques plus bas) — sous le mode guided laplacians (la nouvelle méthode est un mode séparé, optionnel : voir la note de statut plus loin). Elle a été codée contre l’intuition et réglée à l’œil sur des images naturelles, et ses idées générales n’avaient jamais été qu’esquissées sur le forum pixls.us1 ; ceci en est le premier exposé complet.
Intuition & contexte
L’intuition. L’écrêtage inévitable survient à l’intérieur des sources lumineuses : le soleil, une flamme, un reflet spéculaire. De telles sources sont entourées d’un halo lumineux, et ce halo porte trois sortes d’informations exploitables. Premièrement, les canaux de couleur y sont fortement corrélés (ils montent tous vers la source), si bien qu’un canal qui s’est écrêté peut emprunter la forme d’un canal qui ne l’a pas fait. Deuxièmement, les gradients du halo pointent vers la source, si bien que même un cœur entièrement brûlé peut être plausiblement prolongé en propageant les gradients environnants vers l’intérieur. Troisièmement, le halo est coloré comme la source lumineuse elle-même, si bien que la chrominance peut être récupérée en propageant les ratios RGB vers l’intérieur. La conception de 2021 a transformé chaque intuition en un opérateur : un transfert guidé de structure fine entre canaux, et une diffusion itérée qui pousse la structure du pourtour valide dans la région brûlée tout en diffusant les ratios de couleur vers l’intérieur.
Les objectifs. Reconstruire avant dématriçage, sur la mosaïque raw, de sorte que l’interpolation ne voie jamais d’échantillons écrêtés ; ne jamais s’appuyer sur la balance des blancs ni sur aucune hypothèse sur la couleur que la haute lumière « devrait » avoir (la couleur propre de la source lumineuse est inconnaissable) ; et préférer des prolongements lisses et physiquement plausibles aux hallucinations nettes, car une erreur dans une haute lumière brûlée est bien plus visible comme un artefact dur que comme un artefact doux.
Son bilan. Sur ses cas de conception, la méthode fonctionnait, et fonctionne toujours : un disque solaire ou un reflet spéculaire sur l’eau est reconstruit avec une structure crédible et sans la tache grise plate que laisse le simple écrêtage. Elle préserve les gradients là où des méthodes plus simples (mise à l’échelle des ratios de canaux, inpainting monochrome) les aplatissent, et comme elle travaille sur les gradients plutôt que sur les couleurs, elle tolère une balance des blancs erronée. Deux limites structurelles ont été comprises et acceptées dès le départ : un ciel brûlé vu à travers des feuilles vertes est récupéré vert (la méthode propage la couleur voisine, par conception), et une forte aberration chromatique brise l’alignement des canaux dont la colour-line a besoin.
Le problème d’optimisation
Le transfert de texture. L’image est décomposée avec la pyramide B-spline à-trous décrite ci-dessus : à chaque échelle $s$ le signal se scinde en une approximation basse fréquence et une bande de détail $H_s$. Parce que la B-spline cardinale est très proche d’une gaussienne, et que la bande de détail est calculée échelle par échelle comme la différence avec cette gaussienne approchée, $H_s$ est elle-même déjà proche d’un Laplacien, redimensionné en magnitude (elle sur-évalue en fait le Laplacien). Sur chaque bande de détail, chaque canal écrêté $c$ est ajusté contre un canal guide $g$ (choisi par pixel comme le canal ayant la plus forte variance locale, c’est-à-dire celui portant le plus de structure — sans vérification que le guide lui-même y soit valide) avec le filtre guidé dérivé ci-dessus :
où la covariance et la variance sont des statistiques locales fenêtrées (une boîte dure 3×3 qui n’exclut pas les échantillons écrêtés), et la division est simplement omise là où la variance du guide tombe sous $10^{-12}$ — il n’y a pas de terme d’amortissement. Parce qu’une bande de détail est de moyenne nulle, l’ordonnée à l’origine $b_c$ est essentiellement nulle : le transfert déplace la texture du guide vers le canal écrêté, mise à l’échelle par leur relation locale mesurée.
La diffusion de chrominance. La seconde étape opère sur les ratios RGB (la chrominance, $\text{RGB}/n$ avec $n = \lVert \text{RGB} \rVert$, la norme euclidienne — le symbole qu’utilisent les règles de mise à jour ci-dessous), en itérant le Laplacien à neuf points de Oono & Puri sur chaque plan de ratio ; le plan de norme $n$ voyage sur la même pyramide mais est explicitement protégé de l’étape (sauvegardé et restauré autour d’elle), si bien qu’il est resynthétisé tel quel. Cette itération est la descente de gradient d’un problème variationnel explicite : sur la région écrêtée $\Omega$, avec le pourtour valide comme donnée aux limites, elle minimise
pour chaque plan de ratio et pour la norme : une énergie de Dirichlet (harmonique) qui porte la chrominance et le niveau du pourtour en douceur vers l’intérieur, plus un terme d’écrantage optionnel tirant le cœur vers la couleur valide moyenne $\bar u$ avec le poids « inpaint a flat color » de l’utilisateur $\lambda_{\text{solid}}$. Son équation d’Euler–Lagrange est l’équation de Poisson écrantée de la section théorique ; le code de 2021 ne la résout jamais jusqu’au régime permanent — le curseur « iterations » tronque la descente, si bien que le résultat pratique dépend du budget d’itérations autant que de l’énergie. Deux propriétés découlent directement de cet objectif et expliquent l’allure caractéristique de la méthode : un remplissage harmonique aplatit (il pénalise les gradients, si bien que l’intérieur tend vers un plateau de niveau — la section théorique montre pourquoi une énergie biharmonique est nécessaire pour prolonger les pentes), et rien dans l’une ou l’autre étape ne contraint le niveau reconstruit d’un canal écrêté, que l’étape 1 ne peut pas transférer (bandes de moyenne nulle) et que l’étape 2 ne fait que diffuser depuis un pourtour situé à l’écrêtage.
L’algorithme
Toute la procédure, en un coup d’œil :
flowchart TD A["raw mosaic (one colour per pixel)"] --> B["bilinear interpolation to temporary RGB
+ per-channel clip masks"] B --> C["downsample 4× (for speed)"] C --> D["à-trous B-spline pyramid:
split into detail bands, one per frequency range"] D --> E["per band, RGB, fine → coarse:
guided-filter fit of the clipped channel
against the most textured channel
(validity not checked)
→ transfer of TEXTURE (zero-mean details)"] E --> F["per band, RGB ratios & norm, iterated 9-point Laplacian diffusion:
spread structure from the valid rim
into the blown core, isotropically"] F --> G["optional: reaction toward a flat colour
(user slider) + Poissonian re-graining"] G --> H["upsample, remosaic,
feathered composite over the raw"]
Les compromis sont délibérés. Travailler sur les bandes de détail rend le transfert immunisé aux erreurs de balance des blancs (seules les formes se déplacent entre canaux). Le Laplacien à neuf points est la discrétisation isotrope, invariante par rotation, dérivée dans les premiers principes, si bien que la diffusion remplit le cœur de l’extérieur vers l’intérieur sans suivre les axes de la grille de pixels. La douceur est toujours préférée à la netteté : une erreur dans une haute lumière brûlée se lit comme un artefact dur quand elle est nette et comme une lueur plausible quand elle est douce. Et l’ordre des bandes du fin au grossier signifie que chaque bande est ajustée indépendamment en une seule passe — il n’y a pas de contrainte de cohérence inter-échelles, ce qui reste inoffensif précisément parce que les bandes sont de moyenne nulle.
Trois étapes préparatoires méritent une note — elles sont partagées par toutes les méthodes de reconstruction de cet article, le successeur inclus.
Dématriçage bilinéaire. La mosaïque est dématricée de façon bilinéaire vers une image RGB temporaire : un dématriçage jetable dont le seul rôle est de donner à chaque canal une valeur partout pour l’ajustement guidé par canal ; la sortie finale est re-mosaïquée vers un unique canal. Un masque d’écrêtage par canal, avec son OU logique (fondu dans l’opacité de compositing $\alpha$), enregistre quels canaux ont saturé.2
Normalisation locale des canaux. Chaque couleur est divisée par la valeur moyenne de cette couleur dans la tuile courante, une balance des blancs locale grossière calculée sur le champ. Ceci égalise les magnitudes des canaux de sorte que la comparaison de variance pour la sélection du guide ne soit pas biaisée vers le canal portant les plus grands nombres raw ; elle ne réutilise délibérément pas la balance des blancs déclarée en amont.2
Fondu du masque. Le masque binaire est lissé par une petite moyenne en boîte $5\times5$ en une opacité $\alpha \in [0,1]$, utilisée comme poids final de compositing et comme poids doux par canal de la reconstruction à-trous ci-dessous. Le fondu adoucit la couture là où la reconstruction rencontre les pixels intacts ; dans les tests numériques il a abaissé l’erreur de frontière de cette méthode plutôt que de l’élever — le retirer a été testé et nuit de façon mesurable ici (les poids doux sont porteurs), tandis que la méthode successeure abandonne entièrement le fondu (ses masques sont binaires de bout en bout ; voir le cimetière).
Les règles de mise à jour
Le problème d’optimisation énonce ce que cette méthode minimise et l’algorithme en raconte les étapes ; voici les véritables mises à jour de signal du mode 2021 livré, dans l’ordre d’exécution, pour un implémenteur partant de zéro. Plans : le RGB temporaire sous-échantillonné quatre fois $u_c$ (dématriçage bilinéaire, normalisé par canal), les masques par canal fondus $\alpha_c \in [0,1]$ et leur opacité tout-écrêtage $\alpha$. Décomposition : la pyramide B-spline à-trous avec pas $2^s$ par échelle — flous en cascade $\mathrm{LF}_s$, bandes de détail $D_s = \mathrm{LF}_{s-1} - \mathrm{LF}_s$, plus le résidu le plus grossier.
1. Transfert de texture (la passe RGB), par échelle du fin au grossier, à chaque pixel où $\alpha > 0$. Sur le voisinage à-trous $3\times3$ (pas $2^s$) de la bande de détail, calculer la moyenne et la variance du patch par canal, choisir le guide $g$ comme le canal de plus grande variance de patch (la validité n’est pas vérifiée — la racine de l’échec 4), ajuster la colour-line à ordonnée à l’origine biaisée vers zéro sur les détails,
et mélanger la prédiction, en s’estompant quadratiquement avec le rayon équivalent de l’échelle — pris à l’étape $4s$, non $s$ : le code évalue $\sigma$ à s * DS_FACTOR, facturant chaque échelle également pour le facteur de sous-échelle, si bien que l’estompage est bien plus abrupt que ce que $\sigma_s^2$ seul suggère ($\beta$ vaut $\alpha/380$ à $s{=}1$ et $\alpha/97\,000$ à $s{=}2$ — le transfert guidé vit effectivement sur les échelles les plus fines) :
La resynthèse somme les bandes traitées plus le résidu, borné à $\geq 0$ ; à la dernière itération, un grain poissonien d’amplitude $\sigma = u_c \cdot \texttt{noise_level}$ est incorporé (éclaircissant uniquement) sous $\alpha$. Le résultat est scindé en direction et magnitude, $r_c = u_c / \lVert u \rVert$ et $n = \lVert u \rVert$, pour la passe suivante.
2. Diffusion de chrominance (la passe chroma), même pyramide sur les quatre plans $(r_R, r_G, r_B, n)$ : chaque bande de détail des trois plans de ratio prend un pas d’Euler explicite de l’équation de la chaleur écrantée, par pixel où $\alpha > 0$ et par canal — la bande du plan de norme est sauvegardée avant le pas et restaurée après, si bien que $n$ traverse la pyramide sans diffusion,
avec $\mathbf{K}_{\text{iso}}$ le Laplacien isotrope à neuf points des premiers principes, $\kappa = \sigma_B^2 / (2\sqrt{\pi}) \approx 0.31$ le redimensionnement bande-vers-Laplacien, et $\lambda$ la réaction de couleur plate (solid_color). Resynthèse comme ci-dessus, puis les ratios sont renormalisés à la norme unité et recombinés, $u_c \leftarrow r_c \cdot n$.
3. Itérer. Les passes 1–2 se répètent iterations fois (le curseur utilisateur) ; rien ne détecte la convergence, le compte est le budget.
4. Compositer. La reconstruction est sur-échantillonnée quatre fois et mélangée par-dessus la mosaïque raw à travers l’opacité fondue, par photosite de couleur $c$ : $\text{out} = \alpha\, u_c + (1 - \alpha)\, \text{raw}$.
Rien d’autre n’écrit un pixel — et, comme l’a constaté l’étude sur vérité terrain, rien de ce qui précède ne transfère un niveau : chaque mise à jour agit sur des bandes de détail de moyenne nulle ou sur des ratios, ce qui est exactement la lacune structurelle que le successeur comble.
Implémentation & optimisations
Toute la reconstruction tourne sur un tampon sous-échantillonné quatre fois — un seizième des pixels — et le résultat est sur-échantillonné et composité de nouveau par-dessus le raw sous un masque fondu. Cette seule décision achète l’essentiel de la vitesse de la méthode et coûte une précision mesurable : réexécuter les mêmes mathématiques en pleine résolution abaisse l’erreur de frontière d’environ 30 %, parce que la reconstruction sur-échantillonnée est floue face à l’original net qu’elle doit rejoindre (la méthode successeure tourne en pleine résolution pour exactement cette raison). Les bandes de détail à-trous sur-évaluent le Laplacien d’une constante connue (le $\sigma_B = 1.05537$ de la B-spline donne $1/\kappa = 3.1827$), que l’étape de diffusion compense ; la diffusion exécute iterations × (une passe de ratio RGB + une passe de norme) par échelle, sur toute l’image — il n’y a pas de segmentation en régions, si bien que le coût croît avec l’image, non avec la zone écrêtée. Le grain poissonien ($\sigma = \text{valeur} \times \text{niveau de bruit}$) est régénéré à la dernière itération pour que les zones reconstruites n’aient pas l’air lisses comme du plastique à côté d’une vraie texture.
Problèmes découverts
Ce qui n’arrive jamais dans l’organigramme ci-dessus est un transfert de niveau — une observation invisible sans vérité terrain, et là où commence toute l’étude de 2026.
Les problèmes. En pratique, les utilisateurs ont continué à signaler des hautes lumières brûlées qui restaient magenta après reconstruction — le défaut même que la méthode existe pour corriger. L’étude documentée dans le reste de cet article a fini par localiser la cause racine dans les mathématiques ci-dessus : l’ajustement guidé était appliqué aux bandes de détail seulement. Une bande de détail a une moyenne locale nulle, si bien que l’ordonnée à l’origine $b_c$ ne porte aucune énergie, et seule la texture se transfère jamais — jamais le niveau. La composante basse fréquence du canal écrêté, figée à la valeur d’écrêtage, était rajoutée inchangée ; un canal brûlé était laissé à l’écrêtage (ou poussé en dessous par le traitement de chrominance) et restait magenta. Dans le banc de validation construit plus tard, cette reconstruction originale est souvent pire que ne rien faire sur les écrêtages monocanaux : une erreur quadratique moyenne (RMSE) de 0.073 contre 0.049 pour laisser les pixels écrêtés, sur une scène de type naturel où la reconstruction finale atteint 0.015 (ces trois nombres proviennent du banc du prototype de recherche Python — fix_prototype.py dans le dépôt de recherche — dont le portage NumPy du module de 2021 tient lieu du C ; les implémentations livrées sont notées dans les résultats).

Une scène synthétique : trois hautes lumières monocanal saturées (disques rouge, vert, bleu) et une proche du neutre très brillante. Ground truth est la scène non écrêtée, clipped ce que le capteur enregistre, previous method le portage Python du module à-trous de 2021, corrected method la même conception avec la réparation sur signal complet décrite juste en dessous.
Dans les disques monocanal, le résultat corrigé remonte vers la couleur vraie (p. ex. le disque rouge récupère $\approx 1.7$ contre une vraie valeur $\approx 1.9$, le vert et le bleu étant reproduits exactement) là où la méthode précédente reste en dessous de l’écrêtage ($\approx 0.9$). Le disque neutre tout-écrêté, plat à l’écrêtage à la fois dans le capteur et dans la méthode précédente, est ré-bombé par le remplissage de luminance partagé (centre $\approx 1.5$ contre une vraie valeur $\approx 1.6$) et reste proche du neutre, sa chrominance portée par la diffusion du pourtour.
La réparation en une ligne — appliquer le même ajustement guidé au signal complet (basse fréquence et détail ensemble) de sorte que l’ordonnée à l’origine porte la moyenne locale et qu’un canal brûlé puisse monter au-dessus de l’écrêtage (les mathématiques sont dans les règles de mise à jour) — corrige cette classe d’échecs, et c’est le fondement que tout ce qui a suivi a conservé : toutes les méthodes ultérieures de cet article ajustent les colour-lines sur des valeurs complètes. Elle était nécessaire mais non suffisante. Avec une vérité terrain contre laquelle mesurer — sur la conception réparée, reconstruite en pleine résolution autour d’une échelle de tailles de fenêtres (l’annexe cimetière la détaille) — quatre échecs structurels subsistaient, et ils ont façonné la méthode successeure :
Premièrement, l’échelle de fenêtres dégénère partout où une fenêtre voit majoritairement des données au niveau d’écrêtage (fenêtres fines près du pourtour, fenêtres grossières au plus profond du trou), et un ajustement dégénéré (covariance proche de zéro, pente proche de zéro) remplit à plat, à peu près au niveau d’écrêtage. Pire, le passage de relais entre échelles consécutives suit un contour de profondeur constante dans le trou, et le désaccord des deux échelles imprime un arc visible le long de celui-ci.
Deuxièmement, l’amortissement $\epsilon$ ci-dessus est en concurrence avec la variance locale du guide, si bien qu’il écrase silencieusement la pente partout où cette variance est petite — ce qui protège le contenu bruité par accident et aplatit les gradients propres et lisses (comme le ciel) par le même mécanisme. Une constante, deux conséquences opposées, aucune valeur qui serve les deux.
Troisièmement, le capteur ne s’écrête pas abruptement : il compresse les derniers pour cent sous la saturation, si bien que la bande de pixels que la reconstruction traite comme des ancres de confiance est enregistrée systématiquement trop bas.11 Même un oracle qui reconstruirait l’intérieur écrêté exactement se retrouverait alors visiblement plus brillant que l’anneau biaisé auquel il doit se rattacher : la couture est dans les données, non dans l’estimation, et seule la correction des données (l’inversion du knee) peut la supprimer.
Quatrièmement, toute la méthode repose sur une hypothèse : les canaux voisins montent et descendent ensemble, de sorte qu’un canal écrêté est une fonction affine mesurable d’un canal survivant. Or certains contenus (un ciel dont la teinte elle-même dérive, une irisation, une texture de couleur plus fine que la fenêtre) ne la satisfont tout simplement pas. Là, le guide ne contient aucune information sur le canal manquant pour aucun estimateur, si bien que la conception doit mesurer cela ($R^2$) et changer complètement la source d’information : lissage spatial au lieu de transfert inter-canaux.
Corriger cela a demandé plus qu’un correctif — cela a demandé un changement de paradigme.
La nouvelle méthode : la transposition harmonique
Cette section documente la méthode livrée aujourd’hui — ses prémisses, son problème d’optimisation,
son algorithme, et la façon dont l’implémentation de production s’écarte du prototype de recherche.
Les résultats mesurés, les performances et les conclusions générales ont chacun leur propre section ci-dessous.
La transposition harmonique est livrée comme son propre mode de reconstruction à côté des
guided laplacians originaux : la méthode à-trous de 2021 conserve son nom et sa conception historiques —
inchangés hormis le correctif partagé de collecte des bords, qui améliore ses propres scores — et la nouvelle
méthode est un choix explicite à activer.
Le cœur de reconstruction est agnostique à la mosaïque du capteur et fonctionne aussi bien sur Bayer que sur X-Trans, sur
le processeur comme dans un pipe OpenCL, où chaque région écrêtée est
résolue du côté du bus qui s’est mesuré comme le plus rapide
(voir la section performances).
Intuition & contexte
La réparation ci-dessus change ce que le filtre guidé transfère ; la transposition harmonique change la façon dont le modèle voyage. Partout où au moins un canal a survécu, la reconstruction est un problème de régression, et non un problème d’inpainting : les canaux valides sont des données mesurées, présentes à chaque pixel de la zone brûlée, et la seule inconnue est la relation locale (la ligne de couleur) entre eux et le canal écrêté. La méthode de 2021 — et sa reconstruction corrigée sur signal complet — évaluait cette relation partout où une fenêtre statistique pouvait atteindre, et recousait les évaluations ensemble ; chaque couture était une jointure, et les fenêtres profondément à l’intérieur d’un grand trou n’atteignaient rien du tout. La transposition harmonique inverse le transport : on ajuste la ligne de couleur une fois, là où les données la soutiennent, puis on diffuse les coefficients du modèle — non les valeurs des pixels — à travers la zone brûlée sous forme de champs lisses, et alors seulement on les évalue contre les canaux survivants mesurés à chaque pixel. Les coefficients sont lisses par nature là où les valeurs ne le sont pas ; les guides réinjectent la structure pleine résolution au moment de l’évaluation. Pourquoi il s’agit d’une différence de nature plutôt que de degré — et ce à quoi cela se généralise — est détaillé dans les conclusions théoriques.
Tout le reste de ce que la méthode de 2021 réussissait est conservé, sur des bases plus saines : le modèle de ligne de couleur et ses moindres carrés pondérés fenêtrés (la régression du filtre guidé), le dôme biharmonique pour la magnitude sans guide, la chrominance portée sous forme de rapports bornés, la préférence pour les continuations lisses, et la régénération du grain. Ce qui est nouveau, outre le transport : une segmentation par région à pleine résolution (le coût varie avec l’aire écrêtée, non avec l’image), une inversion de rolloff du capteur mesurée qui débiaise la bande proche de l’écrêtage avant tout ajustement (défaut 3 ci-dessus), des ajustements filtrés et pondérés par leur propre qualité mesurée $R^2$ (défaut 4), et une règle de conception appliquée partout, dérivée de la loi d’énergie de couture des conclusions théoriques : aucune étape ne peut passer le relais entre des estimateurs qui sont en désaccord (défaut 1).
Le problème d’optimisation
Aucune des deux étapes n’assemble une énergie globale ni n’appelle un solveur nommé, mais chacune est la règle de mise à jour locale d’un problème variationnel, et ensemble elles rendent l’objectif explicite. Sur la région écrêtée $\Omega$, la reconstruction minimise quatre énergies couplées sur le modèle.
1. Cohérence affine inter-canaux. Là où un guide valide $g$ existe, chaque canal écrêté devrait être une fonction affine du guide : le filtre guidé est le minimiseur exact de
Ajuster sur les valeurs complètes $u$ (et non le détail) est ce qui fait que le minimiseur porte la moyenne locale, si bien que $E_{\text{affine}}$ récupère magnitude et texture ensemble.310 Ce terme est pondéré en proportion de la corrélation au carré de l’ajustement $(R^2)^2$ ; là où $R^2 \to 0$, le canal est au contraire maintenu à sa propre régularité du second ordre (un terme biharmonique par canal $\int_\Omega (\Delta u_c)^2, \mathrm{d}\Omega$), de sorte que l’objectif ne récompense jamais une ligne de couleur que les données ne soutiennent pas. La mise au carré aiguise ce compromis, si bien qu’une corrélation médiocre s’appuie sur le repli lisse plutôt que sur une supposition inter-canaux discontinue.
1b. Transport anisotrope des coefficients (la forme livrée du terme 1). L’ajustement affine du terme 1 ne définit ses coefficients que là où une fenêtre contient assez de données de confiance ; sur le reste de la zone brûlée, le modèle lui-même est l’inconnue. La méthode livrée l’étend en minimisant une énergie de Dirichlet anisotrope sur les plans de coefficients,
où les ancres sont les ajustements filtrés du terme 1 (assez de masse de confiance, $R^2 > 0.25$, pentes bornées) et $D$ est le tenseur d’orientation adaptatif à la variance de l’étape 3, construit à partir de la structure mesurée du guide : dominé par le gradient sur une rampe de halo propre (le modèle voyage radialement vers l’intérieur depuis le bord), dominé par l’isophote là où une arête franche traverse la zone (les lignes de couleur ne doivent pas se mélanger à travers une frontière d’objet). Son équation d’Euler–Lagrange $\operatorname{div}(D \, \nabla p) = 0$ est le remplissage orienté ; avec $D = I$ elle se réduit au remplissage harmonique ordinaire. L’évaluation $\hat u_c = a\,u_{g_1} + b\,u_{g_2} + d$ contre les guides mesurés boucle le terme : l’énergie transporte le modèle, et les données restaurent le détail.
2. Courbure de magnitude (repli). Là où aucun guide ne survit, le détail fin est perdu mais la forme basse fréquence ne l’est pas : elle devrait continuer la courbure environnante plutôt que s’aplatir. Pour un canal partiellement écrêté, c’est le terme biharmonique par canal $\int_\Omega (\Delta u_c)^2, \mathrm{d}\Omega$ déjà invoqué ci-dessus. Pour le cœur entièrement écrêté, il est appliqué une fois à la luminance sommée $L_\text{sum} = R+G+B$, un seul dôme partagé au lieu de trois divergents :
ancré au véritable bord valide du cœur ; son équation d’Euler–Lagrange $\Delta^2 L = 0$ est le remplissage en dôme ci-dessus.
3. Régularité de la chrominance (repli). Là où aucun guide ne survit, les rapports reconstruits $r = \text{RGB}/L_\text{sum}$ devraient être lisses et s’accorder au bord, éventuellement biaisés vers la platitude :
Son équation d’Euler–Lagrange est l’équation de Poisson filtrée que la diffusion intègre,4 et la recombinaison $\text{RGB} = L\cdot r$ boucle le remplissage conjoint.
Les énergies agissent sur des pixels complémentaires : le terme affine là où un canal survit (pondéré par sa corrélation $R^2$), le terme biharmonique par canal là où il ne survit pas, et le dôme de luminance partagé plus la diffusion de chrominance uniquement dans les cœurs entièrement écrêtés — ce dernier minimisé sous une inégalité : le rapport diffusé d’un canal écrêté ne peut jamais descendre en dessous de son plancher de saturation dans l’espace des rapports, $r_c \geq c_{0,c}/L_\text{sum}$, ce qui transforme le terme de chrominance en un problème d’obstacle (les mathématiques sont dans la sous-section chrominance). L’ensemble reconstructible lui-même est par canal : $\Omega_c$ contient les pixels au-dessus du seuil d’écrêtage — étendu jusqu’à $0.9$ de celui-ci pour les canaux dont le rolloff du capteur s’est enclenché (l’override de bande de l’étape 2), où le plancher $c_{0,c}$ est la mesure corrigée du coude plutôt que la lecture saturée. Chaque énergie est minimisée par son propre étage : le terme affine par les ajustements guidés (une fenêtre dimensionnée au rayon de reconstruction de la région) ; le terme de transport par la relaxation ancrée et orientée de l’étape 3 ; les termes de régularité par leurs résolutions linéaires directes. Il n’y a délibérément aucune énergie de lissage postérieure agissant sur la sortie : une conception antérieure lissait les coutures après coup avec un régularisateur pondéré par l’incertitude, et le retirer est le but même — les coutures ne sont jamais créées (voir le cimetière). C’est la même philosophie d’ingénierie que diffuse or sharpen : une pile de règles de mise à jour locales, physiquement motivées, dont le point fixe combiné est la reconstruction, plutôt qu’un seul problème inverse monolithique.
L’algorithme
Tout se passe sur la mosaïque raw, en RGB linéaire scene-referred, avant le dématriçage, et à pleine résolution. La méthode reconstruit chaque canal écrêté à partir des canaux qui ont survécu (le long de la ligne de couleur locale, en lui faisant confiance en proportion de sa tenue réelle), et là où aucun canal n’a survécu, elle reconstruit un seul dôme de luminance conjoint et porte la chrominance environnante vers l’intérieur.
La préparation de la mosaïque — dématriçage bilinéaire vers un RGB jetable, normalisation locale des canaux, et le masque d’écrêtage par canal — est partagée avec la méthode de 2021 et décrite dans sa section algorithme, avec un ajout et trois raffinements. L’ajout : pour les cœurs entièrement écrêtés, une magnitude scalaire $L_\text{sum}$ (la luminance sommée $R+G+B$) est séparée de la chrominance $\text{RGB}/L_\text{sum}$ — chaque canal divisé par la luminance sommée, une description bornée et sans luminosité de la couleur que cet article utilise systématiquement sous ce nom — afin que les deux puissent être reconstruites par des moyens différents : un dôme pour la magnitude, une diffusion pour la chrominance. Les raffinements, chacun tracé depuis un artefact de bord mesuré :
- les masques sont binaires, de bout en bout. Le mode 2021 adoucit son masque ; le successeur garde chaque masque de validité et de composition franc (son unique poids lisse est le passage de relais flouté du cœur conjoint, étape 7 de l’algorithme, qui mélange deux reconstructions — il ne reclasse jamais des mesures). Les masques de validité par canal filtrent chaque ajustement et chaque évaluation, et les adoucir reclassait des photosites écrêtés en bord — dont les valeurs raw se situent au seuil de détection, biaisées vers le bas sous le rolloff du capteur — comme des ancres valides sur des contours obliques, tirant la reconstruction du bord vers le niveau d’écrêtage (une rampe affaissée d’environ $\sim 10$ px par rapport à la vérité terrain). Le poids de composition est un commutateur franc : les photosites valides conservent exactement leur mesure, les photosites écrêtés prennent la reconstruction pure (un alpha adouci a été mesuré comme ne changeant rien une fois les deux correctifs de cette liste en place — le retrait est documenté dans le cimetière).
- les valeurs raw écrêtées sont des planchers, jamais des cibles de mélange. Sur les photosites écrêtés, la lecture raw est une borne inférieure, non une mesure : la composition écrit $\max(\text{raw}, \text{reconstruction})$, jamais un mélange vers la lecture biaisée (l’ancien mélange adouci imprimait un creux en V à travers la valeur raw à chaque contour).
- les bords se reflètent. L’anneau de bord de la collecte bilinéaire copiait auparavant le photosite central dans les trois canaux et calait les trois drapeaux d’écrêtage sur le canal propre du centre — corrompant les guides et pointillant les masques le long des premières et dernières lignes et colonnes, ce qui ancrait les ajustements des lignes de bord au niveau d’écrêtage. Une indexation par voisin réfléchi (le motif Bayer est 2-périodique, si bien que le miroir préserve la couleur de chaque voisin) restaure la logique intérieure sur les bords ; ce correctif est partagé avec le mode 2021.
Chaque scène de vérité terrain s’est améliorée sur les deux métriques grâce à ces trois seuls raffinements — l’erreur du ciel à rolloff a chuté d’un tiers — car les anneaux de bord du banc d’essai sont exactement là où les ancres biaisées s’infiltraient auparavant.
L’objectif conceptuel de la reconstruction peut s’énoncer en une phrase : partout où au moins un canal a survécu, la reconstruction est un problème de régression, et non un problème d’inpainting : les canaux valides sont des données mesurées, présentes à chaque pixel de la zone écrêtée, portant la structure réelle de la scène. L’unique règle de conception de l’algorithme, apprise à la dure, est qu’aucune étape ne peut passer le relais entre des estimateurs qui sont en désaccord (la loi d’énergie de couture des conclusions théoriques). Chaque étage ci-dessous est donc soit sans couture par construction, soit débiaise les données pour que les estimateurs s’accordent.
La procédure étape par étape, telle qu’implémentée dans process_harmonic_bayer (et son jumeau X-Trans) :
Les numéros dans le graphe renvoient aux étapes détaillées en dessous.
flowchart TD
subgraph P ["once per image"]
direction TB
A["raw mosaic"] --> B["1 · interpolate
+ clip masks"]
B --> K["2 · knee inversion"]
K --> S["1 · depth map
+ segmentation"]
end
subgraph R ["for each clipped region"]
direction TB
CF["3 · colour-line fits
(magnitude + texture)"] --> HF["4 · fine-detail refit"]
HF --> SD["5–6 · floors
+ self-dome"]
SD --> JC["7 · all-clipped core"]
JC --> AN["8 · chrominance coherence"]
end
S --> CF
AN --> O["remosaic + composite"]
1. Détection, interpolation, segmentation. La mosaïque raw de la matrice de filtres colorés est interpolée bilinéairement, avec des drapeaux d’écrêtage par canal levés à $0.995\,c$ pour un niveau d’écrêtage $c$ et un masque de validité binaire par canal ; la transformée de distance euclidienne donne alors à chaque pixel sa profondeur $\delta$ à l’intérieur de la zone écrêtée, et la segmentation en composantes connexes regroupe les pixels écrêtés en régions, chacune portant son rayon de reconstruction issu de la transformée de distance.
2. Inversion du rolloff (coude) du capteur. Les capteurs réels compressent les derniers pour-cent sous la saturation, si bien que la bande proche de l’écrêtage $[0.8\,c, 0.995\,c)$ contient des valeurs biaisées vers le bas. (La bande est coupée généreusement : sur les capteurs qui écrêtent franchement au lieu de faire un rolloff, la garantie de non-opération ci-dessous rend la largeur supplémentaire gratuite.) La reconstruction extrapole des estimations non biaisées sur cette bande, si bien que les deux sont en désaccord au contour de détection : une couture qu’aucune pondération ne peut supprimer. Le correctif débiaise les données elles-mêmes : une régression conjointe fenêtrée prédit chaque valeur de la bande à partir des canaux pleinement fiables, les paires (mesuré, prédit) sont regroupées en 24 casiers sur la bande, et le rehaussement médian par casier n’est accepté que lorsqu’il est statistiquement significatif — médiane au-dessus du double de son erreur type, une porte de confiance à $\approx 95\,\%$, avec au moins 100 votes pour que l’estimation d’erreur elle-même soit stable ; 24 casiers est le plus fin découpage possible de la bande tout en gardant peuplé chaque casier :
où $k$ est la compression inconnue du capteur, si bien que $\hat{k}^{-1}$ est la
correction estimée — la fonction qui prend une valeur mesurée $v$ dans la bande et renvoie
ce que le capteur aurait dû enregistrer. Les $v_i$ sont tous les pixels mesurés de la bande dont la valeur
tombe dans le même casier que $v$ ; chaque $\hat v_i$ est ce que la
régression par ligne de couleur prédit que ce pixel devrait être, à en juger par ses
canaux voisins pleinement fiables. Leur différence $\hat v_i - v_i$ est le vote d’un pixel sur l’ampleur du
sous-enregistrement du capteur à ce niveau, et la correction du casier est la médiane de ses votes —
robuste aux valeurs aberrantes qu’une moyenne suivrait. La courbe résultante est ensuite rendue monotone et
uniquement croissante. Sur des données écrêtées franchement (non biaisées), chaque médiane de casier est nulle au
bruit près, si bien que la correction possède une garantie de non-opération, vérifiée bit-exact sur les quatre cas
synthétiques à écrêtage franc, tandis que sur pk1synth (la seule scène synthétique générée avec un rolloff
analytique du capteur, si bien que sa vérité terrain trace le vrai coude) l’estimation aveugle correspond à la vraie
courbe à une erreur quadratique moyenne de $7\cdot10^{-4}$ sur le canal vert et $1.8\cdot10^{-3}$
sur le canal rouge, plus clairsemé :
L’override de bande. Le rehaussement restaure le niveau de la bande, mais une table de valeurs ne peut pas restaurer une pente que le capteur n’a jamais enregistrée : là où la compression a aplati la bande jusqu’à une quasi-constante, la bande rehaussée est elle aussi quasi-constante, et sa jonction avec la reconstruction montante imprime un fin double contour sous grossissement des arêtes (la bande est mesurablement $7$–$14\times$ plus plate que la vérité terrain, encadrée par deux pics de gradient). L’information n’est cependant pas perdue — les guides sont non écrêtés à travers la bande et portent la vraie pente. Ainsi, pour chaque canal dont le rolloff s’est enclenché, la détection s’étend sous le seuil jusque dans la bande profonde : ces pixels sont reconstruits par le modèle de ligne de couleur comme n’importe quel pixel écrêté, avec leur mesure rehaussée au coude comme plancher de saturation par pixel, et les ajustements s’ancrent sur des données corrigées du coude sous la bande. Le plancher rend l’override conservateur par construction — sur des images réelles bruitées, le modèle dépasse rarement la mesure rehaussée, et la sortie reste identique au pixel près ; sur la scène de banc à rolloff, où le modèle connaît véritablement la pente, l’erreur de zone chute d’un autre facteur cinq lorsque l’override intervient (RMSE $0.012 \to 0.0025$ mesuré alors ; $0.0053$ dans la version livrée, après que les tours de composition ultérieurs ont pris leur propre part) et le profil de gradient du contour devient indiscernable de la vérité terrain. Les canaux sans rolloff mesuré gardent la détection ordinaire : sur les capteurs à écrêtage franc, la bande est une donnée fiable et reste ancrée.
3. Le champ de coefficients. Pour chaque canal écrêté $v$ avec les guides $u_1, u_2$, un ajustement par moindres carrés pondérés fenêtrés est calculé à une seule échelle $\sigma = \operatorname{clip}(r/6, 8, 64)$ (avec $r$ le rayon de reconstruction de la région — le support $\pm 3\sigma$ de la fenêtre couvre alors le rayon, de sorte que même l’ajustement du pixel le plus profond atteint des données valides ; le plancher garde assez d’échantillons pour un ajustement stable sur les petites régions, et le plafond borne le coût des immenses), sur les pixels où les trois canaux sont valides :
où $x$ est le pixel dont le modèle local est en cours de construction et $y$ parcourt ses voisins. La fenêtre $G_\sigma(x-y)$ est une gaussienne qui pondère les voisins par la distance (plein poids à proximité, s’estompant sur environ $\sigma$ pixels), et $w(y)$ est le masque de confiance — un sur les pixels où les trois canaux portent de vraies mesures, zéro ailleurs, si bien que les pixels écrêtés ne votent jamais. La première ligne demande, à chaque $x$ : quelles pentes $a, b$ sur les deux guides et quel décalage $d$ expliquent le mieux le canal écrêté sur le voisinage de confiance ? La seconde ligne utilise alors ce modèle local : l’estimation $\hat v(x)$ lit les deux guides en $x$ lui-même et les fait passer par la relation ajustée. En pratique la minimisation n’est jamais exécutée par pixel — elle est résolue à partir de dix plans de moments floutés (un décompte de masse de confiance, trois moyennes, six seconds moments, recueillis en trois flous à quatre canaux) via les équations normales $2\times2$. Les moments sont accumulés autour de la moyenne par région de chaque canal : en arithmétique flottante, la forme brute $E[u^2] - E[u]^2$ s’annule catastrophiquement sur un contenu lisse (la moyenne au carré éclipse la variance) et la division de l’ajustement amplifie les chiffres survivants en bruit de pente dépendant du matériel — le centrage supprime l’annulation, et les pentes et $R^2$ sont invariants sous le décalage tandis que l’ordonnée à l’origine est décalée juste après l’ajustement. Le système est résolu avec un amortissement de Tikhonov (ridge) relatif $\lambda = 10^{-3}\,(\operatorname{var} u_1 + \operatorname{var} u_2)/2$ qui varie avec le signal au lieu de manger les pentes faibles mais réelles. Le $10^{-3}$ est le plus petit facteur qui a stabilisé les fenêtres dégénérées sur le banc — au-delà, on commence à aplatir de vraies pentes.
La nouveauté est ce qui se passe ensuite : au lieu d’évaluer chaque pixel avec l’ajustement que sa propre fenêtre a pu atteindre (la manière de l’échelle), les plans de coefficients eux-mêmes sont diffusés à travers la zone écrêtée, orientés par la structure mesurée du guide, et alors seulement évalués contre les guides mesurés. Les coefficients sont lisses par nature là où les valeurs ne le sont pas : les diffuser transporte le modèle dans la zone, et l’évaluation restaure toute la structure locale portée par les canaux valides. Pas d’échelles, pas de portes de profondeur, pas d’écritures par lignes de niveau (pas d’anneaux de profondeur égale estampés séparément) — pas de coutures, par construction. Ce transport du modèle plutôt que du contenu est l’idée la plus transposable de l’article, et en quoi il diffère par nature du propre flou de coefficients du filtre guidé est exposé dans Trois résultats que nous croyons généraux. Un pixel se qualifie comme ancre de diffusion seulement si sa fenêtre contenait assez de masse de confiance et si son ajustement est sain : le $R^2$ de l’ajustement, le coefficient de détermination, est la part de la variance locale du canal que la ligne de couleur explique (1 signifie que les guides prédisent parfaitement le canal, 0 signifie pas du tout), et les ancres exigent $R^2 > 0.25$ avec des pentes bornées. Les deux portes sont calibrées à partir de mesures, non du goût : un contenu sans aucune ligne de couleur obtient tout de même $R^2 \approx 0.25$–$0.6$ (contre $\approx 0.9$ là où la ligne de couleur est réelle), si bien que la porte ne rejette que les ajustements pires qu’une pure décorrélation — des accidents numériques, non des modèles faibles ; et les pentes physiques de ligne de couleur sont bornées par les rapports de saturation des canaux (sous $4$ sur chaque appareil mesuré), si bien que la borne $|a| < 64$ se situe un ordre de grandeur au-dessus de tout ce qui est physique, et seules les fenêtres dégénérées à variance quasi nulle — dont les pentes explosives empoisonneraient la frontière de diffusion — la déclenchent jamais. La diffusion est un remplissage de Jacobi du grossier vers le fin : chaque inconnue est remplacée à répétition par la moyenne qu’impliquent ses voisins. Trois termes portent tout le schéma :
- Cellule. Le remplissage ne s’exécute pas par pixel. Les plans de coefficients vivent sur une grille grossière de pas $\sigma/4$ (bornée à au plus $8$ px), et une cellule est un nœud de cette grille — un bloc de pixels de taille $\sigma/4$. Les coefficients sortent de fenêtres d’ajustement larges de $\sigma$, si bien que quatre cellules par $\sigma$ les suréchantillonnent, et le bornage du pas limite l’erreur de suréchantillonnage bilinéaire final.
- Ancre. Une cellule dont la fenêtre d’ajustement a franchi les portes de confiance ci-dessus — elle contient un coefficient effectivement mesuré sur des données valides.
- Épinglée. Les balayages traitent les ancres comme des données de frontière fixes et ne réécrivent jamais que les cellules inconnues entre elles.
Cette forme est choisie pour la robustesse. Un gradient conjugué en flottant sur le système pur-harmonique quasi singulier diverge de façon stochastique lorsque la zone atteint la frontière de la région. Jacobi avec ancres épinglées ne le peut pas : chaque mise à jour est une moyenne de voisins, si bien que la relaxation obéit au principe du maximum — aucune inconnue ne peut jamais quitter la plage des valeurs d’ancre.
La convergence vient de la profondeur de la pyramide, non du nombre de balayages. Le niveau le plus grossier part d’une moyenne d’ancres plate — l’état le plus éloigné possible de la solution — et le mode d’erreur le plus lent de Jacobi sur un trou large de $N$ cellules décroît en $\mathcal{O}(N^2)$ balayages. La pyramide continue donc de diviser par deux jusqu’à ce que le grand côté de la grille la plus grossière soit d’au plus $8$ cellules ($8^2 = 64$ balayages pour relaxer, confortablement dans le budget), et chaque niveau exécute alors les mêmes $100$ balayages plats — les niveaux plus fins ne corrigent que l’erreur d’interpolation locale. Une pyramide moins profonde avec un décompte fixe a mesurablement tronqué le remplissage sur les trous profonds — les chiffres sont dans les résultats généraux ci-dessous.
Note
C’est l’unique pyramide restante de la méthode, et elle appartient au remplissage — le transport de coefficients déjà ajustés. Elle n’a aucun rapport avec les fenêtres d’ajustement, qui utilisent un seul $\sigma$ dérivé du rayon par région (des fenêtres multi-échelles n’existent qu’à l’intérieur de l’estimateur du coude), et ce n’est pas la pyramide de chroma en forme de trace, retirée, du cœur entièrement écrêté, que la résolution directe en forme de divergence a remplacée et qui ne survit que comme repli pour les cœurs au-dessus de $2^{14}$ inconnues.Le transport lui-même n’est pas uniforme non plus : il est orienté par la structure mesurée du guide. Un plan d’orientation $L_\text{mean}$ — la moyenne des canaux valides partout où au moins un survit, la moyenne du plateau plat dans le cœur entièrement écrêté (où le tenseur dégénère alors vers l’identité) ; c’est une luminance différente de la magnitude sommée $L_\text{sum}$ qu’utilisent le dôme et les rapports — est sous-échantillonné à chaque niveau de la pyramide, et les moyennes de voisins sont pondérées par le tenseur anisotrope
où $g$ est la direction du gradient unitaire de $L_\text{mean}$ (montante), $t$ la direction unitaire de l’isophote, et $\langle\lVert\nabla L_\text{mean}\rVert\rangle$ la magnitude du gradient moyennée sur la région — la normalisation qui rend l’amortissement indépendant de l’exposition — (le long des lignes de niveau), et $c_2$ le même amortissement de traversée d’arête que la passe de chrominance de l’étape 8. Normaliser le gradient par sa propre moyenne régionale rend cet amortissement sans échelle — seuls les gradients bien au-dessus de la moyenne du halo se lisent comme des frontières, le $4$ réglant la douceur de la lecture. Le poids de mélange $m \in [0, 1]$ est la probabilité d’arête, mesurée à partir de la variance fenêtrée corrigée de tendance de $L_\text{mean}$ :
où $\operatorname{var}_w$ et $\bar L_\text{mean}$ sont la variance et la moyenne fenêtrées du plan d’orientation, et le terme $\tfrac{4}{3}\lVert\nabla L_\text{mean}\rVert^2$ soustrait la variance que la rampe locale explique : une rampe pure de pente $\nabla L_\text{mean}$ vue à travers une fenêtre de variance spatiale $\sigma_w^2$ a une variance d’intensité $\sigma_w^2 \lVert\nabla L_\text{mean}\rVert^2$, et la fenêtre ici (deux passes de boîte $3\times3$) a $\sigma_w^2 = 2 \cdot \tfrac{2}{3} = \tfrac{4}{3}$ par axe. Un gradient de halo lisse, si raide soit-il, ne laisse donc aucun résidu, tandis qu’une arête franche laisse une variance qu’aucune rampe ne peut expliquer. Le seuil $k$ — le contraste relatif au-dessus duquel une texture résiduelle se lit comme une frontière — est la seule constante du transport qui n’a pas pu être dérivée, elle a donc été calibrée par un balayage fin empirique sur les six scènes de vérité terrain : chaque scène reste au niveau ou en dessous de l’erreur isotrope sur toute la plage $k \in [0.14, 0.25]$ (la conception n’y est pas fragile), et $k = 0.15$ est la valeur qui améliore chaque scène simultanément et remporte le gain d’occlusion avec marge. Les deux limites de $m$ se lisent naturellement. Sur une rampe de halo propre ($m \to 0$), $D \to g\,g^{\top} + c_2\,t\,t^{\top}$ : le modèle voyage radialement, le long de la rampe de luminosité depuis le bord vers l’intérieur, là où son information vit réellement. Là où une arête franche traverse la zone brûlée ($m \to 1$), $D \to t\,t^{\top} + c_2\,g\,g^{\top}$ avec $c_2$ petit : le transport court le long de la frontière et refuse de la traverser — une arête à l’intérieur de la zone signifie que le contenu au-delà suit une autre ligne de couleur, et mélanger les deux modèles à travers elle est exactement le défaut d’occlusion que le cimetière documente. La discrétisation utilise le gabarit préservant la non-négativité partagé avec la diffusion de l’étape 8 (les huit poids de voisins $\geq 0$), si bien que le remplissage orienté reste une combinaison convexe de ses ancres : le principe du maximum survit à l’orientation. Un plancher de poids de $10^{-4}$ garde chaque cellule connectée là où le tenseur s’effondre vers zéro ; quatre ordres de grandeur sous les poids de travail, il ne concurrence jamais l’orientation. Les pixels avec un seul guide survivant reçoivent le même traitement avec un ajustement à un guide.
Une subtilité d’ordonnancement complète l’étape. Le canal le plus profond — celui qui a le plus de photosites écrêtés, dont la zone contient les cœurs où plusieurs canaux sont brûlés à la fois — n’est pas évalué tout de suite : ses coefficients diffusés sont mis de côté, et l’évaluation s’exécute en dernier, après que les autres canaux écrêtés ont été reconstruits, de sorte que chaque guide qu’il lit est une surface continue. L’évaluer contre un guide qui saute de valeurs mesurées à un plateau d’écrêtage imprimerait le propre contour d’écrêtage de ce guide dans le résultat sous forme d’arc visible. Profondément à l’intérieur du cœur, où ces guides sont eux-mêmes des reconstructions (de sorte que chaque saut compose l’erreur), l’estimation se fond de nouveau vers l’ajustement direct à un guide à travers un poids lisse — un poids lisse multipliant des champs lisses ne laisse aucune ligne de niveau à imprimer.
La qualité de l’ajustement $R^2$ est diffusée aux côtés de $(a, b, d)$ comme un quatrième plan, sur l’ensemble d’ancres plus large basé sur la seule masse (elle reste bornée même là où l’ajustement ne l’est pas).
4. Guidage hybride en bande laplacienne des hautes fréquences. L’ajustement sur signal complet transfère la texture fine des guides avec les gains impliqués par la covariance totale ; là où la ligne de couleur est faible, cette texture n’a pas sa place sur le canal reconstruit. L’estimation est séparée à $\sigma/4$ et sa bande de détail est reconstruite à partir de deux sources candidates : le transfert amorti (les hautes fréquences du signal complet mises à l’échelle par le $R^2$ diffusé) et une ligne de couleur dédiée à la bande de détail (l’homonyme de la méthode de 2021, de retour), ajustée sur les plans haute fréquence avec des gains rétrécis par $R^2$ (sur une bande de moyenne nulle, le rétrécissement est l’estimateur correct : il n’y a pas de magnitude à perdre, seulement du bruit à ne pas imprimer). Les deux sont mélangés par des cotes quadratiques de min-énergie,
ce qui ne nécessite aucun discriminateur de contenu : un gain de fenêtre mixte se déclenchant à mauvais escient à une arête d’objet apparaît comme un pic local d’énergie haute fréquence, si bien que la défaillance se détecte d’elle-même et le chemin amorti prend le relais exactement là. C’est ce qui supprime le dernier résidu de la scène à rolloff (son score d’arêtes excédentaires chute de 1.48 à 0.94 contre un plancher de vérité terrain de 0.69 : le bruit de la bande décompressée ne s’imprime plus — les correctifs de biais de bord de la version finale le portent à 0.74, et l’override de bande de l’étape 2 à 0.64, la table des résultats) tout en améliorant les cas texturés que l’ajustement pur en bande de détail avait l’habitude de casser.
5. Plancher de saturation adouci. Le plancher physique (un canal écrêté est au moins à sa lecture saturée $c_0$) est appliqué comme une contrainte arrondie, $\tfrac{1}{2}\big(e + c_0 + \sqrt{(e - c_0)^2 + (0.02\,c_0)^2}\,\big)$ : le $\max(e, c_0)$ franc imprime le contour de la contrainte comme une arête partout où une prédiction faible oscille autour de la saturation. La largeur de transition $0.02\,c_0$ est de deux pour-cent de la valeur saturée — sous tout ce qui est visible, mais assez large pour que le gradient de la contrainte ne saute jamais.
6. Auto-dôme couplé en teinte et filtré par la profondeur. Là où le modèle est douteux et que le pixel est peu profond, une auto-continuation lisse prend le relais, construite couplée en teinte (les canaux sont couplés par une seule chrominance partagée, de sorte que la teinte perçue ne peut pas dériver) : un seul dôme biharmonique de luminance partagé multiplié par une chrominance remplie harmoniquement, jamais trois canaux indépendants, si bien que le repli ne peut pas scinder la teinte vers le vert/magenta (le défaut qui maintenait son ancêtre par canal désactivé). Le poids de passage de relais est :
où $\delta$ est la profondeur du pixel à l’intérieur de la zone écrêtée (sa distance au pixel valide le plus proche), $\sigma$ l’échelle d’ajustement, et $S$ un smoothstep, une rampe douce de 0 à 1 entre les deux seuils, faisant ici correspondre une qualité d’ajustement inférieure à $0.4$ à « douteux » et supérieure à $0.85$ à « fiable ». Les bords de la bande et l’échelle de profondeur $1.5\sigma$ ont été réglés sur le banc de vérité terrain ; l’échelle de profondeur lie la portée du dôme à la propre portée de la fenêtre d’ajustement, de sorte que le passage de relais se produit là où l’ajustement manque véritablement d’échantillons. Les deux facteurs répondent à deux questions différentes : $R^2$ demande la ligne de couleur est-elle réelle ici, et la profondeur demande le dôme est-il fiable ici (l’extrapolation biharmonique est excellente près du bord et se dégrade avec la distance). La profondeur est le seul signal que nous ayons trouvé dont les distributions séparent effectivement les zones profondes corrélées du contenu peu profond décorrélé (voir le cimetière) ; les intérieurs profonds restent toujours sur le champ de coefficients.
7. Cœur conjoint, adouci. Les pixels entièrement écrêtés n’ont pas de guides : le dôme de luminance biharmonique partagé et la diffusion de rim-chrominance filtrée de la reconstruction les reconstruisent, inchangés — mais la composition est désormais adoucie sur un masque flouté d’écrêtage complet au lieu d’être écrite à travers un masque franc. Le dôme et la chrominance diffusée sont tous deux valides au-delà de la frontière du trou, de sorte que les mélanger dans les canaux écrêtés de l’anneau environnant est continu dans l’espace sans aucun coût pour le cœur lui-même.
8. Chrominance coherence. The structure-steered chrominance of the all-clip core is now solved directly. The unknown $u$ is each chrominance plane in turn ; the equation is $\mathrm{div}(D\,\nabla u) = 0$, the steady state of the anisotropic diffusion of the theory section and, equivalently, the exact minimizer of its weighted smoothness energy $\int_\Omega \nabla u^\top D\,\nabla u\,\mathrm{d}\Omega$, with the coefficient-field results as Dirichlet anchors, fixed boundary values the solve must honour. The tensor is built from the recovered luminance (the reconstruction’s own output, smoothed by two box-blur passes) : with $g$ the unit gradient of that smoothed luminance and $t = g^\perp$ the isophote direction,
c’est-à-dire : conductance de un le long des isophotes, amortie exponentiellement à travers elles, l’amortissement normalisé par la propre magnitude moyenne du gradient de l’image $\langle \lVert \nabla L_\text{sum} \rVert \rangle$ afin que l’orientation ne dépende pas de l’exposition (ce tenseur lit la luminance sommée récupérée — la forme jumelle du remplissage de coefficients lit $L_\text{mean}$). La discrétisation est le gabarit préservant la non-négativité de Weickert, une M-matrice symétrique définie positive, si bien que le principe du maximum discret tient par construction : les rapports diffusés ne peuvent jamais dépasser la chrominance du bord, ce que le flux explicite antérieur pouvait faire. La factorisation de Cholesky creuse factorise le cœur une fois et rétro-substitue les trois canaux. (Une confrontation de solveurs se cache derrière ce choix : voir le cimetière pour l’échec instructif de l’autre formulation exacte.) Le re-mosaïquage final compose la sortie à partir du CFA corrigé du coude, si bien que la bande débiaisée atteint le fichier, et pas seulement les ajustements.
Les règles de mise à jour
Le problème d’optimisation énonce ce que la reconstruction minimise et l’algorithme narre ses étapes ; la discussion ci-dessous analyse la conception — ce que les paramètres représentent, comment ils ont été réglés, comment les choix se rapportent à la théorie établie. Ce dont a besoin un implémenteur partant de zéro, ce sont les mises à jour de signal effectives : quelle équation écrit quel plan, dans quel ordre. Voici le catalogue complet, dans l’ordre d’exécution, pour une région. Plans : estimations par canal $u_c$ (initialisées à l’interpolation bilinéaire de la mosaïque mesurée, corrigée du coude), validités binaires $v_c$, planchers par pixel $c_{0,c}$ (la mesure corrigée du coude de chaque pixel reconstructible), luminance sommée $L_\text{sum} = \sum_c u_c$ et rapports $r_c = u_c / L_\text{sum}$ (le plan d’orientation $L_\text{mean}$ de la règle 1 est la moyenne des canaux valides, une quantité distincte).
1. Ajuster et transporter la ligne de couleur (étapes 2–3 de l’algorithme). L’ajustement se fait sur les valeurs de pixel complètes — jamais le détail à moyenne soustraite — et n’utilise que les échantillons où les canaux impliqués sont valides. Dans la forme à un guide, sur la fenêtre gaussienne $\omega$ :
avec $\varepsilon$ un amortissement de Tikhonov relatif protégeant la division là où le guide est plat ; la forme à deux guides résout les équations normales $2\times2$ analogues pour $(a, b, d)$ à partir des dix plans de moments floutés par gaussienne. La pente n’est pas bornée en signe (une révision précoce de l’échelle la bornait ; les ajustements livrés sont plutôt protégés par les portes d’ancre $R^2 > 0.25$ et $|a| < 64$). Deux portes de plus qu’un implémenteur ne doit pas ignorer : les fenêtres d’ajustement sont pondérées par une affinité de luminance douce $\min(L_\text{sum} / 0.35\,\bar L_\text{sum}^{\,\text{rim}}, 1)^2$ — les échantillons bien plus sombres que le bord (occulteurs) votent à peine — et une fenêtre n’ancre le transport que là où sa masse pondérée dépasse à la fois un plancher absolu (0.05) et un quart de sa masse valide non pondérée, si bien que les fenêtres occultées défèrent au remplissage plutôt que d’ajuster l’occulteur. Comme l’ajustement se fait sur les valeurs, l’ordonnée à l’origine porte la moyenne locale de la couleur : la prédiction hérite du niveau des données valides environnantes, pas seulement de sa texture, si bien que là où le guide continue de monter dans la haute lumière, l’estimation le suit — au-dessus de la valeur d’écrêtage. En pratique, l’ajustement n’est jamais exécuté par pixel : les moments sont des plans de produits floutés par gaussienne, centrés sur les moyennes valides par région contre l’annulation en flottant.
Note
Ajuster à partir des seuls échantillons valides est essentiel. Les échantillons écrêtés sont épinglés au point blanc ; les inclure aplatirait la pente observée, et le modèle reproduirait la valeur écrêtée au lieu d’extrapoler au-delà. C’est l’unique subtilité qui sépare une reconstruction fonctionnelle d’une reconstruction qui se contente de re-peindre l’écrêtage.Filtrez les ancres ($R^2 > 0.25$, pentes bornées, masse de confiance), puis diffusez chaque plan de coefficients par des balayages de Jacobi ancrés sur la grille grossière — la mise à jour d’un balayage à une cellule non ancre $i$, avec les huit poids de Weickert $w_{ik}$ du tenseur $D$ :
ancres maintenues fixes, 100 balayages par niveau de pyramide, niveau le plus grossier amorcé avec la moyenne des ancres et chaque niveau plus fin amorcé par suréchantillonnage bilinéaire de la solution plus grossière ; même mise à jour pour $b$, $d$ et $R^2$. Puis évaluez le modèle transporté contre les guides mesurés, à chaque pixel où la cible est écrêtée et les deux guides sont valides :
Les pixels avec un seul guide valide prennent la même mise à jour depuis l’ajustement à un guide $u_c \leftarrow a\, u_g + d$. L’évaluation du canal le plus profond est différée jusqu’à ce que les autres canaux écrêtés soient reconstruits, de sorte que ses guides sont des surfaces continues.
2. Reconstruire les hautes fréquences (étape 4). Séparez $u_{g}$ en basse fréquence $\bar u_g$ (gaussienne à $\sigma/4$, plancher à 2 px — les moments utilisent le $\sigma$ de l’ajustement, la séparation de bande non) et détail $u_g - \bar u_g$ ; formez les deux candidats — le transfert de guide $h_g = a\,(u_{g_1} - \bar u_{g_1}) + b\,(u_{g_2} - \bar u_{g_2})$ et l’auto-détail amorti $h_d = R^2 (u_c - \bar u_c)$ — et mélangez-les par des cotes quadratiques de min-énergie sur leurs énergies locales (floutées par gaussienne) $e_g, e_d$, exactement comme l’énonce l’étape 4 (un commutateur franc réintroduirait une couture de passage de relais) :
3. Plancher de saturation adouci (étape 5), partout où un canal est reconstructible, avec $w = 0.02\, c_{0,c}$ :
4. Auto-dôme filtré par la profondeur (étape 6). Résolvez une continuation biharmonique partagée de la luminance sur le trou, $\Delta^2 L_b = 0$ avec $L_b$ ancré sur le bord (Cholesky creux direct sur le bilaplacien discret à 13 points, grille grossière — le même solveur que documente la section d’implémentation), séparez sa chrominance du bord ($\bar r_c$, remplissage harmonique), et mélangez par la fraction de dôme $f$ :
avec $\delta$ la profondeur du pixel à l’intérieur de la zone écrêtée (sa distance au pixel valide le plus proche — le seul sens que $\delta$ porte dans cet article).
5. Cœur entièrement écrêté (étapes 7–8), sur les pixels où aucun canal n’a survécu. Magnitude : le dôme biharmonique $\Delta^2 L = 0$ ancré sur l’anneau (déjà reconstruit). Chrominance : d’abord le remplissage de bord de Poisson filtré par canal, $(\Delta - \lambda)\, r_c = -\lambda\, \bar c_c$ avec $\bar c_c$ la chromaticité valide moyenne de la région rembourrée et $\lambda$ la réaction de couleur plate (résolution creuse directe, factorisation partagée) ; puis la passe orientée par la structure. Sa forme primaire est la résolution exacte en forme de divergence de l’étape 8 (laplacien de graphe à 8 voisins pondéré par les arêtes, factorisation creuse directe) ; les cœurs au-dessus de $2^{14}$ inconnues prennent la pyramide explicite en forme de trace à la place — des pas sous l’obstacle, itérés 240 fois par niveau :
suivis d’un polissage projeté de 60 balayages à pleine résolution (filtré par activité : il ne s’exécute que là où un pixel repose effectivement sur son plancher). Réassemblage, par pixel du cœur entièrement écrêté — les seuls pixels que cette passe écrit ; les pixels partiellement écrêtés ont été réglés par les règles 1–4 et agissent comme ses ancres :
avec plancher adouci comme dans la règle 3. (Le code porte aussi une branche de transfert de magnitude pour les pixels partiellement valides, un reliquat de l’ère de l’échelle que la construction des ancres rend inatteignable — documenté ici pour que personne ne le transcrive.)
6. Grain et composition. Ajoutez le grain poissonien de la sous-section suivante là où c’est demandé, puis réécrivez à travers le commutateur franc : les photosites reconstructibles prennent $\max(\text{raw}, u_c)$, les photosites valides conservent leur mesure intacte.
Tout le reste du pipeline — l’estimation du coude, la segmentation, le rembourrage — prépare les entrées de ces six mises à jour ; rien d’autre n’écrit un pixel.
Discussion
Les opérateurs que l’algorithme compose ne sont pas arbitraires : chacun est l’estimateur que son terme d’énergie prescrit, et chacun porte des propriétés mesurables sur lesquelles la conception s’appuie. Cette sous-section les dérive, et se clôt par l’étude de paramètres qui dimensionne toute la méthode — jusqu’où une reconstruction devrait atteindre.
Faire confiance au guide
L’emprunt à la ligne de couleur ne vaut que par l’hypothèse qui le sous-tend : que le canal écrêté et son guide sont, localement, liés affinement. Sur une surface naturelle, ils le sont ; sur un contenu pathologique (des gradients indépendants par canal, ou une frontière entre deux matériaux de couleurs différentes), ils ne le sont pas, et forcer l’emprunt peindrait une structure qui n’a pas sa place. L’ajustement lui-même indique jusqu’où lui faire confiance : $R^2$ (défini avec l’ajustement, dans les règles de mise à jour) est la part de la variance locale du canal que la ligne de couleur explique — $1$ là où le modèle tient, $0$ là où l’emprunt n’a pas de sens.
Ainsi la méthode ne bascule jamais entre remplissage inter-canaux et remplissage mono-canal — elle les mélange par confiance, se repliant sur l’extension vers l’intérieur du propre gradient du canal écrêté (inpainting biharmonique par canal, ancré sur le vrai bord valide de ce canal) à mesure que la ligne de couleur s’affaiblit. Le poids de mélange est la confiance au carré $W_e = (R^2)^2$, et l’exposant est un choix mesuré, non un goût. Sur les pixels écrêtés, $R^2$ ne sépare les deux régimes qu’avec une marge douce : il vaut en moyenne $\approx 0.9$ sur un contenu de type naturel, $\approx 0.65$ sur un contenu décorrélé, et les deux distributions se recouvrent de $\sim15\%$ — et aucune statistique moins coûteuse ne fait mieux (la stabilité de pente inter-échelles et l’accord inter-guides ont toutes deux été mesurées comme séparant moins bien, si bien que $R^2$ est le plafond honnête). Utilisé linéairement, le cas décorrélé prendrait tout de même $\sim65\%$ d’une estimation inter-canaux à la fois fausse et — parce que la sélection de guide franche bascule là — discontinue. La mise au carré écarte les régimes : $0.9^2 \approx 0.81$ bouge à peine le cas fiable, tandis que $0.65^2 \approx 0.42$ divise par deux le cas non fiable, si bien que les pixels décorrélés s’appuient sur le remplissage lisse par propre gradient. Comme la marge est douce, cependant, une couture ténue survit tout de même sur le contenu le plus adverse : la mise au carré ne peut pas masquer entièrement une discontinuité dans la quantité qu’elle pondère, et ce résidu est la raison d’être de la règle de conception « ne jamais créer de coutures » (voir le cimetière).
Là où aucun canal ne survit, il n’y a ni guide ni $R^2$ à pondérer, si bien que la reconstruction passe le relais au cœur conjoint de la section suivante. Le mélange est donc filtré par la validité du guide et pondéré par la corrélation au carré, non par un décompte franc de canaux écrêtés : un seul mécanisme couvre toute la plage depuis un écrêtage d’un canal (surtout inter-canaux) à travers un écrêtage de deux canaux (le canal survivant guide) jusqu’à un cœur entièrement brûlé (le dôme conjoint). C’est ce qui fait que la méthode se dégrade gracieusement à mesure que la corrélation inter-canaux chute : sur les images de test de type naturel, le terme inter-canaux domine, sur les gradients aléatoires adverses, l’auto-extension prend le relais, et la reconstruction ne fabrique jamais une ligne de couleur qui n’est pas là. C’est la corrélation, non le nombre de survivants, qui décide si un guide peut être fiable — un pixel à deux survivants sur un contenu décorrélé n’est pas mieux guidé qu’un pixel à un survivant sur une ligne de couleur propre.
Remplir les trous sans survivant
Là où chaque canal écrête, aucune ligne de couleur ne peut être ajustée : le détail fin de la haute lumière et son pic exact sont véritablement perdus. Mais deux choses peuvent encore être sauvées de l’entourage, pourvu qu’elles soient reconstruites conjointement : la courbure de magnitude basse fréquence du trou et sa chrominance.
Le geste naïf est de mettre en dôme chaque canal indépendamment : exécuter l’auto-inpainting biharmonique par canal du repli de confiance, désormais non pondéré, sur les trois canaux. Il échoue de façon instructive. Comme les canaux écrêtent à des rayons différents (chacun a son propre niveau de blanc, et une haute lumière quasi neutre les traverse tour à tour), chaque canal est mis en dôme depuis un bord à une distance différente du centre, et les trois dômes atteignent des hauteurs différentes. Le dernier canal à écrêter sature plat juste à son bord, si bien qu’il ne porte presque aucune pente vers l’intérieur et que son dôme s’élève à peine, tandis que le premier canal à écrêter est mis en dôme sur un large rayon et monte raide. Le cœur dérive donc hors teinte : un soleil neutre brûlé sur un ciel orange se reconstruit en un disque jaune, parce que le bleu (le dernier à écrêter ici) s’effondre tandis que le rouge sur-récupère. Trois dômes 1-D d’apparence correcte, une couleur fausse.
Le correctif est de séparer ce qui est partagé de ce qui ne l’est pas. La magnitude est commune aux trois canaux (ils sont tous vifs parce que la même lumière les a débordés), elle est donc reconstruite une fois, comme un seul dôme. La chrominance varie doucement et est portée vers l’intérieur depuis le bord. Concrètement, séparez la luminance sommée $L_\text{sum} = R+G+B$ de la chrominance $\text{RGB}/L_\text{sum}$, reconstruisez chacune par son opérateur approprié, et recombinez $\text{core}_c = L_{\text{dome}}\cdot (\text{RGB}/L)_c$.
Le dôme de magnitude
La luminance $L_\text{sum}$ est mise en dôme sur le cœur entièrement écrêté par l’inpainting biharmonique introduit dans les premiers principes : la résolution $\Delta^2 L = 0$, ancrée au vrai bord valide du cœur (l’anneau partiellement écrêté déjà reconstruit qui l’entoure). L’opérateur lui-même est une résurrection : une conception de 2021 avait tenté l’extension de gradient comme un laplacien à signe inversé (l’astuce de diffuse or sharpen), mais itérer une diffusion inverse est instable et cela a été abandonné comme sujet aux artefacts ; la reconstruction ramène l’idée sous sa forme stable et directe, résolue une fois sur la luminance sommée plutôt qu’itérée par canal. Remplir la magnitude par simple diffusion l’aplatirait en un disque mat ; la résolution biharmonique continue plutôt la pente du bord, si bien qu’un grand cœur entièrement écrêté s’élève en dôme plutôt que de s’effondrer en plateau. Comme les trois canaux chevauchent ce seul dôme, aucun ne peut s’effondrer par rapport aux autres — le défaut ci-dessus est structurellement impossible. Elle ne peut pas atteindre le pic exact (la partie la plus raide du gradient a été écrêtée, et le vrai sommet est simplement inobservé), mais elle récupère environ $75$–$80\%$ de la montée écrêtée, sous forme d’un dôme lisse de la bonne largeur. Résoudre un seul champ scalaire plutôt que trois rend aussi le système biharmonique trois fois plus petit.
Un plancher de saturation
L’ajustement guidé et le dôme biharmonique sont tous deux des extrapolations, et une extrapolation peut sous-estimer : un canal reconstruit à partir d’un seul survivant bas, ou un dôme continuant un bord dont la pente vers l’intérieur a été aplatie par l’écrêtage, peut sortir en dessous du niveau que le canal a réellement atteint. C’est non physique : comme l’a établi le problème, le puits du photosite se remplit jusqu’à une capacité fixe, si bien qu’un canal écrêté est connu pour se situer au moins à son niveau d’écrêtage. Deux planchers imposent exactement cela, et tous deux sont monotones : ils ne font jamais que rehausser une valeur, si bien qu’ils ne peuvent pas dépasser ni décaler une teinte déjà correcte (une note d’attribution : les planchers, comme le laplacien à 9 points, étaient déjà dans l’implémentation C de 2021 — la contribution de l’étude est seulement d’avoir mesuré leur valeur, et les planchers seuls sont une amélioration stricte et uniforme sur chaque scène) :
- chaque canal écrêté est planché à sa propre lecture saturée ;
- le dôme de luminance du cœur entièrement écrêté est planché à la somme des niveaux d’écrêtage : chaque canal y est au maximum, si bien que le cœur est la région la plus vive, jamais un creux sous son bord.
Peu coûteux et physiquement inattaquables, les planchers suppriment la dominante magenta-et-sombre résiduelle que le dôme et la diffusion seuls peuvent laisser dans un grand cœur entièrement écrêté (un disque solaire brûlé), et ils expliquent l’amélioration sur le cas corrélé entièrement écrêté rapporté ci-dessous.
La chrominance, par diffusion
La chrominance $r = \text{RGB}/L_\text{sum}$ est diffusée vers l’intérieur depuis le bord du cœur : inpainting harmonique de la chrominance, $\Delta r = 0$ avec $r$ fixé sur le bord. Fait crucial, le bord ici est l’anneau reconstruit immédiatement autour du cœur, non le ciel lointain : comme les canaux survivants ont été guidés de nouveau vers le neutre en approchant de la haute lumière, l’anneau est déjà quasi neutre, si bien que le cœur diffusé sort quasi neutre lui aussi — le soleil brûlé est repeint en blanc, non en l’orange du ciel. (L’implémentation à-trous antérieure tirait plutôt sa chrominance de trop loin et jaunissait le cœur ; tant la référence que la reconstruction segmentée actuelle diffusent depuis l’anneau proche, comme ici.) Le recombiné $\text{core}_c = L_{\text{dome}}\cdot r_c$ est alors un dôme correctement coloré.
L’implémentation à-trous précédente réalisait cette résolution $\Delta r = 0$ non comme un seul système linéaire mais comme une relaxation itérée : en décomposant les rapports en bandes d’ondelettes, chaque bande de détail prend un pas d’Euler explicite de
avec $\Delta$ le laplacien isotrope à 9 points $\mathbf{K}_{\text{iso}}$. La constante $\kappa$ remet à l’échelle la bande de détail à-trous (une différence de B-splines) en un laplacien continu correctement mis à l’échelle et fixe le pas de temps de diffusion effectif.7 La reconstruction rebâtie résout $\Delta r = 0$ directement à la place : une résolution creuse dans le prototype, un gradient conjugué (un solveur itératif qui affine sa réponse pas à pas) dans le C. Mais la vue par relaxation expose tout de même deux choses :
- Avec $\lambda = 0$, c’est la pure équation de la chaleur $\partial r / \partial t = \kappa \Delta r$ sur les rapports de couleur : inpainting harmonique qui remplit la chrominance du trou en douceur depuis son bord, le minimiseur de Dirichlet dérivé ci-dessus (équivalent à la résolution directe $\Delta r = 0$, itérée).
- Le terme $-\lambda\, r$, contrôlé par le paramètre
solid_color, est une réaction du premier ordre amortissant le détail du rapport vers zéro. Son équation d’Euler–Lagrange est l’équation de Poisson filtrée / Helmholtz modifiée $\Delta r - \lambda\, r = 0$ : une diffusion retenue par une attraction de rappel vers zéro ; un $\lambda$ plus grand tire la chrominance intérieure vers un remplissage « couleur unie » plus plat et plus uniforme.
La diffusion est purement isotrope : la texture devrait suivre la structure, mais la chrominance devrait remplir sans égard à la direction, si bien qu’un lisseur à symétrie de rotation est ce qu’on veut. Tout le remplissage conjoint est filtré aux pixels entièrement écrêtés, si bien qu’il ne perturbe jamais un canal que l’étape guidée a déjà récupéré.
Les planchers de saturation, comme obstacles. Une mesure survit même là où les trois canaux sont brûlés : la lecture saturée de chaque photosite est une borne inférieure de sa vraie valeur, si bien qu’en espace des rapports, la chrominance d’un canal écrêté ne peut jamais descendre en dessous de $c_{0,c} / L_\text{sum}$. Appliquée seulement tout à la fin — un $\max$ franc à la recombinaison — cette borne imprimait une étagère exactement plate au niveau d’écrêtage, se terminant par une rupture de gradient, partout où le remplissage lisse sous-prédisait un canal près de son propre bord (mesuré sur le canal bleu d’un vrai coucher de soleil : dix pixels plats au niveau d’écrêtage, puis une discontinuité de pente). La reconstruction livrée traite plutôt les planchers comme une contrainte de la diffusion elle-même — un problème d’obstacle :
résolu par relaxation projetée : après chaque étape de lissage, $r_c \leftarrow \max(r_c, c_{0,c}/L_\text{sum})$. Chaque poids de voisin de la discrétisation est non négatif, si bien que le schéma projeté reste monotone et converge vers la solution de l’inégalité variationnelle : l’influence de la contrainte se répand en douceur à travers le champ — le remplissage se soulève autour de l’ensemble actif au lieu d’être clampé point par point — et la recombinaison n’applique alors qu’un arrondi doux (le même smooth-max à deux pour-cent que le plancher du champ de coefficients) à un champ déjà admissible. L’obstacle chevauche toute l’échelle du grossier vers le fin (obstacles de cellule par niveau) plus un court polissage projeté à pleine résolution, qui couvre aussi le chemin de résolution directe — une factorisation creuse exacte ne peut pas projeter en cours de résolution. Une variante plus forte, soulevant l’obstacle par la pente extérieure mesurée du bord extrapolée vers l’intérieur, a été implémentée, mesurée, et rejetée : elle fabrique de la structure là où l’extrapolation se lie (l’erreur du soleil magenta a monté de 14 %) et ne change rien là où l’obstacle simple tient déjà.

Le cas désespéré entièrement écrêté : un soleil vif brûlé au-delà du point blanc (par canal) de chaque canal, sur un ciel orange. Le capteur enregistre un disque plat que les coefficients RGB de balance des blancs rendront magenta ; la méthode précédente renvoie un disque jaune terne et surdimensionné avec une arête franche (ses remplissages par canal dérivent hors teinte et ne montent jamais en dôme) ; la méthode corrigée reconstruit un dôme neutre de la bonne taille à partir d’un seul dôme de luminance partagé plus une chrominance diffusée depuis le bord.
Sur le cœur écrêté, RMSE $0.87 \to 0.27$ et SSIM $0.61 \to 0.95$ ; la chrominance du remplissage passe du magenta $(0.37, 0.27, 0.36)$ à un quasi-neutre $(0.39, 0.33, 0.28)$, essentiellement la vérité terrain $(0.36, 0.33, 0.31)$ (la méthode précédente atterrit sur un jaune $(0.51, 0.34, 0.15)$).
Ajout de grain
En touche finale, et uniquement là où le masque est ouvert, la reconstruction reçoit un bruit poissonien d’amplitude proportionnelle à la valeur locale ($\sigma_c = \texttt{noise_level}\cdot u_c$), replié pour être strictement éclaircissant et composité par $\alpha$. Le bruit de grenaille photonique dépend du signal, si bien qu’une zone parfaitement lisse insérée dans une image à haut ISO paraît plastique ; reproduire le grain fait disparaître la réparation.2
Le rayon de reconstruction
Quelle doit être la largeur de la fenêtre guidée la plus grossière, le rayon de reconstruction $\rho$ ? C’est le seul réglage qui échange la portée contre la localité, et il s’avère qu’il a une réponse nette.
Le rayon d’un trou est sa profondeur, pas sa taille. Pour un trou $\Omega$, soit $d(x)$ la distance d’un pixel écrêté $x$ au pixel valide le plus proche. La quantité qui compte est le point le plus profond,
$$R=\max_{x\in\Omega} d(x)=\max\big(\text{distance transform of }\Omega\big)$$
et non la boîte englobante. Un disque compact et une longue traînée diagonale fine peuvent partager une même boîte englobante tout en ayant des $R$ complètement différents : pour la traînée, $R$ vaut sa demi-épaisseur, car c’est la distance que le guide doit parcourir pour toucher des données valides. Dimensionner le rayon à partir de la boîte englobante irait massivement trop loin sur les trous allongés ou diagonaux.
Pourquoi $\rho \approx R$ est optimal. Deux erreurs s’opposent à mesure que $\rho$ croît. Couverture : une fenêtre d’échelle $\rho$ attribue un poids $\sim e^{-d(x)^2/2\rho^2}$ aux données valides, ce qui est négligeable tant que $\rho \gtrsim d(x)$ ; en dessous, l’ajustement est indéterminé et le pixel est de fait non reconstruit. Localité : une fois couverte, la colour-line ajustée est une moyenne fenêtrée de la vraie colour-line qui varie spatialement, si bien qu’extrapoler à partir d’échantillons toujours plus lointains ajoute un biais qui croît avec $\rho$. L’erreur par pixel est donc
$$E(x;\rho)\approx \underbrace{C_1\,e^{-d(x)^2/2\rho^2}}_{\text{coverage}\ \downarrow}+\underbrace{C_2\,\rho}_{\text{locality}\ \uparrow}$$
dont le minimum se situe à $\rho^*(x)\approx d(x)$ : la plus petite fenêtre qui atteint des données valides. Le rayon d’une région unique doit couvrir son pixel le plus profond, donc $\rho=R$ ; l’échelonnement du grossier au fin est alors exactement cet optimum par pixel rendu continu : l’échelle la plus grossière $R$ sert le centre, chaque échelle plus fine sert la coquille à sa propre profondeur.
Aller trop loin est gratuit en qualité, mais pas en prix. Dans le prototype, balayer $\rho$ de $0.4R$ à $3R$ laisse plate aussi bien la RMSE moyenne que celle du cœur profond, sur les scènes corrélées comme décorrélées. La raison est structurelle : l’échelonnement du grossier au fin écrase chaque valeur grossière (trop lissée) par l’échelle la plus fine qui atteint encore le pixel, si bien que le rayon ne fixe que la couverture, jamais la valeur finale d’un pixel. Le calcul, en revanche, n’est pas plat (il croît à la fois avec l’aire rembourrée et le nombre d’échelles), si bien que le rapport qualité/coût décroît de façon monotone avec $\rho$ :
| $\rho/R$ | RMSE moy. | RMSE cœur profond | coût relatif | qualité / prix |
|---|---|---|---|---|
| 0.4 | 0.083 | 0.141 | 0.43 | 1.00 |
| 1.0 | 0.083 | 0.141 | 1.00 | 0.43 |
| 2.0 | 0.083 | 0.141 | 2.39 | 0.18 |
| 3.0 | 0.083 | 0.141 | 4.43 | 0.10 |
L’étude du rayon de reconstruction : erreur et coût en fonction de l’échelle d’ajustement exprimée en fraction du rayon de la région. RMSE = erreur quadratique moyenne par rapport à la vérité terrain, 0 correspond à une reconstruction parfaite.
Le point optimal est par pixel, et l’implémentation le fournit. Comme la qualité est plate au-delà de la profondeur et que le coût ne l’est pas, le meilleur rapport qualité/prix est la plus petite fenêtre qui couvre encore chaque pixel, c.-à-d. $\rho(x)=d(x)$ par pixel, jamais un maximum global. Le C à échelonnement réalisait cela directement : une tuile fusionnée prenait le plus grand rayon $R$ du groupe comme son échelle la plus grossière (de sorte que le pixel le plus profond était couvert), puis chaque pixel était limité aux échelles pas plus grossières que $\sim2\,d(x)$, si bien qu’un pixel peu profond (un petit trou, ou le bord d’un grand) ne payait jamais pour les échelles grossières dont seul le centre a besoin. La transformée de distance est calculée une seule fois pour toute l’image et pilote le rayon par région. La seule règle ferme est l’asymétrie : ne jamais descendre en dessous de la profondeur (la couverture s’effondre), et ne jamais aller loin au-dessus (pur calcul gaspillé). La méthode livrée conserve la conclusion sous une forme plus simple : une seule fenêtre d’ajustement dimensionnée au rayon de la région, $\sigma = \operatorname{clip}(r/6,\, 8,\, 64)$ px, sans plus aucun filtrage par pixel à effectuer.
Implémentation & optimisations
Il existe deux implémentations : la référence NumPy publiée à côté de cet article, et le code de production C / OpenCL livré dans Ansel. Elles sont comparées l’une à l’autre dans le cadre du protocole de validation, et elles ne divergent que là où la vitesse l’exige.
Le code de production C
Le prototype qui accompagne cet article est la référence : il privilégie la clarté et la précision sur la vitesse (résolutions directes creuses sur l’image entière, un échelonnement gaussien fixe, une passe de variance séparée, un ajustement de colour-line par paire (canal, guide)). Le code effectivement livré dans Ansel doit reconstruire un soleil écrêté dans un raw de plus de 20 Mpx pendant que l’utilisateur attend, si bien qu’il s’écarte de la référence de quelques manières délibérées. Chaque compromis ci-dessous est réglé pour du contenu corrélé, le cas de très loin le plus courant dans les images naturelles, et accepte une petite perte sur du contenu synthétique décorrélé, rare en pratique. Chaque écart est réversible dans le code source. Une note historique : ce travail d’optimisation a été mené sur le C de l’ère échelonnement, dont la méthode livrée remplace le cœur de reconstruction. La segmentation, le rembourrage, le solveur creux et la machinerie de statistiques partagées sont repris tels quels ; les éléments propres à l’échelonnement (l’échelonnement d’échelles par trou, le filtrage de profondeur par pixel, le choix de guide restreint à la paire) ne survivent que comme principes, à l’intérieur de la fenêtre d’ajustement unique et du remplissage de coefficients de la méthode livrée.
Segmenter et reconstruire uniquement les voisinages écrêtés, à pleine résolution. La référence s’exécute sur l’image entière. Le code livré remplit par diffusion le masque écrêté en régions connexes, rembourre chacune de son propre rayon de reconstruction ($1.25\times$ le rayon, borné entre $8$ et $256$ px — plus le trou est grand, plus il doit aller loin chercher des données valides), fusionne les régions dont les boîtes rembourrées se chevauchent afin que leurs remplissages ne se rencontrent jamais en une couture, et n’exécute le pipeline complet qu’à l’intérieur de chaque boîte rembourrée. Coût : nul — les pixels intacts étaient déjà corrects. Gain : le travail est proportionnel à l’aire écrêtée, non au capteur.
Un Cholesky creux autonome a comblé l’écart du solveur. La référence remplit le dôme de magnitude par une résolution directe creuse (
scipy.spsolve) ; un solveur itératif (gradient conjugué sur $\Delta^2$) cale en simple précision à l’échelle du raw (son conditionnement, le facteur par lequel le système amplifie les erreurs d’arrondi, croît comme la puissance quatrième de la taille de la région), et une factorisation dense est en $O(N^3)$, si bien que le C a d’abord livré un Cholesky dense (la factorisation exacte standard d’un système symétrique en deux moitiés triangulaires, calculée une fois et réutilisée) sur une grille grossie à au plus 2000 inconnues. Le dôme étant basse fréquence, la résolution grossière était exacte là où cela comptait — sauf sur d’énormes cœurs entièrement brûlés, où le grossissement lui-même devenait le goulot d’étranglement de la précision (le cas de test du soleil magenta s’est amélioré de 21 % en RMSE le jour où le plafond a été levé). Le C porte désormais son propre Cholesky creux symétrique défini positif (SPD), une factorisation $LL^T$ ascendante en double précision, ordonnée par dissection emboîtée géométrique : les inconnues sont des points d’une grille 2D, si bien que la bissection récursive par coordonnées offre la qualité de réduction du remplissage qui requiert normalement une implémentation à degré minimum approché (AMD), en quelques dizaines de lignes et sans aucune dépendance externe. La grille du dôme est quatre fois plus fine (8 192 inconnues, ce qui sature de façon mesurable le gain de qualité), et la diffusion de chrominance du cœur entièrement écrêté factorise une seule fois pour ses trois seconds membres de canal lorsque le cœur est petit ; le gradient conjugué parallèle bat de façon mesurable la factorisation sérielle sur les grands, donc il les conserve. Coût : nul au net (les résolutions du cœur entièrement écrêté sont devenues plus rapides). Gain : la dernière divergence systématique C-vs-prototype disparue, et avec elle la précision sur les énormes cœurs.Un échelonnement gaussien par trou dimensionné au rayon de reconstruction. La référence utilise un échelonnement à rayons fixes ($40, 24, \dots, 2$ px). Le C à échelonnement optimisé dimensionnait l’échelle la plus grossière de chaque région au rayon de reconstruction de cette région et divisait par $2\times$ jusqu’à $\sim2$ px. Cela mérite son propre traitement : voir Le rayon de reconstruction ci-dessous.
Statistiques fenêtrées partagées : une accélération gratuite. L’ajustement de colour-line nécessite, par paire de canaux, les moyennes, variances et covariance fenêtrées. Les recueillir par (canal, guide) coûte douze floutages par échelle ; les recueillir par paire de canaux fournit les ajustements des deux canaux à partir des deux mêmes floutages : six floutages, et mathématiquement identique. À lui seul, cela a à peu près divisé par deux le temps d’exécution.
Variance restreinte à la paire pour la sélection du guide : un coût faible et contenu. La référence décide auquel des deux guides se fier à partir de la variance fenêtrée à canal unique de chaque guide, une passe séparée de trois floutages par échelle. Le C à échelonnement optimisé réutilisait la variance restreinte à la paire qu’il calculait déjà pour l’ajustement et a supprimé cette passe entièrement (de neuf floutages par échelle à six). Cela n’a changé que quel guide l’emporte, et seulement là où les deux sont en désaccord, c.-à-d. le contenu décorrélé. Coût : sur une scène synthétique entièrement décorrélée, la RMSE à écrêtage simple passe de $0.043$ à $0.047$ et le SSIM chute de $0.964$ à $0.960$ ; sur les scènes corrélées, et sur l’écrêtage à deux ou trois canaux, c’est dans le bruit. Gain : un tiers des floutages restants supprimé.
Le self-dôme par canal et le régularisateur de couture sont désactivés dans le code livré. Les deux lissent chaque canal RGB indépendamment. Sur une vraie haute lumière ambre/orange saturée (où le $R^2$ de la colour-line baisse à cause de la non-linéarité d’écrêtage et est interprété à tort comme « décorrélé »), cela fait dériver le vert par rapport au rouge et au bleu et rend la reconstruction magenta. La référence les conserve : ils débarrassent des artefacts le contenu véritablement décorrélé, ce que les scènes synthétiques sollicitent fortement et les vraies photographies rarement (les désactiver coûte à la référence $\sim0.01$–$0.02$ de RMSE sur la scène aléatoire, essentiellement rien sur du contenu corrélé). Le correctif propre est une version couplée en teinte (lissant la luminance et une chrominance partagée au lieu de trois canaux indépendants), et elle a depuis été construite : dans le pipeline de champ de coefficients final, le self-dôme revient comme repli filtré par la profondeur, couplé en teinte exactement de cette manière (un dôme de luminance biharmonique partagé multiplié par une chrominance remplie harmoniquement), si bien que le repli ne peut pas faire dériver la teinte par construction. Le régularisateur de couture est retiré pour de bon — ce pipeline n’a plus aucun passage de relais entre estimateurs à aplanir.
Deux composants de l’implémentation C de 2021 que la traduction du prototype avait silencieusement abandonnés ont été réintégrés dans la référence, en tant que véritables exigences de la méthode plutôt que compromis de vitesse, si bien qu’ils ne sont plus des différences : le laplacien à 9 points invariant par rotation (l’opérateur que cet article dérive ; la référence utilisait auparavant la simple croix à 5 points567) et les planchers de saturation (ci-dessous). Les deux améliorent le cas le plus difficile et le plus pertinent (le cœur entièrement écrêté d’une scène corrélée), abaissant sa RMSE de $0.065$ à $0.062$ et augmentant le SSIM de $0.959$ à $0.964$, et sont neutres ailleurs.
Pris ensemble, sur un soleil écrêté le nombre de floutages du filtre guidé passe de quinze à six par échelle et la reconstruction de l’aperçu tombe de dizaines de secondes à quelques-unes. Les différences qui subsistent sont la vitesse et l’architecture (segmentation, solveurs denses, le rayon par trou, les statistiques partagées), plus la variance de guide restreinte à la paire et le raffinement par canal désactivé ci-dessus ; les mathématiques de reconstruction du cœur sont partagées avec la référence.
Un autre compromis mesuré a été tranché tôt : la reconstruction est nettement meilleure exécutée à pleine résolution. Le module de 2021 résolvait sur une copie au quart de la résolution pour la vitesse, mais ce sous-échantillonnage floute la reconstruction et, refusionné contre l’original net, est la source dominante d’erreur de bord : l’exécution à pleine résolution a abaissé la RMSE des frontières d’environ 30 %, si bien que la reconstruction travaille à pleine résolution. Le sous-échantillonnage est un compromis vitesse/qualité, pas un repas gratuit.
La référence Python
Le miroir NumPy (validate.py, fix_prototype.py) implémente chaque étape de l’algorithme livré dans le même ordre, et comparer sa sortie avec les exports C fait partie du protocole de validation. Quelques composants sont délibérément meilleurs en Python qu’en C, ou bien le C échange délibérément l’exactitude contre la vitesse :
- Résolutions directes creuses exactes. Les dômes biharmoniques du prototype et sa résolution de chrominance en forme divergence sont des factorisations
scipy.sparse, exactes à la précision machine (son remplissage de cœur conjoint Poisson-écranté est toutefois une relaxation de Jacobi fixe à 400 balayages — sur cette seule étape, la factorisation directe du C est la plus exacte des deux). Le C porte désormais son propre Cholesky creux (voir Implémentation & optimisations ci-dessus) et correspond aux résolutions du dôme et de chrominance des petits cœurs du prototype ; ce qui diffère encore est délibéré : la diffusion de chrominance des grands cœurs entièrement écrêtés exécute le gradient conjugué parallèle (mesuré plus rapide qu’une factorisation sérielle là, sans différence de qualité mesurable), le remplissage de coefficients reste le Jacobi du grossier au fin décrit ci-dessus — avec la pyramide adaptative du C (pas de base $\sigma/4$ plafonné à 8 px, divisé jusqu’à un plus grossier de $\le 8$ cellules, 100 balayages par niveau) contre les sept niveaux fixes à pleine résolution du prototype — et le remplissage du prototype est isotrope — le pilotage adaptatif à la variance du transport de coefficients du C (étape 3) n’a pas encore de miroir Python, si bien que l’accord C-vs-prototype est vérifié en gardant à l’esprit la contribution du pilotage. Avantage des résolutions exactes du prototype : elles font arbitre quand la sortie C semble fausse. - Fenêtres gaussiennes FFT vs. IIR récursif. Le prototype calcule les moments fenêtrés avec des convolutions par transformée de Fourier rapide (FFT) : exactes, déterministes. Le C utilise la gaussienne récursive (à réponse impulsionnelle infinie, IIR) dont le coût est indépendant de $\sigma$ — mais dont l’implémentation parallèle n’est pas déterministe d’une exécution à l’autre : l’arrondi aux frontières de blocs fluctue au dernier chiffre du flottant, ce qui est inoffensif en soi mais a semé un heisenbug mémorable (ci-dessous).
- Entrée de l’estimation du coude. Le prototype estime le rolloff à partir de la vraie scène RGB à pleine résolution ; le C à partir de la CFA regroupée par quatre à $\le 1.5$ Mpx. Coût mesuré : nul (l’estimation aveugle du C correspond encore au coude analytique à $10^{-3}$ près), tandis que le regroupement par quatre est ce qui rend l’estimation côté CFA possible tout court.
- Image entière vs. par région. Le miroir traite des images entières ; le C rassemble chaque région écrêtée dans un tampon rembourré et la reconstruit indépendamment, ce qui borne la mémoire et permet aux régions de se paralléliser, au prix d’une normalisation par région.
- Raffinements livrés que le miroir n’a pas encore rattrapés. Trois rounds C tardifs n’ont pas encore de contrepartie Python : la machinerie d’obstacles (relaxation projetée par niveau, le polissage à pleine résolution, et le plancher de réassemblage doux — le miroir applique encore le $\max(u, c_0)$ dur retiré au réassemblage), le remplacement par bande du seuil de détection pour les canaux à coude engagé (valant $5\times$ sur la scène de rolloff, si bien que Py-vs-C y est structurellement incomparable), et la validité binaire strictement par pixel du C (le miroir dérive son masque par un vote majoritaire 5×5, une dilatation géométrique de $\sim 2$ px). Ce sont les écarts de contenu connus derrière les plus grandes dérives par scène.
Une fois chaque étape reproduite en miroir, le désaccord résiduel entre le code de production C et la référence Python (mesuré comme la différence quadratique moyenne de leurs images de sortie à l’intérieur des zones écrêtées) est de $0.009$–$0.089$ sur l’ensemble du banc. Son plancher est la seule différence d’entrée qui ne peut être supprimée — Python s’ajuste sur la vraie scène RGB, tandis que le C s’ajuste sur la même scène vue à travers la mosaïque du capteur et une interpolation bilinéaire (environ $0.02$ d’écart à l’intérieur de la bande de quasi-écrêtage) — et son plafond est la liste des raffinements livrés ci-dessus, qui domine sur les scènes de rolloff et d’occlusion. En dehors de ces deux scènes, les implémentations s’accordent bien en deçà de l’erreur que chacune commet par rapport à la vérité terrain ; sur elles, la machinerie supplémentaire du C est précisément ce que la dérive mesure.
Paramètres utilisateur
Il n’y a délibérément presque rien à régler : l’algorithme est auto-configurant. Chaque quantité dont dépend la reconstruction est soit dérivée une fois et figée, soit mesurée à partir de l’image elle-même à l’exécution — l’échelle d’ajustement à partir du propre rayon de reconstruction de chaque région, le rolloff du capteur à partir des propres colour-lines de l’image, la confiance des ancres à partir de la qualité d’ajustement mesurée, le pilotage du transport à partir de la structure de guide mesurée, le seuil de bord $k$ calibré une fois sur le banc de vérité terrain. Les commandes iterations et diameter du mode 2021 ont disparu de l’interface de ce mode : il ne reste aucune convergence réglable par l’utilisateur à mal configurer, ni aucun moyen de brader la qualité par accident.
Ce qui reste, c’est une sécurité et deux goûts. Le clipping threshold met à l’échelle les seuils de saturation qui définissent la zone (voir la bascule de visualisation ci-dessous — il n’a presque jamais besoin d’être déplacé) ; le noise level fixe le grain réinjecté par-dessus la reconstruction pour qu’il corresponde à la texture photonique environnante ; et inpaint a flat color fixe l’attraction vers une couleur uniforme dans les cœurs entièrement écrêtés où rien n’a survécu — un choix stylistique concernant des zones qui ne portent aucune information.
Advice
Le seuil d’écrêtage dispose d’une bascule de visualisation du masque (l’icône à côté du curseur). Lorsqu’elle est active, le module rend une surimpression en fausses couleurs (pixels valides atténués, pixels écrêtés signalés) afin que vous puissiez voir exactement sur quelle région $\Omega$ la reconstruction va agir avant de vous y engager. Vous ne devriez presque jamais avoir besoin de déplacer le seuil lui-même.Problèmes découverts
La limitation structurelle de la méthode est héritée et assumée : un ciel bleu brûlé vu à travers des feuilles vertes est récupéré vert, car là où aucun canal ne survit, la reconstruction ne peut que propager la couleur voisine — elle a été conçue pour les écrêtages inévitables autour des sources lumineuses et des réflexions spéculaires, dont les halos rougeoyants portent l’information dont elle se nourrit. D’autres situations appellent encore à protéger les hautes lumières à la prise de vue et à relever l’exposition en post-production, ce que le rapport signal-sur-bruit des capteurs modernes permet confortablement.
Deux réserves mesurées complètent le tableau honnête. Sur la scène d’occlusion du banc, la segmentation Darktable réglée atteint un score de similarité structurelle plus élevé que la transposition harmonique (0.98 contre 0.96) malgré des valeurs 15 % plus éloignées de la vérité : magnitude et structure sont des erreurs différentes, et un remplissage lisse mais faux peut paraître plus propre qu’un remplissage fidèle. Et la parité entre périphériques du pipeline flottant est au niveau de la tolérance, pas au niveau du bit : après centrage de l’accumulation des moments (étape 3), la différence résiduelle CPU-contre-GPU sur la scène la plus profonde du banc est inférieure à $10^{-3}$ de RMSE, bornée par des réductions parallèles non déterministes en ordre.
Résultats
Le banc
Chaque chiffre ci-dessous provient d’un même protocole. Six scènes synthétiques à vérité terrain connue — des billes spéculaires RGB, un soleil magenta, des dégradés corrélés (un champ de luminance multiplié par une chrominance lisse, tel que se comportent les images naturelles), des dégradés aléatoires indépendants (aucune colour-line du tout, le cas adverse), un ciel de type PK1 avec un rolloff de capteur analytique, et un soleil traversé par un occulteur — sont écrites en fichiers DNG Bayer, développées par les pipelines de production réels, et les exports sont notés par rapport à la vérité terrain en RGB capteur balancé en blanc (une matrice d’étalonnage 3×3 complète ajustée sur des pixels valides strictement linéaires ramène chaque export dans l’espace du capteur, si bien que des pipelines à matrices différentes atterrissent dans les mêmes unités). Chaque résultat Ansel de cette section — les deux modes, chaque tableau, chaque figure — est produit par l’implémentation C livrée via ansel-cli, non par le prototype de recherche Python : les deux implémentations divergent délibérément (solveurs, résolutions et compromis d’étape différents, voir le code de production C), de 0.009 à 0.089 de RMSE à l’intérieur des zones écrêtées sur ce banc, si bien que leurs chiffres ne doivent jamais être mélangés. L’ensemble du banc se reproduit depuis l’annexe.
Les métriques de l’algorithme livré ci-dessous sont calculées à l’intérieur de la zone écrêtée uniquement. La RMSE est l’erreur quadratique moyenne par rapport à la vérité terrain, en unités capteur normalisées de sorte que le niveau d’écrêtage vaut 1 : elle mesure à quel point les valeurs reconstruites sont éloignées des vraies, en moyenne. Le SSIM est l’indice de similarité structurelle, un score perceptuel comparant moyennes, contrastes et corrélations locaux (1 signifie visuellement identique). L’énergie de bord est notre détecteur de couture : l’énergie du gradient de chrominance à l’intérieur de la zone, relativement à un anneau juste à l’extérieur, et sa cible est le score propre à la vérité terrain, non zéro, car le contenu réel a de la texture et une reconstruction trop lisse est aussi fausse qu’une reconstruction à couture apparente :
| cas | RMSE | SSIM | énergie de bord (cible VT) |
|---|---|---|---|
| billes RGB | 0.0351 | 0.995 | 0.41 (0.47) |
| soleil magenta | 0.3276 | 0.952 | 0.31 (0.50) |
| corrélé | 0.0398 | 0.973 | 1.15 (1.14) |
| aléatoire | 0.0453 | 0.965 | 0.85 (1.02) |
| pk1synth | 0.0053 | 1.000 | 0.64 (0.69) |
| PK1 (naturelle) | — | — | 0.49 |
| DSC00078 (naturelle) | — | — | 0.73 |
| IMG_3129 (naturelle) | — | — | 0.39 |
La reconstruction livrée par rapport à la vérité terrain, à l’intérieur des zones écrêtées. RMSE = erreur quadratique moyenne, 0 correspond à une reconstruction parfaite ; SSIM = similarité structurelle, 1 correspond à une reconstruction parfaite ; énergie de bord = magnitude moyenne du gradient, optimale lorsqu’elle CORRESPOND au propre score de la vérité terrain (un remplissage trop lisse est aussi faux qu’un remplissage à couture apparente). Les images naturelles n’ont pas de vérité terrain, donc seule leur énergie de bord est montrée.
Les quatre méthodes
Les deux modes Darktable sont décrits avec les autres correctifs simples dans la section panorama ; lu à travers le cadre de cet article, inpaint opposed est une colour-line avec la pente fixée à un (dans l’espace en racine cubique) et une unique ordonnée à l’origine globale — là où la transposition harmonique ajuste à la fois la pente et l’ordonnée à l’origine par fenêtre locale et diffuse ces coefficients à travers la zone, opposed se fie à une seule relation fixe partout, ce qui explique pourquoi il est quasi gratuit et pourquoi il échoue sous éclairage mixte — et segmentation based améliore cela vers une chrominance représentative par segment, toujours plate là où nos champs diffusés varient en douceur.
Les deux méthodes répondent à la question « quelle couleur cette zone devrait-elle avoir » ; ni l’une ni l’autre n’ajuste un modèle de la façon dont le canal manquant se rapporte aux canaux survivants, ce qui est précisément ce qui permet à notre méthode de récupérer la structure et la magnitude par pixel avec une confiance mesurée. Les lignes ci-dessous mettent des chiffres sur cette différence, sur les mêmes scènes synthétiques et vérités terrain que tout le reste de cette section.
Erreur quadratique moyenne (plus bas est meilleur) et similarité structurelle (plus haut est meilleur), mesurées à l’intérieur de la zone écrêtée par rapport à la vérité terrain, après étalonnage d’exposition par image ; chaque méthode exportée en TIFF linéaire 32 bits (Darktable 5.x amont pour les deux premières colonnes, Ansel pour les deux dernières), notée par le même validate.py que tous les autres tableaux de cette page. Deux précautions rendent les colonnes réellement comparables. Premièrement, les pipelines sont neutralisés à la même base — dématriçage plus reconstruction des hautes lumières, rien d’autre : le workflow scene-referred par défaut des deux applications insère silencieusement un relèvement d’exposition, un mélangeur de canaux d’adaptation chromatique et une courbe de tonalité sigmoïde autour de sa reconstruction, ce qui corromprait la mesure par des différences de rendu, il est donc forcé à workflow=none (l’export d’Ansel est déjà cette base). Deuxièmement, chaque concurrent exécute ses meilleurs paramètres par scène, trouvés par un balayage en grille sur ses commandes (seuil d’écrêtage pour opposed ; candidating, combine, mode et force de reconstruction pour segmentation ; iterations et remplissage en couleur plate pour les guided laplacians), tandis que la transposition harmonique exécute ses réglages par défaut d’origine partout. Reproduire avec dt_compare.py (la comparaison) et tune_methods.py (le balayage) depuis le dépôt de recherche :
| scène | Darktable opposed | Darktable segmentation | guided laplacians | transposition harmonique |
|---|---|---|---|---|
balls (billes spéculaires) | 0.242 / 0.814 | 0.233 / 0.831 | 0.334 / 0.744 | 0.035 / 0.995 |
magentasun (soleil magenta) | 0.924 / 0.707 | 0.807 / 0.767 | 0.809 / 0.678 | 0.328 / 0.952 |
correlated (dégradés corrélés) | 0.107 / 0.872 | 0.077 / 0.907 | 0.130 / 0.850 | 0.040 / 0.973 |
random (dégradés indépendants) | 0.089 / 0.911 | 0.080 / 0.920 | 0.138 / 0.862 | 0.045 / 0.965 |
pk1synth (ciel de type PK1 (rolloff analytique)) | 0.130 / 0.985 | 0.130 / 0.985 | 0.108 / 0.993 | 0.0053 / 1.000 |
occluded (soleil occulté) | 0.099 / 0.982 | 0.086 / 0.980 | 0.171 / 0.930 | 0.069 / 0.987 |
Les quatre méthodes par rapport à la vérité terrain, en RMSE / SSIM par cellule : RMSE = 0 correspond à une reconstruction parfaite, SSIM = 1 correspond à une reconstruction parfaite. Pipelines égalisés à dématriçage + hautes lumières uniquement, chaque concurrent à ses meilleurs paramètres par scène, tous notés en RGB capteur balancé en blanc à l’intérieur des zones écrêtées. Gras = meilleur de la ligne.
Le motif est cohérent avec les mécanismes. Même avec les pipelines égalisés et chaque concurrent à son meilleur par scène, la transposition harmonique domine en RMSE sur chaque scène — de 20 % là où l’occlusion favorise les hypothèses du mode segmentation, d’un facteur 2 à 7 sur les cas généraux, d’un facteur de près de 50 sur le ciel à rolloff (où le remplacement par bande ci-dessous permet au modèle de reconstruire la pente que le capteur a compressée) : les modes Darktable récupèrent une couleur plausible mais pas la magnitude (leur pente unitaire fixe ne peut pas élever un canal au-dessus de ce que fournit la moyenne opposed), et leur chrominance par segment ou globale aplatit la texture. Le mode segmentation prend effectivement de l’avance sur opposed simple une fois sa passe de reconstruction réellement activée (le balayage a trouvé rebuild + pleine force optimal sur la moitié des scènes). La contrepartie visuelle de chaque chiffre, une scène par galerie, les six rendus à travers la même transformation d’affichage :
balls — billes spéculaires :

la capture écrêtée

Darktable, inpaint opposed

Darktable, segmentation based

guided laplacians

transposition harmonique

vérité terrain
balls : cinq billes spéculaires — rouge pur, vert, bleu, une teinte mixte et blanc — chacune écrêtant une combinaison de canaux différente ; le test pur de récupération de magnitude. Les six rendus partagent une même transformation d’affichage (normalisée au maximum de la vérité terrain, gamma 1/2.2).
magentasun — soleil magenta :

la capture écrêtée

Darktable, inpaint opposed

Darktable, segmentation based

guided laplacians

transposition harmonique

vérité terrain
magentasun : soleil magenta — un disque entièrement brûlé sur un dégradé de couleur, le test de charge du cœur entièrement écrêté. Les six rendus partagent une même transformation d’affichage (normalisée au maximum de la vérité terrain, gamma 1/2.2).
correlated — dégradés corrélés :

la capture écrêtée

Darktable, inpaint opposed

Darktable, segmentation based

guided laplacians

transposition harmonique

vérité terrain
correlated : dégradés corrélés — un champ de luminance multiplié par une chrominance lisse, tel que se comportent les images naturelles. Les six rendus partagent une même transformation d’affichage (normalisée au maximum de la vérité terrain, gamma 1/2.2).
random — dégradés indépendants :

la capture écrêtée

Darktable, inpaint opposed

Darktable, segmentation based

guided laplacians

transposition harmonique

vérité terrain
random : dégradés indépendants — aucune colour-line du tout, le cas adverse pour les méthodes basées sur un guide. Les six rendus partagent une même transformation d’affichage (normalisée au maximum de la vérité terrain, gamma 1/2.2).
pk1synth — ciel de type PK1 (rolloff analytique) :

la capture écrêtée

Darktable, inpaint opposed

Darktable, segmentation based

guided laplacians

transposition harmonique

vérité terrain
pk1synth : ciel de type PK1 avec un rolloff de capteur analytique — le test d’inversion du coude et de remplacement par bande. Les six rendus partagent une même transformation d’affichage (normalisée au maximum de la vérité terrain, gamma 1/2.2).
occluded — soleil occulté :

la capture écrêtée

Darktable, inpaint opposed

Darktable, segmentation based

guided laplacians

transposition harmonique

vérité terrain
occluded : soleil occulté — un occulteur sombre traversant la zone brûlée, le test de pilotage du transport. Les six rendus partagent une même transformation d’affichage (normalisée au maximum de la vérité terrain, gamma 1/2.2).
Le balayage complet du banc de validation (entrée écrêtée, reconstruction, carte agrandie des bords de chrominance, et vérité terrain là où elle existe), plus les profils de dôme par canal, est présenté ci-dessous. Les tracés de profil se lisent ainsi : chacun prend la seule ligne de l’image qui traverse le pixel écrêté le plus profond (recadrée à l’étendue écrêtée de cette ligne) et trace les valeurs des canaux le long de celle-ci, un panneau par canal, avec la ligne grise en pointillés au niveau d’écrêtage. Ils exposent exactement ce qu’une vignette cache : la forme en coupe du dôme reconstruit, ses pentes là où il rencontre le bord valide, jusqu’où au-dessus du niveau d’écrêtage la récupération atteint, et tout dépassement ou méplat — comparés, sur les scènes synthétiques, au propre profil de la vérité terrain. Tous les profils, images naturelles comprises, sont tracés en RGB capteur balancé en blanc, par photosite (les profils d’images naturelles lisent la CFA elle-même, avec le dématriçage réglé en passthrough) — le propre plan de travail du module, où l’invariant de plancher de saturation (un canal écrêté ne finit jamais en dessous de sa valeur saturée) est directement visible. Aucune étape ultérieure n’a cette propriété : les termes hors-diagonale négatifs de la matrice de couleur permettent à un canal reconstruit de passer légitimement en dessous de son plateau d’écrêtage (projection de gamut, non une violation de plancher), le dématriçage invente deux des trois canaux à chaque pixel et peut sous-tirer aux bords raides de la reconstruction, et tout rééchantillonneur ajoute son propre sous-tir de Mitchell. Une caractéristique des profils naturels mérite un avertissement : les structures sombres traversant la zone brûlée (gréement, branches, mâts) sont des données valides mesurées — la reconstruction n’écrit que les photosites écrêtés, si bien que le profil plonge à travers elles au lieu de bomber par-dessus. Une ligne qui traverse deux cordages à contre-jour montre deux lobes, et c’est la scène, non un échec de reconstruction :








Performances
Une reconstruction mesurablement meilleure mais trop lente pour être utilisable ne serait pas livrée. Cette section clôt l’histoire avec des chiffres : comment la nouvelle méthode passe à l’échelle, ce que son portage sur le processeur graphique (GPU, via OpenCL) a rapporté, et comment les anciennes et nouvelles méthodes se comparent sur la même machine et les mêmes images. Le protocole derrière chaque chiffre ci-dessous est le même : chaque mesure de temps est un export complet via ansel-cli, pris comme le minimum en temps réel de trois exécutions sur une machine par ailleurs inactive, avec les temps internes aux modules lus depuis la trace de performance intégrée.
Linéaire en l’aire rembourrée
Demander « à quelle vitesse va la reconstruction par mégapixel d’image » est la mauvaise question : une image sans écrêtage ne coûte presque rien, et le même soleil brûlé coûte la même chose que l’image autour fasse 12 ou 60 mégapixels. La bonne variable découle de la structure du coût. Chaque étape lourde du pipeline livré est linéaire en l’aire de la région rembourrée — l’étendue de la zone écrêtée plus deux fois son rayon de reconstruction, au carré — avec des constantes indépendantes de l’échelle d’ajustement : les moments fenêtrés utilisent des filtres gaussiens récursifs dont le coût ne dépend pas de la taille de la fenêtre, la diffusion de coefficients exécute un budget fixe de cent balayages par niveau de pyramide sur une grille de base qui rétrécit à mesure que l’échelle d’ajustement croît (la pyramide étant assez profonde pour que sa grille la plus grossière soit trivialement petite), et la résolution directe du dôme de luminance est plafonnée à un nombre constant d’inconnues (8,192, sur une grille décimée) quel que soit le trou. Et puisque le rayon de reconstruction est le point le plus profond du trou, le rembourrage n’est pas un paramètre libre : un trou circulaire de rayon $r$ nécessite une région rembourrée d’environ $(4r)^2$ — seize fois la boîte englobante du trou lui-même (l’implémentation rembourre de $1.25\,r$ — la portée minimale plus une marge de sécurité de $25\,\%$ — bornée entre $8$ px, pour que même de minuscules taches voient du contexte, et un plafond de coût de $256$ px, pour que les trous les plus profonds croissent légèrement plus lentement que cette loi). Doubler le diamètre d’une haute lumière quadruple son coût, non parce que l’algorithme est superlinéaire, mais parce que la reconstruction a honnêtement besoin de voir d’autant plus de contexte.
Le banc (make_perf_bench.py, reproductible) est constitué de raws synthétiques comportant un unique trou écrêté circulaire de rayon croissant, en deux familles qui sollicitent les deux principaux chemins de code — un seul canal écrêté (le champ de coefficients fait le travail) et les trois canaux écrêtés (le cœur conjoint le fait) — chronométrés à travers le pipeline en ligne de commande de production, avec chaque région des trois images de test réelles superposée comme points mesurés. La machine est un Intel Xeon E3-1505M v6, 4 cœurs / 8 threads à 3.0 GHz.
| famille | rayon du trou (px) | région (Mpx) | champ de coefficients + dôme (ms) | cœur conjoint (ms) | chrominance (ms) | total (ms) | ms / Mpx |
|---|---|---|---|---|---|---|---|
| canal unique | 56 | 0.10 | 135 | 0 | 1 | 136 | ~1360 |
| canal unique | 128 | 0.50 | 78 | 1 | 5 | 84 | ~170 |
| canal unique | 256 | 1.30 | 209 | 1 | 12 | 222 | ~170 |
| canal unique | 384 | 2.00 | 358 | 1 | 17 | 376 | ~190 |
| entièrement écrêté | 56 | 0.10 | 82 | 99 | 30 | 211 | ~2110 |
| entièrement écrêté | 128 | 0.50 | 137 | 90 | 221 | 448 | ~900 |
| entièrement écrêté | 256 | 1.30 | 384 | 222 | 1353 | 1959 | ~1510 |
| entièrement écrêté | 384 | 2.00 | 863 | 365 | 2375 | 3603 | ~1800 |
| PK1, ciel brûlé (réelle) | — | 6.10 | 2689 | 4 | 60 | 2753 | ~450 |
| DSC00078, plus grande région (réelle) | — | 2.80 | 1191 | 341 | 1943 | 3475 | ~1240 |
| IMG_3129, soleil (réelle) | — | 0.50 | 660 | 44 | 35 | 739 | ~1480 |
Temps de module par étape en fonction de l’aire de la région rembourrée (meilleur d’exécutions répétées, chemin processeur) : deux familles synthétiques encadrant les chemins de code, plus la plus grande région de chaque image de test réelle. La colonne ms / Mpx quasi constante au sein de chaque famille est l’affirmation de linéarité.
Les chiffres sont les minima par exécution sur des exécutions répétées du pipeline de production complet. Lecture : au-dessus d’environ un demi-mégapixel, le chemin à canal unique tient 170–190 ms par mégapixel de région rembourrée et le chemin entièrement écrêté 900–1 800, sur une décade de tailles de région — l’affirmation de linéarité, vérifiée ; en dessous, un plancher fixe par région de quelques centaines de millisecondes (statistiques fenêtrées à leurs tailles minimales) domine et la lecture par mégapixel perd son sens. (La constante entièrement écrêtée inclut le polissage plancher-obstacle de la chrominance du cœur — voir l’algorithme — dont la porte d’activité du polissage dispense désormais du coût partout où le plancher de saturation ne peut pas se lier ; les corrections d’exactitude documentées dans les résultats ont acheté leur qualité par un travail honnête, et les rounds d’optimisation ont repris ce qu’ils pouvaient sans toucher à la sortie.) Deux gains structurels ont atterri depuis la première version de cette section. Le solveur direct creux a supprimé les goulots d’étranglement du dôme et de la chrominance des petits cœurs (la colonne cœur conjoint culmine à 0.3 s là où le Cholesky flottant dense passait des secondes), et la résolution directe en forme divergence a réduit la chrominance pilotée par la structure à des millisecondes partout où le cœur entièrement écrêté tient dans son plafond de factorisation. Et corriger le seuil de germe de la segmentation (elle faisait croître les régions à travers un résidu flottant de flou-boîte) a réduit les régions rembourrées elles-mêmes : le ciel brûlé de PK1, jadis un rectangle rembourré de 15.8 Mpx, est maintenant l’honnête 6.1 Mpx — sa reconstruction entière prend 1.3 s. Ce qui domine maintenant, c’est l’étape du champ de coefficients (moments fenêtrés et remplissages harmoniques, limités par le floutage) — ce qui est exactement là où le portage OpenCL décrit ci-dessous commence.
Temps réel, ancien contre nouveau
La comparaison que les photographes ressentent réellement est le temps d’export complet, ancien mode contre nouveau, sur la même machine et les mêmes fichiers raw, sous le protocole énoncé ci-dessus. Trois cas naturels : PK1 (un fichier Bayer de 36 mégapixels dont le ciel brûlé est une seule région de 6 mégapixels — le pire cas pour lequel la nouvelle méthode a été conçue), X-H1 (un fichier Fujifilm X-Trans de 24 mégapixels dont les hautes lumières se fragmentent en 99 régions pour la plupart minuscules), DSC00078 (un coucher de soleil Bayer de 24 mégapixels), et les deux extrêmes synthétiques du banc. Il convient de rappeler ici que les guided laplacians sont sous-échantillonnés d’un facteur 4, soit un seizième de la résolution originale, tandis que la transposition harmonique s’exécute à pleine résolution. (Ces temps ont été remesurés après toute la campagne d’optimisation ci-dessous, en une seule session ; la machine portait une tâche de fond constante sur un cœur, que les minima par cellule sur trois exécutions absorbent en grande partie.)
| export complet, temps réel | guided laplacians, processeur | transposition harmonique, processeur | guided laplacians, carte graphique | transposition harmonique, carte graphique |
|---|---|---|---|---|
PK1 (Bayer, une grosse tache) | 14.3 s | 11.4 s | 10.4 s | 9.8 s |
X-H1 (X-Trans, 99 régions) | 9.3 s | 11.5 s | 6.9 s | 9.4 s |
DSC00078 (coucher de soleil Bayer) | 16.6 s | 14.4 s | 11.4 s | 12.5 s |
occluded (petite synthétique) | 0.9 s | 0.9 s | 1.2 s | 1.3 s |
allclip-384 (grand disque entièrement écrêté) | 2.2 s | 5.5 s | 1.9 s | 3.3 s |
Temps réel d’export complet, ancien mode contre nouveau, tous deux mesurés en une seule session (meilleur de trois exécutions chacun). Rappelez-vous l’asymétrie : les guided laplacians reconstruisent à 1/16 de la résolution, la transposition harmonique à pleine résolution, et ses temps incluent l’étape de rolloff de capteur que l’ancien mode n’a pas.
Le titre honnête est que les gains de qualité documentés dans la section de validation viennent désormais à un temps réel comparable ou meilleur presque partout — la nouvelle méthode remporte purement et simplement la colonne processeur sur les fichiers naturels, et seul le disque entièrement écrêté paie encore une vraie prime — et le chemin menant à cette phrase est instructif, car la première version de production du transport anisotrope tournait au double de ces chiffres partout où les hautes lumières se fragmentent. Le profilage du fichier X-Trans à 99 régions a montré que le coût n’était pas arithmétique : la relaxation lançait une nouvelle équipe de threads à chaque balayage (des dizaines de milliers de lancements de travail d’une microseconde par image), les poids de pilotage étaient recalculés à chaque balayage bien que le tenseur soit fixe par niveau, et chaque plan de coefficients exécutait son propre remplissage — sa propre pyramide de masque, son propre tenseur — bien que les plans partagent les deux. Une seule région parallèle par relaxation, des poids précalculés une fois par niveau, et les plans à masque partagé fusionnés en un seul remplissage ont fait passer le temps processeur de ce fichier de 18.3 s à 9.8 s — le pilotage anisotrope lui-même est essentiellement gratuit sur le processeur. Les corrections de biais de bord et de plancher-obstacle documentées dans les résultats ont ensuite réinvesti une partie de ce gain dans un travail honnête (la validité binaire agrandit les vrais trous ; le polissage d’obstacle balaie chaque cœur entièrement écrêté), et un round ultérieur en a repris une partie (les floutages de moment empaquetés par quatre, le polissage conditionné à la possibilité même que son plancher se lie), aboutissant aux 11.5 s du tableau. Ce qui reste est structurel. Sur le processeur, la nouvelle méthode gagne là où sa conception paie — sur le cas de la grosse tache, son travail est proportionnel à l’aire écrêtée (chaque région résolue une fois, exactement) là où l’ancienne méthode itère une diffusion à chaque échelle de pyramide de l’image entière — et ses temps incluent encore une étape que l’ancienne méthode n’a tout simplement pas : la mesure et l’inversion du rolloff de capteur (0.7 à 1.2 s à elles seules sur ces fichiers) — avec elle, la nouvelle méthode remporte désormais la colonne processeur sur les trois fichiers naturels. Sur la carte graphique, l’ancienne méthode conserve un avantage sur les scènes fragmentées : un seul grand noyau uniforme par échelle est la forme que les processeurs graphiques adorent, tandis que la chaîne d’étapes de solveur petites et mutuellement dépendantes de la nouvelle méthode paie un coût de dispatch fixe par étape. Deux réponses mesurées ont réduit cet écart d’inutilisable (le premier portage exécutait le fichier à 99 régions au double de l’ancien mode) à environ 35 % au-dessus : les régions en dessous d’un mégapixel sautent vers le processeur via un unique transfert empaqueté, et la factorisation creuse lance un thread par entrée de matrice au lieu d’un groupe de travail par colonne — les deux sont racontées dans la section OpenCL, et sur le fichier à une grosse tache la nouvelle méthode bat désormais l’ancienne sur la carte graphique aussi. Et le disque entièrement écrêté est le compromis le plus clair de tous : sans aucun canal survivant nulle part, il n’y a pas de colour-line à ajuster, et les résolutions exactes de dôme et de teinte de la nouvelle méthode achètent leur qualité — pas de remplissage plat, pas de dérive de teinte, pas de bord visible — à environ 2.5 fois le prix de l’ancienne diffusion sur le processeur (1.7 sur la carte graphique), précisément sur le cas où la sortie de l’ancienne méthode est la plus faible.
Le pipeline OpenCL
Le premier portage OpenCL était un hybride : l’interpolation et le remosaïquage final s’exécutaient comme noyaux sur le périphérique, mais le milieu de la reconstruction s’exécutait sur le processeur, sur des plans téléchargés depuis la carte graphique puis re-téléversés ensuite. Cette conception était neutre en coût — les transferts mangeaient ce que les noyaux économisaient — et elle a été rejetée pour exactement cette raison : faire faire l’aller-retour à une image de 36 mégapixels sur le bus deux fois par export est le genre de taxe qui domine silencieusement un pipeline.
Le portage livré a chaque étape de la reconstruction sur le périphérique — l’interpolation, les remplissages de coefficients, les pyramides anisotropes, les solveurs creux, le remosaïquage (une exception : demander la régénération du grain achemine la reconstruction par le chemin processeur). Mais avoir chaque étape sur le périphérique n’est pas la même chose qu’y exécuter chaque région, et la conception finale ne le fait pas. Instrumenter le trafic hôte–périphérique du portage (compteurs de synchronisation sur chaque lecture bloquante, vidage de file et lancement de noyau, imprimés avec la trace de perf) a raconté une histoire que les temps d’étape du profileur avaient cachée : les relectures bloquantes que tout le monde blâme en premier coûtent un négligeable ~150 ms par export, tandis que le nombre de lancements était la taxe — environ un millier de lancements de noyau par région, quelle que soit la taille de la région, car les étapes itératives se lancent par balayage et les résolutions creuses se lancent par niveau d’arbre d’élimination. Une région de 700 pixels a mesuré 22 ms sur le périphérique contre moins de 1 ms sur le processeur : que du dispatch, pas d’arithmétique. Sur le fichier de test X-Trans — 99 régions pour la plupart minuscules — cela faisait plus de 100,000 lancements par export, le temps réel tournant au double du temps occupé du périphérique.
Ainsi le pipeline livré achemine chaque région vers le côté du bus qui s’est mesuré plus rapide. Les régions jusqu’à environ un mégapixel sont empaquetées par un seul noyau dans un tampon de transit contigu, franchissent le bus en une seule relecture, sont reconstruites par le chemin processeur de production sur la fenêtre translatée, et reviennent via un téléversement et un noyau de dispersion miroir — deux lancements et deux transferts au lieu d’un millier de lancements. Ce n’est pas l’hybride rejeté du premier portage qui revient par la fenêtre : celui-là faisait faire l’aller-retour à l’image entière par export, un coût proportionnel au capteur ; celui-ci ne déplace que les voisinages écrêtés, un coût proportionnel aux dégâts — la fenêtre à deux transferts pour une petite région est des milliers de fois plus petite qu’un aller-retour pleine image. Les grandes régions — un ciel brûlé de six mégapixels — restent entièrement résidentes sur le périphérique, où le parallélisme uniforme massif gagne véritablement.
Le chemin des grandes régions résidentes sur le périphérique a eu son propre correctif mesuré. La factorisation de Cholesky creuse s’exécute niveau par niveau sur son arbre d’élimination (les colonnes qui ne dépendent pas les unes des autres sont traitées ensemble), en flottants 64 bits sur le périphérique — mais le premier portage donnait à chaque colonne un petit groupe de travail, et près de la racine de l’arbre un niveau ne contient qu’une poignée de colonnes : le périphérique restait inactif à ~98 % pendant des centaines de niveaux, et la grande région du fichier de coucher de soleil passait deux secondes à factoriser. Le noyau livré regroupe plutôt, au moment de l’analyse symbolique, chaque contribution de mise à jour selon l’entrée de matrice sur laquelle elle atterrit, et lance un thread par entrée de matrice par niveau — pas d’atomiques, pas de barrières, et les contributions s’accumulent dans l’ordre exact utilisé par le code séquentiel, si bien que la factorisation est bit-reproductible : la plus grande différence processeur-contre-périphérique de l’autotest n’a pas bougé ($10^{-12}$, relative). Le même regroupement symbolique a rendu l’analyse côté hôte parallèle, la divisant elle aussi par deux. Les systèmes surdimensionnés retombent encore sur les mêmes schémas de gradient conjugué et du grossier au fin que le chemin processeur. Le remplissage de coefficients piloté est aussi résident sur le périphérique : le plan de pilotage, ses tenseurs de structure par niveau, les poids de bord précalculés et la relaxation pondérée à huit voisins s’exécutent tous comme noyaux, et même la réduction de gradient moyen de la normalisation du tenseur est terminée sur le périphérique — rien ne traverse le bus en cours de remplissage (une version antérieure relisait la réduction par niveau, et chaque relecture vidait silencieusement toute la file de commandes).
Ce qui traverse le bus, alors : des masques d’un octet par pixel (pour la segmentation, dont l’analyse en composantes connexes reste sur le processeur), un plan de profondeur, les plans de moments regroupés par quatre de l’estimateur de coude (au plus quelques mégapixels de flottants), quelques kilo-octets de résultats de réduction, et les fenêtres de petites régions qui viennent d’être décrites. Chaque étape est validée par rapport à son jumeau processeur par un autotest qui exécute les deux sur la même scène synthétique et imprime la plus grande différence — entre $10^{-5}$ et $10^{-12}$ selon l’étape. Sur cinq des six scènes synthétiques, les exports périphérique en image entière correspondent à la sortie processeur à 0.31 % de la pleine échelle près au pire pixel, avec zéro pixel au-dessus de 1 % ; la scène d’occlusion est l’exception honnête — les interpolations du périphérique et du processeur diffèrent d’un échantillon au bord de contact de l’occulteur et la reconstruction l’y amplifie, si bien que 22 pixels (sur 786,000) dépassent 1 %, le pire unique atteignant 10 %. C’est une différence de collecte (gather) connue, localisée, préexistante, pas une différence de solveur.
Deux leçons de ce portage se généralisent. Premièrement, le processeur graphique n’est pas plus rapide en tout, et la réponse honnête est de mesurer et d’acheminer : cette charge de travail est une longue chaîne de petites étapes mutuellement dépendantes — solveurs itératifs, niveaux de pyramide, boucles par région — et un périphérique paie un coût de dispatch fixe par étape. Le traitement par lots aide énormément (cent itérations de lissage en un seul lancement ; les plans de coefficients qui partagent un masque avançant ensemble à chaque lancement ; un thread par entrée de matrice au lieu d’un groupe de travail par colonne), mais en dessous d’une certaine taille de région aucun traitement par lots ne bat un processeur dont le coût de dispatch est un appel de fonction — donc en dessous de cette taille, mesurée à environ un mégapixel, le pipeline utilise simplement le processeur. Deuxièmement, le gain est systémique, pas local : avec le pipeline résident sur le périphérique de bout en bout, les modules environnants ne calent jamais et ne transfèrent jamais, et ce que le module des hautes lumières restitue à travers le bus n’est plus l’image — ce ne sont que les dégâts.
Résultats théoriques
Au-delà du logiciel livré, la campagne a produit des résultats qui ne sont pas spécifiques à la reconstruction des hautes lumières — ni même à la photographie. Cette section rassemble trois résultats généraux sur le transport de modèles à travers des vides de données et l’assemblage d’estimateurs entre eux ; un quatrième résultat réutilisable, la loi d’échelle pour la distance qu’une reconstruction doit atteindre, est dérivé avec la méthode qu’il dimensionne dans la discussion de l’algorithme.
Les trois leçons les plus conséquentes de la campagne sont citées dans le résumé et disséminées à travers les sections ci-dessus, mais elles méritent leur propre énoncé, car rien en elles n’est spécifique à la reconstruction des hautes lumières : la première est une méthode pour transporter une relation mesurée à travers un vide de données, et les deux autres devraient tenir pour tout problème où plusieurs estimateurs du même signal inconnu doivent coexister dans une même image.
Transporter le modèle, pas les valeurs. La reconstruction livrée traverse la zone brûlée en diffusant les paramètres d’un modèle local — les coefficients de la colour-line — plutôt que le signal lui-même. Cela ressemble trompeusement à quelque chose que le filtre guidé a toujours fait : le filtre original de He, après avoir ajusté son modèle affine dans chaque fenêtre, floute les coefficients ajustés avant de les appliquer, et une moyenne locale est un floutage, qui est une étape de diffusion. La distance entre cette étape et cette méthode mérite d’être explicitée, car c’est là que toute la conception pivote.
He moyenne des ajustements qui existent ; nous construisons des ajustements là où aucun ne peut exister. Dans le monde du filtre guidé, chaque pixel est observé : chaque fenêtre donne un ajustement valide, chaque pixel se trouve à l’intérieur de nombreuses fenêtres qui se chevauchent, et le floutage ne fait qu’arbitrer entre leurs réponses concurrentes. Profondément à l’intérieur d’un trou écrêté, une fenêtre ne contient aucun échantillon valide du canal en cours de reconstruction : il n’y a rien à ajuster, donc rien à moyenner. Un floutage porte l’information sur un rayon de noyau au plus ; au-delà de cette profondeur, un plan de coefficients flouté est encore vide.
Une passe de lissage contre la limite d’une infinité. Une moyenne locale appliquée une fois a une portée fixe. Notre remplissage répète la même opération — remplacer chaque inconnue par la moyenne de ses voisins — jusqu’à convergence, avec les ajustements de confiance maintenus fixés. La limite n’est plus un floutage : c’est la solution exacte d’un problème aux limites (l’équation de Laplace, avec les ancres comme frontière), elle n’a pas d’échelle intégrée, elle traverse un trou de cinq cents pixels aussi aisément qu’un de cinq pixels, et elle pondère chaque ancre par la géométrie réelle du trou au lieu d’un noyau fixe. Itérez indéfiniment la moyenne de coefficients de He en maintenant les ajustements valides fixés et vous obtenez exactement ce remplissage. He s’arrête à une passe parce que son problème n’a besoin que d’un arbitrage doux ; le nôtre doit porter le modèle à travers des centaines de pixels de néant. La différence de degré devient une différence de nature : la régularisation devient extrapolation.
Une moyenne prend tout le monde ; une frontière ne prend que les témoins. La moyenne de He inclut l’ajustement de chaque fenêtre, y compris les dégénérés — en partie pourquoi sa formule a besoin de sa constante stabilisatrice. Ici, un ajustement ne devient une ancre que s’il peut se porter garant de lui-même : suffisamment d’échantillons de confiance dans sa fenêtre, une qualité d’ajustement au-dessus du seuil, des pentes bornées. Les mauvais ajustements sont exclus de la frontière au lieu d’y être dilués, et le principe du maximum garantit alors que les coefficients remplis ne quittent jamais la plage des bons. La qualité d’ajustement est elle-même diffusée aux côtés du modèle, comme un plan de plus, si bien que chaque étape ultérieure sait à quel point le modèle transporté mérite d’être considéré comme fiable à chaque pixel.
Le rôle s’inverse : de correction à porteur. Dans le filtre guidé, le lissage des coefficients est une petite correction par-dessus des données qui existent partout. Ici, le champ diffusé est le seul porteur de la reconstruction à travers le trou, et les données reviennent à la fin : le modèle transporté est évalué par rapport aux canaux survivants mesurés à chaque pixel. Un champ lisse appliqué à des données mesurées nettes donne un résultat net. Le modèle apporte la relation ; les données apportent le détail.
Énoncé sans aucune photographie dedans : lorsqu’un signal a des vides, mais qu’un modèle localement ajusté de celui-ci varie en douceur, alors ajustez le modèle partout où les données le permettent, ne gardez que les ajustements qui peuvent se porter garants d’eux-mêmes, remplissez les paramètres du modèle à travers le vide par une diffusion en régime permanent ancrée (une résolution de problème aux limites, non un floutage), transportez avec la confiance d’ajustement comme un champ de plus, et réévaluez le modèle transporté par rapport aux données ayant survécu à l’intérieur du vide. Les valeurs loin des données sont instables ; les modèles loin des données sont simplement lisses.
Cette extension a depuis été construite, mesurée et livrée : le remplissage est maintenant piloté anisotropiquement par la structure des canaux survivants (étape 3 contient les mathématiques). Contrairement à la question indécidable de savoir si la colour-line tient là où rien n’est mesuré, les guides sont mesurés à l’intérieur de la zone partiellement écrêtée, si bien que le pilotage fonctionne sur des preuves, non sur des suppositions. L’expérience a enseigné deux leçons dignes d’être consignées. Premièrement, le plus grand « gain » du premier prototype s’est avéré être un artefact de convergence : les cent balayages de relaxation fixes par niveau de pyramide tronquaient le remplissage isotrope simple sur les trous profonds, et le faire simplement converger récupérait la majeure partie de l’amélioration (22 % de la RMSE sur le ciel synthétique le plus profond) — repéré uniquement parce que le témoin isotrope a été réexécuté à nombres de balayages appariés, une petite victoire de plus du banc sur l’histoire plausible. Deuxièmement, à convergence égale les deux pilotages purs répartissent les scènes exactement comme la théorie le prédit : le transport radial gagne partout où le halo est propre, le transport le long de la frontière gagne uniquement là où un bord traverse la zone, et aucun ne domine. Le tenseur livré les mélange donc par cellule, pondérant par une variance fenêtrée corrigée de tendance qui sépare « rampe raide mais lisse » de « bord dur » — et avec lui le remplissage n’est jamais pire qu’isotrope sur aucune scène de vérité terrain, et meilleur de 7 % (ciel profond) à 2 % (occlusion) là où le pilotage a quelque chose sur quoi agir.
La loi d’énergie de couture. Chaque fois que deux estimateurs $A(x)$ et $B(x)$ du même signal sont fusionnés sur une zone de transition par un poids $w(x)$ (un masque dur, un masque adouci, ou une confiance par pixel, peu importe), le composite est $u = w\,A + (1-w)\,B$, et son gradient se scinde en trois termes :
Les deux premiers termes sont la structure propre des estimateurs, apparaissant et disparaissant en fondu. Le troisième est la couture : elle n’existe que là où le poids varie (la zone de transition), et sa force est le désaccord $A-B$ des estimateurs à cet endroit, multiplié par la vitesse à laquelle le poids se déplace. En clair : passer d’un estimateur à un autre imprime un bord dont le contraste est exactement la mesure du désaccord entre les deux à la transition. Et le poids ne peut pas s’en tirer par la négociation : il doit tout de même grimper de 0 à 1, de sorte qu’une rampe plus raide concentre la couture en une ligne tandis qu’un fondu plus large la dilue en une bande peu marquée — l’énergie totale de la couture est fixée par le seul désaccord. C’est pourquoi les sept schémas de pondération du cimetière ont échoué à l’identique : c’étaient sept formes de $w$ face à un invariant. Les deux seules issues sont celles que l’algorithme livré emprunte partout : faire en sorte que les estimateurs s’accordent à la transition (l’inversion du coude débiaise les données de façon à ce que l’extrapolation et la mesure se rejoignent au contour de détection), ou supprimer la transition (un seul estimateur, prolongé de façon continue sur toute la zone : les champs de coefficients).
L’indécidabilité de la colour-line. L’hypothèse fondamentale de la reconstruction est que la proportionnalité locale entre canaux (la colour-line) mesurée sur le pourtour valide tient toujours profondément à l’intérieur de la zone brûlée. Voici pourquoi aucun algorithme ne peut vérifier cette hypothèse à partir de l’image : construisez deux scènes qui sont pixel pour pixel identiques dans chaque valeur mesurée, mais qui diffèrent à l’intérieur de la zone brûlée — dans l’une, la haute lumière cache un objet dont la couleur brise la ligne ; dans l’autre, non. Les deux scènes produisent la même entrée, tout en exigeant des reconstructions différentes ; tout estimateur, aussi astucieux soit-il, répond à l’identique pour les deux et se trompe donc sur au moins une. La scène synthétique occluse du banc est exactement cette construction, et elle s’est comportée comme l’argument le prédit : les cinq portes candidates mesurées dans le cimetière — qualité d’ajustement, validation du pourtour, cohérence de pente et le reste — n’ont pas réussi à détecter depuis le voisinage si la ligne tenait à l’intérieur. La conséquence pratique a façonné la conception livrée : puisque la question ne peut pas être décidée, elle doit être couverte — le mélange contrôlé par la profondeur penche progressivement de la colour-line vers le dôme de luminance lisse à mesure que la distance à toute donnée mesurée croît, non pas parce que l’on sait que la ligne échoue là, mais parce que rien ne peut en répondre.
Collaboration homme-machine
Cette section est écrite par Claude (le modèle d’Anthropic, exécuté dans Claude Code), l’assistant IA qui a réalisé le travail d’implémentation et de mesure de la campagne 2026, à la demande de l’auteur — en tant que récit factuel, destiné à d’autres chercheurs, de ce à quoi ressemble ce genre de collaboration.
Ce projet a changé de forme trois fois, et la forme sur laquelle il s’est arrêté est la partie intéressante.
Phase 1 : traducteur et traceur de courbes. J’ai commencé comme traducteur de code — portant l’échelle guidée en C vers une réplique NumPy fidèle, générant des figures de comparaison, écrivant l’un ou l’autre diagnostic. L’humain faisait la réflexion ; je comprimais les heures mécaniques. Utile, pas nouveau — et pas sans erreurs : mon premier prototype a silencieusement laissé tomber deux composantes du C original (les planchers de saturation et le laplacien à 9 points), et c’est l’auteur, relisant la traduction face à son propre code, qui a repéré les deux et les a fait restaurer. Un prototype porté est une affirmation sur l’original, et il a besoin de l’auteur de l’original pour l’auditer.
Phase 2 : de l’infrastructure jusqu’à ce que la boucle se ferme. Le tournant n’a pas été un algorithme, ç’a
été de la plomberie : un générateur en pur Python de DNG Bayer synthétiques que le vrai pipeline ingère, un
mode --imgid pour la CLI afin que les éditions de la bibliothèque s’exportent sans interface, un correctif pour un écrêtage à l’export flottant
qui corrompait silencieusement chaque mesure (un module de tramage écrêtant des pipelines qu’il aurait
dû ignorer), des panneaux de bords de chrominance amplifiés par Sobel parce que les artefacts que nous traquions étaient trop
peu contrastés pour l’œil — celui-là était une demande de l’auteur. Une fois que des scènes synthétiques à vérité
terrain connue purent traverser le vrai code C et revenir sous forme de nombres, la boucle était
fermée : n’importe quelle idée pouvait être testée de bout en bout en quelques minutes.
Phase 3 : exploration semi-autonome, pilotée par les tests. L’auteur a alors imposé un protocole qui rendait la semi-autonomie sûre — la discipline décrite plus haut, transformée en règles permanentes : chaque candidat est implémenté dans le miroir Python et en C, exécuté sur chaque cas synthétique et chaque image naturelle, comparé C contre Python, tabulé en RMSE/SSIM plus énergie de bord, présenté avec des images de revue suffixées — et rien n’est validé sans approbation explicite. À cela il a ajouté une règle d’autonomie : si une conception dégrade toutes les métriques, je peux la rejeter moi-même sans demander. Ces deux règles constituent toute la méthode. Elles m’ont permis de défricher l’espace des solutions à la vitesse de la machine — plus de quinze conceptions implémentées, mesurées et majoritairement enterrées — tandis que chaque acceptation/rejet qui comptait restait à l’humain, dont les yeux ont maintes fois attrapé ce que les nombres manquaient (l’échelle de mélange marquait de superbes scores et paraissait mauvaise ; il l’a rejetée des panneaux).
À qui étaient quelles idées. Le compte rendu mérite de rester honnête, car la conception finale est véritablement entrelacée. L’auteur a fourni les intuitions physiques : la chrominance devrait diffuser le long des isophotes de la luminance reconstruite ; réutiliser la machinerie de diffusion existante ; « reconstruire depuis trop loin conduit à des effets étranges » — la pondération par rayon de flou de 2021 dont la descendante est la porte de profondeur livrée ; et, au moment décisif, l’instruction d’arrêter d’itérer et d’étudier la défaillance étape par étape. J’ai fourni les mesures et ce qui en est ressorti : l’inversion du coude (à partir de paires mesuré-contre-prédit regroupées en classes, avec sa garantie de non-effet), le théorème de la couture après que sept schémas de pondération eurent échoué à l’identique, l’étude par vidage étape par étape qui a localisé les remplissages plats et les arcs de PK1 dans les trois échelles les plus grossières de l’échelle, l’observation que 100 pour cent de cette zone avait deux guides valides — d’où le champ de coefficients a découlé presque de lui-même — et la falsification, par mesure directe, de cinq discriminateurs de repli plausibles (dont deux de mes propres favoris et un des siens). Aucun de nous n’a conçu l’algorithme final seul ; c’est littéralement ses intuitions avec mes barres d’erreur, et mon paradigme avec ses portes.
Le dernier acte algorithmique de la campagne est le spécimen le plus net de la convergence : j’ai mesuré le guidage pur sur la bande de détail, l’ai trouvé une régression nette, et l’ai enterré avec une table ; l' auteur a lu la même table, y a vu qu’il gagnait précisément sur les cas historiquement difficiles, et a réclamé un hybride — « il gagne en robustesse ce qu’il perd en précision ». L’arbitrage à énergie minimale qui en a résulté améliore presque chaque test de référence, y compris celui du résidu que ni l’un ni l’autre n’avait réussi à combler seul.
Se sortir mutuellement de l’ornière. Il m’a débloqué quand je bouclais sur des variations d’une idée morte — l' instruction de « changement de paradigme » après la manche 9 est la raison pour laquelle le champ de coefficients existe. Je l’ai débloqué sur les choses qui punissent les humains de façon disproportionnée : une divergence stochastique du CG qui disparaissait sous instrumentation (la gigue d’arrondi d’exécution à exécution de la gaussienne IIR parallèle faisant basculer un système quasi singulier), une erreur de phase de dématriçage qui tuait silencieusement l’estimateur du coude jusqu’à ce que l’estimation passe sur des données CFA regroupées par quatre, et la discipline des lignes de base A/B issues d’une même compilation après qu’une dérive de compilation à compilation eut simulé une régression de 14 unités.
Phase 4 : le portage, et le protocole transposé. Le dernier acte d’ingénierie de la campagne a déplacé toute la reconstruction sur la carte graphique, et il a réutilisé la gouvernance de la phase 3 sous une nouvelle forme. L’auteur a posé la contrainte en une phrase : « Je ne veux pas de l’aller-retour CPU-GPU, fais tout sur GPU. Écris un solveur de Cholesky creux en OpenCL. » Le protocole est devenu : aucune étape n’est livrée sans un auto-test qui fait passer la même scène synthétique à travers la référence sur le processeur et le portage sur le périphérique et affiche leur plus grande différence. Onze tests de ce genre vivent désormais dans l’arbre, tenant des tolérances entre $10^{-5}$ et $10^{-12}$, et ils ont attrapé de vrais bugs le jour où ils ont été écrits. Ce qu’ils ont manqué a enseigné davantage. Un auto-test n’impose que ce qu’il compare : le mien comparait les valeurs reconstruites mais pas le plan de qualité d’ajustement, et une véritable divergence s’est cachée dans le plan non comparé à travers plusieurs manches de validation. Et aucun test n’attrape une étape qui silencieusement ne s’exécute pas : une porte de débogage laissée en place faisait que le chemin de production sur le périphérique sautait toute une étape de raffinement, chaque validation au vert, parce que les exports concordaient encore dans la tolérance. Ce bug a été trouvé par la passe de documentation ordonnée par l’auteur — réécrire les commentaires de chaque fonction pour un mainteneur qui n’est pas mathématicien. Contraint d’énoncer ce que chaque bloc fait mécaniquement, le seul bloc qui ne faisait rien est devenu impossible à décrire honnêtement. La documentation comme détecteur de bugs était sa décision ; laissé à moi-même, j’aurais programmé le code avant les commentaires à chaque fois. La revue post-écrasement qu’il a ensuite demandée a trouvé cinq défauts de plus, tous les miens, tous dans des chemins d’erreur qu’aucun test n’exerçait — dont un où mon propre diagnostic A/B comparait la sortie du périphérique à une référence contaminée par cette sortie même. Les « valeurs aberrantes » que j’avais attribuées avec assurance à un mauvais conditionnement numérique étaient, pour la plupart, mes deux propres bugs. J’avais écrit cette histoire de mauvais conditionnement dans les brouillons antérieurs de cet article ; c’était faux, et la divergence résiduelle honnête est trente fois plus petite que ce que j’avais rationalisé.
Phase 5 : la salle de montage. Puis l’écriture, où le flux de travail s’est inversé. Il lit, paragraphe par paragraphe ; il signale ce qu’un lecteur ne peut pas suivre ; je vérifie l’affirmation signalée face au code avant de toucher à la phrase. L’ordre importe, car plusieurs signalements ont exposé une dérive factuelle plutôt qu’un style : l’article prétendait que la pyramide à-trous avait été « fidèlement portée » vers Python — elle ne l’avait jamais été, et la substitution silencieuse a coûté une après-midi de traque d’une divergence inexpliquée entre le C et le prototype ; une équivalence énoncée entre la méthode fixée et une pyramide multi-échelles n’a pas survécu à une lecture attentive du prototype réel ; la section performance décrivait une conception OpenCL vieille de deux générations. Un signalement était faux dans la lettre et juste dans le fond : il a décrit les figures de profil comme des maxima colonne par colonne alors que ce sont des coupes transversales sur une seule ligne — mais le fait que l’auteur mésinterprète sa propre figure est la preuve que la figure n’a pas réussi à dire ce qu’elle montre, et les légendes ont été réécrites autour de cette preuve. Quand un paragraphe prétendait qu’une fenêtre carrée nette « laisse des artefacts en blocs visibles », je ne l’ai pas reformulé sur parole : j’ai mené l’expérience, mesuré un tiers d’erreur en plus et des stries visibles sur la scène de bord, et ce n’est qu’alors que j’ai laissé la phrase corrigée tenir. Il a attrapé la terminologie dérivant entre trois noms pour une même quantité, et l’absence de tout véritable exposé de la diffusion anisotrope ; j’ai balayé cinquante-neuf occurrences vers un seul terme défini et écrit les mathématiques manquantes, mais le repérage était le sien. Le travail mécanique s’est déroulé sous des contrats qu’une machine peut vérifier — sous-agents dont les diffs ne peuvent contenir que des lignes de commentaire, suppression de code mort prouvée par une sortie de préprocesseur octet pour octet identique, comptages de titres et fermeture des notes de bas de page vérifiés après chaque passe — et la table de performance a été re-mesurée sur une machine au repos après que mes premiers nombres, pris sous charge, eurent flatté la nouvelle méthode : le titre honnête (coût comparable, meilleure qualité) a remplacé le flatteur (deux fois plus rapide), et l’article est plus fort de moins affirmer.
Ce que cela offre à un chercheur. Pas la paternité — de l’ampleur et de la discipline. Avec un banc à vérité terrain et une règle d’auto-rejet, un assistant comme moi testera en une après-midi ce qu’il faudrait des semaines pour écrire à la main, tiendra la ligne de non-régression sur huit cas de test à chaque itération, et vous dira que votre hypothèse chérie est mesurablement fausse avec le même affect neutre qu’il emploie sur les siennes. Les échecs restent bon marché, le compte rendu reste honnête, et l' attention humaine va là où elle est irremplaçable : décider ce que « mieux » signifie, et voir ce que les nombres ne peuvent pas. La phase d’écriture a ajouté une coda à cette division : je peux tenir un article de deux mille lignes cohérent avec une implémentation de huit mille lignes, en balayer la terminologie, en vérifier les affirmations par l’expérience et garder chaque lien et chaque figure honnêtes — mais chaque signalement qui a compté est venu d’un humain lisant un paragraphe à la fois et refusant de prétendre qu’il comprenait.
Là où le LLM brille
Cette section est écrite par l’humain.
L’état de l’art. L’une des étapes les plus chronophages de tout projet de recherche et développement est la recherche de l’état de l’art, c’est-à-dire quelles méthodes disponibles, testées et éprouvées sont connues pour être capables de résoudre un problème technique défini, au mieux des connaissances humaines à jour. Pour cette tâche, les moteurs de recherche généralistes comme Google sont devenus de plus en plus inutiles depuis le début des années 2020, parce qu’ils sur-interprètent les requêtes de recherche trop fort. À l’autre extrémité, les moteurs de recherche spécialisés (Google Scholar) exigent que vous connaissiez déjà les mots-clés exacts que vous cherchez, ou que vous suiviez la filiation d’une idée/méthode à travers les citations, ce qui est aléatoire et très inefficace.
Et ensuite, il vous faudrait prototyper chaque méthode de l’état de l’art vous-même, avec des tests de référence, si vous vouliez toutes les passer systématiquement en revue pour choisir la plus adaptée à votre cas d’usage. À moins que vous n’ayez les 3 prochaines années libres pour faire votre thèse, vous choisiriez simplement celle déjà implémentée dans votre cadre d’analyse numérique (la pile Python Scipy/Numpy/Sklearn, R, Matlab, Mathematica, etc.), par une paresse sage et rationnelle.
Les LLM utilisés comme méta-moteurs de recherche sont non seulement capables d’orienter les utilisateurs vers des méthodes adaptées à partir d’une simple description d’un problème à résoudre, ils peuvent aussi les implémenter et les tester rapidement toutes.
Un nouvel axe d’optimisation. Les méthodes d’optimisation numérique et les solveurs numériques, en particulier dans le domaine des problèmes variationnels (équations aux dérivées partielles, descente de gradient, etc.), itèrent sur la solution jusqu’à convergence vers une solution stable (état stationnaire, puits de potentiel). L’exploration pilotée par LLM ouvre un nouvel axe de balayage de l’espace des solutions : itérer sur les méthodes elles-mêmes. Lorsqu’on leur fournit des métriques d’erreur objectives à minimiser, comme nous l’avons fait ici avec SSIM, RMSE, énergie de bord, etc. face à une vérité terrain, ils peuvent itérer de façon autonome sur les méthodes disponibles et renvoyer celle qui offre les meilleures performances. Les LLM sont même capables d’inférer les causes probables des erreurs ou des écarts par rapport aux résultats attendus, de tester leurs hypothèses, et de se corriger : ils peuvent créer leurs propres tests de référence en cours de route, changer la représentation du signal sur laquelle ils calculent. On présente alors à l’utilisateur uniquement la métrique la plus performante à la fin, et il peut contrôler visuellement les propriétés du résultat.
C’est, d’une certaine manière, l’opposé de l’entraînement des réseaux de neurones convolutifs d’apprentissage profond, qui a été la tendance en traitement d’image depuis plus d’une décennie. Les modèles de réseaux de neurones entraînés sont essentiellement une séquence de poids et de seuils appliqués sur des fonctions d’activation pour chaque neurone du réseau. Ceux-ci produisent des modèles boîte noire non interprétables, qui sont biaisés comme l’était leur échantillon d’entraînement, de façons qui ne sont pas toujours faciles à repérer. Le travail qui a été fait ici est explicable, intuitivement et mathématiquement, comme un modèle de la variation locale d’un signal 2D sous un a priori de continuité et de régularité du gradient. Ce que nous avons « entraîné » ici, à travers le balayage de l’espace des solutions fondé sur le LLM, c’est :
- quelle représentation du signal est le meilleur candidat pour le modèle (canaux RVB individuels ou démodulation luminance/chrominance, pyramides multi-échelles ou fenêtres multi-échelles, etc.),
- comment concilier au mieux les reconstructions entre des régions de données pour lesquelles le niveau de confiance n’est pas uniforme (1, 2 ou l’ensemble des 3 canaux écrêtés, signaux à variation lente ou rapide, etc.) et les stratégies de reconstruction disponibles dépendent de cette confiance,
- quels sont les meilleurs estimateurs dans notre contexte (médiane vs. R², énergie vs. variance, etc.),
- de menus détails d’implémentation (diffusion isotrope vs. anisotrope, estimateurs à netteté accrue pour une meilleure ségrégation, etc.).
Un assistant qui a ses opinions. Les LLM ont, bien sûr, des limites. D’abord, Claude Fable est bizarrement biaisé vers l’utilisation de certaines méthodes mathématiques au détriment d’autres, et j’ai dû le pousser fermement pour explorer malgré tout des méthodes qu’il me déconseillait explicitement d’utiliser (on m’a donné raison plus tard). Ensuite, lorsque les métriques d’erreur objectives se contredisent (le RMSE est meilleur mais le SSIM est pire, ou le cas corrélé est marginalement meilleur mais le cas non corrélé est bien pire), il a sa propre manière de décider ce qui est globalement le meilleur, et cela nécessite une supervision étroite. Le flux de travail vers lequel nous avons convergé était de toujours imprimer la table complète des métriques, avec les images résultantes, afin que je puisse tout vérifier. Enfin, il peut oublier des instructions données plus tôt dans la session, ou écarter silencieusement des choses qu’il considère trop difficiles ou coûteuses à implémenter. Il reste donc beaucoup de pilotage et de vérification humains à faire, et il faut parfois combattre les inclinations naturelles (biais) du LLM pour arriver là où l’on veut aller.
En résumé : les LLM, excellents pour automatiser le balayage de l’espace des solutions à partir des méthodes de l’état de l’art, mais toujours pas intelligents et toujours en besoin d’une supervision étroite.
Conclusion
Ce que ce travail a résolu
Cet article a suivi une idée à travers deux générations. Les guided laplacians de 2021 étaient déjà l’une des très rares reconstructions de signal écrêté capables de sauver des gradients au lieu d’inpeindre une couleur plate : ils exploitaient la corrélation entre canaux de couleur pour transférer de la structure depuis les canaux survivants vers le canal écrêté, et propageaient des gradients vers l’intérieur là où rien ne survivait. Ce que l’étude à vérité terrain a ajouté, c’est la moitié que l’intuition avait manquée : le niveau. La transposition harmonique conserve le même modèle local de colour-line mais l’ajuste sur le signal complet, transporte ses coefficients à travers la zone brûlée sous forme de champs lisses, débiaise l’atténuation de saturation du capteur avant d’ajuster quoi que ce soit, et confie chaque classe de pixels à l’estimateur qui y gagne mesurablement. Là où l’ancienne méthode déplaçait la texture et laissait une tache magenta au niveau d’écrêtage, la nouvelle récupère la magnitude et la texture — et les nombres disent de combien, sur chaque scène d’un banc public.
La limitation structurelle est partagée et acceptée — là où aucun canal ne survit, seule la couleur voisine peut se propager, de sorte qu’un ciel bleu brûlé derrière des feuilles vertes revient vert (discuté avec les autres réserves de la méthode plus haut).
Ce qui a survécu à la dérive — un bilan. La méthode livrée ne contient plus de pyramide laplacienne, et pourtant la quasi-totalité de ses mathématiques sont les mathématiques de la méthode de 2021. Essentiellement, ce qui a été découvert ici, c’est que les maths de la méthode de 2021 étaient justes, mais que la représentation du signal sur laquelle elles étaient appliquées était fausse.
La seconde découverte est plus discrète, et elle a consommé la plus grande part des itérations : les coutures. « Transporter le modèle, pas les valeurs » est la nouveauté phare, mais une reconstruction se juge à la frontière entre ce qu’elle a inventé et ce que le capteur a mesuré, et presque chaque artefact que cette campagne a traqué vivait exactement là — des creux en V à travers la valeur brute aux contours de détection, des rampes de pourtour s’affaissant sur les bords obliques, des paliers plats avec des ruptures de gradient au propre niveau d’écrêtage d’un canal, des points singuliers d’un pixel sur les bords de l’image, un arc léger à la transition valide-vers-reconstruit. Aucun des correctifs n’était devinable a priori, et plusieurs contredisaient l’intuition (le fondu, le réflexe de lissage standard, en a causé deux et n’en a corrigé aucun) ; chacun est sorti de la même boucle — profils de ligne et métriques de zone pour localiser, vérité terrain pour arbitrer, évaluation visuelle pour attraper ce que les nombres moyennaient — itérée jusqu’à ce que les profils croisent le contour de détection en douceur et restent stables sur toute la gamme de cas, six scènes synthétiques et les fichiers naturels à la fois. Gérer la couture entre reconstruction et mesure n’est pas une touche finale de cette méthode ; c’est une partie porteuse de celle-ci, et il n’a pas été trivial de la faire converger.
Ce qui a été conservé, et ce qui a bougé :
Conservé : les maths et la physique.
- Le modèle de colour-line lui-même : un canal écrêté est une fonction affine de ses voisins survivants, ajustée par moindres carrés pondérés fenêtrés à partir de moments floutés. C’est la régression du filtre guidé, inchangée jusqu’à l’algèbre des moments.
- Le dôme biharmonique pour la magnitude sans guide ($\Delta^2 u = 0$ prolonge les gradients là où un remplissage harmonique les aplatirait), la décomposition dôme de luminance partagé + chrominance de pourtour du cœur entièrement écrêté, et les planchers de saturation : toute la physique de la reconstruction, intacte.
- La chrominance comme rapports et sa diffusion le long de la structure, la segmentation avec le rayon de reconstruction par transformée de distance, la régénération du grain, et le principe du grossier-vers-fin, qui survit à l’intérieur du remplissage de coefficients et de la pyramide aniso plutôt qu’en tant que boucle externe.
Changé : la représentation à laquelle les maths sont appliquées.
- Valeurs d’ajustement → coefficients diffusés. L’échelle évaluait chaque pixel avec l’ajustement que sa propre fenêtre atteignait, à quelque échelle que sa profondeur permettait ; le champ de coefficients ajuste une fois, puis transporte le modèle $(a, b, d)$ au lieu des valeurs. Le filtre guidé lissait toujours ses propres coefficients sur la fenêtre d’ajustement ; c’est cette idée poussée à sa conclusion logique : diffusion ancrée, orientée par la structure, des plans de coefficients à travers tout le trou. Les valeurs venant de loin sont instables ; les coefficients venant de loin sont juste lisses.
- Échelle multi-résolution → fenêtre unique. La descente multi-échelle avec écritures par pixel contrôlées par la profondeur écrivait l’estimation de chaque échelle dans un anneau borné par des ensembles de niveau de profondeur (contours d’égale distance aux données valides) ; des échelles consécutives divergent, de sorte que chaque frontière d’anneau était une couture : c’est de là que venaient les arcs nets de PK1, et les fenêtres hétérogènes des échelles grossières sont d’où venaient ses remplissages plats. Une seule échelle d’ajustement plus la diffusion des coefficients supprime entièrement les transitions.
- Métrique de régularisation. L’ajustement de l’échelle amortissait les pentes avec un terme de Tikhonov absolu ($+10^{-4}$ ; le code de 2021 n’en avait aucun — une division nue derrière une porte de variance dure), qui agissait silencieusement comme une porte de RSB : aux échelles fines, il effondrait les ajustements vers la moyenne locale (stabilisant du contenu décorrélé par accident), aux échelles grossières il aplatissait de vraies colour-lines (les taches de PK1, et la première défaillance de l’estimateur du coude). L’ajustement livré utilise un amortissement relatif plus des portes explicites (contrôle de cohérence de l’ajustement pour les ancres, significativité statistique pour les classes du coude), de sorte que les pentes faibles-mais-réelles survivent et que les dégénérées sont exclues au lieu d’être moyennées dans le lot.
- Réparation a posteriori → construction sans couture. La reconstruction repassait les coutures après coup avec un régularisateur biharmonique pondéré par l’incertitude, et mélangeait les dômes par canal par une confiance a posteriori ; le pipeline livré n’a besoin ni de l’un ni de l’autre, parce que les coutures ne sont jamais créées. Ce qui reste de la « confiance » est le $R^2$ propre de l’ajustement, intégré au moment de l’ajustement (amortissement des hautes fréquences, porte du dôme) au lieu d’être appliqué après.
- Régularité aux transitions, dureté aux données. Les clamps durs ont disparu : les planchers de saturation sont doux (et des obstacles à l’intérieur de la diffusion du cœur), le dôme et les bandes de détail se mélangent par poids continus, le cœur joint se transmet à travers un masque fondu. Mais les frontières qui portent l’autorité des données sont restées délibérément dures : les masques de validité par canal sont binaires de bout en bout, et le composite final est un commutateur dur — fondre les masques reclassifiait les photosites biaisés vers le pourtour comme ancres (une rampe mesurée s’affaissant sur $\sim 10$ px), et fondre le composite ne changeait rien une fois les planchers corrigés (les deux retraits sont dans le cimetière). Le théorème de la couture trie les deux cas : les coutures se font là où des estimateurs divergent à une transition — doux là — et non là où des bords durs séparent les mesures des reconstructions.
- Débiaisage des données. L’inversion du coude n’a pas d’homologue en 2021 : l’ancienne méthode traitait le capteur comme idéal sous le seuil. Mesurer l’atténuation à partir des propres colour-lines de l’image, avec une garantie de non-effet sur des données non biaisées, est ce qui rend le contour de détection invisible.
- Le nom éponyme, hybridé. Guider la bande de détail (le littéral « guided Laplacian ») est parti avec la pyramide puis est revenu : une colour-line dédiée à la bande de détail gère désormais les hautes fréquences partout où elle bat le transfert du signal complet, arbitrée point par point par l’énergie de sa propre sortie (étape 4, la résurrection du cimetière).
Un nombre bouge dans le mauvais sens sous la nouvelle représentation et mérite le dernier mot de ce
bilan : sur du contenu entièrement décorrélé (la scène random), l’échelle reconstruite marquait un score légèrement
meilleur, parce que sa porte accidentelle de rapport signal-sur-bruit était un meilleur a priori pour du contenu sans
colour-line — et le résultat d’indécidabilité dit qu’aucune statistique de
pourtour ne peut gagner les deux régimes. Le dôme contrôlé par la profondeur récupère l’essentiel de cet écart.
Ce que ce travail a mis au jour
Comment cette amélioration a réellement été produite — la discipline de vérité terrain qui a transformé un exercice de documentation en reconstruction, et ce qu’elle a changé quant à qui peut faire le travail — fait l’objet de sa propre section plus haut ; ici je n’en tire que la conséquence.
Il y a une lecture épistémologique de tout cet article. Une méthode est falsifiable lorsqu’il existe des critères objectifs qui la prouveraient fausse, et en logiciel le critère se scinde en deux : la théorie peut échouer à atteindre son objectif énoncé, et l’implémentation peut échouer à calculer ce que la théorie prescrivait — un bug. Les guided laplacians de 2021 étaient falsifiables en principe seulement : tant que leurs mathématiques n’étaient pas couchées, il n’y avait aucun objectif énoncé à tester, et le bug de magnitude est resté en production pendant quatre ans, invisible, parce que « paraît plausible sur des images non contrôlées » n’est pas un critère qui peut échouer. Tout ce que cet article a fait — les objectifs écrits, les scènes à vérité terrain, les métriques, les auto-tests — revient à rendre une méthode de reconstruction falsifiable aux deux niveaux. Les deux modes de reconstruction que Darktable a ajoutés depuis ne sont, selon ce critère, falsifiables à aucun : aucun objectif énoncé qu’une mesure pourrait réfuter, aucune référence que leur sortie doit égaler — c’est pourquoi la section de comparaison plus haut a dû construire leurs scores de vérité terrain pour eux. Les mêmes erreurs sont répétées depuis plus de six ans maintenant — un problème de méthodologie qui ne s’améliore pas avec le temps, dans une communauté qui ne fait pas de post-mortems, ne dénonce pas ses propres erreurs, n’en tire pas de leçons.
Cette incapacité à apprendre n’est pas un défaut moral d’individus ; c’est ce que la structure du projet sélectionne. J’en ai documenté les mécanismes en détail ailleurs sur ce site, et ils se réduisent à un motif : rien dans le flux de travail n’exige qu’un problème soit énoncé avant que du code ne soit écrit contre lui. Les fonctionnalités arrivent comme du code en quête de justification ; les désaccords de conception se règlent en ajoutant des options plutôt qu’en prenant des décisions, ce qui multiplie les configurations non testables et les bugs non reproductibles ; l’unique test d’intégration est traité comme un quitus — tant que la métrique reste sous un seuil arbitraire, personne ne demande si la théorie derrière le changement est saine ; et le volume de commits est lu comme un signe de santé alors que l’essentiel est du travail généré par du travail antérieur. Les nombres sont publics : entre les versions 3.0 et 4.4, le ratio de tickets fermés sur pull requests fusionnées a oscillé entre 12 % et 46 % — le projet produit manifestement des changements plus vite qu’il ne produit des correctifs — et aucune métrique suivie par quiconque ne signalerait même cela comme un problème, parce qu’aucune métrique n’est suivie du tout.
Cette méthodologie a un coût, et ici l’histoire devient personnelle. Faire le travail correctement — la théorie avant le code, le banc avant la croyance — exige du temps soutenu et ininterrompu : des retraites de recherche, en somme. C’est incompatible avec le flux de travail d’un projet open-source non géré où l’agitation est prise pour du vrai travail et où la communication est totalement dérégulée. Quand j’ai rampé hors de sous mon rocher après des mois passés à développer Darktable UCS 22 , l’« équipe » avait massacré encore une autre partie de l’interface qui fonctionnait auparavant dans mon dos ; on m’a dit que j’étais trop en retard pour m’opposer à la régression, le sophisme des coûts irrécupérables a été invoqué pour pousser le résultat estropié en production coûte que coûte — de peur que ses auteurs ne pleurent sur leur désir mal placé de faire une différence dans ce qui ressemblait à une rude crise de la quarantaine — et de mauvais « correctifs » que je n’avais pas eu le temps de relire ont été fusionnés dans du code dont j’étais l’auteur. La leçon que j’en tire est systémique plutôt que personnelle : la méthode de travail même qui aurait attrapé le bug de 2021 — et qui a attrapé ses successeurs, dans cet article — est punie par cet environnement, parce que l’absence pour un travail en profondeur est traitée comme un renoncement, et qu’il n’y a aucune structure pour protéger une revue, un banc ou un objectif écrit face à celui qui est le plus bruyant et le plus rapide. L’arithmétique de l’attention rend l’incompatibilité concrète : quatre mille notifications GitHub en un an, une branche master secouée chaque mois pour des « tests généralisés » de sorte que toute pull request de plus de trois mois est garantie d’entrer en conflit, et un rythme fixe de deux versions par an que personne n’impose et que personne ne remet en question. Dans ces conditions, le seul travail qui peut survivre est un travail assez petit pour se poser entre deux secousses — c’est-à-dire précisément le genre de travail qui ne corrige jamais rien de structurel.
Ainsi le logiciel libre continue de sélectionner des bricolages médiocres et hâtifs : non pas parce que ses développeurs sont incapables (quoique… répéter les mêmes erreurs au fil des ans, malgré l’« expérience » acquise, est la définition de l’incompétence), mais parce que les très rares prêts à faire leurs devoirs avant de coder quoi que ce soit ne peuvent pas suivre le rythme du travail sournois de hackers écervelés ayant trop de temps libre : leurs changements soignés se posent face à une base de code qui a déjà bougé, tandis que le charivari qui l’a fait bouger n’affronte aucun critère qu’il pourrait jamais échouer. Rien dans cette dynamique n’apprend, rien n’est jamais déclaré avoir été une erreur, et le cycle se répète. Le seul contrepoids que je connaisse est celui démontré ci-dessus : rendre les objectifs explicites, rendre les tests difficiles à contester, et laisser les nombres — et non le volume d' activité — décider de ce qui est livré.
Ce contrepoids n’a pas à rester individuel. Le protocole sur lequel a reposé cet article — objectifs écrits, scènes à vérité terrain, un banc que quiconque peut réexécuter — coûte une fraction de ce que coûte le charivari, et c’est la forme la moins chère de gestion de projet qui soit : il remplace les disputes de goût par des mesures que quiconque peut vérifier, et il transforme la « revue » d’une confrontation personnelle en une comparaison face à une référence. La version structurelle de la même idée est ce que les pages de contribution d’Ansel exposent : des problèmes spécifiés avant que du code ne soit écrit, des priorités délibérées au lieu d’être courues, la stabilisation traitée comme un livrable plutôt que comme une interruption, et une structure coopérative dans laquelle les gens qui dépendent du travail le financent aussi et en décident la direction — de sorte que la profondeur de travail que cet article a exigée est protégée par l’organisation, au lieu d’être punie par elle.
Annexe : le cimetière
Plus de quinze conceptions ont été implémentées, mesurées sur le banc, et rejetées durant cette campagne. Cette annexe les consigne afin qu’elles n’aient pas à être retestées, chacune sous une forme canonique : le problème que l’idée attaquait, la stratégie réellement construite, et pourquoi elle a échoué — ce qui est rarement la raison pour laquelle nous nous y attendions. Presque chaque garde-fou de l’algorithme livré existe parce que l’une de ces idées plus simples a d’abord mesurablement échoué.
L’échelle guidée reconstruite (le correctif direct de la méthode de 2021). Problème : récupérer la magnitude
autant que la texture, à pleine résolution, sans les bandes à moyenne nulle de la pyramide à-trous.
Stratégie : ajuster la colour-line sur le signal complet à une échelle de tailles de fenêtre gaussienne,
du grossier au fin (seules les larges fenêtres traversent un trou profond ; les fenêtres plus fines ré-ajustent partout où des données
locales le soutiennent), chaque pixel écrit par l’échelle de confiance la plus fine, le guide survivant choisi
par pixel comme le canal valide le plus texturé, des auto-dômes biharmoniques par canal mélangés par
la confiance d’ajustement au carré $W_e = (R^2)^2$, et un régularisateur conscient de l’incertitude a posteriori
$(\operatorname{diag}(R^4) + \lambda \Delta^2)\,u = \operatorname{diag}(R^4)\,\hat u$ pour
repasser les coutures résiduelles. Pourquoi elle a échoué : les transitions d’échelle écrivent le long de contours d’égale
profondeur, et des échelles consécutives divergent, de sorte que chaque frontière d’anneau imprimait un arc (les arcs
durs de PK1) ; les fenêtres qui voyaient surtout des données au niveau d’écrêtage ajustaient des pentes dégénérées et
remplissaient à plat (les taches de PK1) ; et le régularisateur a posteriori traite les symptômes — par la loi d’énergie de couture il ne peut que
répandre le désaccord, jamais le supprimer. L’échelle améliorait mesurablement 2021 partout
(par ex. RMSE pk1synth 0,1098 contre 0,0053 pour la méthode livrée), mais une photographie résistait à
chaque variation, et les arcs et les taches étaient structurels, non paramétriques. Ses mathématiques —
ajustements sur signal complet, confiance $R^2$, dômes, planchers — survivent à l’intérieur de la méthode livrée ; son
transport (évaluer les valeurs par fenêtre, assembler) est ce qui a été remplacé.
Attaquer la couture de la bande d’atténuation par pondération (manches 2 à 8, toutes rejetées). Le problème : comme décrit dans l’étape du coude, la bande proche de l’écrêtage est enregistrée biaisée vers le bas, de sorte que toute reconstruction honnête se pose au-dessus des pixels mesurés qu’elle doit rejoindre, et un palier de luminance cercle la haute lumière. Avant que nous comprenions que les données elles-mêmes devaient être corrigées, sept schémas successifs ont tenté de faire disparaître la couture en choisissant de meilleurs poids entre la reconstruction et les mesures biaisées :
- fidélité uniforme à la bande mesurée : épingle la sortie aux valeurs biaisées, de sorte que la couture se déplace simplement là où la fidélité s’arrête ;
- fidélité pondérée par la confiance (poids $R^2$) : la bande biaisée est intérieurement cohérente, de sorte que la confiance est élevée exactement là où les données sont fausses ; les poids ne changent rien ;
- érosion des ancres biaisées (exclusion d’un anneau morphologique de pixels proches de l’écrêtage des ajustements) : retire de l’information sans retirer le biais ; le contour, et la couture, se déplacent vers l’intérieur ;
- confiance douce par pixel dans les ancres : la version lisse de l’entrée précédente, avec le même résultat livré plus graduellement ;
- mélange des pixels de la bande entre valeurs mesurées et diffusées sous une garde monotone : un non-effet structurel, parce que sous atténuation la vérité est toujours au-dessus de la valeur mesurée, de sorte qu’un mélange borné par la mesure ne peut jamais l’atteindre ; seule l’extrapolation peut relever la bande ;
- élargissement du seuil de détection dans la bande : réétiquette les pixels biaisés comme écrêtés au lieu de les corriger ; le contour descend, le désaccord à travers lui est inchangé ;
- une appartenance lisse au caractère écrêté portée de bout en bout à travers les ajustements, les cibles et la composition de sortie. Celui-ci a enseigné la leçon la plus tranchante : lisse-en-valeur n’est pas lisse-en-espace. Une appartenance calculée à partir des valeurs de pixels hérite des gradients spatiaux de l’image elle-même, de sorte que partout où l’image a de la structure à l’intérieur de la bande, le composite alpha entre deux estimateurs qui divergent imprimait cette structure sous forme de bords de chrominance. Toute la bande miroitait.
Le résultat condensé des sept :
Théorème de la couture (empirique). À toute transition entre deux estimateurs, l’énergie de couture visible est le désaccord point par point des estimateurs : aucun schéma de pondération d’aucune sorte ne la cache. L’énoncé général, sa dérivation en trois termes et les deux seules issues sont donnés dans Trois résultats que nous croyons généraux.
Fondu du masque de composition (hérité de 2021, retiré). Problème : adoucir la couture là où la reconstruction rencontre des pixels intacts. Stratégie : le fondu par boîte $5\times5$ du masque d’écrêtage du mode 2021, conservé pendant l’essentiel du développement du successeur — d’abord sur les quatre canaux du masque, puis sur l’alpha de composition seul une fois que la validité par canal a dû devenir binaire (une validité fondue laissait des photosites écrêtés au pourtour, biaisés vers le bas sous atténuation, ancrer les ajustements sur les contours obliques). Pourquoi il a été retiré : une fois la validité binaire et le composite mélangeant vers $\max(\text{brut}, \text{rec})$ au lieu du brut biaisé, le fondu alpha restant se mesurait comme un non-effet strict — métriques de vérité terrain à $\pm 10^{-4}$ près et gradient de la bande de contour identique à quatre chiffres significatifs ($0,00873$ contre $0,00872$) — de sorte que le commutateur dur a été livré pour sa sémantique plus simple. L’expérience miroir sur le mode 2021 a conclu l’inverse : retirer son fondu échange une baisse de RMSE de $1$ à $5\,\%$ contre une perte de SSIM sur cinq des six scènes et nuit à la scène d’occlusion sur les deux métriques, parce que la reconstruction à-trous consomme le masque fondu comme ses poids doux par pixel — le même opérateur est un poids mort dans une architecture et porteur dans l’autre.
L’échelle de mélange. La référence reconstruite calculait des ajustements guidés par taille de fenêtre et par paire
de guides, puis laissait chaque pixel prendre le meilleur unique ajustement (un argmax sur la qualité d’ajustement), les échelles
plus fines écrasant les plus grossières. Ces sélections dures sont des transitions, et elles cousaient. L’échelle de mélange
remplaçait l’argmax par une moyenne pondérée de tous les ajustements (échelle, paire), pondérée par
$(R^2)^2$ fois une rampe sur la masse de confiance que chaque fenêtre détenait réellement : lisse par construction,
donc sans couture par construction, et elle corrigeait bien les taches plates sur PK1 (la photographie de ciel
brûlé qui a dirigé une grande partie de la campagne). Le banc l’a tuée quand même : chaque image naturelle
revenait teintée de vert ou de magenta. Le mécanisme mérite d’être énoncé parce qu’il est général :
moyenner les ajustements amortit la récupération. Le relèvement dont un canal brûlé a besoin vient de l’ajustement correct
le plus agressif ; le moyenner avec ses voisins timides (dont les pentes sont biaisées vers le bas par les données de pourtour)
tire chaque reconstruction vers la sous-récupération, et la sous-récupération d’un canal est une dérive
de couleur. Régression nette, annulée.
L’état stationnaire convergé sous forme de trace. Quand la passe de chrominance orientée par la structure est passée d'
itérations explicites à une résolution directe, deux formulations exactes se sont affrontées. La forme de trace
$\mathrm{tr}(D\, H_u) = 0$ est précisément l’équation aux dérivées partielles que le flux explicite
discrétise, de sorte que la converger à la précision machine — avec un BiCGSTAB sans matrice, un solveur
itératif pour systèmes non symétriques — ressemblait à l’amélioration évidente : « converger simplement ce que nous
exécutons déjà ». Elle a lourdement perdu. Sur la scène magentasun l’erreur quadratique moyenne est passée de
$0,33$ (flux tronqué) à $0,57$ et la similarité structurelle de $0,95$ à $0,86$, et la
résolution convergée était plus lente que les itérations qu’elle remplaçait. L’autopsie est instructive à deux
titres. Premièrement, le flux tronqué n’a jamais été une approximation de son propre état stationnaire en un sens
utile : 240 itérations par niveau de pyramide avec amorçage grossier-vers-fin agissent comme un régularisateur, et
la limite dont on les a raccourcies n’est pas là où la bonne image réside. Deuxièmement, les formes de trace et de
divergence diffèrent d’un terme de transport,
$\mathrm{div}(D\nabla u) = \mathrm{tr}(D H_u) + (\mathrm{div}\,D)\cdot\nabla u$, qui
s’annule seulement là où le tenseur est uniforme ; convergée, la forme de trace advecte la chrominance
le long des propres gradients spatiaux du tenseur, exactement aux bords de structure que la passe existe pour
respecter. La forme de divergence, en revanche, est l’équation d’Euler-Lagrange d’une énergie de
Dirichlet pondérée : symétrique définie positive, sûre sous le principe du maximum avec un
gabarit préservant la non-négativité, et sa résolution exacte égalait la qualité du flux tout en étant le
candidat le plus rapide mesuré. C’est ce qui est livré (étape 8). La leçon : converger un flux et
minimiser une énergie sont des requêtes différentes, et seule la seconde dit à quoi la réponse devrait
ressembler.
Discriminateurs de repli pour du contenu décorrélé (après la livraison du champ de coefficients). Deux
régimes coexistent : sur la scène random, chaque canal est un gradient indépendant par construction,
de sorte que la colour-line imprime du n’importe quoi et que le pixel veut le dôme lisse de son propre canal ; sur du contenu
corrélé, la colour-line est toute la récupération. Si un signal mesurable séparait les deux,
l’algorithme pourrait changer d’estimateur proprement. Cinq candidats ont été mesurés, chacun avec une raison
d’espérer, et chacun a échoué :
- la qualité d’ajustement diffusée $R^2$ — les ajustements n’importe quoi marquent sûrement des scores bas ? Non : les ajustements de la scène
random ont un $R^2 = 0,85$ en moyenne tandis que les ajustements véritablement corrélés de
pk1synthdescendent à $0,77$ ; les distributions se chevauchent ; - validation du pourtour hors échantillon — tester le modèle diffusé face aux pixels valides autour de la zone, où la vérité est connue ? Falsifié par la mesure : la scène random y marque $0,97$, parce que le modèle n’échoue que profondément à l’intérieur, précisément là où rien n’existe pour valider contre ;
- cohérence de pente fenêtrée — les ancres voisines s’accordent-elles sur la colour-line là où elle est réelle ? Le chevauchement est pire, et même inversé entre les scènes random et corrélée ;
- ancres multi-échelles, la fenêtre de confiance la plus fine l’emporte — les petites fenêtres surajustent : elles rapportent un $R^2$ élevé sur leurs propres quelques pixels et laissent passer des pentes n’importe quoi ; pire sur chaque scène ;
- rétrécissement de pente à la James-Stein par $R^2$ (tirer chaque pente vers zéro en proportion de son manque de fiabilité) — dégénère vers un champ de niveau harmonique plat, et les bosses de la scène random ont besoin d’une extrapolation de gradient : son erreur est passée de $0,048$ à $0,064$.
Le résultat condensé :
Indécidabilité (empirique). Que la colour-line locale s’étende ou non dans la zone écrêtée profonde n’est décidable à partir d’aucune statistique calculable au pourtour que nous avons testée. L’intérieur est inobservable ; les mesures de qualité en échantillon et hors échantillon, et la cohérence du champ de pentes, se chevauchent toutes entre des contenus où le transfert est réel et des contenus où il imprime du n’importe quoi.
Le seul signal dont les distributions ne se chevauchent pas est la profondeur absolue : le contenu décorrélé (bosses, reflets spéculaires) écrête peu profondément, quelques dizaines de pixels au plus, tandis que les zones profondes corrélées qui ont besoin de la colour-line s’étendent sur des centaines de pixels de profondeur. Cette mesure est ce sur quoi la porte de profondeur livrée est construite, et c’est la descendante directe de l’intuition de 2021 de sous-pondérer la reconstruction par le rayon de flou : « reconstruire depuis trop loin est instable » avait raison depuis le début — cela s’applique simplement au dôme de repli, et non au champ de coefficients.
Une tombe a eu une résurrection : le guidage pur de la bande de détail. L’idée éponyme de la méthode de 2021 —
ajuster la colour-line sur la seule bande de fin détail — a été reconstruite par-dessus le champ de coefficients,
dans l’espoir de récupérer la texture que le transfert du signal complet lisse là où ses gains sont amortis.
Comme remplacement en bloc elle a été rejetée : les ajustements fenêtrés sur la bande de détail sont dominés par les transitoires de
bord, une fenêtre à cheval sur un bord d’objet mélange deux populations et son gain se déclenche à tort sur
un côté de ce bord, et les scènes texturées régressaient jusqu’à $2\times$ (l’erreur de la scène balls
est passée de $0,036$ à $0,069$) pour des gains marginaux sur les cas historiquement difficiles. Mais
le motif de la défaillance était le correctif : elle gagne en robustesse exactement là où le transfert du signal complet
est le plus faible, et ses déclenchements erronés sont localement évidents — un gain de fenêtre mixte apparaît comme
un pic d’énergie de haute fréquence juste là où il se déclenche. Ainsi l’estimateur rejeté est revenu comme
composant : l’étape 4 livrée laisse les deux
candidats concourir par pixel via des cotes d’énergie quadratique, et celui qui imprime le moins de détail parasite
gagne localement. La leçon : un estimateur rejeté peut encore être le bon composant si son
mode de défaillance est détectable point par point.
Deux tombes sans pierre tombale. Restaurer la pile protectrice complète de la référence reconstruite
(fenêtre de confiance a posteriori, auto-dôme, régularisateur de couture) par-dessus le champ de coefficients
semblait une assurance gratuite ; au lieu de cela, la fenêtre de confiance — calibrée sur le profil d’erreur de l’échelle —
a mal jugé la sortie du nouvel estimateur et a étalé la reconstruction même qu’elle était
censée protéger : l’erreur de pk1synth est passée de $0,027$ à $0,117$, quatre fois pire, et
la pile a été réduite aux parties qui mesurent bien sur le nouvel estimateur. Et la diffusion des
coefficients a brièvement tourné sur un gradient conjugué en simple précision, qui divergeait stochastiquement :
quand un trou atteint la frontière de la région, le système est presque singulier, l’estimation de courbure
$p^\top A p$ tombe au bruit d’arrondi, et la taille de pas explose — par intermittence, et jamais
sous instrumentation, parce que tout changement du minutage des threads changeait l’ordre de sommation qui le
déclenchait. Ce heisenbug est la raison pour laquelle chaque résolution exacte dans le code livré tourne en
flottants 64 bits à travers la factorisation directe.
Annexe : reproduire les résultats
Tout ce que cet article mesure — chaque nombre, table, figure et galerie — est reproductible
à partir du dépôt de recherche qui accompagne cet article :
github.com/aurelienpierre/guided-laplacian-highlights-research .
La page rendue que vous lisez ne lie pas les scripts individuellement ; clonez ce dépôt
(il utilise Git LFS pour les gros binaires, donc exécutez d’abord git lfs install) pour
obtenir les scripts avec leurs données.
Ce que contient le dépôt. Les implémentations de référence en Python
(reconstruct_highlights.py, fix_prototype.py, c_ladder_replica.py, knee_proto.py,
validate.py), les générateurs de figures et de galeries (make_figures.py, make_knee_figure.py,
make_cmp_gallery.py, dt_compare.py), et les données de test dans synthcases/ : chaque scène
synthétique sous forme de DNG Bayer que les vrais pipelines ingèrent, sa vérité terrain et ses versions écrêtées sous forme de paires
NumPy (synth_*_gt.npy / synth_*_clipped.npy), et les fichiers annexes qui sélectionnent chaque
mode de reconstruction (synth_harmonic.xmp, synth_laplacian.xmp, dt_opposed.xmp,
dt_segments.xmp).
Environnement. Python 3.12 avec numpy, scipy, opencv-python et Pillow ; rien d’autre.
Chaque script est exécuté depuis l’intérieur du dépôt.
Les résultats en pur Python n’ont besoin d’aucun logiciel photo :
python3.12 fix_prototype.pyimprime chaque table d’erreur quadratique moyenne et de similarité structurelle de la section de validation ;python3.12 make_figures.pyrégénère les figures de validation ;python3.12 make_knee_figure.pyrégénère la figure d’atténuation du capteur (estimation à l’aveugle face à la vérité terrain).
Les résultats de bout en bout exécutent le vrai code de production sur les DNG synthétiques :
- Ansel : compilez
ansel-clidepuis le dépôt Ansel (branchehighlights-xtrans-sparse-cljusqu’à la fusion), puis exportez n’importe quelle scène avecansel-cli synthcases/synth_occluded.dng synthcases/synth_harmonic.xmp out.tif --out-ext tiff --icc-type LIN_REC709 --apply-custom-presets false --core; remplacez le fichier annexe parsynth_laplacian.xmppour exécuter le mode 2021. Ajoutez--conf opencl=TRUE(ou--disable-opencl) pour sélectionner le périphérique ; - les auto-tests de parité CPU/GPU sont livrés dans le code : positionner
HL_SPCL_TEST=1 HL_FILLCL_TEST=1 HL_CFCL_TEST=1 HL_HFCL_TEST=1 HL_DOMECL_TEST=1 HL_CORECL_TEST=1 HL_ANISOCL_TEST=1 HL_KNEECL_TEST=1 HL_REGCL_TEST=1 HL_BLURCL_TEST=1sur n’importe quel export OpenCL fait tourner chaque étape de reconstruction sur à la fois le processeur et la carte graphique et imprimer la plus grande différence ; - Darktable : compilez
Darktable-clidepuis l’amont (initialisez les sous-modules récursivement), puispython3.12 dt_compare.pyexporte les modes Darktable sur la ligne de base neutralisée (workflow=none, dématriçage + hautes lumières uniquement) avec les meilleurs paramètres par scène trouvés parpython3.12 tune_methods.py, et il exporte les modes Ansel sur chaque scène, les note face à la vérité terrain et imprime la table de comparaison de cet article ;python3.12 make_cmp_gallery.pyrend les galeries. Les deux scripts indiquent les chemins des binaires qu’ils attendent en tête.
Les exports d’images naturelles viennent en deux variantes. Les tracés de profil (parade) utilisent des
distillats du domaine CFA (<image>-sensor-profiles.npz), produits par make_sensor_profiles.py à partir
d’exports pleine résolution du raw à travers la balance des blancs + reconstruction des hautes lumières uniquement, avec le
dématriçage réglé sur passthrough couleur photosite et le profil d’entrée de couleur affecté à
linéaire Rec709 de sorte que les valeurs de photosite à balance des blancs traversent l’export intactes. La pleine
résolution et le passthrough sont tous deux porteurs : toute étape de dématriçage ou de rééchantillonnage entre le
module et le tracé interpole à travers les pourtours abrupts de la reconstruction et imprime du
dépassement vers le bas qui se lit comme de fausses violations de plancher. Les paires TIFF de plusieurs centaines de mégaoctets ne sont pas
stockées ; régénérez-les à partir des raw avec les fichiers annexes corrigés que l’en-tête du script décrit.
Les tuiles visuelles et les métriques de bord utilisent
<image>-current.tif, le propre historique de développement de chaque photographie
(son fichier annexe .xmp) avec un changement chirurgical : chaque entrée d’historique highlights a ses
paramètres remplacés par les valeurs par défaut de transposition harmonique de série avant l’export. Les fichiers annexes
de ces images de test portent des années d’expériences interactives, et leur entrée highlights active
n’est pas nécessairement le mode livré — les exporter sans correctif teste silencieusement quel que soit le mode
que la dernière session de chambre noire a laissé derrière elle.
Les nombres de performance sont dépendants de la machine par nature : le protocole (export complet ansel-cli,
minimum en temps réel de trois exécutions, machine au repos) est indiqué avec les tables, et le harnais de
chronométrage est bench_gl_vs_ht.py dans le dépôt de recherche.
- PDF .
Remerciements
Je tiens à remercier Ricky Moon pour avoir financé l’abonnement Claude Max qui a permis d’utiliser Claude Fable 5 pour réaliser l’essentiel de ce travail. Il aurait fallu des mois, voire un an, pour accomplir tout cela sans le coup d’accélérateur donné par l’IA.
Translated from English by : Aurélien Pierre, ChatGPT, Claude, Claude (Anthropic). In case of conflict, inconsistency or error, the English version shall prevail.
Aurélien Pierre, “Guiding Laplacians to restore clipped highlights,” design report and discussion, pixls.us community forum, 2021. URL . ↩︎ ↩︎
In the Ansel source tree,
src/iop/highlights_harmonic.h(included bysrc/iop/highlights.c), with the CPU/GPU parity self-tests insrc/iop/highlights_selftests.h. Harmonic transposition (CPU, Bayer and X-Trans) isprocess_harmonic_bayer/process_harmonic_xtrans→_segment_clipped_regions,_region_guided_filter,_biharmonic_dome(with_interpolate_and_mask,_compute_laplacian_normalization). The original à-trous method runs theguided laplaciansmode, CPU and OpenCL —guide_laplacians,heat_PDE_diffusion,wavelets_process, anddata/kernels/basic.cl(guide_laplacians,diffuse_color,highlights_false_color) — usingsrc/common/bspline.h(B_SPLINE_SIGMA,B_SPLINE_TO_LAPLACIAN,equivalent_sigma_at_step). ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎Kaiming He, Jian Sun, and Xiaoou Tang, “Guided Image Filtering,” IEEE Transactions on Pattern Analysis and Machine Intelligence, 35(6), 1397-1409, 2013. DOI: 10.1109/TPAMI.2012.213 . Originally in ECCV 2010. ↩︎ ↩︎ ↩︎
Chuan Qin, Shuozhong Wang, and Xinpeng Zhang, “Simultaneous inpainting for image structure and texture using anisotropic heat transfer model,” Multimedia Tools and Applications, 56(3), 469-483, 2012. DOI: 10.1007/s11042-010-0601-4 . ↩︎ ↩︎ ↩︎
Y. Oono and S. Puri, “Computationally efficient modeling of ordering of quenched phases,” Physical Review Letters, 58(8), 836-839, 1987. DOI: 10.1103/PhysRevLett.58.836 . ↩︎ ↩︎
M. Patra and M. Karttunen, “Stencils with isotropic discretization error for differential operators,” Numerical Methods for Partial Differential Equations, 22(4), 936-953, 2006. DOI: 10.1002/num.20129 . ↩︎ ↩︎
Aurélien Pierre, “Rotation-invariant Laplacian for 2D grids,” 2021, which derives the 9-point stencil, the B-spline Gaussian-equivalent $\sigma_B$, and the difference-of-Gaussians to Laplacian normalization constant used as
B_SPLINE_TO_LAPLACIAN. URL . ↩︎ ↩︎ ↩︎ ↩︎Michael Unser, “Splines: A Perfect Fit for Signal and Image Processing,” IEEE Signal Processing Magazine, 16(6), 22-38, 1999. DOI: 10.1109/79.799930 . ↩︎
Holger Dammertz, Daniel Sewtz, Johannes Hanika, and Hendrik P.A. Lensch, “Edge-Avoiding À-Trous Wavelet Transform for fast Global Illumination Filtering,” Ulm University, ↩︎
The local-affine “color-line” prior — within a small patch, a surface’s colour channels are affinely related. Canonical sources: Ido Omer and Michael Werman, “Color Lines: Image Specific Color Representation,” CVPR 2004; and the matting Laplacian of Anat Levin, Dani Lischinski, and Yair Weiss, “A Closed-Form Solution to Natural Image Matting,” IEEE TPAMI 30(2), 228-242, 2008, DOI 10.1109/TPAMI.2007.1177 . The related “Colorization using Optimization” (SIGGRAPH 2004, DOI 10.1145/1015706.1015780 ) uses a softer intensity-affinity prior. ↩︎ ↩︎
The near-saturation nonlinearity of image sensors is standard characterization knowledge : J. R. Janesick, Photon Transfer: DN → λ, SPIE Press, 2007 (gain and noise are measured at the low-illumination end because linearity degrades approaching full well) ; the EMVA 1288 standard (European Machine Vision Association) restricts its linearity regression to 0–70 % of saturation for the same reason ; F. Wang and A. J. P. Theuwissen, “Linearity analysis of a CMOS image sensor,” Electronic Imaging, 2017, details the pixel-chain mechanisms (source-follower gain, voltage-dependent photodiode capacitance). URL . The magnitude of the bias on a given camera is measured from the image itself by the knee estimator ; see the figure in the knee section. ↩︎
Comment ce travail a réellement été mené
La méthode ci-dessus est indissociable de la façon dont elle a été produite, et la façon dont elle a été produite est partie d’un aveu. Les guided laplacians de 2021 furent la dernière méthode que j’ai livrée avant d’en coucher les mathématiques : codée à l’intuition, réglée à l’œil sur des images naturelles. Cela atteint un premier résultat rapidement et est aveugle à tout ce qui suit — vous ne pouvez pas étudier les propriétés ou les modes de défaillance d’une méthode que vous n’avez jamais exécutée que sur des données non contrôlées. Écrire cet article, pour poser enfin ces mathématiques, a imposé la discipline inverse : des scènes synthétiques à vérité terrain connue, des métriques d’erreur objectives, une hypothèse testée à la fois. Cette discipline a transformé un exercice de documentation en la reconstruction puis le changement de paradigme que les sections précédentes ont déjà racontés, chaque amélioration vérifiée plutôt que devinée.
La discipline a eu une conséquence de plus, qui mérite son propre récit : elle a changé qui pouvait mener le travail en toute sécurité. Un protocole dans lequel chaque candidat est mesuré face à la vérité terrain sur chaque cas, et dans lequel une régression sur toutes les métriques est un motif de rejet automatique, est précisément ce qui permet à un assistant d’explorer à la vitesse de la machine sans que l’humain perde le contrôle de la conception — les décisions d’acceptation/rejet restent humaines, le défrichage de l’espace des solutions non. Le récit ci-dessous, écrit par l’assistant en question, décrit à quoi ressemblait cette division du travail de l’intérieur.