Colore medio di un'immagine


21

Colore medio di un'immagine

Gli scienziati sono stati in grado di determinare il colore medio dell'universo, ma in quanti byte possiamo trovare il colore medio su un'immagine?

Il tuo compito

Il tuo input sarà una singola immagine di cui avrai bisogno per trovare la media dei colori nell'immagine e produrre una stringa di colore esadecimale ( #??????). L'immagine può essere in uno dei seguenti formati

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

L'input può anche essere preso come un URL / URI all'immagine.

Le funzioni integrate che calcolano le medie o campionano l'immagine contemporaneamente ImageMeasurementsnon sono consentite.

Esempi

I risultati differiranno leggermente a seconda di come si calcola la media e di quali modelli di colore si utilizzano. Ho aggiunto i valori RGB e LCH (HSV) per le immagini seguenti.

Campione 1uscita: #53715FRGB, può anche essere #3B7D3DLCH (HSV)


Campione 2uscita: #8B7D41RGB, #96753CLCH (HSV)


Quali formati di immagine dobbiamo gestire? In particolare, possiamo scegliere di gestire solo PPM?
Dennis,

Posso avere un test case più piccolo per favore? La mia sceneggiatura è molto lenta e mentre la eseguirò sul caso grande, non perdo tempo se è sbagliata. O anche solo lo script con cui lo hai calcolato.
Maltysen,

@Maltysen Ho aggiunto un esempio 240x140. Spero che sia abbastanza piccolo
Downgoat il

Dovremmo sempre arrotondare per difetto? Nel primo esempio, il 95.6..., che hai arrotondato 95nell'output specificato.
Dennis,

4
PS Non ha senso pubblicare una domanda nella sandbox a meno che non la lascerai lì per almeno 24 ore, in modo che le persone in altri fusi orari possano vederla e realisticamente devi dargli 72 ore perché non tutti controllano il sandbox ossessivamente.
Peter Taylor,

Risposte:


19

Pyth - 23 22 19 18 16 byte

Traspone per ottenere tutti i canali, quindi somma, divide ed esita ciascuno. Termina concatenando e anteponendo a #.

+\#sm.H/sdldCs'z

Prende un nome di file immagine (qualsiasi tipo) da stdin e l'output a stdout. MOLTO LENTO .

+               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

Esecuzione del campione

>>>pyth avg.pyth 
V5VAR.jpg
#8b7d41

Si consiglia di specificare il tipo di immagine, se presente.
Isaacg,

1
@isaacg buon punto. Ci vuole tutto.
Maltysen,

Come prende qualcosa, decodifica il jpeg in bitmap?
Alec Teal,

3
@AlecTeal Secondo la documentazione Pyth controlla se il file è un'immagine e lo converte automaticamente in bitmap. Cercando nel repository GitHub sembra che usi la PILlibreria per gestire le immagini. Cerca qui la fonte esatta.
Bakuriu,

@Bakuriu - Non ho votato a favore di questa risposta perché non ero consapevole di come Pyth gestisse le immagini in modo da sembrare un po 'sospetto per me ... ma ora che hai fornito informazioni lì, questo mi dà il mio voto. Grazie per il chiarimento!
rayryeng - Ripristina Monica il

22

Bash, 46 byte

ImageMagick ridimensiona l'immagine su un pixel che contiene la media dei colori nell'immagine, quindi l'output come testo.

convert $1 -scale 1x1\! txt:-|egrep -o '#\w+'

4
È intelligente! +1
Maltysen,

10

MATLAB - 68 byte

