Crea immagini avatar ghiacciate per la stagione invernale


29

È inverno, ed è giunto il momento dell'anno per iniziare a fare freddo (e per apparire strani stracci colorati per la testa ... presto). Scriviamo del codice per rendere le immagini degli avatar e altre immagini congelate, per adattarle al tema!

Ingresso

L'input per l'invio di questa sfida dovrebbe essere un'immagine (l'immagine da congelare) e un numero (la soglia, che verrà spiegata in seguito).

Puoi inserire l'immagine in qualsiasi modo la tua lingua li supporti (un percorso di file o URL come argomento, prenderlo dagli appunti, trascinare e rilasciare un'immagine, ecc.) E in qualsiasi formato elencato qui che esprima i colori in RGB (tu puoi supportare / richiedere RGBA invece se vuoi, ma questo non è un requisito).

Puoi inserire il numero nel modo che preferisci (argomento della riga di comando, STDIN, finestra di dialogo di input, ecc.), Ad eccezione di codificarlo nel tuo programma (es. n=10). Se si utilizza un percorso / URL del file per l'immagine, anche questo deve essere inserito in questo modo.

Produzione

Il programma deve elaborare l'immagine secondo la descrizione che segue e quindi emetterla nel modo desiderato (su un file, mostrandolo sullo schermo, mettendolo negli appunti, ecc.).

Descrizione

Gli invii devono elaborare l'immagine con i seguenti tre passaggi. nsi riferisce al numero ricevuto dal programma come input insieme all'immagine.

  1. Applica una sfocatura del raggio nall'immagine di input sostituendo i valori R, G e B di ciascun pixel con i valori R, G e B medi di tutti i pixel entro una distanza di Manhattan di npixel, ignorando tutte le coordinate fuori dai limiti. (Vale a dire tutti i pixel in cui la somma della differenza in X e la differenza in Y è minore o uguale a n.)

    (nota: ho usato una sfocatura gaussiana per le immagini sopra perché c'era una comoda funzione incorporata, quindi le tue immagini potrebbero apparire un po 'diverse.)

  2. Impostare ciascun pixel su un pixel casuale entro una distanza di n/2pixel (la "distanza" è definita nello stesso modo del passaggio precedente).

    Questo dovrebbe essere fatto facendo un ciclo attraverso l'immagine e impostando ciascun pixel su un pixel casuale in questo intervallo, quindi alcuni pixel potrebbero scomparire del tutto e alcuni potrebbero essere duplicati.

    Tutte le modifiche devono essere applicate contemporaneamente. In altre parole, utilizzare i vecchi valori dei pixel (dopo il passaggio 1 ma prima di questo passaggio), non i nuovi valori dopo averli impostati su un pixel casuale.

  3. Moltiplica il valore RGB "blu" di ciascun pixel per 1,5, limitandolo a 255 (o qualunque sia il valore massimo per una banda di pixel) e arrotondando per difetto.

Regole

  • È possibile utilizzare librerie di immagini / funzioni relative all'elaborazione delle immagini integrate nella propria lingua; tuttavia, non è possibile utilizzare alcuna funzione che esegua una delle tre attività principali menzionate nella descrizione. Ad esempio, non è possibile utilizzare una blurfunzione, ma una getPixelfunzione va bene.

  • Questo è , quindi vince il codice più corto in byte!


1
Il passaggio 1 ha due punti che devono essere chiariti. Innanzitutto, quale metrica? Dici Manhattan (L-1) e descrivi L-infinito. In secondo luogo, come devono essere gestiti i confini dell'immagine: nessun avvolgimento, riducendo il denominatore alla media solo sui pixel all'interno del confine? Il passaggio 2 ha un punto che deve essere chiarito: il campionamento da una copia dell'immagine dopo il passaggio 1 o può propagarsi le modifiche dall'inizio del passaggio 2? Per il passaggio 3, il limite a 255 è appropriato solo in un modello di colore a 24 bit e la domanda non lo richiede da nessuna parte.
Peter Taylor,

@PeterTaylor Ho provato a chiarire tutti quei punti, tranne il primo. Non capisco davvero cosa stai dicendo; dx <= n && dy <= nè una rappresentazione accurata della distanza di Manhattan, no?
Maniglia della porta

No, la distanza di Manhattan è | dx | + | dy | <= n.
Peter Taylor,

@PeterTaylor Va bene, grazie, ho risolto anche quello.
Maniglia della porta

