Durchschnittliche Farbe eines Bildes

21

Durchschnittliche Farbe eines Bildes

Wissenschaftler konnten die durchschnittliche Farbe des Universums bestimmen, aber in wie vielen Bytes können wir die durchschnittliche Farbe auf einem Bild finden?

Deine Aufgabe

Ihre Eingabe wird ein einzelnes Bild sein, das Sie benötigen, um den Durchschnitt der Farben im Bild zu ermitteln und eine hexadezimale Farbfolge ( #??????) auszugeben . Das Bild kann eines der folgenden Formate haben

  • JPEG / JFIF
    • JPEG 2000
  • TIFF
  • GIF
  • BMP
  • PNG
  • PNM
    • PPM

Die Eingabe kann auch als URL / URI zum Bild verwendet werden.

Eingebaute Funktionen, die Durchschnittswerte berechnen oder das Bild sofort abtasten, ImageMeasurementssind nicht zulässig.

Beispiele

Die Ergebnisse unterscheiden sich geringfügig, je nachdem, wie Sie den Durchschnitt berechnen und welche Farbmodelle Sie verwenden. Ich habe RGB- und LCH-Werte (HSV) für die folgenden Bilder hinzugefügt.

Probe 1Ausgabe: #53715FRGB, kann auch #3B7D3DLCH (HSV) sein


Probe 2Ausgang: #8B7D41RGB, #96753CLCH (HSV)

Downgoat
quelle
Welche Bildformate müssen wir handhaben? Können wir uns speziell dafür entscheiden, nur PPM zu verarbeiten?
Dennis
Kann ich bitte einen kleineren Testfall haben? Mein Skript ist sehr langsam, und während ich es auf dem großen Fall ausführen werde, verschwende ich diese Zeit nicht, wenn es falsch ist. Oder auch nur das Skript, mit dem Sie es berechnet haben.
Maltysen
@Maltysen Ich habe ein 240x140 Beispiel hinzugefügt. Hoffentlich ist das klein genug
Downgoat
Sollen wir immer abrunden? Im ersten Beispiel das 95.6..., auf das Sie 95in der angegebenen Ausgabe gerundet haben .
Dennis
4
PS Es hat keinen Sinn, eine Frage in die Sandbox zu stellen, es sei denn, Sie lassen sie mindestens 24 Stunden dort, damit andere Zeitzonen sie sehen können. Realistisch gesehen müssen Sie 72 Stunden angeben, da nicht jeder die Frage überprüft Sandkasten besessen.
Peter Taylor

Antworten:

19

Pyth - 23 22 19 18 16 Bytes

Transponiert, um alle Kanäle abzurufen, summiert, dividiert und hexiert dann die einzelnen Kanäle. Abschluss durch Verketten und Voranstellen von a #.

+\#sm.H/sdldCs'z

Nimmt einen Bilddateinamen (beliebiger Typ) von stdin und gibt ihn an stdout aus. SEHR LANGSAM .

+               String concat
 \#             "#"
 s              String concat all channels
 m              Map
  .H            Hex string
    /  ld       Divided by length of channel
     sd         Sum of channel
  C             Transpose to separate into channels
   s            Concatenate all rows
    'z          Read image with filename input

Probelauf

>>>pyth avg.pyth 
V5VAR.jpg
#8b7d41
Maltysen
quelle
Eventuell möchten Sie den Bildtyp angeben.
isaacg
1
@isaacg guter Punkt. Es braucht alles.
Maltysen
Wie braucht es etwas, dekodiert es das JPEG in eine Bitmap?
Alec Teal
3
@AlecTeal Gemäß der Dokumentation prüft Pyth, ob es sich bei der Datei um ein Bild handelt, und konvertiert es automatisch in eine Bitmap. Beim Durchsuchen des GitHub-Repositorys sieht es so aus, als würde die PILBibliothek zur Verarbeitung von Bildern verwendet. Suchen Sie hier nach der genauen Quelle.
Bakuriu
@Bakuriu - Ich habe diese Antwort nicht positiv bewertet, weil ich nicht wusste, wie Pyth mit Bildern umgeht, so dass es für mich ein bisschen faul aussah ... aber jetzt, da Sie mir einen Einblick gegeben haben, hat dies meine Stimme bekommen. Danke für die Klarstellung!
Rayryeng - Wiedereinsetzung von Monica
22

Bash, 46 Bytes

ImageMagick skaliert das Bild auf ein Pixel, das den Durchschnitt der Farben im Bild enthält, und gibt es dann als Text aus.

convert $1 -scale 1x1\! txt:-|egrep -o '#\w+'
SteelRaven
quelle
4
Das ist Schlau! +1
Maltysen
10

MATLAB - 68 Bytes

Das Bild wird eingelesen mit imreadkombiniert mit uigetfile, um eine GUI zu öffnen und das Bild auszuwählen, in das Sie laden möchten. Die Annahme mit diesem Code ist, dass alle Bilder RGB sind, und um die durchschnittliche Farbe zu berechnen, addieren wir über jeden Kanal einzeln und teilen dann auf durch so viele Elemente wie es in einem Kanal gibt, was die Gesamtzahl der Pixel im RGB-Bild ( ) geteilt durch 3 ist. Da der Durchschnitt möglicherweise Gleitkommawerte erzeugen kann, ist ein Aufruf von erforderlich, um die Zahl auf Null abzurunden . zusammen mit der hexadezimalen Formatierungszeichenfolge ( ) wird verwendet, um jeden ganzzahligen Wert im Durchschnitt in seine hexadezimale Entsprechung zu drucken. Das ist jedoch da, um sicherzustellen, dass eine zusätzliche 0 nach links aufgefüllt wird, sollte der Durchschnittswert für einen Kanal kleiner als 16 seinnumel(I)fixsprintf%x02* .

I=imread(uigetfile);
['#' sprintf('%02x',fix(sum(sum(I))*3/numel(I)))]

Probeläufe

Das Schöne daran imreadist, dass Sie Bilder direkt von URLs einlesen können. Nehmen wir als reproduzierbares Beispiel an, Sie haben die Bilder auf Ihren Computer heruntergeladen und den obigen Code ausgeführt. Zur Demonstration lese ich die Bilder jedoch direkt von Code Golf:

Erstes Bild

>> I=imread('http://i.stack.imgur.com/dkShg.jpg');
>> ['#' sprintf('%02x',fix(sum(sum(I))*3/numel(I)))]

ans =

#53715f

Zweites Bild

>> I=imread('http://i.stack.imgur.com/V5VAR.jpg');
>> ['#' sprintf('%02x',fix(sum(sum(I))*3/numel(I)))]

ans =

#8b7d41

* Hinweis: Dies war eine Zusammenarbeit von StackOverflow-Benutzern im MATLAB- und Octave-Chatroom .

rayryeng - Setzen Sie Monica wieder ein
quelle
7

CJam, 27 Bytes

'#[q~]5>3/_:.+\,f/"%02X"fe%

Dies liest ein PPM-Bild von STDIN.

CJam hat keine eingebaute Bildverarbeitung, daher erwartet dieser Code eine tragbare ASCII-PixMap (magische Zahl P3) mit vollständiger 24-Bit-Palette (Maximalwert 255) und ohne Kommentare.

Testlauf

$ cjam avg.cjam < dkShg.ppm 
#53715F

Wie es funktioniert

'#     e# Push that character.
[q~]   e# Evaluate the input and collect the results in an array.
5>     e# Discard the first first results (Pi, 3, width, height, range).
3/     e# Split into chunks of length 3 (RGB).
_:.+   e# Push a copy and add across the columns (RGB).
\,f/   e# Divide each sum by the length of the array (number of pixels).
"%02X" e# Push that format string (hexadecimal integer, zero-pad to two digits).
fe%    e# Format each integer, using the format string.
Dennis
quelle
7

HTML5 + JavaScript (ES6), 335 Byte

Das wird nicht gewinnen, aber ich hatte trotzdem Spaß daran.

Verwendet die HTML5 Canvas API . Die Eingabe ist eine URL eines CORS-fähigen Bildes .

f=(u,i=new Image)=>{i.crossOrigin='';i.src=u;i.onload=e=>{x=(c=document.createElement('canvas')).getContext('2d');a=w=c.width=i.width;a*=h=c.height=i.height;x.drawImage(i,0,0);for(d=x.getImageData(m=0,0,w,h).data,r=[0,0,0];m<d.length;m+=4){r[0]+=d[m];r[1]+=d[m+1];r[2]+=d[m+2]}console.log('#'+r.map(v=>(~~(v/a)).toString(16)).join``)}}

Demo

Da es sich um ES6 handelt, funktioniert es derzeit nur in Firefox und Edge.

f = (u,i = new Image) => {
  i.crossOrigin = '';
  i.src = u;
  i.onload = e => {
    x = (c = document.createElement('canvas')).getContext('2d');
    a = w = c.width = i.width;
    a *= h = c.height = i.height;
    x.drawImage(i, 0, 0);
    for (d = x.getImageData(m = 0, 0, w, h).data, r = [0, 0, 0]; m < d.length; m += 4) {
      r[0] += d[m]
      r[1] += d[m + 1];
      r[2] += d[m + 2];
    }
    console.log('#' + r.map(v => (~~(v/a)).toString(16)).join``)
  }
}

// Snippet stuff
console.log = x => document.body.innerHTML += x + '<br>';

f('http://crossorigin.me/https://i.stack.imgur.com/dkShg.jpg');

f('http://crossorigin.me/https://i.stack.imgur.com/V5VAR.jpg');

rink.attendant.6
quelle
3
Hey, ich mag es, dass es direkt in deiner Antwort ausführbar ist, weil es HTML + JS :) +1 ist.
Rayryeng - Wiedereinsetzung von Monica
Kannst du nicht ersetzen new Imagedurch Image()?
Ismael Miguel
@IsmaelMiguelTypeError: Constructor Image requires 'new'
rink.attendant.6
Mist. Aber Sie können erstellen W='width'und H='height'und verwenden i[H]oderi[W]
Ismael Miguel
1
@ IsmaelMiguel Das verwendet mehr Zeichen
rink.attendant.6
6

