Outils de base (didactiel 3/5)

Publié le par jö

Afin d'illuster mon propos, je vais déjà me munir d'une image dont j'ai bien vérifié les droits (en utilisation et en modification) dans la mesure où je cite le nom de son auteur. Il s'agit donc d'une image de madnzany que l'on peut se procurer ici sous la licence "By" de Creative Commons. Voici de quoi elle a l'air :
Il s'agit de la photo au format 500x375 pixels d'une pièce de mobilier orné d'un disque partagé en 13 secteurs correspondant à 13 des (1600?) Chevaliers de la Table Ronde : le roi Arthur à la base et, dans l'ordre anti-horaire Lancelot,Tristan, Bedwere, Gaheris, Gawain, Kay, Lamorak, Geraint, Gareth, Bors, Galahad et enfin Perceval.
Inétressons-nous justement au secteur attribué à ce dernier et au petit coeur qui orne son blason. Etant données les dimensions de l'image d'origine, on peut faire tenir ce coeur dans une boîte de 11x11 pixels et l'extraction de cette boîte peut se faire gràce au code Octave suivant qui conserve le codage img (liste de couleurs et matrice de positions) en fabriquant ainsi une petite image à part entière :

function [imcrop,mapcrop]=crop (im,map,x1,xn,y1,yn)
dimx = size(im)(2);
dimcropy = yn-y1+1;
xcrop=x1:xn;
ycrop=y1:yn;
imcrop=[];
for x=1:xn-x1+1
row=[];
for y=1:dimcropy,row=[row; dimcropy*(x-1)+y];end
imcrop=[imcrop,row];
end
domcrop=[];
for x = xcrop
for y = ycrop, domcrop=[domcrop,(y-1)*dimx+x]; end
end
mapcrop=[map(:,1)(domcrop),map(:,2)(domcrop),map(:,3)(domcrop)];

On l'utilise par exemple avec
[imcrop,mapcrop]=crop(im,map,225,235,215,225);
ce qui dans notre cas produit une image de 121 pixels que Gnuplot interprète ainsi :




Il semble raisonnable, d'après cette représentation, de concevoir que Gnuplot considère chaque pixel comme le centre d'un carré et, afin d'afficher la petite image, il se charge de remplir chaque carré de la couleur porté par son pixel.
Avant de poursuivre notre chemin vers le 'droste effect', il faut se demander si cette façon de procéder est souhaitable. Comme le principe du 'droste effect' repose sur un repliement de l'image sur elle-même, certaines zones vont se recroqueviller sur elles-mêmes tandis que d'autres vont au contraire s'étaler. Comme la couleur entre deux pixels initialement voisins est inconnue, quand ces deux pixels s'éloignent l'un de l'autre, on augmente la taille d'une zone remplie de pixels de couleurs tout autant inconnues et le problème de coloriage se complique. Remarquons que ce problème n'intervient que quand les couleurs des deux pixels en question sont différentes car, dans le cas contraire, il est raisonnable de considérer que tous les pixels intermédiaires auront la même couleur.
Ainsi, dans le cas général, on ne peut pas se satisfaire d'une représentation ccomme celle de Gnuplot, et on va mettre en oeuvre par interpolation un procédé de régularisation permettant d'approcher une meilleure continuité dans l'image.

Tout d'abord quelques fonctions auxiliaires :

function [a,b] = two (v)
a = v(1);
b = v(2);
function [a,b,c]=three (v)
a=v(1);
b=v(2);
c=v(3);
function d=distance2(x0,y0,x1,y1)
d= sqrt((x1-x0).^2+(y1-y0).^2);
function s=surface(x0,y0,x1,y1,x2,y2)
s=(x0.*(y1-y2)+x1.*(y2-y0)+x2.*(y0-y1))/2;

Une fonction récursive cherchant à partir d'une position approximative le carré qui contient le point considéré  :

function [i,j]=tweak(ii,jj,x,y,Dx,Dy)
if ii*Dx<=x
if x<=(ii+1)*Dx
if jj*Dy<=y
if y<=(jj+1)*Dy
i=ii;
j=jj;
else [i,j]=tweak(ii,jj+1,x,y,Dx,Dy);
end
else [i,j]=tweak(ii,jj-1,x,y,Dx,Dy);
end
else [i,j]=tweak(ii+1,jj,x,y,Dx,Dy);
end
else [i,j]=tweak(ii-1,jj,x,y,Dx,Dy);
end


puis une fonction principale pour régulariser une image aux taux donnés par mulx et muly :

function [imint,mapint]=regularize2(im, map,mulx,muly)
[dimy, dimx] = size(im);
[nx,ny]=two(round ([mulx*dimx, muly*dimy]));
[Dx,Dy]=two([1/(dimx-1),1/(dimy-1)]); % dom : [0,1]^2
[dx,dy]=two([1/(nx-1),1/(ny-1)]); % dom : [0,1]^2
mapint=zeros(nx*ny,3);
imint=[];
for xx=1:nx
row=[];
for yy=1:ny
idx = ny*(xx-1)+yy;
row=[row; idx];
x=(xx-1)*dx;
y=(yy-1)*dy;
ii=floor(x/Dx);
jj=floor(y/Dy);
[i,j]=tweak(ii,jj,x,y,Dx,Dy);
if i>dimx-2, i=dimx-2;end
if j>dimy-2, j=dimy-2;end
if distance2(x,y,i*Dx,(j+1)*Dy) < distance2(x,y,(i+1)*Dx,j*Dy)
[i0,i1,i2] = three([i,i+1,i]);
[j0,j1,j2] = three([j,j+1,j+1]);
else
[i0,i1,i2] = three([i,i+1,i+1]);
[j0,j1,j2] = three([j,j,j+1]);
end
v0=map(dimy*i0+j0+1,:);
v1=map(dimy*i1+j1+1,:);
v2=map(dimy*i2+j2+1,:);
x0=i0*Dx;x1=i1*Dx;x2=i2*Dx;
y0=j0*Dy;y1=j1*Dy;y2=j2*Dy;
s=[surface(x,y,x1,y1,x2,y2),surface(x0,y0,x,y,x2,y2),surface(x0,y0,x1,y1,x,y)];
mapint(idx,:) = (s(1)*v0+s(2)*v1+s(3)*v2)/(surface(x0,y0,x1,y1,x2,y2));
end
imint=[imint,row];
end

dont voici l'effet après avoir évalué
[imint,mapint]=regularize2(imcrop,mapcrop,8.0,8.0);




Publié dans mathblog

Commenter cet article