1
@stokastic Penso che "entro una distanza di n / 2 pixel" sia un'affermazione perfettamente valida senza arrotondare / pavimentare n / 2 affatto (in modo efficace, "pavimentato", penso).
Martin Ender,

Risposte:


14

Python 2 - 326 339 358

Riceve input dall'utente. Prima il file, quindi n.

from PIL.Image import*;from random import*
a,N=input()
i=open(a)
d=list(i.getdata())
x,y=i.size
R=range(x*y)
m=lambda p,n,r:[p[i]for i in R if abs(n%x-i%x)+abs(n/y-i/y)<=r]
k=d[:]
for p in R:t=map(lambda x:sum(x)/len(x),zip(*m(k,p,N)));d[p]=t[0],t[1],min(255,t[2]*3/2)
i.putdata([choice(m(d,p,N/2))for p in R])
i.save('t.png')

Questo potrebbe probabilmente essere giocato a golf molto di più: P Grazie a @ SP3000 per le idee sul golf!

Input di esempio: (Windows)

"C:/Silly/Optimizer/Trix/Are/For/Kids.png",7

Modifica : Bug risolto in cui il blu veniva propagato (Martin con n = 20 non è più un fiume; _;)

Martin con n = 2:

inserisci qui la descrizione dell'immagine

Martin con n = 10:

inserisci qui la descrizione dell'immagine

Martin con n = 20:

inserisci qui la descrizione dell'immagine


3

Python 2 - 617 byte

EDIT: ho giocato a golf, sembra che FryAmTheEggMan mi abbia battuto :)

from PIL import Image
import sys,random
j,i,n=sys.argv
n=int(n)
i=Image.open(i)
w,h=i.size
o=Image.new("RGB",(w,h))
D=list(i.getdata())
D=[D[i*w:i*w+w] for i in range(h)]
O=[]
d=n/2
z=range(-n,n+1)
M=lambda n:[[x,y] for x in z for y in z if abs(x)+abs(y)<=n]
m=M(n)
L=w*h
for i in range(L):
 y,x=i/w,i%w;c=r=g=b=0
 for q in m:
  try:C=D[y+q[1]][x+q[0]];r+=C[0];g+=C[1];b+=C[2];c+=1
  except:pass
 r/=c;g/=c;b/=c
 O.append((r,g,min(b*3/2,255)))
R=lambda:random.randint(-d,d)
for i in range(L):
 x,y=i%w,i/w;u=R();v=R()
 while not(0<x+u<w and 0<y+v<h):u=R();v=R()
 O[y*w+x]=O[(y+v)*w+(x+u)]
o.putdata(O)
o.save("b.png")

3

Java - 1009 byte

eh, pensavo di poter fare di meglio ...

import java.awt.*;import java.io.*;import java.util.*;import javax.imageio.*;class r{public static void main(String[]v)throws Exception{java.awt.image.BufferedImage i=ImageIO.read(new File("y.png"));int n=Byte.valueOf(v[0]),w=i.getWidth(),h=i.getHeight();for(int z=0;z<w*h;z++){int x=z/h,y=z%h,r=0,g=0,b=0,c=0,x2,y2,k;for(x2=x-n;x2<=x+n;x2++){for(y2=y-n;y2<=y+n;y2++){if(Math.abs(x2-x)+Math.abs(y2-y)<=n&&x2>=0&&x2<w&&y2>=0&&y2<h){k=i.getRGB(x2,y2); r+=(k>>16)&0xFF;g+=(k>>8)&0xFF;b+=k&0xFF;c++;}}}i.setRGB(x,y,new Color(r/c,g/c,b/c).getRGB());}int[]t=new int[w*h];for(int z=0;z<h*w;z++){int x=z/h,y=z%h,x2,y2;ArrayList<Integer>e=new ArrayList<>();for(x2=x-n;x2<=x+n;x2++){for(y2=y-n;y2<=y+n;y2++){if(Math.abs(x2-x)+Math.abs(y2-y)<=n/2&&x2>=0&&y2>=0&&x2<w&&y2<h)e.add(i.getRGB(x2,y2));}}int p=e.get((int)(Math.random()*e.size())),b=(int)((p&0xFF)*1.5);t[x*h+y]=new Color((p>>16)&0xFF,(p>>8)&0xFF,b>255?255:b).getRGB();}for(int d=0;d<w*h;d++){i.setRGB(d/h,d%h,t[d]);}ImageIO.write(i,"PNG",new File("n.png"));}}

