AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Bitmap zeichen (gehts noch schneller?)
Thema durchsuchen
Ansicht
Themen-Optionen

Bitmap zeichen (gehts noch schneller?)

Ein Thema von Amateurprofi · begonnen am 28. Feb 2016 · letzter Beitrag vom 1. Mär 2016
Antwort Antwort
Seite 1 von 2  1 2      
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.077 Beiträge
 
Delphi XE2 Professional
 
#1

Bitmap zeichen (gehts noch schneller?)

  Alt 28. Feb 2016, 13:45
Mit den in der untenstehenden Test-Prozedur enthaltenen Prozeduren DrawBitmap und DrawGPBitmap zeichne ich eine Bitmap auf den Canvas einer maximierten Form.
Größe der Bitmap : 4000 x 3000 Pixel
Größe des Canvass : 1920 x 1000 Pixel

Meine Erwartung war, das das mit der GPBitmap (TGPGraphics.DrawImage) schneller geht als mit DrawBitmap (StretchBlt).

Ich habe folgende Zeiten gemessen, jeweils für 100 maliges Zeichnen:

DrawBitmap : 234 ms.
DrawGPBitmap: 31809 ms, also knapp 136 mal so lange.

Da ich mir kaum vorstellen kann, dass das DrawImage (immerhin GDI+) so viel langsamer ist, als das StretchBlt, vermute ich, dass ich irgend etwas verkehrt mache.

Weiß jemand, wie man eine GPBitmap schnell ausgibt?

Das Bild kann hier [URL="https://commons.wikimedia.org/w/index.php?curid=6558322"] heruntergeladen werden.

Delphi-Quellcode:
PROCEDURE TMain.Test;
//------------------------------------------------------------------------------
FUNCTION DrawBitmap(const Dsn:String; Count:Integer):Cardinal;
var I,W,H:Integer; Image:TGPImage; Graphics:TGPGraphics; Bmp:TBitmap;
begin
   Bmp:=TBitmap.Create;
   Image:=TGPImage.Create(Dsn);
   W:=Image.GetWidth;
   H:=Image.GetHeight;
   Bmp.SetSize(W,H);
   Graphics:=TGPGraphics.Create(Bmp.Canvas.Handle);
   Graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
   Graphics.DrawImage(Image,MakeRect(0,0,W,H));
   Graphics.Free;
   Image.Free;
   Result:=GetTickCount;
   for I:=1 to Count do begin
      SetStretchBltMode(Canvas.Handle,COLORONCOLOR);
      SetBrushOrgEx(Canvas.Handle,0,0,nil);
      StretchBlt(Canvas.Handle,0,0,ClientWidth,ClientHeight,
                 Bmp.Canvas.Handle,0,0,Bmp.Width,Bmp.Height,SrcCopy);
   end;
   Result:=GetTickCount-Result;
   Bmp.Free
end;
//------------------------------------------------------------------------------
FUNCTION DrawGPBitmap(const Dsn:String; Count:Integer):Cardinal;
var I:Integer; Image:TGPBitmap; Graphics:TGPGraphics;
begin
   Image:=TGPBitmap.Create(Dsn);
   Result:=GetTickCount;
   for I:=1 to Count do begin
      Graphics:=TGPGraphics.Create(Canvas.Handle);
      Graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
      Graphics.DrawImage(Image,MakeRect(0,0,ClientWidth,ClientHeight));
      Graphics.Free;
   end;
   Result:=GetTickCount-Result;
   Image.Free;
