Durchschnittsfarbe eines Bildes

Für allgemeine Fragen zur Programmierung mit PureBasic.
s91
Beiträge: 20
Registriert: 07.09.2022 17:20
Wohnort: HY

Durchschnittsfarbe eines Bildes

Beitrag von s91 »

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?
DarkDragon
Beiträge: 6267
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Re: Durchschnittsfarbe eines Bildes

Beitrag von DarkDragon »

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.
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.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
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

Beitrag von NicTheQuick »

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.
Bild
s91
Beiträge: 20
Registriert: 07.09.2022 17:20
Wohnort: HY

Re: Durchschnittsfarbe eines Bildes

Beitrag von s91 »

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 [...]
Du hast vollkommen recht. Hier hatte ich einen Denkfehler, wollte multiplizieren...

Ich mache mich mal an eine Implementierung.

Danke Euch beiden! :D
Benutzeravatar
Mijikai
Beiträge: 754
Registriert: 25.09.2016 01:42

Re: Durchschnittsfarbe eines Bildes

Beitrag von Mijikai »

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
fabulouspaul
Beiträge: 120
Registriert: 01.04.2011 21:59

Re: Durchschnittsfarbe eines Bildes

Beitrag von fabulouspaul »

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?
Antworten