AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi Durchschnittsfarbe eines Bitmap "schnell" ermitteln

Durchschnittsfarbe eines Bitmap "schnell" ermitteln

Ein Thema von KodeZwerg · begonnen am 10. Mai 2021 · letzter Beitrag vom 12. Mai 2021
Antwort Antwort
Seite 4 von 6   « Erste     234 56   
Amateurprofi

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

AW: Durchschnittsfarbe eines Bitmap "schnell" ermitteln

  Alt 11. Mai 2021, 19:59
Hallo KodeZwerg:
Ich hab dir mal etwas zusammengestoppelt.
Aufruf mit GetAvgColor(Dateiname) oder GetAvgColor(Bitmap)
Mit TestGetAvgColor; hab ich das Ergebnis und die Performance getestet und mit der Funktion aus #3 verglichen.
Die zurückgegebenen Durchschnittsfarben sind identisch, die Ausführungszeiten sind dagegen höchst unterschiedlich.
Danke Amateurprofi, dein Code arbeitet zwar schneller aber liefert bei mir kein Ergebnis.
Ich habe ihn gegen den Turbo von TiGü antreten lassen, siehe Anhang.

Muss ich noch eine besondere Einstellung vornehmen damit mir Dein Code einen Farbwert über 0 liefert?

Getestet mit Delphi Rio, 32-bit build, Release, unter Windows 10 64bit aktuellste patches.
Oh, das ist mir jetzt aber peinlich.
In der Funktion GetAvgColor(Dsn:String):TColor; steht in der vorletzten Zeile
Code:
GetAvgColor(Bmp);
Ändere das bitte in
Code:
Result:=GetAvgColor(Bmp);
Hintergrund ist, dass ich ursprünglich die Funktion GetAvgColor(Bmp:TBitmap):TColor; hatte, also die, mit einer Bitmap als Parameter.
Die Funktion mit dem Dateinamen als Parameter habe ich später hinzugefügt, aber nicht mehr getestet.
Dummerweise hatte ich da vergessen, Result zu setzen.
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
3.306 Beiträge
 
Delphi 10.4 Sydney
 
#32

AW: Durchschnittsfarbe eines Bitmap "schnell" ermitteln

  Alt 11. Mai 2021, 20:10
Nein, man muß gucken, wie oft 256 Platz hat,
denn die 0 ist auch ein gültiger Wert.

1..255 bzw. 0..254 wäre Platz für 255.
So sehe ich das auch, siehe 2^8 = Platz für 256 Werte.
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
608 Beiträge
 
Delphi 10.4 Sydney
 
#33

AW: Durchschnittsfarbe eines Bitmap "schnell" ermitteln

  Alt 11. Mai 2021, 20:28
@Michael II
Nun passiert da was... aber mein Ergebniss ist falsch.
Delphi-Quellcode:
function GetAvgGDIColor(const Filename: string): TColor;
var
  gr: TGPGraphics;
  Bmap: TGPBitmap;
  col: TGPColor;
begin
  Result := 0;
  bmap := TGPBitmap.Create(Filename);
  try
    gr := TGPGraphics.Create( bmap );
    try
      gr.ScaleTransform( 1/bmap.GetWidth, 1/bmap.GetHeight );
      gr.DrawImage( bmap, 0,0 );
      bmap.GetPixel(0,0, col);
      Result := RGB(GetRValue(col), GetGValue(col), GetBValue(col));
    finally
      gr.Free;
    end;
  finally
    bmap.Free;
  end;
end;
Falls Du Dich nochmal reinklinken könntest

Dein Code ist fast voll ok so.
Einzig bei der Auswertung von col....
Du musst darauf achten, dass TGPColor (anders als TColor!) wie folgt die Farbe speichert:
ARGB d.h. ALPHA ROT GRÜN BLAU
Und die von dir verwendeten Winapi.Windows TColor Funktionen GetRValue... rechnen mit (A)BGR=(ALPHA) BLAU GRÜN ROT.

Du willst ein Resultat in TColor:
Wenn du GetRValue auf col : TGPColor anwendest wirst du den Blauanteil der Farbe erhalten. Entsprechend: Wenn du GetBValue auf eine TGPColor anwendest wirst du den Rotanteil erhalten.

Testen könntest du die Sache zum Beispiel so.
Du erstellst eine hbit: TBitMap von der Grösse 500x500. Wir setzen alle Pixel auf RGB(255,128,64). Das Pixel (0,0) auf RGB(0,0,0).

Delphi-Quellcode:
hbit := TBitMap.Create;
  hbit.SetSize( 500, 500 );

for x := 0 to hbit.Height-1 do
    for y := 0 to hbit.Width-1 do
      hbit.Canvas.Pixels[x,y] := rgb(255,128,64);

hbit.Canvas.Pixels[0,0] := rgb(0,0,0);

fn := 'C:\Users\micha\Desktop\test.bmp';
hbit.SaveToFile( fn );
hbit.Free;
Nun lässt du deine Funktionen auf hbit (mit anderen Farben auch prüfen!) los.
TiGü via scanline liefert - da dort nach dem Summieren div anzahlpixels (statt trunc(summe/anzahlpixels+0.5) verwendet wird - als Durchschnittsfarbe (254,127,63).

Nun lässt du die Funktion auf grizzlys GDI+ Idee, bzw. deine Lösung los: Du erhältst wie erwartet (255,128,64).
Michael Gasser
  Mit Zitat antworten Zitat
Amateurprofi

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

AW: Durchschnittsfarbe eines Bitmap "schnell" ermitteln

  Alt 11. Mai 2021, 20:44
@KodeZwerg:

In #16 wurde in den Raum geworfen, ob man nicht einfach ein Resize auf 1x1 Pixel machen kann.
Ich hab das mal geprüft und in meiner Funktion TestGetAvgColor; vor dem Bmp.Free folgendes eingefügt:

Delphi-Quellcode:
   T3:=GetTickCount;
   Bmp2:=TBitmap.Create;
   Bmp2.PixelFormat:=pf24Bit;
   Bmp2.SetSize(1,1);
   SetRect(R,0,0,1,1);
   Bmp2.Canvas.StretchDraw(R,Bmp);
   CL3:=Bmp2.Canvas.Pixels[0,0];
   Bmp2.Free;
   T3:=GetTickCount-T3;
Das ShowMessage am Ende hab ich abgeändert in:

ShowMessage('$'+IntToHex(CL1,8)+' '+IntToStr(T1-T0)+#13+
'$'+IntToHex(CL2,8)+' '+IntToStr(T2-T1)+#13+
'$'+IntToHex(CL3,8)+' '+IntToStr(T3));

Scheint zu funktionieren, was aber auch daran liegen könnte, dass in der Testprozedur alle Pixel die gleiche Farbe haben.
Korrektur: Hab es gerade mit einem echten Bild geprüft.
Die Methode, das Bild auf 1x1 Pixel zu reduzieren, liefert eine andere Durchschnittsfarbe.
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
608 Beiträge
 
Delphi 10.4 Sydney
 
#35

AW: Durchschnittsfarbe eines Bitmap "schnell" ermitteln

  Alt 11. Mai 2021, 20:46
Nein, man muß gucken, wie oft 256 Platz hat,
denn die 0 ist auch ein gültiger Wert.

1..255 bzw. 0..254 wäre Platz für 255.



Aber keine Sorge, auch andere vergessen die 0 gern.
Daher wurde die Zahl 0 in vielen Kulturen auch erst sehr spät erfunden.

Nein das stimmt nicht. Kulturen hin oder her.

Schau noch einmal in den Code, um welchen es geht. Dort wird eine Variable r vom Typ integer auf 0 gesetzt. Und danach wird Pixel für Pixel geschaut, welcher Rotanteil vorliegt. Dieser Rotanteil wird jedes Mal zu r addiert.

Nun wollen wir herausfinden, wann r frühestens überläuft. r läuft in Kulturen wo der Rotanteil aller Pixel immer 0 ist gar nie über, da r konstant 0 bleibt. D.h. in solchen Kulturen kannst du unendlich viele Rotanteile zu r addieren.

Es gibt aber auch Kulturen (zum Beispiel bei gewissen Kulturen im Pferdekopfnebel), in welchen der Rotanteil aller Pixel immer maximal maxbyte = 11111111(bin) = 255(dec) ist.
Wenn du dir jetzt überlegen willst, wann es bei der Summenbildung frühestens knallt, dann musst du einen Taschenrechner zur Hand nehmen und eine 0 eintippen.

Nun addierst du 255 für Pixel 1, 255 für Pixel 2, 255 für Pixel 3...
Nach p Pixeln bist du bei p*255 angelangt.

Irgendwann fragst dich, wann p*255 > maxint erreicht wird.

Diese Ungleichung kannst du lösen:

p>maxint/255.

Die Lösung lautet: Nach p>maxint/255 Pixeln läuft r über.
Michael Gasser
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
608 Beiträge
 
Delphi 10.4 Sydney
 
#36

AW: Durchschnittsfarbe eines Bitmap "schnell" ermitteln

  Alt 11. Mai 2021, 20:54
@KodeZwerg:

Die Methode, das Bild auf 1x1 Pixel zu reduzieren, liefert eine andere Durchschnittsfarbe.

Ich nehme auch an, dass GDI+ beim Skalieren auf 1x1 nicht oft die gleiche Durchschnittsfarbe berechnet. Du könntest ja auch auf ein 10x10 oder ähnlich skalieren und dort rechnen.

Die 1x1 Bitmap Farbe hängt natürlich u.a. vom verwendeten Skalier-Algorithmus ab.

Bliebe die Frage: Welche Farbe ein Mensch als die "bessere" Durchschnittsfarbe bewerten würde.

Hast du irgendwo einen Link auf wissenschaftliche Literatur (wäre interessant), wo sowas wie eine "Durchschnittsfarbe" besprochen wird. Ich nehme an, dass in der Grafikbranche nicht einfach über RGB addiert und der Mittelwert genommen wird. Da werden doch sicher andere Modelle "bemüht"?
Michael Gasser
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.081 Beiträge
 
Delphi 10.3 Rio
 
#37

AW: Durchschnittsfarbe eines Bitmap "schnell" ermitteln

  Alt 11. Mai 2021, 20:55
@Amateurprofi: Ich war da auch blind, es klappt nun bestens!
@Michael II: Ich habe es nun hinbekommen das alles funktioniert! Danke mit den Alpha-Kanal Tipp, das hat mich irgendwie auf die richtige Spur geführt auch wenn ich teilweise nur Bahnhof verstanden habe

Im Anhang, für alle Interessierten, meine Testergebnisse bei einem Durchlauf incl Abbildung des GDI+ codes. (GetRed() GetGreen() GetBlue() war die Lösung, so hoffe ich jedenfalls)

Ich muss fairer Weise sagen ich die Topic falsch betitelt habe, es müsste nicht Bitmap sondern Bild heißen.

Ich werde es nochmal testen wenn ich eine "TBitmap bzw HBITMAP" Konvertierung eingepflanzt habe damit es mehr als nur reine Bitmaps annehmen kann.
Ausgangspunkt sollte in allen Fällen ein WIC-Image sein, damit ich alles was Microsoft verarbeitet auch unterstützen kann.
Diese Konvertierung von WIC nach ein passendes Bitmap-Format wird sich dann natürlich negativ auswirken und wahrscheinlich den jetzigen Vorsprung zumindest etwas egalisieren.

Danke Euch beiden für diese sehr Interessanten Beiträge!!
Miniaturansicht angehängter Grafiken
screenshot-benchmark.png  
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.081 Beiträge
 
Delphi 10.3 Rio
 
#38

AW: Durchschnittsfarbe eines Bitmap "schnell" ermitteln

  Alt 11. Mai 2021, 21:00
Hast du irgendwo einen Link auf wissenschaftliche Literatur (wäre interessant), wo sowas wie eine "Durchschnittsfarbe" besprochen wird. Ich nehme an, dass in der Grafikbranche nicht einfach über RGB addiert und der Mittelwert genommen wird. Da werden doch sicher andere Modelle "bemüht"?
Nein leider nicht, ich habe mich da auf mein Bauchgefühl verlassen das man es so machen könnte, einfach angefangen zu tippsen ohne Recherche(!), rein Augenscheinlich betrachtet, liefert mir TiGü's verfahren (mit meiner simplen berechnung) sehr gute Ergebnisse.
Reine Bitmaps habe ich gar keine zum Testen damit ich auch Eure (Assembler und GDI+) besser testen kann.
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Benutzerbild von KodeZwerg
KodeZwerg

Registriert seit: 1. Feb 2018
3.081 Beiträge
 
Delphi 10.3 Rio
 
#39

AW: Durchschnittsfarbe eines Bitmap "schnell" ermitteln

  Alt 11. Mai 2021, 21:15
In #16 wurde in den Raum geworfen, ob man nicht einfach ein Resize auf 1x1 Pixel machen kann.
Ich hab das mal geprüft und in meiner Funktion TestGetAvgColor; vor dem Bmp.Free folgendes eingefügt:
Scheint zu funktionieren, was aber auch daran liegen könnte, dass in der Testprozedur alle Pixel die gleiche Farbe haben.
Korrektur: Hab es gerade mit einem echten Bild geprüft.
Die Methode, das Bild auf 1x1 Pixel zu reduzieren, liefert eine andere Durchschnittsfarbe.
Danke für den Test! Das schonmal vorweg.
Anstelle auf 1x1, wäre meine Überlegung ein sinnvolles Resize erst dann durchzuführen wenn Int64 für die Berechnung nicht mehr ausreicht.
Es wurden zwar viele Zahlen in den Raum geworfen, aber wie sollte man da Sinnvoll vorgehen?...

Ein Bild besteht ja aus zwei Dimensionen, ein Int64 ist nur eine.
Was ich meine, gibt es eine logik die so etwas berechnen kann, ein bild kann ja 100 million pixel Hoch aber nur 1 pixel breit sein.
Andersrum genauso.
Oder eben in beide Dimensionen sehr sehr viele Pixel besitzen.
Also es gäbe halt mehr als nur eine Möglichkeit diese berechnung hier zum platzen zu bringen.
Ein Resize auf eine Dimension die es nicht zum platzen bringt, das wäre das Sahnetörtchen
Gruß vom KodeZwerg
  Mit Zitat antworten Zitat
Michael II

Registriert seit: 1. Dez 2012
Ort: CH BE Eriswil
608 Beiträge
 
Delphi 10.4 Sydney
 
#40

AW: Durchschnittsfarbe eines Bitmap "schnell" ermitteln

  Alt 11. Mai 2021, 21:40
Resize erst dann durchzuführen wenn Int64 für die Berechnung nicht mehr ausreicht.
Da deine RGB Werte nie negativ sind kannst du statt Int64 auch UInt64 verwenden. Dann hast du alle 64Bit (und nicht nur 63Bit) zur Verfügung für die Summenbildung.

High(Uint64)=2^64-1=18446744073709551615

Da du momentan RGB Werte im Bereich 0..255 verwendest, kannst du nach dem grössten p (Anzahl Pixel deiner Bitmap) suchen, welches
p*255 <= 1844674407370955165
erfüllt.

p(max)=72’340’172’838’076’673

D.h. du kannst enorm grosse Bitmaps (mit maximal p(max) Pixeln) verarbeiten.
Michael Gasser
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 11:22 Uhr.
Powered by vBulletin® Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf