Gyors képfeldolgozás

Gyors képfeldolgozás
2014-07-02T23:20:31+02:00
2014-08-07T14:26:15+02:00
2022-12-01T11:00:38+01:00
ricsi28
Sziasztok! 
Írtam egy függvényt ami egy Bitmapot képes elforgatni megadott szögben. Kis méretű (200x200) képeknél nagyon gyors, tehát akár a kurzor mozgásához is lehetne igazítani a forgatás mértékét. Mondjuk egy olyan 800x800-as képet is elég gyorsan elforgat, ha nem folytonosan forgatom a képet, akkor észre sem venni, hogy dolgozott rajta a gép. Viszont nagyon nagy méretű képeknél egy  3000x1600-asnál kb 1mp-be tellik.  
De ennek ellenére is elég büszke voltam a munkámra :), de gondoltam megnézem mások, hogy oldották meg ezt a problémát, és ekkor találtam a RotateImage komponenst, rögtön ki is próbáltam és igen, ez akár egy nagyon nagy méretű képet is képes gyorsan elforgatni. Mondanom se kell rögtön belenéztem a programkódba, hogy hogyan működik, de a  rengeteg változó, a számomra ismeretlen függvények és az shr/shl bit eltolós parancsok olyan bonyolulttá tették, hogy nem tudtam kiolvasni a gyorsaságának okát.
Valaki esetleg nem tudja hogyan működik az a komponens, és hol bukik el az én módszerem?
Az én függvényem a következőképpen néz ki:

Működési elve:
1. Létrehoz egy tömböt, amibe Scanline módszerrel beleteszi a kép Pixeleit
2. Létrehoz egy üres Bitmapot az eredeti képet tartalmazó Bitmap méreteivel
3. Scanline módszerrel végig futja az új Bitmap összes pixelét
   -És itt jön egy számítás, hogy az új kép aktuális pixele, melyik pixellel lesz egyenlő a régi képről 
4. Majd a legvégén az új Bitmap képét belemásolja a régibe

procedure Rotate(Bitmap:TBitmap; Degree:Single); overload; begin Rotate(Bitmap,Degree,Bitmap.Width div 2,Bitmap.Height div 2); end; procedure Rotate(Bitmap:TBitmap; Degree:Single; RotateX,RotateY:Integer); overload; var X,Y:Word; NewX,NewY:Integer; Angle,Hypotenusa,NewDegree:Single; bmp:TBitmap; bmpRow:PRGBTripleArray; Row: array of PRGBTripleArray; begin SetLength(Row,Bitmap.Height); for Y:=0 to Bitmap.Height-1 do Row[Y]:=Bitmap.ScanLine[Y]; bmp:=TBitmap.Create; try bmp.Width:=Bitmap.Width; bmp.Height:=Bitmap.Height; bmp.PixelFormat:=pf24bit; for Y:=0 to bmp.Height-1 do begin bmpRow:=bmp.ScanLine[Y]; for X:=0 to bmp.Width-1 do begin Hypotenusa:=Hypot(X-RotateX,Y-RotateY); //Átfogó kiszámítása if Hypotenusa>0 then begin Angle:=ArcSin((Y-RotateY)/Hypotenusa)/PI*180; //Szög kiszámítás: Szemközti oldal / Átfogó (szögfüggvény) if X>RotateX then NewDegree:=Angle-Degree else NewDegree:=180-Angle-Degree; NewX:=RotateX+Round(Hypotenusa*cos(NewDegree*PI/180)); NewY:=RotateY+Round(Hypotenusa*sin(NewDegree*PI/180)); if (NewX>=0) and (NewX<=bmp.Width-1) and (NewY>=0) and (NewY<=bmp.Height-1) then bmpRow[X]:=Row[NewY,NewX]; end else bmpRow[X]:=Row[Y,X]; end; end; Bitmap.Canvas.Draw(0,0,bmp); finally bmp.Free; end; end;
Mutasd a teljes hozzászólást!
Szerintem a sok szorzással, osztással, szögfüggvény számítással rontod el.

Meglehet csinálni ezt "egyszerűbben" is.
Mellékelek egy ábrát, ha sikerül, ami segít elmagyarázni.

Tehát az elforgatandó kép a bal oldali.
Abból ki kell számolni, hogy az adott elforgatással hová fognak kerülni az A, B és C pontok, amik a kép sarokpontjai.

Ha megvannak ezek a koordináták, akkor két vektort kell gyártani.
Az egyik az A pontból a B pontba (V1 vektor) mutasson, a másik az A pontból a C pontba (V2 vektor).
Ezt nem is olyan nehéz

V1.X = (B.X - A.X) / képszélesség V1.Y = (B.Y - A.Y) / képszélesség V2.X = (C.X - A.X) / képmagasság V2.X = (C.Y - A.Y) / képmagasság
Ezek után a két for ciklus valahogy így kell kinéznie.

for Y:=0 to bmp.Height-1 do begin bmpRow:=bmp.ScanLine[Y]; sor.X = A.X; sor.Y = A.Y; for X:=0 to bmp.Width-1 do begin NewX := Round(Sor.X); NewY := Round(Sor.Y); if (NewX>=0) and (NewX<=bmp.Width-1) and (NewY>=0) and (NewY<=bmp.Height-1) then bmpRow[X]:=Row[NewY,NewX]; Sor.X := Sor.X + V1.X; Sor.Y := Sor.Y + V1.Y; end; A.X := A.X + V2.X; A.Y := A.Y + V2.Y; end;

Tehát amikor jobbra lépsz, akkor az aktuális koordinátához, hozzáadod a V1 vektort, amikor pedig lefelé lépsz a V2 vektort kell hozzáadni.

Vagyis a bonyolult szögszámítások helyett amit minden pixelnél alkalmazol csak az A,B,C pontoknál kell megtenned, majd utána a két for ciklusban a következő pixel koordinátáját megkapni csupán két lebegőpontos szám összeadásáról szól.

Úgy gondolom, hogy ez sokat gyorsíthatna a programodon.
Mutasd a teljes hozzászólást!
Csatolt állomány

Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd