TP de "Documents Multimédia", 2014
Exercices du 12.12.2014

Traitement d'images en Javascript

Les exemples montrés ici jouent aussi le rôle de tutoriels. Les scripts commentés sont à votre disposition, suivez les techniques de codage et les consignes. Je fais presque tout le travail difficile pour vous, mais codez tout vous-même, changez les images, dimensions, transformations, et paramètres, afin de vous entraîner.

Les pages qui contiennent plusieurs scripts sont fragiles, car la portée des variables est globale, et il est facile de provoquer des conflits.

1. Travaux préliminaires.

Apprenez à afficher une image sur le canevas par un script. On peut charger une image dans HTML, par <img ...> mais avec le style display:none, et un id pour la référence. Les détails sont dans le cours, la rectification de la panorama cylindrique ; on utilise le script panorm.js.

Alternativement vous pourrez charger une image dans le canevas directement par le script.

var cnv = $("#monCan")[0];
var ctx = cnv.getContext("2d");
var imaj = new Image();
imaj.src = "Images/aj.jpg";
 
imaj.onload=function(){
 hh=imaj.height; ww=imaj.width;}
 
function go1(){
 cnv.width=ww; cnv.height=hh;
 ctx.drawImage(imaj, 0, 0);
} 
Le canevas "monCan"est ici
?!
Fin du canevas

Observez comment changer dynamiquement la taille du canevas, en l'adaptant au contenu ; ceci n'est possible qu'après le chargement d'image.

Chargez la carte équirectangulaire de la Terre ici, et affichez-la, mais rétrécisez-la par, disons, 4 ; la largeur d'origine est de 2048 pixels. Regardez le cours, et le script bunrot.js, et tournez aussi cette image. Le script montre comment tourner un objet autour d'un point quelconque (ici : centre).


2. Gérer les pixels.

En JS, comme en Java, les objets visuels "cachent" le contenu : une image "n'a pas" de pixels, elle contient un objet interne, ImageData, qui possède des dimensions et autres attributs, mais toujours pas de pixels...

Cet objet possède un champ .data, le tableau interne dont les éléments sont des pixels. Ce tableau est 1-dimensionnel, 1 pixel occupe 4 éléments, les composantes R, G, B et A (rouge, vert, bleu et opacité).

?! Je ne montrerai pas le script, vous le trouverez en lisant la source de ce document (en dessous de ce texte). La tâche est de créer l'image à droite comme une contrainte géométrique. Que les coordonnées "virtuelles" soient [-1 – +1], le canevas représente 4 carrés unité, le centre du système de coordonnées se trouve au milieu.

Le disque est spécifié par l'inégalité \(\sqrt{x^2+y^2}< 0.7\). L'intérieur est orange, l'extérieur bleu. Tout le travail géométrique consiste à mapper les indices entiers (ici entre 0 et 300) en nombres entre -1 et 1.

La solution pour l'image à droite se trouve dans le script. Essayez d'imaginer une contrainte mathématique permettant de peindre l'image à gauche.

(Hint : utilisez la fonction abs, une fonction périodique et le seuillage.)

Si vous n'arrivez pas à trouver la contrainte géométrique adéquate, faites d'autres expériences, avec d'autres formules, et montrez fièrement vos résultats. Par exemple, parametrez le rayon du disque par une variable modifiable de l'extérieur par un slider. L'important est d'obtenir un résultat !

Ceci est une des techniques standard de coder les textures dans les shaders 3D. Avec des fonctions bruit, on peut créer également des motifs aléatoires, ou déformer les autres.


Ceci est votre devoir obligatoire final. A rendre au moins une semaine avant le Jury (?).

Le Vrai, Grand Exercice : Projection cartographique azimuthale (ortho).

Ici vous aurez beaucoup de consignes géométriques, mais le codage est à vous. Cette projetion prend la carte équirectangulaire, et construit une image circulaire, la Terre vue du Cosmos, de loin (pas de perspective). L'image-source est la carte équi-rectangulaire mentionné ci-dessus. Vous savez comment récupérer les données pixel, et vous savez également comment créer et afficher une nouvelle image. Ce qui reste est la transformationmathématique ["inverse"] entre un carré contenant le disque rempli par l'image de la Terre, et l'équi-carte.

Voici la géométrie du problème. L'espace de projection de la sphère est un plan, comme dans le cas gnomonique, sauf que la projection n'est pas centrale ! Toutes les lignes de projection des points sur la sphère vers le plan image sont parallèles à \(\vec{V}_0\).

L'axe local \(\vec{y}\) est calculé comme en cours, comme vecteur perpendiculaire à \(\vec{V}_0\), et "proche" de l'axe Z global (le pôle nord).

Regardez les notes de cours pour quelques détails. Une partie des calculs se répète.

Le rapport de distances est : \(r=\sin(\theta)\), non pas la tangente.

On peut visualiser ainsi une demi-sphère sans singularités, pas d'"explosion" gnomonique. L'autre moitié de la sphère est simplement cachée. Ceci est assez naturel. Pour tout point \(\vec{V}\) sur la surface de la sphère, si l'angle entre \(\vec{V}\) et \(\vec{V}_0\) dépasse 90°, le point se trouve sur face cachée de la sphère.

Mais en travaillant avec la transformation inverse de l'image vers la sphère, nous aurons d'autres conditions à respecter (par ex \(r>1\), qui ne correspond à aucun point sur la surface).

L'image à droite montre le résultat ; j'ai corrigé (off-line) un peu le facteur gamma, afin de éclairer les zones très sombres. Ceci n'a pas trop d'importance, même si savoir comment effectuer la correction gamma sur le canevas, ou avec les images SVG peut s'avérer utile.

Répétons le raisonnement géométrique utile pour le redressage des panoramas sphériques équi. Sur le plan de projection nous avons les coordonnées \(x\) et \(y\). (Tout est "virtuel" ; la transposition en coordonnées pixel est triviale, et ici je n'ai pas envie de vous aider trop, sauf si vous avez des questions concrètes).

Le vecteur sur le plan image est \(\vec{r} = x \cdot \vec{x} + y \cdot \vec{y}\). Ce vecteur est par définition orthogonal à \(\vec{v}_0\).

Puisque on regarde la sphère de loin, toutes lignes de projection sont parallèles, colinéaires avec \(\vec{v}_0\), alors un vecteur déplacé perpendiculairement au plan : \(\vec{V} = \vec{r} + \alpha \vec{v}_0\) se trouve sur la sphère pour une valeur de \(\alpha\) précise.

Ce paramètre doit être tel, que \(|\vec{V}|=1\). Il doit être évident (une équation quadratique triviale à résoudre) que \(\alpha=\sqrt{1-r^2}\). La valeur négative de ce paramètre correspond justement à la face cachée.

Ayant \(\vec{v}\), nous calculons \((\lambda,\phi)\), trouvons les coordonnées pixel de l'image source, et transportons ce pixel.

L'image - résultat a été rendue avec la taille de 900 pixels, et ensuite mise en échelle, car je ne voulais pas alourdir le programme par l'interpolation des pixels. Mais dans un vrai projet professionnel, ceci serait envisageable, voire obligatoire.



Modalités de ce devoir



Retour