Średni kolor obrazu

21

Średni kolor obrazu

Naukowcy byli w stanie określić średni kolor wszechświata, ale w ilu bajtach możemy znaleźć średni kolor na obrazie?

Twoje zadanie

Twój wkład będzie pojedynczym obrazem, który będziesz musiał znaleźć średnią kolorów na obrazie i wyprowadzić szesnastkowy ciąg kolorów ( #??????). Obraz może mieć dowolny z następujących formatów

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

Dane wejściowe można również traktować jako adres URL / URI obrazu.

Wbudowane funkcje, które obliczają średnie lub próbkują obraz jednocześnie, takie jak ImageMeasurementssą niedozwolone.

Przykłady

Wyniki będą się nieco różnić w zależności od sposobu obliczania średniej i używanych modeli kolorów. Dodałem wartości RGB i LCH (HSV) dla poniższych obrazów.

Próbka 1wyjście: #53715FRGB, może być również #3B7D3DLCH (HSV)


Próbka 2wyjście: #8B7D41RGB, #96753CLCH (HSV)

Downgoat
źródło
Jakie formaty obrazu musimy obsłużyć? W szczególności, czy możemy wybrać obsługę tylko PPM?
Dennis
Czy mogę prosić o mniejszą walizkę testową? Mój skrypt jest bardzo wolny i chociaż uruchamiam go na dużej skrzynce, nie marnuję tego czasu, jeśli jest źle. Lub nawet skrypt, z którym go obliczyłeś.
Maltysen
@Maltysen Dodałem przykład 240x140. Mam nadzieję, że to wystarczająco małe
Downgoat
Czy zawsze powinniśmy zaokrąglać w dół? W pierwszym przykładzie 95.6...zaokrąglono do 95określonego wyniku.
Dennis
4
PS Nie ma sensu zamieszczać pytania w piaskownicy, chyba że zostawisz je tam przez co najmniej 24 godziny, aby ludzie w innych strefach czasowych mogli je zobaczyć, a realistycznie musisz dać 72 godziny, ponieważ nie wszyscy sprawdzają piaskownica obsesyjnie.
Peter Taylor

Odpowiedzi:

19

Pyth - 23 22 19 18 16 bajtów

Transponuje, aby uzyskać wszystkie kanały, a następnie sumuje, dzieli i szesnastkuje każdy. Kończy się przez połączenie i przygotowanie a #.

+\#sm.H/sdldCs'z

Pobiera nazwę pliku obrazu (dowolnego typu) ze standardowego wejścia i wyjścia na standardowe wyjście. BARDZO WOLNY .

+               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

Przykładowy przebieg

>>>pyth avg.pyth 
V5VAR.jpg
#8b7d41
Maltysen
źródło
Możesz określić typ obrazu, jeśli taki istnieje.
isaacg
1
@isaacg good point. To zajmuje wszystko.
Maltysen
Jak to wszystko bierze, czy dekoduje plik JPEG na mapę bitową?
Alec Teal
3
@AlecTeal Zgodnie z dokumentacją Pyth sprawdza, czy plik jest obrazem i automatycznie konwertuje go na mapę bitową. Przeszukując repozytorium GitHub, wygląda na to, że używa PILbiblioteki do obsługi obrazów. Poszukaj tutaj dokładnego źródła.
Bakuriu
@ Bakuriu - Nie głosowałem za odpowiedzią, ponieważ nie wiedziałem, jak Pyth radzi sobie z obrazami, więc wyglądało to trochę podejrzanie ... ale teraz, gdy dostarczyłeś wgląd w to, otrzymuję mój głos. Dziękuję za wyjaśnienie!
rayryeng - Przywróć Monikę
22

Bash, 46 bajtów

ImageMagick skaluje obraz do jednego piksela, który zawiera średnią kolorów na obrazie, a następnie wyświetla go jako tekst.

convert $1 -scale 1x1\! txt:-|egrep -o '#\w+'
SteelRaven
źródło
4
To sprytne! +1
Maltysen
10

MATLAB - 68 bajtów

Obraz jest odczytywany w imreadpołączeniu z, uigetfileaby otworzyć GUI, aby wybrać obraz, który chcesz załadować. Założeniem tego kodu jest to, że wszystkie obrazy są RGB, i aby obliczyć średni kolor, sumujemy dla każdego kanału indywidualnie, a następnie dzielimy przez tyle elementów, ile jest w jednym kanale, czyli całkowitą liczbę pikseli na obrazie RGB ( ) podzieloną przez 3. Ponieważ średnia może ewentualnie generować wartości zmiennoprzecinkowe, konieczne jest wywołanie do zaokrąglenia liczby w dół w kierunku zera . w połączeniu z szesnastkowym łańcuchem formatującym ( * .numel(I)fixsprintf%x ) służy do wydrukowania każdej wartości całkowitej jako wartości średniej w ekwiwalencie szesnastkowym. Jest jednak po 02to, aby dopilnować, aby dodatkowe 0 było wstawiane w lewo, jeśli średnia wartość dla dowolnego kanału będzie mniejsza niż 16

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

Przykładowe przebiegi

Zaletą imreadjest to, że możesz czytać obrazy bezpośrednio z adresów URL. Jako powtarzalny przykład załóżmy, że pobrałeś obrazy na swój komputer i uruchomiłeś powyższy kod ... ale dla celów demonstracyjnych przeczytam obrazy bezpośrednio z Code Golf:

Pierwszy obraz

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

ans =

#53715f

Drugi obraz

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

ans =

#8b7d41

* Uwaga: To był wspólny wysiłek użytkowników StackOverflow na czacie MATLAB i Octave .

rayryeng - Przywróć Monikę
źródło
7

CJam, 27 bajtów

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

To odczytało obraz PPM ze STDIN.

CJam nie ma wbudowanego przetwarzania obrazu, więc ten kod oczekuje Portable PixMap ASCII (magiczna liczba P3) z pełną 24-bitową paletą (maksymalna wartość 255) i bez komentarzy.

Testowe uruchomienie

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

Jak to działa

'#     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
źródło
7

HTML5 + JavaScript (ES6), 335 bajtów

To nie wygra, ale i tak dobrze się bawiłem.

Wykorzystuje HTML5 Canvas API . Dane wejściowe to adres URL obrazu z obsługą 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``)}}