end;
//------------------------------------------------------------------------------
// https://commons.wikimedia.org/w/index.php?curid=6558322
const Dsn='E:\Daten\DownLoads\PfauVonVorne.jpg';
var T1,T2:Cardinal;
begin
   T1:=DrawBitmap(Dsn,100);
   T2:=DrawGPBitmap(Dsn,100);
   ShowMessage(IntToStr(T1)+#13+IntToStr(T2));
// Ausgabe
// DrawBitmap 234 ms bei 100 Durchläufen
// DrawGPBitmap 31809 ms bei 100 Durchläufen
end;
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Bitmap zeichen (gehts noch schneller?)

  Alt 28. Feb 2016, 17:07
Mach doch mal das erzeugen und freigeben des Bildes außerhalb der Schleife. Und der Rückgabewert von makerect kann man auch vorher holen und zwischenspeichern.
  Mit Zitat antworten Zitat
Progman

Registriert seit: 31. Aug 2007
Ort: 99974 MHL
695 Beiträge
 
Delphi 10.1 Berlin Starter
 
#3

AW: Bitmap zeichen (gehts noch schneller?)

  Alt 28. Feb 2016, 17:25
Canvas verfügt doch selbst über die Methoden Draw, StretchDraw u.a.
Warum nicht gleich direkt zeichnen ohne den Umweg über das Bitmap?
Karl-Heinz
Populanten von Domizilen mit fragiler, transparenter Aussenstruktur sollten sich von der Translation von gegen Deformierung resistenter Materie distanzieren!
(Wer im Glashaus sitzt sollte nicht mit Steinen werfen)
  Mit Zitat antworten Zitat
Benutzerbild von Memnarch
Memnarch

Registriert seit: 24. Sep 2010
737 Beiträge
 
#4

AW: Bitmap zeichen (gehts noch schneller?)

  Alt 28. Feb 2016, 21:01
BitBlt, StretchBlt und andere Funktionen der GDI-Lib sind Hardwarebeschleunigt(XP, Vista Nicht, ab W7 wieder). GDI+ ist es nicht.
GDIP hat außerdem bessere interpolationen, die brauchen aber auch mehr cpu.

Wobei zugegeben 136 mal langsamer schon komisch aussieht.

Konnte nur noch diesen Artikel wiederfinden. Den wo GDI+ als nicht HW-beschleunigt genannt wird, nicht
https://msdn.microsoft.com/en-us/lib...=vs.85%29.aspx

PS: Wäre natürlich gut zu wissen unter welchem OS du bist. Ab W8 wurde dass ja schonwieder geändert.
Da man Trunc nicht auf einen Integer anwenden kann, muss dieser zuerst in eine Float kopiert werden

Geändert von Memnarch (28. Feb 2016 um 21:03 Uhr)
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.077 Beiträge
 
Delphi XE2 Professional
 
#5

AW: Bitmap zeichen (gehts noch schneller?)

  Alt 29. Feb 2016, 00:11
Mach doch mal das erzeugen und freigeben des Bildes außerhalb der Schleife. Und der Rückgabewert von makerect kann man auch vorher holen und zwischenspeichern.
Das MakeRect dauert etwa 1.1 MicroSekunden, beeinflußt also das Ergebnis kaum.

Zudem geht es ja nicht darum 100 Mal das gleiche hintereinander zu zeichnen sondern darum entweder ein TBitmap oder ein TGPBitmap zu zeichnen. Zu diesem Zeichnen gehört nun mal auch das MakeRect.
Dass ich hie das Zeichnen 100 mal wiederhole ist nur, damit die Messung per GetTickCount verwertbar ist.

Unter diesem Gesichtspunkt wäre ein separates MakeRect also eher schädlich, allerdings auch nur unwesentlich.

Und was meinst du mit "erzeugen und freigeben des Bildes außerhalb der Schleife" ?
Die Bitmaps werden doch außerhalb der Schleife erzeugt und freigegeben.
Falls du damit das TGPGraphics.Create / und Free meinst, gilt ähnliches wie für MakeRect.

Trotzdem Danke für Deinen Input.
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.077 Beiträge
 
Delphi XE2 Professional
 
#6

AW: Bitmap zeichen (gehts noch schneller?)

  Alt 29. Feb 2016, 00:22
Canvas verfügt doch selbst über die Methoden Draw, StretchDraw u.a.
Warum nicht gleich direkt zeichnen ohne den Umweg über das Bitmap?
Verstehe ich nicht.
Canvas.StretchDraw braucht doch eine Info, WAS gezeichnet werden soll, in diesem Fall eben das Bitmap.

Oder meinst du die TGPGraphic mit Canvas.StretchDraw zu zeichnen?
Das geht leider nicht.
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.077 Beiträge
 
Delphi XE2 Professional
 
#7

AW: Bitmap zeichen (gehts noch schneller?)

  Alt 29. Feb 2016, 00:36
BitBlt, StretchBlt und andere Funktionen der GDI-Lib sind Hardwarebeschleunigt(XP, Vista Nicht, ab W7 wieder). GDI+ ist es nicht.
GDIP hat außerdem bessere interpolationen, die brauchen aber auch mehr cpu.

Wobei zugegeben 136 mal langsamer schon komisch aussieht.

Konnte nur noch diesen Artikel wiederfinden. Den wo GDI+ als nicht HW-beschleunigt genannt wird, nicht
https://msdn.microsoft.com/en-us/lib...=vs.85%29.aspx

PS: Wäre natürlich gut zu wissen unter welchem OS du bist. Ab W8 wurde dass ja schonwieder geändert.
Danke Memnarch,
Das wusste ich bisher nicht.
Aber einen offensichtlichen Fehler in meinem Code, der das langsame Zeichnen verursacht siehst du auch nicht, oder?
Siehst du denn eine Möglichkeit aus einer TGPBitmap SCHNELL eine TBitmap zu machen?
Wie ich das bisher mache siehst du in der Prozedur DrawBitmap.

Mein OS ist übrigens Win 7 Prof.
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Benutzerbild von Memnarch
Memnarch

Registriert seit: 24. Sep 2010
737 Beiträge
 
#8

AW: Bitmap zeichen (gehts noch schneller?)

  Alt 29. Feb 2016, 09:20
Um überhaupt vergleichen zu können, würde ich erstmal die interpolationen in TGPGraphic abstellen. Dann die Frage warum überhaupt GDI+? Wenn du ein so hochauflösendes Bild hast, kannst du nicht auch SetStretchBLTMode HalfTone zum runterskalieren nehmen?

Benutz ich z.B. in meinem AsciiImage:
TGDIRenderContext.EndScene(Zeile 135)

Und so schauts aus:
AsciiImage for Delphi: GDI-Downsampling, FireMonkey and more!

EDIT: Vergiss nicht, dass du da bei GDI+ mitunter unsäglich viel konvertierst(Kann dir auch bei GDI passieren). Wenn die Pixel-Formate zwischen Source und Target nicht gleich sind, wird die source immer konvertiert beim Zeichnen! IIRC solltest du am besten mit 32bit Grafiken arbeiten.
Da man Trunc nicht auf einen Integer anwenden kann, muss dieser zuerst in eine Float kopiert werden

Geändert von Memnarch (29. Feb 2016 um 09:23 Uhr)
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.077 Beiträge
 
Delphi XE2 Professional
 
#9

AW: Bitmap zeichen (gehts noch schneller?)

  Alt 29. Feb 2016, 14:17
Um überhaupt vergleichen zu können, würde ich erstmal die interpolationen in TGPGraphic abstellen. Dann die Frage warum überhaupt GDI+? Wenn du ein so hochauflösendes Bild hast, kannst du nicht auch SetStretchBLTMode HalfTone zum runterskalieren nehmen?

Benutz ich z.B. in meinem AsciiImage:
TGDIRenderContext.EndScene(Zeile 135)

Und so schauts aus:
AsciiImage for Delphi: GDI-Downsampling, FireMonkey and more!

EDIT: Vergiss nicht, dass du da bei GDI+ mitunter unsäglich viel konvertierst(Kann dir auch bei GDI passieren). Wenn die Pixel-Formate zwischen Source und Target nicht gleich sind, wird die source immer konvertiert beim Zeichnen! IIRC solltest du am besten mit 32bit Grafiken arbeiten.
zu: "würde ich erstmal die interpolationen in TGPGraphic abstellen"
ich hab alle Modi probiert:
InterpolationModeInvalid 270 ms
InterpolationModeDefault 270 ms
InterpolationModeLowQuality 270 ms
InterpolationModeHighQuality 325 ms
InterpolationModeBilinear 270 ms
InterpolationModeBicubic 620 ms
InterpolationModeNearestNeighbor 180 ms
InterpolationModeHighQualityBilinear 370 ms
InterpolationModeHighQualityBicubic 320 MS
Alle Zeiten für einmal zeichnen.
Dagegen StretchBlt 2 ms
Bringt also die benötigte Zeit nicht einmal ansatzweise in die Zeit für StretchBlt.

Und warum bin ich so spitz auf TGPBitmap bin, statt TBitmap?
Das Bild liegt idR als .jpg vor, kann aber auch als .png oder .tif oder .bmp sein.

Bisher habe ich z.B. .jpg entsprechend der untenstehenden "LoadBmpViaJPEG" geladen.
Zur Zeit benutze ich die untenstehende "LoadBmpViaGPBitmap"
Und dann hab ich die untenstehende "LoadGPBitmap" getestet.
Die jeweils benötigten Zeiten:
"LoadBmpViaJPEG" : 970 ms
"LoadBmpViaGPBitmap" 270 ms
"LoadGPBitmap" 319 µs

Da ich das Bild nur ausgeben kann, wenn ich es vorher lade, drängt sich das laden in eine TGPBitmap förmlich auf.
Deshalb möchte auch bei allem was folgt am liebsten mit TGPBitmap weitermachen.



Delphi-Quellcode:
FUNCTION LoadBmpViaJPEG(const Dsn:String):Int64;
var Jpg:TJpegImage; Bmp:TBitmap;
begin
   Result:=TimeStamp;
   Jpg:=TJPEGImage.Create;
   Bmp:=TBitmap.Create;
   Jpg.LoadFromFile(Dsn);
   Bmp.Assign(Jpg);
   Jpg.Free;
   Result:=TimeStamp-Result;
   Bmp.Free;
end;
Delphi-Quellcode:
FUNCTION LoadBmpViaGPBitmap(const Dsn:String):Int64;
var W,H:Integer; Image:TGPBitmap; Graphics:TGPGraphics; Bmp:TBitmap;
begin
   Result:=TimeStamp;
   Bmp:=TBitmap.Create;
   Image:=TGPBitmap.Create(Dsn);
   W:=Image.GetWidth;
   H:=Image.GetHeight;
   Bmp.SetSize(W,H);
   Graphics:=TGPGraphics.Create(Bmp.Canvas.Handle);
   Graphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
   Graphics.DrawImage(Image,MakeRect(0,0,W,H));
   Graphics.Free;
   Image.Free;
   Result:=TimeStamp-Result;
   Bmp.Free;
end;
Delphi-Quellcode:
FUNCTION LoadGPBitmap(const Dsn:String):Int64;
var I:Integer; Image:TGPBitmap;
begin
   Result:=TimeStamp;
   Image:=TGPBitmap.Create(Dsn);
   Result:=TimeStamp-Result;
   Image.Free;
end;
Zur Vollständigkeit:
Delphi-Quellcode:
FUNCTION TimeStamp:Int64;
asm
   rdtsc
   {$IFDEF CPUX64}
   shl rdx,32
   or rax,rdx
   {$ENDIF}
end;
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.070 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Bitmap zeichen (gehts noch schneller?)

  Alt 29. Feb 2016, 14:32
Da ich das Bild nur ausgeben kann, wenn ich es vorher lade, drängt sich das laden in eine TGPBitmap förmlich auf.
Wenn es dir einzig und allein darum geht, verschiedene Grafik-Formate zu laden und du sonst nichts mit der GDI+-Biblothek machst, kannst du auch Vcl.Graphics.TWicImage nehmen.

Siehe hier:
http://www.tek-tips.com/faqs.cfm?fid=7568
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:38 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz