Aus den grafischen Betriebssystemen kennt man mitunter den Vorgang, ein Bild - gleich welcher Größe - auf eine Durchschnittsfarbe zu reduzieren und dann mit dieser Farbe etwas zu tun. Beispielsweilse kann die Windows 10 Benutzeroberfläche mit der Durchschnittsfarbe des Desktop-Wallpapers die grafischen Elemente farblich ausstatten.
In aller Regel kann man mit einem Befehl wie ResizeImage () oder durch Verwendung einfacher Grafiksoftware den "Farbdurchschnitt" eines beliebigen Bildes errechnen lassen indem man es auf Größe 1x1 runterrechnen lässt. (Wenn mein Bild zum Beispiel die Größe 2x1 hat und aus einem weißen und einem schwarzen Pixel besteht, ergibt das 1x1 Durchschnittspixel exakt grau=127,127,127)
Das kann bei großen Bildern dann auch etwas dauern, aber mich interessiert, wie solch eine Berechnung auf Bildgröße 1x1 technisch funktioniert. Der Computer kann vermutlich nicht alle Pixel aufsummieren und dann den Durchschnittswert ziehen. Die Formel Summe (aller Pixelwerte) durch Anzahl (aller Pixel) kann man verwenden wenn man aus Bytes ein Quad errechnet, aber wie geht das wenn beliebig viele Pixel im Bitmap liegen?
Vielleicht taugen Floats bzw. Doubles dazu... ich habe das nicht getestet und wollte hier erstmal um Rat fragen. Wäre es technisch in Ordnung, eine Fließkommazahl als Träger für die Summe (aller Farbwerte) zu verwenden und den Wert dann durch die Anzahl der Pixel zu dividieren?
Klar, das dabei red/green/blue unterschieden werden muss... einfacher geht es eben mit Graustufen. Da liegen alle Pixel zwischen 0 und 255 bzw. -128 und 127 ... aber taugen Fließkommazahlen zu so etwas oder verlässt uns da die Genauigkeit? Was wäre sonst ein besserer Weg?
Durchschnittsfarbe eines Bildes
-
- Beiträge: 6267
- Registriert: 29.08.2004 08:37
- Computerausstattung: Hoffentlich bald keine mehr
- Kontaktdaten:
Re: Durchschnittsfarbe eines Bildes
Eine Lösung wäre ein streaming online Algorithmus für den Durchschnitt. Welford's online algorithm ( https://en.m.wikipedia.org/wiki/Algorit ... g_variance ):
mean(x_n) = mean(x_(n-1)) + (x_n - mean(x_(n-1))) / n
Also updaten mit
n = n + 1
mean = mean + (nächste zahl - mean) / n
Aber bei Bildern wird in der Regel schon einfach aufsummiert würde ich behaupten. ResizeImage geht auch etwas anders vor insgesamt, das hat verschiedene Interpolationsmodi usw.
Bei Fließkommazahlen würde ich die Farbwerte im Range [0, 1] halten statt [0, 255]. Und wenn du häufiger Mittelwerte von Ausschnitten aus einem Bild brauchst gibt es Integralbilder/Summed Area Tables und das Inklusions-Exklusions-Prinzip.
mean(x_n) = mean(x_(n-1)) + (x_n - mean(x_(n-1))) / n
Also updaten mit
n = n + 1
mean = mean + (nächste zahl - mean) / n
Aber bei Bildern wird in der Regel schon einfach aufsummiert würde ich behaupten. ResizeImage geht auch etwas anders vor insgesamt, das hat verschiedene Interpolationsmodi usw.
Bei Fließkommazahlen würde ich die Farbwerte im Range [0, 1] halten statt [0, 255]. Und wenn du häufiger Mittelwerte von Ausschnitten aus einem Bild brauchst gibt es Integralbilder/Summed Area Tables und das Inklusions-Exklusions-Prinzip.
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
- NicTheQuick
- Ein Admin
- Beiträge: 8679
- Registriert: 29.08.2004 20:20
- Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti - Wohnort: Saarbrücken
- Kontaktdaten:
Re: Durchschnittsfarbe eines Bildes
Ein Quad reicht locker aus um alle Pixelwerte eines Bildes aufzusummieren. Du bräuchtest ein Bild der Größe 190184348x190184348 um ein Quad auszureizen, wenn alle Pixel weiß sind, also jeder Farbkanal den Wert 255 hat.
Re: Durchschnittsfarbe eines Bildes
Du hast vollkommen recht. Hier hatte ich einen Denkfehler, wollte multiplizieren...NicTheQuick hat geschrieben: ↑30.01.2023 11:29 Ein Quad reicht locker aus um alle Pixelwerte eines Bildes aufzusummieren. Du bräuchtest ein Bild der Größe 190184348x190184348 um ein Quad auszureizen [...]
Ich mache mich mal an eine Implementierung.
Danke Euch beiden!
Re: Durchschnittsfarbe eines Bildes
Beispiel:
Code: Alles auswählen
EnableExplicit
UsePNGImageDecoder()
UseJPEGImageDecoder()
Procedure.i ImageAverageColor(Image.i,*Color.Long)
Protected.i px,py,pw,ph,pp,c
Protected.q r,g,b,a
If IsImage(Image)
If StartDrawing(ImageOutput(Image))
pw = OutputWidth()
ph = OutputHeight()
pp = pw * ph
pw - 1
ph - 1
For py = 0 To ph
For px = 0 To pw
c = Point(px,py)
r + Red(c)
g + Green(c)
b + Blue(c)
a + Alpha(c)
Next
Next
StopDrawing()
*Color\l = RGBA(r / pp,g / pp,b / pp,a / pp)
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i Main()
Protected img.i
Protected color.i
img = LoadImage(#PB_Any,"xyz.jpg")
If img
Debug ImageAverageColor(img,@color)
FreeImage(img)
EndIf
Debug color
ProcedureReturn #Null
EndProcedure
Main()
End
-
- Beiträge: 120
- Registriert: 01.04.2011 21:59
Re: Durchschnittsfarbe eines Bildes
Ich frage mich gerade, ob es die durchschnittliche Farbe eines Images ist, die man als "Umgebungsfarbe" verwenden sollte.
Nimmt man beispielsweise ein Images das ungefähr zur Hälfte aus einem einheitlichen Rot und zur anderen Hälfte aus Grün besteht, dann erhält man als Durchschnitt einen Braunton.
Vielleicht ist die am häufigsten vorkommende Farbe eine bessere Wahl?
Nimmt man beispielsweise ein Images das ungefähr zur Hälfte aus einem einheitlichen Rot und zur anderen Hälfte aus Grün besteht, dann erhält man als Durchschnitt einen Braunton.
Vielleicht ist die am häufigsten vorkommende Farbe eine bessere Wahl?