DÉFORMER UNE IMAGE AUX DIMENSIONS D'UN QUADRANGLE QUELCONQUE

blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013 - 8 oct. 2008 à 21:41
cs_barbichette Messages postés 220 Date d'inscription lundi 30 octobre 2000 Statut Membre Dernière intervention 15 juillet 2013 - 13 oct. 2008 à 11:30
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/48145-deformer-une-image-aux-dimensions-d-un-quadrangle-quelconque

cs_barbichette Messages postés 220 Date d'inscription lundi 30 octobre 2000 Statut Membre Dernière intervention 15 juillet 2013
13 oct. 2008 à 11:30
ah, juste un point, j'avais pas regardé en détail...
Dans ce genre de transformation, il vaut mieux faire les calculs à l'envers.
Parcourir tous les pixels de l'image finale et regarder où il est dans l'image initiale.
ainsi, on est sur qu'il n'y a pas de trou et c'est avec ce calcul qu'on utilise mon interpolation.
Je vais essayer de retrouver l'algo en inversant les calculs.
cs_barbichette Messages postés 220 Date d'inscription lundi 30 octobre 2000 Statut Membre Dernière intervention 15 juillet 2013
13 oct. 2008 à 11:10
histoire de mettre mon grain de sel. J'avais fait la même chose, mais avec des calculs en réel et non dans les entiers.
Ainsi, quand tu cherche le pixel de l'image de départ, tu peux "facilement" faire une interpolation des couleurs, surtout si on étire l'image.
Sinon, c'est bien foutu..
barbichette
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
9 oct. 2008 à 20:59
@Spatul:

j'avais coché "verification des limite" dans un autre programme et l'avais conservé..
cela dit, tu devrais définir les deux paramètres du tableau à deux demensions.
SetLength(TSLFinal, BmpFinal.Height);

sinon ça marche, quelques soucis de saturation et d'aliasing..
original 8/10.

bon courage
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
9 oct. 2008 à 19:00
Ah excusez-moi j'avais pas vidé le cache, mes messages n'étaient pas apparents.

Cordialement, Bacterius !
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
9 oct. 2008 à 19:00
Pourquoi tous mes messages sont supprimés ? D'abord sur l'horloge binaire, maintenant ici ?

Est-ce moi qui bug ?

Cordialement, Bacterius !
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
9 oct. 2008 à 18:15
Et plus que quatre points ?
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
9 oct. 2008 à 17:52
Pas mal !
Un petit peu d'anti-aliasing sur les bords et c'est nikel !
D'ailleurs ça serait particulièrement simple vu que tu connais les côtés à lisser ... Un petit flou léger sur les bords :)

Cordialement, Bacterius !
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
9 oct. 2008 à 17:49
Pour le recto verso : 2 TBitmap qui sont dessinés l'un derriere l'autre !

Pour le transparent : en 24 bits, il suffit d'utiliser une transparent color avec une constant que tu définis...Je suis sur Embarcadero (newsgroup) pour la définir...

DH
Spatul Messages postés 12 Date d'inscription mercredi 21 août 2002 Statut Membre Dernière intervention 9 octobre 2008
9 oct. 2008 à 17:01
Merci CIREC, j'ai mis à jour la source d'après tes conseils d'optimisation (je n'avais pas pensé à regrouper les calculs redondants).
Je serai intéressé par le 32bits, ça me permettrai de dessiner l'image déformé en mode "transparent". en ce qui concerne les pointeurs à la place des tableaux, il faudrait que je me penche un peu plus dessus :-)
Utilisateur anonyme
9 oct. 2008 à 16:19
ben non ... voici la suite ^^

j'ai modifié le code pour éviter des calcules répétitifs et inutiles:

function Distorsion(AQuadrangle:TQuadrangle; ABitmap:TBitmap; BkColor:TColor):TBitmap;
var
TabScanLine, TSLFinal : array of pRVBArray;
BmpOrigin : TBitmap;
BmpFinal : TBitmap;
v, u, x, y, xd, yd : integer;
RQWidth, RQHeight : integer;
TauxY, TauxX : real;
DistAB, DistDC, PosXAB, PosXDC, TmpX : real;
DistAD, DistBC, PosYAD, PosYBC, TmpY : real;
begin

//--calcul de la zone rectangle (rectangle maitre) contenant le quadrangle
Ox := min(min(AQuadrangle.A.X,AQuadrangle.B.X),min(AQuadrangle.C.X,AQuadrangle.D.X));
Oy := min(min(AQuadrangle.A.Y,AQuadrangle.B.Y),min(AQuadrangle.C.Y,AQuadrangle.D.Y));
Fx := max(max(AQuadrangle.A.X,AQuadrangle.B.X),max(AQuadrangle.C.X,AQuadrangle.D.X));
Fy := max(max(AQuadrangle.A.Y,AQuadrangle.B.Y),max(AQuadrangle.C.Y,AQuadrangle.D.Y));
RQWidth := Fx-Ox;
RQHeight := Fy-Oy;

//--création d'une copie du bitmap d'origine
BmpOrigin := TBitmap.Create;
BmpOrigin.HandleType := bmDIB;
BmpOrigin.PixelFormat := pf24Bit;
BmpOrigin.Height := RQHeight;
BmpOrigin.Width := RQWidth;

//--création du bitmap final qui sera transféré à "result"
BmpFinal := TBitmap.Create;
BmpFinal.HandleType := bmDIB;
BmpFinal.PixelFormat := pf24Bit;
BmpFinal.Height := RQHeight;
BmpFinal.Width := RQWidth;
BmpFinal.Canvas.Brush.Color := BkColor;
BmpFinal.Canvas.FillRect(rect(0,0,RQWidth,RQHeight));

//--mise à l'échelle du bitmap d'origine par rapport au rectangle maitre
BmpOrigin.Canvas.StretchDraw(rect(0,0,RQWidth,RQHeight),ABitmap);

//--définir la taille des tableaux dynamiques
SetLength(TabScanLine,BmpOrigin.Height);
SetLength(TSLFinal,BmpFinal.Height);

// transférer les données (pixels) dans chaque tableau
For v:=0 to RQHeight-1 do
begin
// transférer les information de l'image dans les tableaux
TabScanLine[v] := BmpOrigin.ScanLine[v];
TSLFinal[v] := BmpFinal.ScanLine[v];
end;

//--Transférer les pixels au bon endroit
DistAD := AQuadrangle.D.Y-AQuadrangle.A.Y;
DistBC := AQuadrangle.C.Y-AQuadrangle.B.Y;

DistAB := AQuadrangle.B.X-AQuadrangle.A.X;
DistDC := AQuadrangle.C.X-AQuadrangle.D.X;
{Pour chaque pixel, calcule le taux de positionnement de x et y}
For v:=1 to BmpOrigin.Height-1 do
begin
TauxY := v / BmpOrigin.Height;
PosYAD := AQuadrangle.A.Y-OY+(DistAD*TauxY);
PosYBC := AQuadrangle.B.Y-OY+(DistBC*TauxY);

For u := 1 to BmpOrigin.Width-1 do
begin
TauxX := u / BmpOrigin.Width;
PosXAB := AQuadrangle.A.X-OX+(DistAB*TauxX);
PosXDC := AQuadrangle.D.X-OX+(DistDC*TauxX);

TmpX := PosXAB+(PosXDC-PosXAB)*TauxY;
TmpY := PosYAD+(PosYBC-PosYAD)*TauxX;

x := round(Int(TmpX));
y := Round(Int(TmpY));

xd := Round(Frac(TmpX));
yd := Round(Frac(TmpY));

{transfère les pixels au bon emplacement}
TSLFinal[y,x] := TabScanLine[v,u];

//pour lever les "trous..."
if (xd>0) and (x0) and (y<BmpOrigin.Height-2) then
TSLFinal[y+1,x] := TabScanLine[v,u];
end;
end;

//--assigne le bitmap final au "result"
result := TBitmap.create;
Result.Assign(bmpFinal);
bmpFinal.Free;
BmpOrigin.free;
end;

