Un modèle aléatoire pour le grain photographique
Pista negra El 4 agosto 2020 Ver los comentarios (1)
De nos jours, de nombreux photographes et réalisateurs considèrent toujours que la photographie numérique n’a pas le charme de la pellicule argentique, et cherchent à traiter leurs images pour retrouver, entre autres, l’aspect granuleux de la pellicule traditionnelle. Dans cet article, nous allons voir comment un modèle aléatoire tout simple permet d’imiter le rendu du grain sur des images numériques, et comment on peut le simuler numériquement.
L’apparition de la photographie numérique avant le tournant du millénaire a changé la manière dont on prend, gère, stocke, transmet et «consomme» des images. Malgré les nombreux avantages du format numérique, des photographes et réalisateurs continuent à préférer la pellicule argentique, pour des raisons artistiques. Ainsi, Quentin Tarantino n’hésite pas à déclarer lors du festival de Cannes 2014 que «la projection digitale... est la mort du cinéma tel que je le connais» [Smi14].
La figure suivante, due à Rob Taylor-Case, représente les différentes couches d’une pellicule argentique.
Cette pellicule a une spécificité : elle contient du grain, une texture créée par les agrégats (amas) de particules photosensibles qui la constituent. A l’échelle microscopique, le négatif analogique peut donc être représenté comme une image en noir et blanc (sans niveau de gris) : soit une particule est présente et la lumière est bloquée, soit il n’y a pas de particule et la lumière passe. Ces particules ou cristaux sont microscopiques, ils font quelques micromètres ($10^{-6}m$), les humains ne peuvent donc pas les percevoir en regardant une photographie ou un négatif : ce que nous voyons, ce sont des moyennes locales de cette densité de grains.
Imiter le grain. Des logiciels dédiés aux photographes (Dxo FilmPack par exemple) proposent de reproduire la texture de grain des images argentiques sur des images numériques. Pour cela, ils scannent des négatifs d’images argentiques, et tentent d’appliquer la texture de grain obtenue sur des images numériques. Les résultats sont donc déterministes, dans le sens où si le grain est appliqué deux fois sur la même image, nous obtiendrons le même résultat. Ce manque d’aléa est un défaut lorsqu’on veut appliquer ce type d’approche à des vidéos. De plus, la qualité du résultat dépend directement de la qualité du scan de l’image de grain.
Dans cet article, nous allons voir que l’effet du grain sur une image peut être reproduit simplement grâce à un modèle aléatoire, appelé modèle booléen [1].
Le processus photographique
Le processus photographique argentique est divisé en deux étapes. Lors de la prise de vue, les cristaux photosensibles de la pellicule sont exposés à la lumière, et leur interaction avec les photons les rend «développables». Lors du développement photographique, ces cristaux ayant interagi avec la lumière sont transformés en grains d’argent solides. Le résultat est le négatif photographique, qui est à nouveau exposé à la lumière et développé en «positif» sur du papier photosensible. Une illustration est proposée ci-dessus : à gauche la scène, à droite le négatif et au milieu le positif. Le zoom en bas à droite des images correspond à la zone près de l’oeil encadrée en rouge.
Un moyen de modéliser le processus photographique mathématiquement est de considérer que les grains sont des ensembles fermés et bornés du plan. Le négatif serait donc une image constituée d’un fond blanc sur lequel on aurait jeté ces ensembles noirs.
Le modèle booléen homogène
Pour définir un modèle booléen homogène du plan $\mathbb{R}^2$, il faut d’abord définir ce qu’on appelle un processus ponctuel de Poisson homogène d’intensité $\lambda$ [2] du plan. C’est un ensemble aléatoire de points du plan $\{x_1,x_2,x_3\dots\}$, qui vérifie les deux propriétés suivantes :
- le nombre de points qui tombent dans une région $A$ d’aire $|A|$ suit une loi de Poisson [3] de paramètre $\lambda \times |A|$,
- les nombres de points tombant dans des ensembles disjoints du plan sont indépendants.
Les points $x_i$ représentent les centres de nos grains. On choisit un rayon $r$ positif, et on définit alors notre modèle booléen comme l’ensemble aléatoire
$Z = B(x_1) \cup B(x_2) \cup B(x_3) \cup \dots$
où $B(x)$ est un disque de rayon $r$ centré en $x$. On utilise ici des disques pour simplifier mais on pourrait les remplacer par des ensembles aléatoires plus généraux.
Cet ensemble $Z$ est aléatoire (dépend du hasard) car les positions des points $x_i$ le sont. Visuellement, on peut se le représenter comme un ensemble de disques blancs jetés aléatoirement sur un fond noir, comme ci-dessous.
On peut montrer que la proportion de la surface du plan recouverte par les disques blancs vaut
$1 - e^{-\lambda \pi r^2}.$
Plus le rayon des disques est grand et plus l’intensité $\lambda$ est
élevée, plus cette proportion est proche de $1$.
Le bloc replié ci-dessous propose une explication de cette formule, sa lecture demande des notions un peu plus avancées que le reste de l’article.
Ce modèle booléen est utilisé pour représenter le grain à l’échelle microscopique. On peut déjà noter qu’une particularité de ce modèle est sa tendance à créer un effet visuel d’amas de grains, très important pour le réalisme de reproduction du grain argentique. Ce modèle est également assez facile à simuler numériquement à l’aide d’un ordinateur.
Comment utiliser le modèle booléen pour imiter le grain argentique sur une image ?
Une image numérique en niveau de gris est une matrice dont chaque entrée représente un pixel et contient une valeur de gris, généralement entre $0$ et $255$ (pour une image codée sur 8 bits), comme illustré ci-dessous.
Une image couleur n’est rien d’autre que 3 images en niveau de gris, correspondant aux canaux vert, rouge et bleu.
Normalisation.
Supposons que l’on observe une image numérique en niveau de gris et qu’on souhaite en créer une version avec du grain. On commence par normaliser l’image : on divise toutes ses valeurs par une valeur légèrement supérieure à $M$, où $M$ est le niveau de gris maximum apparaissant dans l’image. On peut alors décrire l’image par l’ensemble de ses pixels $u(0,0),\dots,u(m-1,n-1)$ si l’image possède $m$ lignes et $n$ colonnes. Chaque valeur est un nombre entre $0$ et $1$. On exclut la valeur 1 car elle ne sera pas physiquement réalisable par notre modèle booléen : il faudrait en effet une infinité de grains pour être certain qu’ils couvrent tout le plan.
Un modèle booléen homogène par morceaux.
Pour simuler un «négatif argentique» de notre image numérique $u$, on simule un modèle booléen $Z$ sur le rectangle $[0,m)\times [0,n)$ [4], le rectangle de sommets $(0,0)$, $(n,0)$, $(m,n)$ et $(0,m)$. Ce sous ensemble est divisé en carrés : le carré $[k,k+1)\times[j,j+1)$ correspond au «pixel» $(k,j)$ de l’image $u$.
On remplit chacun de ces carrés selon un modèle booléen homogène (avec un rayon $r$ beaucoup plus petit que $1$, par exemple $0.05$) dont on choisit l’intensité afin d’obtenir la bonne moyenne, définie par $u(k,j)$ sur le
carré $(k,j)$, c’est-à-dire de sommets $(k,j)$, $(k+1,j)$, $(k+1,j+1)$ et
$(k,j+1)$ [5]. On obtient ainsi
une image définie en chaque point du rectangle et non plus carré
par carré.
On montre ci-dessous une figure montrant la réalisation d’un tel modèle booléen pour une image à 4 pixels.
Filtrer l’image positive.
Une réalisation de ce modèle booléen nous donne une image binaire, c’est-à-dire composée uniquement de noir et de blanc, qui vaut $1$ sur l’ensemble $Z$ et $0$ partout ailleurs. Mathématiquement, on la note $\mathbf{1}_Z$ et on l’appelle l’indicatrice de l’ensemble $Z$. Elle est définie partout sur l’ensemble $[0,m)\times [0,n)$. On peut la voir comme notre positif argentique (le négatif serait $1 - \mathbf{1}_Z$).
Une étape importante du processus photographique n’a pas encore été modélisée : l’étape dite d’exposition pendant laquelle le négatif est projeté sur du papier photosensible. Lors de cette étape, le film négatif est illuminé et la lumière passe à travers un objectif agrandisseur qui la projette sur le papier. Le passage de la lumière à travers cet objectif introduit un flou dans l’image projetée : chaque point du négatif illuminé devient une petite tache symétrique sur le papier. On parle de filtrage optique.
Mathématiquement, ce filtrage optique s’écrit comme une opération dite de convolution, notée $*$ ici, entre notre image $\mathbf{1}_Z$ et un filtre $\psi$. Le résultat $\psi * \mathbf{1}_Z$ est une image définie partout sur $[0,m)\times [0,n)$ et qui n’est plus une image binaire (elle prend des valeurs de gris).
Discrétisation.
Pour obtenir une image finale sous forme numérique, notre image continue $\psi * \mathbf{1}_Z$ définie sur $[0,m)\times [0,n)$ doit ensuite être discrétisée sur une grille. Cette grille n’a pas nécessairement à être la même que celle de l’image $u$ de départ. Par exemple, elle peut être deux fois plus fine : à chaque pixel de l’image d’entrée correspondront quatre pixels dans l’image de sortie. On obtient ainsi une image de sortie de résolution (nombre de lignes et nombre de colonnes) différente de celle de l’image de départ.
Algorithme et rendu
Tout cela est bien joli, mais comment fait-on en pratique pour implémenter ce qui précède sur un ordinateur ? On décrit ci-dessous un algorithme permettant ce rendu et nous allons voir que certaines étapes demandent un peu d’astuce.
Comme nous venons de le faire remarquer, si l’on part d’une image numérique d’entrée de taille $m \times n$, rien ne nous oblige à ce que l’image de sortie de l’algorithme soit de même taille. On suppose dans ce qui suit que cette image de sortie est de taille $ms \times ns$, avec $s$ un facteur de zoom entre l’image d’entrée et l’image de sortie. Par exemple $s=2$ donnera une image de sortie avec deux fois plus de lignes et deux fois plus de colonnes, et $s=1$ donnera une image de même taille.
Pour faciliter la lecture, l’algorithme que nous allons décrire est illustré par le schéma ci-dessous.
1. Calcul des intensités du modèle booléen.
Le début est simple. On rappelle que notre processus de Poisson a une intensité constante sur chaque carré $[k,k+1)\times[j,j+1)$. Pour le carré correspondant au pixel $(k,j)$ de $u$, on calcule donc l’intensité $\lambda(k,j)$ du processus de Poisson de manière à ce que la moyenne du modèle booléen sur ce carré soit égale à $u(k,j)$ [6].
2. Échantillonnage des grains.
On simule ensuite les centres des boules de notre modèle booléen sur chaque pixel. Pour simuler notre processus ponctuel sur le pixel $(k,j)$, on tire d’abord le nombre $p$ de points du processus, selon une loi de Poisson de paramètre $\lambda(k,j)$, puis on tire avec une loi uniforme $p$ points dans le carré $[k,k+1)\times[j,j+1)$. La réalisation de l’ensemble de ces processus peut être stockée sous la forme d’une liste de points $\{x_i\}_{i\in I}$ sur la surface $[0,m)\times [0,n)$, qui représentent les centres des grains de notre modèle $Z$.
3. Evaluation du modèle filtré.
La troisième étape consiste à calculer numériquement la convolution $\psi * \mathbf{1}_Z$ en tout point de notre image de sortie, c’est-à-dire pour chaque centre d’un pixel sur la grille de sortie de taille $ms \times ns$. Le filtre $\psi$ choisi ici est une gaussienne de moyenne nulle et de variance $\sigma^2$. Cette étape est délicate : potentiellement, notre modèle booléen $Z$ peut contenir plusieurs milliards de disques, donc calculer la convolution $\psi * \mathbf{1}_Z$ peut s’avèrer très compliqué numériquement.
Pour rendre les calculs envisageables, une solution consiste à approcher la convolution $\psi * \mathbf{1}_Z$ par simulation de Monte Carlo.
La méthode de Monte Carlo est une méthode numérique pour approcher une intégrale (ici le produit de convolution) à partir d’une somme. Nous pouvons en donner une interprétation intuitive pour notre application. Comme expliqué plus haut, le filtrage optique se traduit par le fait que chaque pixel illuminé de l’image $\mathbf{1}_Z$ a pour image une tache dans l’image projetée. L’intensité de cette tache peut être vue comme une densité de probabilité sur le plan, et est égale à notre filtre $\psi$. La méthode de Monte-Carlo consiste à réinterpréter ce flou en termes probabilistes, un peu comme si on suivait les photons un à un lors de l’étape d’exposition et que les photons étaient décalés de la position $x$ d’un pixel blanc en un point $x-v$, où la déviation $v$ suit la loi de densité de probabilité $\psi$. L’intensité moyenne observée en un point donné $x$ de l’image finale $\psi * \mathbf{1}_Z$ sera la moyenne des valeurs de l’image $\mathbf{1}_Z$ en $x-v$, où $v$ suit toujours cette même loi $\psi$. Or, cette moyenne peut se calculer en tirant des déplacements
aléatoires $v_1, v_2, v_3,....$ de loi $\psi$, et en prenant la moyenne
$(\mathbf{1}_Z(x-v_1)+\mathbf{1}_Z(x-v_2)+...+\mathbf{1}_Z(x-v_N))/N$ pour $N$ grand. C’est une conséquence de la loi des grands nombres. On doit en pratique faire ça pour tous les points $x$ de notre nouvelle grille de taille $ms \times ns$.
On peut voir une illustration de cette approche dans l’image suivante.
Le bloc suivant donne une explication un peu plus poussée mathématiquement de la méthode de Monte Carlo.
On décrit plus précisément dans le bloc suivant l’algorithme tel qu’il est implémenté en pratique.
Quelques résultats
Visualisons maintenant quelques résultats de rendu de cet algorithme. Nous partons d’images argentiques qui ont été numérisées, et pour lesquelles le grain a été perdu à la numérisation. L’utilisateur peut régler les paramètres de l’approche afin d’avoir un grain d’aspect qui lui convient : un grain plus ou moins fin, avec plus ou moins d’amas. La taille de grain peut par exemple varier entre 0.02 pixels (très fin) et 0.1 pixels (assez épais).
Ci-dessous, nous montrons deux exemples de rendus à plusieurs échelles de zoom, de plus en plus fines (la valeur de $s$ est de plus en plus grande). L’encadré rouge correspond à la zone de l’image que l’on visualise à l’échelle suivante. A l’échelle la plus fine, on peut clairement voir les grains et l’image binaire sous-jacente.
L’algorithme permet de réaliser le rendu à n’importe quelle échelle, donc pour n’importe quelle taille de tirage de sortie. Ce point est très important, car on peut souhaiter faire un tirage de très grande taille.
Remarquons qu’on ne pourrait pas modéliser le grain avec un simple bruit indépendant et identiquement distribué (du bruit blanc) sur les pixels. Dans l’image suivante, divisée en deux parties, on a ajouté du bruit blanc en bas à gauche, alors qu’en haut à droite on a simulé du grain avec l’algorithme décrit ci-dessus.
On voit que le bruit blanc ne permet pas de retrouver les effets d’«amas» de grains.
Observons maintenant le rendu du grain sur une image d’entrée compressée. On part de l’image ci-dessous
Dans cette image d’entrée, les blocs de compression sont clairement visibles, notamment au voisinage de la main. On utilise alors notre simulateur de grain pour créer une nouvelle image. Nous avons l’impression subjective que la qualité et résolution de l’image ont été améliorées. Cette propriété est liée à une technique appelée dithering (ou détramage en français), qui consiste à ajouter du bruit à un signal avant de le quantifier pour éviter de voir apparaître des défauts de quantification.
Comparaison avec d’autres approches
Il existe d’autres méthodes de synthèse de grain de film argentique, et celles-ci sont souvent des méthodes dite «par l’exemple» : elles imitent des pellicules spécifiques. Dans ce type d’approche, on commence par scanner une photographie argentique d’une zone constante, prise avec la pellicule que l’on souhaite imiter, puis on calque cette image scannée sur une l’image numérique à laquelle on veut ajouter du grain. Cette étape de calque n’est pas une simple combinaison linéaire mais c’est une étape déterministe. Il n’y a donc aucune modélisation aléatoire ou générative du grain dans ce type de méthode. Ces approches ont l’avantage d’être simples à utiliser une fois que la photo du grain est obtenue, et par conséquent assez rapides.
Cependant, elles sont limitées par la qualité et la résolution de l’exemple. Notamment, elles ne permettent pas de dépasser la résolution de l’image de grain numérisée, ce qui est problématique si l’on souhaite ajouter du grain à une image ou une vidéo de résolution supérieure. Par ailleurs, ces méthodes ne peuvent pas inventer du grain, elle ne font que recopier le grain scanné. C’est un problème lorsqu’on souhaite les utiliser sur des vidéos, où il faut appliquer des images de grain différentes aux images successives du film.
Dans l’exemple ci-dessous, nous comparons le rendu de l’outil commercial DxO FilmPack (en haut à droite) avec celui de notre approche par modèle booléen (en bas à gauche).
Les paramètres de notre modèle sont choisis afin d’imiter le résultat de FilmPack. On voit que les résultats sont visuellement très similaires. En terme de temps d’exécution, l’outil de FilmPack prend environ une seconde pour une image haute résolution ($2048\times2048$). La méthode aléatoire présentée dans cet article nécessite beaucoup plus de calculs, mais les temps de calculs restent raisonnables avec du matériel adéquat et une programmation sur carte graphique. Voici quelques exemples de temps d’exécution sur un ordinateur équipé d’une GPU Nvidia Tesla T10, et pour plusieurs tailles d’images :
Résolution | 256x256 | 512x512 | 1024x1024 | 2048x2048 |
Temps d’exécution | 0.137 s | 0.429 s | 1.275 s | 4.534 s |
Pour finir cette présentation, on peut se demander comment appliquer du grain à des images couleur. Un film argentique couleur consiste en plusieurs couches d’émulsion, chacune séparée par un filtre qui permet une interaction avec une seule couleur. Ainsi, on peut faire l’hypothèse que les couches sont indépendantes, et appliquer notre algorithme séparément à chaque canal couleur ! On illustre ci-dessous le résultat de synthèse sur deux images.
Si vous voulez aller plus loin et tester le rendu argentique sur vos propres photographies, vous pouvez vous rendre sur ce site, dans l’onglet démo !
Références.
[Newson17CGF] Alasdair Newson, Julie Delon, Bruno Galerne, A Stochastic Film Grain Model for Resolution-Independent Rendering, Comput. Graph. Forum36(8): 684-699 (2017)
[Newson17ipol] Alasdair Newson, Noura Faraj, Bruno Galerne, Julie Delon, Realistic Film Grain Rendering. IPOL Journal 7: 165-183 (2017)
[Smi14] S MITH N. M.: Quentin Tarantino Blasts Digital Projection at Cannes: ’It’s the death of cinema.’, May 2014.
Nous remercions Clotilde Fermanian, Angela Gammella-Mathieu et Jérôme Buzzi pour leurs relectures attentives et leurs commentaires constructifs !
Notas
[1] George Boole (1815-1864) est un mathématicien anglais, en grande partie autodidacte, et l’un des fondateurs de la logique moderne. Il a également beaucoup contribué à la théorie des probabilités.
[2] la lettre grecque $\lambda$ désigne ici un nombre réel.
[3] Une variable aléatoire $X$ suit loi de Poisson de paramètre $\lambda$ si elle ne prend que des valeurs entières et que $\mathbb{P}[X = k ] = \frac{\lambda ^k }{k ! } e^{-\lambda k}$ pour tout entier naturel $k$.
[4] La notation $[a,b)$ désigne l’intervalle des réels entre $a$ (compris) et $b$ (exclu).
[5] Pour cela, l’intensité du processus ponctuel sur le carré $[k,k+1)\times[j,j+1)$ est définie par
$\lambda(k,j) =\frac{1}{\pi r^2}\log \left( \frac 1 {1 - u(k,j)}\right)$,
où $u(k,j)$ est la valeur de l’image discrète de départ sur le pixel $(k,j)$ et $r$ est le rayon des disques du modèle booléen.
[6] Idem note [2].
Comparte este artículo
Para citar este artículo:
Julie Delon, Alasdair Newson — «Un modèle aléatoire pour le grain photographique» — Images des Mathématiques, CNRS, 2020
Comentario sobre el artículo
Un modèle aléatoire pour le grain photographique
le 12 de noviembre de 2020 à 11:17, par Nathanael