Ombrage, Rendu et Description d`Image

Transcription

Ombrage, Rendu et Description d`Image
Analyse et Synthèse d'Images
pour l'Interaction Homme Machine
James L. Crowley
DEA ISC
1999/00
Séance 6 :
16 novembre 1999
Plan de la Séance :
Ombrage, Rendu et Description d’Image
La Rendu de Formes en Maille.......................... 2
Rappel de l’Algorithme fillPoly2d() ......................................2
L'algorithme de Z-Buffer ................................. 4
Affichage des polygones en profondeur .................................6
Interpolation de la profondeur sur une arête...........................7
Calcul de l'intensité d'une surface ......................10
Cas simple : Ombrage constant sur un polygone.................... 10
Méthode de Gouraud.......................................................... 11
Estimation de la normale à des vertices................................ 11
Interpolation de l'intensité sur une arête............................... 12
Ombrage par Interpolation de Normales (Méthode de Phong).15
Description d’Image......................................17
Sources de contraste :......................................................... 18
Segmentation par seuillage.................................................. 19
Comment Choisir le seuil ?................................................. 20
Segmentation par les statistiques de la couleur ...................... 21
Application de la Règle de Bayes......................................... 22
Ombrage, Rendu et Description d’Image
Séance 6
La Rendu de Formes en Maille
Les techniques de la rendu des surfaces s’appui sur des variations de l’algorithme
de remplissage de polygone.
Rappel de l’Algorithme fillPoly2d()
Le remplissage d’une polygone peut-être fait en deux étape :
1) composer une liste triée de colones d'intersection pour chaque ligne de l'image.
Chaque paire de colones sur chaque ligne est un trait.
2) Tracer les très en appliquant une interpolation.
Encodage en trait :
y0
y1
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
x
6-2
Ombrage, Rendu et Description d’Image
Séance 6
Le Pseudo-code pour fillPoly2d()
fillPoly2D(Poly2D P)
{
double x;
int y;
Atom * List[P.Ny];
/* tableau de traits, une liste per ligne
Atom * L1, * L2;
/* pour traiter les listes */
*/
for (n=0; n<=P.Nsegs; n++)
if (P.Seg[n].y1 ==
/* pour chaque segment du polygone */
P.seg[n].y2)
/* cas special des aretes horizontal
*/
{
insertSort(x1, List[y1]);
/* le arete est un trait */
insertSort(x2, List[y1]);
/*
les
sommets
sont
les
limites
de
le
trait */
} else
/* cas de aretes non-horizontales */
for (y=P.Seg[n].ymin; y< P.seg[n].ymax; y++)
{
/* Pour chaque ligne
*/
/* du rectangle englobant de l'arete
*/
x = P.Seg[n].m * y
+
insertSort(x, List[y]);
P.Seg[n].c ;
/* calculer le colone et */
/*
inserer
le
colone
au
liste */
}
/* end for() */
/*affichage des traits */
for (k=0; k< P.Ny; k++)
/* pour chaque ligne du rectangle englobante
*/
L1 = List[k].next;
while (L1 != Null)
{
L2 = L1.next;
/* draw un trait sur le ligne y = k+P.Seg[n].ymin */
drawTrait(L1.x, L2.x, k+P.Seg[n].ymin, Gray);
L1 = L2.next;
}
}
Un premier exemple est fourni par l’algorithme de Z- Buffer
6-3
Ombrage, Rendu et Description d’Image
Séance 6
L'algorithme de Z-Buffer
Problème : Eliminer l’affichage des surfaces cachés par d’autre surfaces.
Ceci est fait après un “back-face cull” (vu la semaine dernière).
⇒
Principe :
On créait une deuxième image, dans lequel on marque la valeur de "z" pour
chaque pixel affiché. On n'affiche pas des pixels si leur z est derrière le pixel de jas
affiché.
Par exemple - pour chaque colonne :
ymin
ymax
image Z Buffer (2 ou 4 octets per pixel)
6-4
Ombrage, Rendu et Description d’Image
Séance 6
Nous prendrons la convention .
z = MaxZ; Profondeur maximale.
z = 0; plane de la rétine.
Attention : dans certaines réalisations du z-buffer, la plane le plus profonde est
notée comme z=0, avec z > 0 en approche de la caméra.
L'affichage est géré par insertZ();
void insertZ(int x; int y; int
z; int
color;)
{
if (z
<
ZBuf[x][y] ) then /* if z is in front of current valeur de ZBuf
*/
{
ZBuf[x][y] = z;
/* then enter new value */
drawPixel(x, y, color)
return true;
} else return false;
}
void zBufferInit(void)
{
iamge * Zbuf = newByteImage(Xmax, Ymax);
int x, y;
for (y=0; y < Ymax; y++)
for (x=0; x < Xmax; x++)
Zbuf[x][y] = MaxZ;
return Zbuf;
}
Calculation de z pour un polygone exprimé en repère Caméra
Ax + By + Cz + D = 0
⇒
z=
–D – Ax – By
C
formule incrémentale :
Si à (x, y), z = calculZ(x, y)
alors à (x+∆x,y)
A
z2 = z – C (∆x)
6-5
Ombrage, Rendu et Description d’Image
Séance 6
Affichage des polygones en profondeur
Pour un polygone 3D, il faut calculer la profondeur (z) de chaque point
afin de l'entrer dans un z buffer. Ceci peut-être fait à partir d'une interpolation
linéaire des profondeurs des sommets.
x1, z1
x
x1 F
z
F
x2, z2
z
x2 F
z
Supposons que nous avons un polygone 3D composé d'une liste de sommets 3D
en repère caméra.
S3D =
xc
yc .
zc 
1 
S2D =
 xcF/zc
 y F/z  à la distance z.
 c c
 1 