L'immagine viene letta in imreadcombinazione con uigetfileper aprire una GUI per scegliere l'immagine in cui si desidera caricare. Il presupposto con questo codice è che tutte le immagini sono RGB e per calcolare il colore medio, sommiamo individualmente ogni canale quindi dividiamo di quanti più elementi ci sono in un canale, che è il numero totale di pixel nell'immagine RGB ( ) diviso per 3. Poiché la media può eventualmente generare valori in virgola mobile, è necessaria una chiamata a per arrotondare il numero verso lo zero . combinato con la stringa di formattazione esadecimale ( ) viene utilizzato per stampare ogni valore intero nella media nel suo equivalente esadecimale. Tuttavia, è lì per garantire che uno 0 in più sia riempito a sinistra nel caso in cui il valore medio per qualsiasi canale sia inferiore a 16numel(I)fixsprintf%x02* .

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

Esecuzioni campione

La cosa bella imreadè che puoi leggere le immagini direttamente dagli URL. Come esempio riproducibile, supponiamo che tu abbia scaricato le immagini sul tuo computer e abbia eseguito il codice sopra ... ma per dimostrazione, leggerò le immagini direttamente da Code Golf:

Prima immagine

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

ans =

#53715f

Seconda immagine

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

ans =

#8b7d41

* Nota: questo è stato uno sforzo collaborativo fatto dagli utenti StackOverflow sulla chat room MATLAB e Octave .


7

CJam, 27 byte

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

Questo ha letto un'immagine PPM da STDIN.

CJam non ha un'elaborazione dell'immagine integrata, quindi questo codice prevede una PixMap portatile ASCII (numero magico P3) con una tavolozza completa a 24 bit (valore massimo 255) e nessun commento.

Prova

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

Come funziona

'#     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.

7

HTML5 + JavaScript (ES6), 335 byte

Questo non vincerà, ma mi sono comunque divertito a farlo.

Utilizza l' API HTML5 Canvas . L'input è un URL di un'immagine abilitata per CORS .

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``)}}

dimostrazione

Essendo ES6, attualmente funziona solo con Firefox e 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');


3
Ehi, mi piace che sia eseguibile direttamente nella tua risposta perché è HTML + JS :) +1.
rayryeng - Ripristina Monica il

Non puoi sostituirlo new Imagecon Image()?
Ismael Miguel,

@IsmaelMiguelTypeError: Constructor Image requires 'new'
rink.attendant.6

Una schifezza. Ma puoi creare W='width'e H='height'utilizzare i[H]oi[W]
Ismael Miguel il

1
@IsmaelMiguel che utilizza più personaggi
rink.attendant.6

6

Python [3] + SciPy, 144 133 121

Carica dati pixel, somme per ciascun canale, divide per dimensione *, formati. I valori sono arrotondati a zero.

* dimensioni = larghezza * altezza * canali, quindi moltiplicati per 3

from scipy import misc,sum
i=misc.imread(input())
print('#'+(3*'{:2x}').format(*sum(i.astype(int),axis=(0,1))*3//i.size))

1
Perché non usare input()per prendere il percorso? Ti farà risparmiare 20 byte.
Kade,

Grazie! Sono riuscito a salvare 11 byte però.
Trang Oul,

Hai solo bisogno di un'importazione, import scipy. Cambia m.imreadin misc.imread.
Kade,

Non funziona senza importare Varie, NameError: name 'misc' is not defined. Ho provato from scipy import*, non funziona neanche.
Trang Oul,

2
@TrangOul Che dire from scipy import sum, misc as m? Risparmia quando usi anche la somma, quindi.
matsjoyce,

3

R, 90 byte

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

Il percorso del file PNG viene letto da STDIN. Il pacchetto pngdeve essere installato.

Passo dopo passo:

#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"

2

C, 259 byte

Prende un file PPM senza commenti .

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));}

Processi

Codice iniziale:

#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;
}

Taglia le variabili e rimuovi il ciclo:

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;
}

Da lì ho combinato le varie dichiarazioni in una singola dichiarazione di ritorno. Rimosso e qualsiasi altra informazione di tipo estraneo, variabili rinominate e tagliare gli spazi bianchi.


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('')

2

Java, 449 447 446 430 426 byte

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());}}

Grazie a questa risposta overflow dello stack per il String.formattrucco.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.