Ś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)


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

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+'

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 .


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.

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


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

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"

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ę.


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

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.