import java.awt.*;
import java.io.*;
import java.util.*;
import javax.imageio.*;
class IceBlur{
    public static void main(String[]v)throws Exception{
        java.awt.image.BufferedImage i=ImageIO.read(new File("blah.png"));
        int n=Byte.valueOf(v[0]),w=i.getWidth(),h=i.getHeight();
        for(int z=0;z<w*h;z++){
            int x=z/h,y=z%h,r=0,g=0,b=0,c=0,x2,y2,k;
            for(x2=x-n;x2<=x+n;x2++){
                for(y2=y-n;y2<=y+n;y2++){
                    if(Math.abs(x2-x)+Math.abs(y2-y)<=n&&x2>=0&&x2<w&&y2>=0&&y2<h){
                        k=i.getRGB(x2,y2);
                        r+=(k>>16)&0xFF;
                        g+=(k>>8)&0xFF;
                        b+=k&0xFF;
                        c++;}}}i.setRGB(x,y,new Color(r/c,g/c,b/c).getRGB());}
        int[]t=new int[w*h];
        for(int z=0;z<h*w;z++){
            int x=z/h,y=z%h,x2,y2;
            ArrayList<Integer>e=new ArrayList<>();
            for(x2=x-n;x2<=x+n;x2++){
                for(y2=y-n;y2<=y+n;y2++){
                    if(Math.abs(x2-x)+Math.abs(y2-y)<=n/2&&x2>=0&&y2>=0&&x2<w&&y2<h)e.add(i.getRGB(x2, y2));}}
            int p=e.get((int)(Math.random()*e.size())),b=(int)((p&0xFF)*1.5);
            t[x*h+y]=new Color((p>>16)&0xFF,(p>>8)&0xFF,b>255?255:b).getRGB();}
        for(int d=0;d<w*h;d++){i.setRGB(d/h, d%h, t[d]);}
        ImageIO.write(i,"PNG",new File("blah2.png"));}}

Martin con n = 5:

inserisci qui la descrizione dell'immagine

n = 20:

inserisci qui la descrizione dell'immagine

Io con 10:

inserisci qui la descrizione dell'immagine


È passato un po 'di tempo da quando avevo fatto qualcosa, ma non ci riuscivi k&0xFF00? Inoltre, non potresti usare 255al posto di 0xFF?
FryAmTheEggman,

3

C, 429 (391 + 38 per i flag di definizione)

i,R,G,B,q;char*c,t[99];main(r,a,b,k,z,p){scanf("%*[^ ]%d%*6s%d%[^N]%*[^R]R\n",&a,&b,t);int j=a*b,d[j],e[j];F(c=d;c<d+j;*c++=getchar());F(;i<j;e[i++]=X<<24|B/q<<16|G/q<<8|R/q,R=G=B=q=0)F(k=0;k<j;)p=d[k++],D<r&&(++q,R+=p&X,G+=p>>8&X,B+=p>>16&X);F(i=!printf("P7\nWIDTH %d\nHEIGHT %d%sNDHDR\n",a,b,t);i<j;d[i++]=e[k])F(;k=rand()%j,D>r/2;);F(c=d;q<j*4;i=(q%4-2?2:3)*c[q]/2,putchar(i>X?X:i),++q);}

Formato di input: pamfile senza commenti o spazi bianchi extra nell'intestazione, contenuto trasmesso tramite STDIN.

n sono richiesti argomenti (possono essere qualsiasi cosa).

Formato di output: pamfile in STDOUT.

Compilare:

gcc -DX=255 -DF=for "-DD=z=abs(k-i),z/b+z%a" -Wl,--stack,33554432 -funsigned-char icyavatars.c -o icyavatars

-Wl,--stack,33554432aumenta le dimensioni dello stack; questo può essere modificato o rimosso, a seconda della dimensione dell'immagine in elaborazione (il programma richiede una dimensione dello stack maggiore del doppio del numero di pixel per 4).

-funsigned-charha gcc use al unsigned charposto di signed charfor char. Gli standard C consentono una di queste opzioni, e questa opzione è necessaria solo perché gcc usa signed chardi default.

Per eseguire (n = 5):

./icyavatars random argument here fourth fifth < image.pam > output.pam

Nota: Se la compilazione su Windows, stdio.h, fcntl.he io.hdevono essere inclusi, e il seguente codice aggiunto dell'inizio main()in modo che il programma di lettura / scrittura a STDIN / STDOUT come binario, non il testo, ruscelli (questo è irrilevante su Linux, ma Windows utilizza \r\ninvece che \nper i flussi di testo).

