TP5: Insertion d'objets virtuels

- Création d'image HDR à partir d'image LDR (Image Based Lighting) -

par Olivier Duguay

GIF-4105/7105 Photographie Algorithmique, Hiver 2015

1-Objectifs du projet 2-Description des étapes de l'algorithme 3-Utilisation de logiciel de rendu (Blender) 4-Améliorations

1-Objectifs du projet

Résultat d'un rendu final
Résultat d'un rendu final
Dans le cadre de ce cinquième projet du cours de photographie algorithmique, il nous faut implémenter une application qui permet de créer une image HDR (High Dynamic Range) à partir d'images prises avec une caméra standard qui produit des photos dites LDR (Low Dynamic Range). En effet, en utilisant plusieurs images de la même scène, avec différentes expositions, il existe un moyen de construire une image de haute qualité. L'image HDR est une image dont la plage dynamique de valeurs de pixels est augmentée dans le but de bien définir l'intensité lumineuse de ceux-ci. Finalement en captant cette image HDR de façon panoramique (de sorte que l'on capte tous les rayons lumineux de la scène), il est possible de reconstruire l'information lumineuse de cette scène et ainsi pouvoir recréer les effets d'ombrages, de réflexion etc. à l'aide d'un logiciel de modélisation tel que Blender. Pour capter l'image panoramique, nous utiliserons ici une sphère métallique.

Pour plus de détails, voyez l'énoncé complet ICI !.

2-Description des étapes de l'algorithme

Étape 1 - Capturer la carte de radiance en haute plage dynamique

Tout d'abord, il faut capturer la carte de radiance en haute plage dynamique de la scène désirée. Pour ce faire, à l'aide d'une caméra standard (dont on peut modifier les temps d'exposition), il faut prendre plusieurs photos de la même scène, et ce pour différentes expositions. Plus la plage d'exposition sera grande et plus le nombre de photos exposées pendant des temps différents sera grand, meilleur le résultat sera. Pour de meilleurs résultats, il faut que les temps d'expositions maximal et minimal soit environ 4 fois plus grand que le taux d'exposition moyen (sur lequel on effectuera le rendu de la scène).

Exposition de 1/8s Exposition de 8s Image sans la balle métallique
Exposition de 1/8s Exposition de 8s Image sans balle (vide)


Afin de capter tous les rayons lumineux de la scène, on utilise un sphère métallique que l'on inclut dans la scène et qui fera en sorte de rediriger les rayons lumineux sur 360 degrés vers l'objectif de la caméra. Une fois les scènes prisent en photos, il suffit de prendre cette même scène, sans la boule métallique et il ne restera plus qu'à faire le redimensionnement des photos pour ne conserver que la balle métallique. Ces photos des différentes balles permettent donc de trouver l'image HDR et la scène vide servira d'arrière-plan pour notre scène.

Exposition de 1/8s Exposition de 1/2s Exposition de 1s Exposition de 2s Exposition de 4s Exposition de 8s
Exposition de 1/8s Exposition de 1/2s Exposition de 1s Exposition de 2s Exposition de 4s Exposition de 8s


Pour couper les images, un script MATLAB à été conçu :

drawRect.m

Celui-ci permet de sélectionner un rectangle dans une image et de faire une image avec cette sélection. Par la suite, si toutes les images ne sont pas de la même taille, un autre script à été conçu :

cutAll.m

qui permet de sélectionner une image et d'appliquer un redimensionnement pour toutes les images du même dossier (y compris l'image sélectionnée). Il faut dire que n'importe quel logiciel de traitement d'image, tel que le fameux PAINT de Windows, aurait pu être utilisé.

Étape 2 - Construction de la carte de radiance (image HDR)

Pour reconstruire l'image HDR, l'algorithme présenté dans le document de Paul Debevec et Jitendra Malik a été utilisé. D'abord, à l'aide de la fonction imfinfo.m et exifread.m il est aisé de déterminer le temps d'exposition (t) pour chacune des photos qui sera variable indispensable au calcul de la carte. Puis, il nous faut déterminer Z(i,j) qui est la valeur de chacun des pixels de l'emplacement (i) dans l'image (j). Cette valeur servira à calculer g(z) et lE(i) soit l'exposition soit l'exposition du pixel de valeur (z) et la radiance des pixels à l'emplacement (i). Ces valeurs seront déterminées à l'aide de la fonction fournie par Debevec :