La projection sur l'image se fait par division par F/z.
xr
xc
=
F
zc
⇒ xr = xc zFc
Lors de la projection, on associe la distance zc à chaque sommet 2D (xr, y r).
Pour l'affichage, on fait une interpolation linéaire sur les arêtes et les traits.
6-6
Ombrage, Rendu et Description d’Image
Séance 6
Interpolation de la profondeur sur une arête
Lors de l'affichage, on fait un rasterisation pour chaque segment.
z2
z
z
z1
y1
y
y
y2
La rasterisation utilise une interpolation linéaire en x. Au même temps,
on fait une interpolation linéaire en z.
z1 : profondeur au sommet S1.
z2 : profondeur au sommet S2
z2–z1
mz : Change profondeur per ligne : mz = y –y
2 1
cz : interception de l'intensité : cz = z 1 – mz . y 1
Ensuite pour chaque ligne, y , de l'arête z = m z y + cz.
Seg: int x1, y1, x2, y2;
double m, c;
/* les sommets 2D du segment */
/ pente et intercept du segment */
int xmin, ymin, xmax, ymax ;
double z1, z2, mz, cz.;
/* rectangle englobant du segment */
/* parametres de l'interpolation en z */
Atom:
double x;
double z;
Atom * next;
6-7
Ombrage, Rendu et Description d’Image
Séance 6
L'algorithme d'interpolation est une extension de l'algorithme de fillPoly();
fillPolyZ(Poly2D P)
{
double x, z;
int y;
Atom * List[P.Seg[n].Ny];
for (n=0; n<=P.Nsegs; n++)
if (P.Seg[n].y1 ==
/* pour chaque segment du polygone */
P.seg[n].y2)
/* cas special des segment horizontal
*/
{
/* le segment est un trait */
insertSort(P.Seg[n].x1, P.Seg[n].z1, List[P.Seg[n].y1]);
insertSort(P.Seg[n].x2, P.Seg[n].z2, List[P.Seg[n].y1]);
} else
/* cas des autre segments */
for (y=P.Seg[n].ymin; y< P.seg[n].ymax; y++)
/* Pour chaque ligne du seg
*/
{
x = P.Seg[n].m * y
z =
+
P.Seg[n].c ;
P.Seg[n].mz * y + P.Seg[n].cz;
insertSort(x, z, List[y]);
/* calculer le colone et */
/* calculer la profondeur */
/* Inserer le colone au liste */
}
for (k=0; k< P.Ny; k++)
/* pour chaque ligne du rectangle englobante
*/
L1 = List[k].next;
while (L1 != Null)
{
L2 = L1.next;
/* draw un trait sur le ligne y = k+P.Seg[n].ymin */
drawZTrait(L1.x, L1.z, L2.x, L2.z, k+P.Seg[n].ymin, gray);
L1 = L2.next;
}
}
6-8
Ombrage, Rendu et Description d’Image
Séance 6
Pour afficher le trait, il faut une interpolation entre les profondeurs.
/* affichage d'un trait sur une ligne */
drawZTrait (double x1; double z1; double
x2; double
z2; int y; int gray)
{
int z;
double mz= (z2–z1)/(x2–x1);
/* pente de l'intensité */
double cz = z1–mz*x1;
/* intercept de l'intensité */
int c1 = floor(x1) + 1;
/* round up colone 1 */
int c2 = floor(x2);
/* round down colone 2 */
for (x=c1; x<=c2; x++)
{
z = round( i*mz+z1);
insertZ(x, y, z, gray);
}
}
6-9
Ombrage, Rendu et Description d’Image
Séance 6
Calcul de l'intensité d'une surface
Rappel : Pour la reflectance Lambertian :
Lumiere
Camèra
N
V
e
→
Pour une surface lambertienne :
N
L
i
. L→
= Cos(i).
Cas simple : Ombrage constant sur un polygone.
Pour un maillage de polygones 3D, il est tres simple de calculer un ombrage.
Le cosinus entre la normale de la surface et une source de la lumière.
Ceci repose sur les hypothèses que :
→
1) la source est à l'infini. N
. L→
→
est constant.
→
2) l'observateur est à l'infini : N . V est constant.
3) Le polygone est le veritable surface.
L'intérêt est qu'on calcule une seule couleur pour le remplissage de chaque
polygone.
L'inconvénient est qu'il y a des discontinuités à chaque arête.
Ces discontinuités sont amplifiées par une illusion visuelle : L'effet de Mach.
On peut éliminer ces discontinuités par une interpolation de l'ombrage.
6 - 10
Ombrage, Rendu et Description d’Image
Séance 6
Méthode de Gouraud
La méthode de Gouraud consiste à interpoler l'ombrage sur chaque trait d'un
polygone par un calcul différentiel. Il s'agit d'une approximation permettant
d'éliminer les discontinuités d'ombrage aux arêtes.
Estimation de la normale à des vertices
L'algorithme de Gouraud détermine une intensité aux sommets
en utilisant les normales et une réflexion Lambertienne.
Il fait une interpolation de l'intensité sur les arêtes. Les intensités calculées sur
les arêtes sont utilisées afin de faire une interpolation sur les traits.
L'algorithme de Gouraud demande des valeurs des normales aux sommets de
chaque polygone. Cependant, les sommets et les arêtes sont des discontinuités en
normale! il n'y a pas de valeurs stables.
Gouraud propose une approximation par un normale "moyenne" calculer avec
les normales des faces qui incluent le sommet.
1 K-1 →
N s= K ∑ N k
k=0
→
A partir de la normale de chaque sommet, on calcule une intensité par réflexion
Lambertienne.
→
→
g = ρL( N s . L )
On projet les sommets (3D) du polygone 3D vers l'image, afin d'obtenir des
sommets 2D d'un polygone 2D.
On obtient ainsi un polygone 2-D composé de N sommets 2-D.
A chaque sommet, on associe sa "z" et son intensité, g. z et g sont ensuite
interpolé sur l’arêtes et les traits.
6 - 11
Ombrage, Rendu et Description d’Image
Séance 6
Interpolation de l'intensité sur une arête
Pour l'affichage, on fait un rasterisation pour chaque ligne du rectangle englobant.
g2
g
g
g1
y1
y
y
y2
Pour ceci il faut ajouter des paramètres d'intensité et de pente et interception
aux segments du polygone 2D :
g1 :
g2 :
Intensité au sommet S1.
Intensité au sommet S2
g2–g1
Change d'intensité par ligne : mg = y –y
2 1
Interception de l'intensité : cg = g 1 – mg y 1
mg :
cg :
Ensuite pour chaque ligne, y , de l'arête gy = mg y + cg.
Seg: int x1, y1, x2, y2;
double m, c;
/* les sommets 2D du segment */
/ pente et intercept du segment */
int xmin, ymin, xmax, ymax ;
double g1, g2, mg, cg;
/*
/* rectangle englobant du segment */
parametres
pour
l'interpolation
de
l'intensité */
On ajoute l'intensité aux traits, afin de faire une interpolation :
6 - 12
Ombrage, Rendu et Description d’Image
Séance 6
L'algorithme de Gouraud est une extension de l'algorithme de fillPoly()
semblable à l'interpolation en profondeur.
Atom:
double x;
double z;
int g;
Atom * next;
fillGouraud(Poly2D P)
{
double x, z;
int g, y;
for (n=0; n<=P.Nsegs; n++)
if (P.Seg[n].y1 ==
/* pour chaque segment du polygone */
P.seg[n].y2)
/* cas special des segment horizontal
*/
{
/* le segment est un trait */
insertSort(P.Seg[n].x1, P.Seg[n].z1, P.Seg[n].g1, List[P.Seg[n].y1]);
insertSort(P.Seg[n].x2, P.Seg[n].z2, P.Seg[n].g1, List[P.Seg[n].y1]);
} else
/* cas des autre segments */
for (y=P.Seg[n].ymin; y< P.seg[n].ymax; y++)
/* Pour chaque ligne du seg
*/
{
x = P.Seg[n].m * y
+
P.Seg[n].c ;
/* calculer le colone et */
z =
P.Seg[n].mz * y + P.Seg[n].cz;
/* calculer la profondeur */
g =
(int) P.Seg[n].mg * y + P.Seg[n].cg;
/* calculer la intensité
*/
insertSort(x, z, g, List[y]);
/*
Inserer
le
colone
au
liste */
}
for (k=0; k< P.Ny; k++)
/* pour chaque ligne du rectangle englobante
*/
L1 = List[k].next;
while (L1 != Null)
{
L2 = L1.next;
/* draw un trait sur le ligne y = k+P.Seg[n].ymin */
drawZTrait(L1.x, L1.z, L1.g,
L2.x, L2.z, L1.g,
k+P.Seg[n].ymin);
L1 = L2.next;
}
}
6 - 13
Ombrage, Rendu et Description d’Image
Séance 6
Pour afficher le trait, il faut une interpolation entre les intensités.
drawZTrait (double x1; double z1; double g1; double
x2; double z2; double
g2;
int y;)
{
int g;
int z;
double mz= (z2–z1)/(x2–x1);
double cz = z1–mz*x1;
double mg= (g2–g1)/(x2–x1);
double cg = g1–mg*x1;
/* pente de l'intensité */
/* intercept de l'intensité */
/* pente de l'intensité */
/* intercept de l'intensité */
int i1 = floor(x1) + 1;
/* round up x1 */
int i2 = floor(x2);
/* round down x2 */
for (i=i1; i<=i2; i++)
{
g = round ( i*mg+g1);
z = round( i*mz+z1);
insertZ(x, y, z, g);
}
}
Intérêt de l'ombrage par interpolation : Rapidité
Problème avec l'ombrage par interpolation :
1) approximation "grossière".
2) Ne permettent pas de calculer les reflets.
6 - 14
Ombrage, Rendu et Description d’Image
Séance 6
Ombrage par Interpolation de Normales (Méthode de Phong).
La méthode de Phong remplace l'interpolation de l'intensité par l'interpolation
des normales du polygone. L'intensité est calculée pour chaque pixel à partir
de sa normale, N.
Comme avec Gouraud, on estime une normale "moyenne" pour chacun
sommet 3D.
K
→
N s=
∑
→
N k
k=0
Pour chaque sommet 2D du POly2D, on associe sa normale :
Seg: int x1, y1, x2, y2;
double m, c;
/* les sommets 2D du segment */
/ pente et intercept du segment */
int xmin, ymin, xmax, ymax ;
/* rectangle englobant du segment */
double a1, b1, c1;
/* normale du sommet s1 */
double a2, b2, c2;
/* normale du sommet s1 */
double ma, mb, mc;
double ca, cb, cc;
/*pente du normal
sur le segment */
/*intercepte du normal
sur le segment */
En effet, il s'agit d'une interpolation linéaire sur A, B, et C en fonction de y.
pente :
a2–a1
ma = y –y
2 1
intercepte :
ca = a 1 – ma y 1
b2–b1
mb = y –y
2 1
cb = b 1 – mb y 1
c2–c1
mc = y –y
2 1
cc = c 1 – mc y 1
6 - 15
Ombrage, Rendu et Description d’Image
Séance 6
Le reste de l'algorithme est la même. On ajoute les paramètres, A, B, C
aux éléments des traits :
élément :
X, A, B, C.
Puis insertSort est
insertSort(x, a, b, c, List[y]);
Puis en drawTrait, on a
drawZTrait(List[k].x, List[k].z, List[k].a,
List[k].b, List[k].c,
List[k+1].x, List[k].z, List[k+1].a,
List[k+1].b, List[k+1].c,
y);
drawZTrait (
double x1; double a1; double b1; double b1;
double
x2; double a2; double b2; double b2; int y;)
{
int a, b, c, z;
double mz= (z2–z1)/(x2–x1);
double cz = z1–mz*x1;
/* pente de l'intensité */
/* intercept de l'intensité */
double ma= (a2–a1)/(x2–x1);
/* pente de A */
double mb= (b2–b1)/(x2–x1);
/* pente de B */
double mc= (c2–c1)/(x2–x1);
/* pente de C */
double ca = a1–ma*x1;
/* intercept de A */
double cb = b1–mb*x1;
/* intercept de B */
double cc = c1–mc*x1;
/* intercept de C */
int c1 = floor(x1) + 1;
/* round up colone 1 */
int c2 = floor(x2);
/* round down colone 2 */
for (x=c1; x<=c2; x++)
{
a =
i*ma+a1;
b = i*mb+b1;
c = i*mc+c1;
z = round( i*mz+z1);
insertZ(x, y, z, a, b, c);
}
}
6 - 16
Ombrage, Rendu et Description d’Image
Séance 6
Description d’Image
Rôle des Indices d'image en Vision
Description
Symbolique
Description
Géometrique
Indices Invariants
(monde extérieure)
La description du monde extérieur est basée sur les "Invariants"
Les "phénomènes" observables restent stables quels que soient le point de vue et la
luminosité ambiante.
La première phase d'un processus de vision est l'extraction des "Indices"
Les Indices d'image servent à :
1) Réduire la quantité d'informations (coût mémoire, calcul et communication)
2) Simplifier l'interprétation
Le système visuel humain de perçoit mal l’intensité absolue d’une image.
Une image uniforme grise resemble une image uniforme blanche.
Ceci est dû au fait que l’intensité absolue varie selon l’éclairage.
(Ce n’est pas un “invariant”.)
Le système visuel humaine perçoit les structures de changement en intensité.
Ce changement s’appelle le contraste.
6 - 17
Ombrage, Rendu et Description d’Image
Séance 6
Sources de contraste :
Les contours de contraste sont supposés êtres stables par rapport au point de vue
et à l'éclairage. En effet, les sources de contraste dans une image sont :
1) Changement d'orientation d'une surface (Discontinuité en profondeur)
2) Bordure d'un ombrage
3) Marquage d'une surface (ex: écriture sur une feuille)
4) Reflets
Le premier est utile pour les objets polyédriques.
Le deuxième peut indiquer la forme 3D si on sait l'interpréter.
Le troisième ne dépend pas de la forme, mais peut fournir une texture
Le quatrième dépend du point de vue et de l'éclairage.
6 - 18
Ombrage, Rendu et Description d’Image
Séance 6
Segmentation par seuillage
Segmentation : Le découpage d’une image en région élémentaire.
Les régions sont supposées de correspond aux objets d’intérêt.
Les algorithmes de segmentation recherche les régions uniformes.
La technique la plus simple de segmentation est de comparer les pixels à un seuil.
Considère la ligne J, de l'image g(i, j).
niveau
de Gris
255
Seuil
0
512 Colonne
0
On remplace chaque pixel par une valeur binaire