Próbny

Ponieważ jest to ES6, obecnie działa tylko w Firefox i 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');

lodowisko. dozorca 6
źródło
3
Hej, podoba mi się, że można uruchomić bezpośrednio w odpowiedzi, ponieważ jest HTML + JS :) +1.
rayryeng - Przywróć Monikę
Nie można zastąpić new Imagez Image()?
Ismael Miguel
@IsmaelMiguelTypeError: Constructor Image requires 'new'
rink.attendant. 6
Bzdury. Ale możesz stworzyć W='width'i H='height'używać i[H]lubi[W]
Ismael Miguel
1
@ IsmaelMiguel Który używa więcej znaków
rink.attendant.6
6

Python [3] + SciPy, 144 133 121

Ładuje dane w pikselach, sumy dla każdego kanału, dzieli przez rozmiar *, formaty. Wartości są zaokrąglane w kierunku zera.

* size = szerokość * wysokość * kanałów, pomnożona przez 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
źródło
1
Dlaczego nie wykorzystać input()do podążenia ścieżką? Zaoszczędzi ci to 20 bajtów.
Kade
Dzięki! Udało mi się jednak zaoszczędzić 11 bajtów.
Trang Oul,
Musisz tylko jeden import, import scipy. Zmień m.imreadna misc.imread.
Kade
Nie działa bez importowania misc NameError: name 'misc' is not defined. Próbowałem from scipy import*, też nie działa.
Trang Oul,
2
@TrangOul O czym from scipy import sum, misc as m? Zaoszczędzisz także wtedy, gdy użyjesz sumy.
matsjoyce,
3

R, 90 bajtów

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

Ścieżka do pliku PNG jest odczytywana ze STDIN. Pakietpng musi zostać zainstalowany.

Krok po kroku:

#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
źródło
2

C, 259 bajtów

Pobiera plik PPM bez komentarzy .

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

Proces

Kod początkowy:

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

Przytnij zmienne i usuń pętlę:

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

Stamtąd połączyłem różne instrukcje w jedną instrukcję return. Usunęliśmy go i wszelkie inne informacje o typie zewnętrznym, zmieniliśmy nazwy zmiennych i wycięliśmy spację.

LambdaBeta
źródło
2

Kobra - 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('')
Obrzydliwe
źródło
2

Java, 449 447 446 430 426 bajtów

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

Dzięki tej odpowiedzi na przepełnienie stosu dla String.formatlewy.

SuperJedi224
źródło