setmode(fileno(stdin), _O_BINARY);
setmode(fileno(stdout), _O_BINARY);

Versione commentata

int i,R,G,B,q;
char *c,t[99];
main(r,a,b,k,z,p){
    // read all of header
    // save a large chunk to t, save width to a, save height to b
    scanf("%*[^ ]%d%*6s%d%[^N]%*[^R]R\n", &a, &b, t);
    // create arrays for holding the pixels
    int j = a * b, d[j], e[j];
    // each pixel is 4 bytes, so we just read byte by byte to the int arrays
    for(c = d; c < d + j; ++c)
        *c=getchar();

    // calculating average rgb
    for(i = 0; i < j; ++i){
        // check every pixel; add r/g/b values to R/G/B if manhattan distance < r-1
        for(k = 0; k < j; ++k){
            // pixel being checked
            p = d[k];
            // manhattan distance
            z = abs(k - i)/b + abs(k - i)%a;
            if(z < r){
                // extract components and add
                ++q;
                R += p & 255;
                G += p >> 8 & 255;
                B += p >> 16 & 255;
            }
        }
        // set pixel in e (not d) to average RGB and 255 alpha
        e[i]= 255<<24 | B/q<<16 | G/q<<8 | R/q;
        // clear temporary variables
        R = G = B = q = 0;      
    }

    // print header
    printf("P7\nWIDTH %d\nHEIGHT %d%sNDHDR\n",a,b,t);
    // choose random pixels
    for(i = 0; i < j; ++i){
        // loop until randomly generated integer represents a pixel that is close enough
        do{
            k = rand() % j;
            // manhattan distance
            z = abs(k - i)/b + abs(k - i)%a;
        }while(z > r/2);
        // set d to the new pixel value
        d[i] = e[k];
    }
    // apply blue scaling and output
    for(c = d, q = 0; q < j * 4; ++q){
        // 3/2 if blue component, 1 otherwise
        i = (q % 4 - 2 ? 2 : 3)*c[q]/2;
        // cap components at 255
        putchar(i > 255 ? 255 : i);
    }
}

Martin con n = 10:

Martin con n = 10

Martin con n = 20:

Martin con n = 20

Martin con n = 100:

Martin con n = 100


1

R, 440 caratteri

f=function(n,p){a=png::readPNG(p);b=a;N=nrow(a);M=ncol(a);r=row(a[,,1]);c=col(a[,,1]);for(i in 1:N)for(j in 1:M)b[i,j,]=apply(a,3,function(x)mean(x[abs(r-i)+abs(c-j)<=n]));for(i in 1:N)for(j in 1:M){g=which(abs(r-i)+abs(c-j)<=n/2,arr.ind=T);o=sample(1:nrow(g),1);b[i,j,]=b[g[o,1],g[o,2],]};b[,,3]=b[,,3]*1.5;b[b>1]=1;png(w=M,h=N);par(mar=rep(0,4));plot(0,t="n",xli=c(1,M),yli=c(1,N),xaxs="i",yaxs="i",ax=F);rasterImage(b,1,1,M,N);dev.off()}

Con interruzioni di riga per leggibilità:

f=function(n,p){
    a=png::readPNG(p) #use readPNG from package png
    b=a
    N=nrow(a)
    M=ncol(a)
    r=row(a[,,1])
    c=col(a[,,1])
    for(i in 1:N){ #braces can be deleted if all is contained in one line
        for(j in 1:M){
            b[i,j,]=apply(a,3,function(x)mean(x[abs(r-i)+abs(c-j)<=n]))
            }
        }
    for(i in 1:N){ #i'm sure this loop could be shortened
        for(j in 1:M){
            g=which(abs(r-i)+abs(c-j)<=n/2,arr.ind=T)
            o=sample(1:nrow(g),1)
            b[i,j,]=b[g[o,1],g[o,2],]
            }
        }
    b[,,3]=b[,,3]*1.5 #readPNG gives RGB values on a [0,1] range, so no need to round
    b[b>1]=1
    png(w=M,h=N)
    par(mar=rep(0,4))
    plot(0,t="n",xli=c(1,M),yli=c(1,N),xaxs="i",yaxs="i",ax=F)
    rasterImage(b,1,1,M,N)
    dev.off()
    }

Input di esempio: f(2,"avatar.png")

Risultati con n = 2

Il mio avatar con n = 2

... con n = 10

con n = 10

... con n = 20

con n = 20

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.