b(i, j) := 

niveau
de Gris
1
si g(i, j) ≥ Seuil
0
Sinon
255
Seuil
0
0
512 Colonne
La bordure donne les zones de contraste. pres on peut appliquer
un codage en traits aux lignes.
Segmentation par seuillage est bien adaptée aux problèmes de l’analyse d’images 2D
tel qu’images de satellite et certaines images médicales ou le signal est constant.
6 - 19
Ombrage, Rendu et Description d’Image
Séance 6
Il est très mal adapté à la vision des objet 3-D dans un environment naturel.
Comment Choisir le seuil ?
Le seuil peut être déterminé à partir d’un histogramme.
En théorie, les modes de l’histogramme correspondent aux régions.
Les seuils sont à placer dans les vallées.
Nombre
des
Pixels
0
255
0
Niveau
de gris
Seuil
Pratique :
ou
1) choisir le seuil "interactivement"
2) Calculer une image de probabilité
6 - 20
Ombrage, Rendu et Description d’Image
Séance 6
Segmentation par les statistiques de la couleur
Un histogramme de couleur peut fournir une densité de probabilité afin de trouver
les pixels qui sont les images d'un objet, par exemple, la peau humaine.
La Luminance, L=R+V+B décrit la forme 3D d'une surface.
On peut simplifier l'histogramme par une normalisation de la luminance.
Pour chaque pixel P(i,j) = [R, V, B], on normalise par la luminance :
R
r = R+V+B
V
v = R+V+B
Calcul d’un histogramme des valeurs h(r, v).
On alloue un tableau 2D de taille Nh (exemple 32 x 32 = 1024 cellules : h(r, v). )
r(i, j)
Pour chaque pixel C = c(i, j) = v(i, j)  , on incrémente la cellule de l'histogramme
qui correspond à (r, v)
h(r, v) := h(r, v) +1
Un histogramme des couleurs, h(C), de N pixels donne une approximation de la
probabilité de chaque couleur
p(C) =
1
Lim { N
N→ ∞
h(C)}
Un histogramme des de couleurs, htot(C), de les Ntot pixels dans une l'image donne
une approximation de la probabilité de chaque couleur dans l'image.
1
p(C) ≈ N
tot
htot(C)
Un histogramme des de couleurs d’un objet , ho(C), de les No pixels dans une
région d'une image de l'objet, w(i, j), donne une approximation de la probabilité
de chaque couleur de l'objet .
1
p(C | objet ) ≈ N
o
ho(C)
6 - 21
Ombrage, Rendu et Description d’Image
Séance 6
Application de la Règle de Bayes.
L histogramme permet d'utiliser la règle de Bayes afin de calculer
la probabilité qu'un pixel corresponde à un objet.
p(objet)
p(objet | C) = p( C | objet ) p(C)
Soit M images de N pixels. Ceci fait Ntot Pixels.
Soit htot(r, v), l'histogramme de tous les Ntot pixels.
Soit ho(r, v), l'histogramme des No pixels de l'objet "o".
No
p(objet) = N
tot
1
p(C) = N
htot(r, v)
tot
1
p(C | objet ) = N
ho(C)
o
Donc
p(objet)
p(objet | C) = p( C | objet ) p(C)
No
N tot
1
= N ho(C) 1
o
Ntot h tot(C)
ho(C)
p(objet | C) = h (C)
tot
Cependant, il faut assurer que htot(C) ≠ 0 !!
Pour cela il faut que Ntot >> N h (nombre de cellules de l'histogramme.).
Ainsi, on peut créer une image de probabilité de l'objet.
En peut ensuite déterminer un seuil pour l’image de probabilité.
Image d’un visage
Image de probabilités de
la peau
Image binaire des
probabilités après seuillage
6 - 22

Documents pareils