mais on peut faire mieux en utilisant des pointeurs à la place des tableaux et en passant en 32bits
Spatul Messages postés 12 Date d'inscription mercredi 21 août 2002 Statut Membre Dernière intervention 9 octobre 2008
9 oct. 2008 à 16:15
Bonjour,

A quelle ligne de code et dans quelles conditions apparait l'erreur d'étendue ?

Pour un recto/verso ? Retourner l'image ?
Utilisateur anonyme
9 oct. 2008 à 15:47
Salut,

le redu est bon mais le code pour y arriver peut et même doit être modifier dans un souci de rapidité mais surtout pour éviter de grosses fuites de mémoire ce qui est malheureusement le cas pour l'instant.

Tu as choisi, dans ta fonction, de créer, en guise de paramètre de sortie, un Bitmap que tu ne libères jamais !!!

Donc chaque appel à "Distorsion" crée un Bitmap qui reste en mémoire à la fin du programme.

pour éviter ces fuites il faut modifier comme suit:
{déformation & rendu de l'image}
procedure TForm1.Render;
var aBMP: TBitmap;
begin
...
// deformation //
aBMP := Distorsion(Quadrangle,Image,clWhite);
try
RenderBuffer.Canvas.Draw(OX,OY, aBMP);
finally
aBMP.Free;
end;
...
end;

Rapidement:
comme tu ne changes pas les valeurs RGB des pixels il n'est pas utile de les affecter individuellement

{transfère les pixels au bon emplacement}
TSLFinal[y,x].rgbtRed := TabScanLine[v,u].rgbtRed;
TSLFinal[y,x].rgbtGreen := TabScanLine[v,u].rgbtGreen;
TSLFinal[y,x].rgbtBlue := TabScanLine[v,u].rgbtBlue;

peut être remplacer par:
{transfère les pixels au bon emplacement}
TSLFinal[y,x] := TabScanLine[v,u];

c'est valable aussi pour les deux suivants:
if (x0) then
TSLFinal[y,x+1] := TabScanLine[v,u];
et
if (y0) then
TSLFinal[y+1,x] := TabScanLine[v,u];

j'en reste là pour l'instant ;)
Spatul Messages postés 12 Date d'inscription mercredi 21 août 2002 Statut Membre Dernière intervention 9 octobre 2008
9 oct. 2008 à 11:41
BLUEPERFECT : pour un recto/verso ? si c'est juste pour inverser/retourner l'image, on peut le faire comme ça :

// Mirroir vertical ou horizontal du bitmap
procedure Flip(ABmp:TBitmap; Sens:TSensFlip);
begin
if Sens=fVertical then ABmp.Canvas.StretchDraw(Rect(0,ABmp.height-1,ABmp.width,-1),ABmp);
if Sens=fHorizontal then ABmp.Canvas.StretchDraw(Rect(ABmp.width-1,0,-1,ABmp.Height),ABmp);
end;

CANTADOR : Je vais vérifier l'erreur. Ça se déclenche dans quelles conditions ?

SIMONPELLOQUIN : Je vais rajouter cette option dans la prochaine mise à jour du source.

Merci à vous en tout cas !
sp40 Messages postés 1276 Date d'inscription mardi 28 octobre 2003 Statut Contributeur Dernière intervention 3 juillet 2015 15
9 oct. 2008 à 09:47
Salut,

Vraiment pas mal du tout... Si tu pouvais juste ajouter de quoi charger et enregistrer une image transformée, ça serait tip-top !

Simon
cs_cantador Messages postés 4720 Date d'inscription dimanche 26 février 2006 Statut Modérateur Dernière intervention 31 juillet 2021 13
9 oct. 2008 à 09:46
Bonjour,

un petit souci sur :

SetLength(TSLFinal, BmpFinal.Height);
et
TSLFinal[y, x].rgbtRed := TabScanLine[v, u].rgbtRed;

->> erreur d'étendue..
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
8 oct. 2008 à 22:47
Au fait, tu ferais comment pour un recto/verso ?
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
8 oct. 2008 à 21:41
Splendeurs....

DH