Python [3] + SciPy, 144 133 121

Lädt Pixeldaten, summiert für jeden Kanal, dividiert durch Größe *, Formate. Die Werte sind gegen Null gerundet.

* Größe = Breite * Höhe * Kanäle, also multipliziert mit 3

from scipy import misc,sum
i=misc.imread(input())
print('#'+(3*'{:2x}').format(*sum(i.astype(int),axis=(0,1))*3//i.size))
Trang Oul
quelle
1
Warum nicht input()für den Weg nutzen? Sie sparen 20 Bytes.
Kade
Vielen Dank! Ich habe es geschafft, 11 Bytes zu sparen.
Trang Oul
Sie benötigen nur einen Import import scipy. Wechseln Sie m.imreadzu misc.imread.
Kade
Funktioniert nicht ohne Import von Sonstiges NameError: name 'misc' is not defined. Versucht from scipy import*, funktioniert auch nicht.
Trang Oul
2
@TrangOul Was ist mit from scipy import sum, misc as m? Sie sparen dann, wenn Sie auch die Summe verwenden.
Matsjoyce
3

R, 90 Bytes

rgb(matrix(apply(png::readPNG(scan(,"")),3,function(x)sum(x*255)%/%length(x)),nc=3),m=255)

Der Pfad zur PNG-Datei wird aus STDIN gelesen. Paket pngmuss installiert sein.

Schritt für Schritt:

#Reads path from stdin and feeds it to function readPNG from package png
p = png::readPNG(scan(,""))
#The result is a 3d matrix (1 layer for each color channel) filled with [0,1] values
#So next step, we compute the mean on each layer using apply(X,3,FUN)
#after moving the value to range [0,255] and keeping it as an integer.
a = apply(p,3,function(x)sum(x*255)%/%length(x))
#The result is then moved to a matrix of 3 columns:
m = matrix(a, nc=3)
#Which we feed to function rgb, while specifying that we're working on range [0,255]
rgb(m, m=255)

# Example:
rgb(matrix(apply(png::readPNG(scan(,"")),3,function(x)sum(x*255)%/%length(x)),nc=3),m=255)
# 1: ~/Desktop/dkShg.png
# 2: 
# Read 1 item
# [1] "#53715F"
Plannapus
quelle
2

C 259 Bytes

Nimmt eine PPM-Datei ohne Kommentare auf .

double*f,r,g,b;x,y,z,i;char*s="%d %d %d";main(a,_){(a-2)?(feof(f)?0:(fscanf(f,s,&x,&y,&z),r+=(x-r)/i,g+=(y-g)/i,b+=(z-b)/i++,main(0,0))):(f=fopen(((char**)_)[1],"r"),fscanf(f,"%*s%*d%*d%*d"),r=g=b=0.,i=1,main(0,0),printf(s,(int)r,(int)g,(int)b),fclose(f));}

Verarbeiten

Anfangscode:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    FILE *f = fopen(argv[1],"r");
    int w,h,d,x,y,z,i;
    double r,g,b;
    fscanf(f,"%*s %d %d %d",&w,&h,&d);//get width, height, depth, ignore P6
    r = g = b = 0.0; //zero r, g, and b totals
    for (i=1; i<=w*h; ++i) {
        fscanf(f,"%d %d %d",&x,&y,&z);//get next pixel
        r+=(x-r)/i;//update averages
        g+=(y-g)/i;
        b+=(z-b)/i;
    }
    printf("%d %d %d",(int)r,(int)g,(int)b);//print result
    fclose(f);
    return 0;
}

Variablen trimmen und Schleife entfernen:

double r,g,b;
FILE *f;
int i;
int main(int argc, char *argv[])
{
    if (argc==2) { // {./me} {file.ppm}
        f = fopen(argv[1],"r");
        fscanf(f,"%*s%*d%*d%*d");//drop info
        r = g = b = 0.0;
        i = 1;
        main(0,0);//begin load loop
        printf("%d %d %d",(int)r,(int)g,(int)b);
        fclose(f)
    } else {
        if (feof(f)) return 0;
        fscanf(f,"%d%d%d",&x,&y,&z);
        r+=(x-r)/i;
        g+=(y-g)/i;
        b+=(z-b)/i;
        i++;
        main(0,0);
    }
    return 0;
}

Von dort habe ich die verschiedenen Anweisungen zu einer einzigen return-Anweisung zusammengefasst. Entfernte es und alle anderen fremden Typinformationen, benannte Variablen um und schnitt das Leerzeichen aus.

LambdaBeta
quelle
2

Cobra - 371

@ref 'System.Numerics'
use System.Drawing
use System.Numerics
class P
    def main
        i,d=Bitmap(Console.readLine?''),BigInteger
        r,g,b,c=d(),d(),d(),d()
        for x in i.width,for y in i.height,r,g,b,c=for n in 4 get BigInteger.add([r,g,b,c][n],d([(p=i.getPixel(x,y)).r,p.g,p.b,1][n]))
        print'#'+(for k in[r,g,b]get Convert.toString(BigInteger.divide(k,c)to int,16)).join('')
Οurous
quelle
2

Java, 449 447 446 430 426 Bytes

import java.awt.*;interface A{static void main(String[]a)throws Exception{java.awt.image.BufferedImage i=javax.imageio.ImageIO.read(new java.io.File(new java.util.Scanner(System.in).nextLine()));int r=0,g=0,b=0,k=0,x,y;for(x=0;x<i.getWidth();x++)for(y=0;y<i.getHeight();k++){Color c=new Color(i.getRGB(x,y++));r+=c.getRed();g+=c.getGreen();b+=c.getBlue();}System.out.printf("#%06X",0xFFFFFF&new Color(r/k,g/k,b/k).getRGB());}}

Dank dieser Antwort auf Stapelüberlauf für den String.formatTrick.

SuperJedi224
quelle