[g, lE] = gsolve(Z,B,l,w) *Ne pas oubliez que ces valeurs sont souvent logarithmiques.

Avec Z(i,j) de déterminés, B(j) qui correspond au logarithme du temps d'exposition de l'image (j), le lambda (l) qui est un facteur qui détermine la quantité de paufinage de l'image, il ne reste plus qu'à déterminer (w) qui est la fonction de pondération de poids des pixels. Celle-ci permet de mettre l'emphase sur le paufinage de la courbe et de faire tendre les termes vers le milieu de la courbe g(z); on s'éloigne donc des cas de saturation, car les pixels de sous-exposés auront un faible poids et les pixels surexposés seront ignorés (valeur infini)). La fonction suivante implémente la contribution des pixels :

weight = double(128-abs([z]-128));

où z correspond à la plage de valeur que peut prendre le pixel. Il faut également moyenner le tout.

Finalement, il faut choisir judicieusement le facteur lambda afin d'avoir un bon rendu d'image. On peut savoir si son choix est bon en évaluant la courbe g(z). Celle-ci devrait être le plus lisse possible. Voici quelques résultats avec différentes valeurs de lambda. À noter que sa valeur est arbitraire et dépend beaucoup de la scène et surtout de la lumière. Le soleil est agréable sauf pour nos algorithmes !

Image HDR (lambda = 1) Image HDR (lambda = 100) Image HDR (lambda = 1000)
Image HDR (lambda = 1) Image HDR (lambda = 100) Image HDR résultante

Fonction g(z) (lambda = 1) Fonction g(z) (lambda = 100) Fonction g(z) (lambda = 1000)
Fonction g(z) (lambda = 1) Fonction g(z) (lambda = 100) Fonction g(z) (lambda = 1000)

Les 3 différentes couleurs de graphiques représente les différents canaux de couleurs de l'image (RGB).


Avec tous ces images, les valeurs d'expositions et de radiances des pixels, il est donc possible de créer l'image HDR en utilisant la fonction que nous avons programmé :

imgHDR = computeHDR(images, g, ln_t, w)

Cette fonction permet de passer au travers tous les pixels de de chacune des images pour y déterminer sont poids et sa contribution dans l'image HDR. Il faut prendre soin de bien calculer «g» pour chacun des canaux de couleurs de l'image individuellement et donc de faire le calcul des poids des pixels (création de l'image HDR) pour les 3 canaux et les fusionner par la suite. Ceci donne de meilleurs résultats. Ne pas oublier de gérer les cas de «sur et sous» saturation (soit des valeurs Nan ou Inf dans MATLAB). De plus il est nécessaire de faire la résolution de g(z) que pour un échantillon de pixels sinon la résolution va être très longue et risque d'entraîner un manque de mémoire de l'ordinateur. Pour ce faire dans le script d'exécution, un rééchantillonnement de l'image à été fait selon un nombre de lignes et de colonnes. On réduit l'image en quelques sorte.

Étape 3 - Transformation panoramique

Avec l'image HDR de la sphère métallique, il est possible d'intégrer celle-ci dans un projet de modélisation afin de recréer la lumière de la scène. Cependant, il faut utiliser une des transformations suivantes :

Projection
Type de projection de lumière

Bien que l'image de la sphère pourrait être utilisé, la fonction suivante à été implémenté pour faire la conversion de l'image de la sphère vers un domaine équirectangle :

latlon = ball2LatLong(imageHDR)

L'algorithme va comme suit; on calcule d'abord les points de la sphère en coordonnées cartésienne (x,y) puis on détermine la valeur de notre valeur en «z» à l'aide de la formule x2+y2+z2 = r. On se retrouve donc avec notre système d'équation cartésien en 3d (x,y,z). En déterminant pour chaque points, une normale N(x,y,z) et un vecteur de direction d'orientation V = (-1,0,0) qui est donc constant, on peut calculé les vecteurs de réflexion à l'aide de l'équation suivante :

R = V - 2 .* dot(V,N) .* N

On s'assure ainsi de prendre qu'un rayon de 1 dans notre image et donc on élimine les pixels non essentiel à la création de l'image dans la domaine équirectangle tel que les coins qui sont en effet le fond de la scène. Puis il faut déterminer les phis(φ) = atan(y/z) et theta(θ) = acos(y/x). On à donc tous les vecteurs pour construire l'image. Il faut par la suite utiliser la fonction suivante pour créer une image vide, de dimension 2X plus large qui permettera d'accueillir les pixels de l'image de la sphère métallique dans le format cartésien :

[phis, thetas] = meshgrid([pi:pi/360:2*pi -pi/2:pi/360:pi/2], 0:pi/360:pi)

Finalement, on fait l'interpolation d'un domaine à l'autre et on écrit l'image HDR équirectangle à l'aide des fonctions suivantes :

scatteredInterpolant((φ),(θ),valeur du pixel)

latlon = hdrwrite(latlon, 'latlon.hdr')

3-Utilisation de logiciel de rendu (Blender)

Étape 1 - Modélisation de la scène et rendu d'images (ajout de plans et d'objets)

Pour modéliser la scène à l'aide de Blender, il faut d'abord y insérer l'image de la scène (arrière-plan ou encore «background»). Et y ajouter une vue (caméra de sorte que celle-ci est orientée avec l'axe +z en haut et l'axe +x vers l'avant afin que la luminosité à base d'image soit correcte puisque nous utilisons cette technique pour effectuer/recréer l'éclairage de la scène.

Image d'arrière-plan
Image d'arrière-plan

Puis, il faut ajouter l'image HDR (équirectangle ou angulaire) dans le logiciel afin de reproduire la luminosité lors de la prise de la photo. Par la suite, il faut déterminer un plan dans l'image où l'on désire ajouter des objets. De préférence, ce plan devrait être non loin de l'endroit où se situait la sphère métallique lors de la prise de photos afin de bien reproduire les effets de luminosité. Il faut également appliquer une couleur diffuse et d'une couleur non-loin de la couleur du plan correspondant dans l'image de la scène ce qui sera utile lors du rendu final.

Ainsi dans la scène précédente, le plan suivant à été déterminé :

Image du plan
Image du plan


Par la suite, il est possible d'ajouter des objets sur le plan précédement déterminé. Chaque objet peut possèder sa propre texture, être fait en «pièces détachées» et très détaillées etc. Les possibilitées sont énormes mais pour se simplifier la vie, il existe le site www.turbosquid.com où l'on peut avoir accès à des tonnes de modèles 3D et leurs textures.

Voici donc le plan avec des objets qui y ont été apposés :

Image avec objets
Image du plan (avec objets)


Cependant afin d'effectuer un meilleur rendu finale, qui conservera d'avantage de détails d'ombrages lors de la composition, il est primordial de déterminer un masque des objets qui diffère de la scène. Pour ce faire, il faut mettre tout en blanc, les objets de la scène, et tout de noir le reste de l'image.

Le rendu donne ceci :

Masque des objets
Image du masque (objets VS scène)


Étape 2 - Composition des images

La finalisation de l'image rendue finale est composée à partir des différentes images obtenues à l'étape précédente, soit, une image du plan, une image du plan avec les objets et le masque des objets. La technique employée se nomme rendu différentiel qui peut être facilement résolue à l'aide de l'équation suivante :

composite = M.*R + (1-M).*I + (1-M).*(R-E).*c

où M est l'image du masque, R est le rendu de l'image AVEC les objets, E est le rendu d'image SANS les objets et I est l'image d'arrière-plan. Pour ce qui est du facteur «c» celui-ci détermine une certaine quantité d'effets d'illumination provenant des objets et du plan. Si celui-ci est trop élevé, des effets indésirables apparaîtront au final. Ce paramètre doit être ajusté selon la prise de photo comme on peut le constater avec les photos suivantes :

Rendu final Rendu final (trop d'effet d'illumination)
Image rendu finale Surplus d'effet d'illumination

4-Améliorations


1- Il faut s'assurer de bien positionner la caméra dans le logiciel Blender afin de bien modéliser l'illumination de la scène.

2- L'utilisation d'une meilleure caméra permettant des temps d'exposition beaucoup plus courts et un peu plus long aurait été préférable.

3- Avoir une boule propre et exempt d'égratignures donnerait de meilleurs résultats car c'est la source de toute notre illumination.

4- Éviter d'avoir comme source de lumière, un soleil «tappant» directement sur la sphère métallique.

5- Utiliser un autre type de transformation pour l'image de l'illumination

6- Prendre 2 photos à 180 degrés de la sphère pour «effacer» la possible réflexion du photographe

7- Utiliser un reproduction tonale locale pour constituer l'image de haute plage dynamique

8- ETC :P !