Twórz lodowate zdjęcia awatarów na sezon zimowy

29

Jest zima i nadeszła pora roku, aby zaczęło się robić zimno (i dziwne kolorowe chusty na głowie zaczęły pojawiać się ... wkrótce). Napiszmy kod, aby zamrozić zdjęcia awatarów i inne obrazy, aby pasowały do ​​motywu!

Wkład

Dane wejściowe do zgłoszeń do tego wyzwania powinny być obrazem (obraz, który ma zostać zamrożony) i liczbą (próg, który zostanie wyjaśniony później).

Możesz wprowadzić obraz w dowolny sposób, w jaki obsługuje go Twój język (ścieżka pliku lub adres URL jako argument, biorąc go ze schowka, przeciągając i upuszczając obraz itp.) Oraz w dowolnym wymienionym tutaj formacie, który wyraża kolory w RGB (ty może zamiast tego obsługiwać / wymagać RGBA, ale nie jest to wymagane).

Możesz wprowadzić liczbę w dowolny sposób (argument wiersza poleceń, STDIN, okno dialogowe wprowadzania danych itp.), Z wyjątkiem zakodowania jej na stałe w programie (np. n=10). Jeśli używasz ścieżki pliku / adresu URL obrazu, należy go również wprowadzić w ten sposób.

Wydajność

Program musi przetworzyć obraz zgodnie z poniższym opisem, a następnie wydrukować go w dowolny sposób (do pliku, pokazując go na ekranie, umieszczając w schowku itp.).

Opis

Zgłoszenia powinny przetwarzać obraz w trzech następujących krokach. nodnosi się do liczby otrzymanej przez program jako dane wejściowe wraz z obrazem.

  1. Stosowanie rozmycia promienia ndo obrazu wejściowego przez zastąpienie R każdego piksela, G, i wartości B o średniej R, G, i wartości B wszystkich pikseli w odległości Manhattan z npikseli, ignorując się aut współrzędnych. (Tj. Wszystkie piksele, w których suma różnicy w X i różnicy w Y jest mniejsza lub równa n.)

    (uwaga: Użyłem rozmycia Gaussa dla powyższych obrazów, ponieważ była dla niego wygodna wbudowana funkcja, dzięki czemu twoje obrazy mogą wyglądać nieco inaczej.)

  2. Ustaw każdy piksel na losowy piksel w odległości kilku n/2pikseli („odległość” jest zdefiniowana w taki sam sposób, jak w poprzednim kroku).

    Należy to zrobić, zapętlając obraz i ustawiając każdy piksel na losowy piksel w tym zakresie, aby niektóre piksele zniknęły całkowicie, a niektóre mogły zostać powielone.

    Wszystkie zmiany muszą obowiązywać w tym samym czasie. Innymi słowy, użyj starych wartości pikseli (po kroku 1, ale przed tym krokiem), a nie nowych wartości po ustawieniu ich na losowy piksel.

  3. Pomnóż „niebieską” wartość RGB każdego piksela przez 1,5, ograniczając go do 255 (lub jakąkolwiek maksymalną wartością dla pasma pikseli) i zaokrąglając w dół.

Zasady

  • Możesz korzystać z bibliotek obrazów / funkcji związanych z przetwarzaniem obrazu wbudowanych w twój język; nie można jednak używać żadnych funkcji, które wykonują jedno z trzech głównych zadań wymienionych w opisie. Na przykład nie możesz użyć blurfunkcji, ale getPixelfunkcja jest w porządku.

  • To jest , więc wygrywa najkrótszy kod w bajtach!

Klamka
źródło
1
Krok 1 ma dwa punkty wymagające wyjaśnienia. Po pierwsze, która metryka? Mówisz Manhattan (L-1) i opisujesz L-nieskończoność. Po drugie, w jaki sposób należy postępować z granicami obrazu: bez zawijania, zmniejszając mianownik do średniej tylko ponad pikselami wewnątrz granicy? Krok 2 ma jeden punkt, który wymaga wyjaśnienia: czy pobieranie próbek z kopii obrazu po kroku 1, czy może propagować zmiany od początku kroku 2? W kroku 3 ograniczenie do 255 jest odpowiednie tylko w 24-bitowym modelu kolorów, a pytanie nigdzie tego nie wymaga.
Peter Taylor,
@PeterTaylor Próbowałem wyjaśnić wszystkie te punkty, z wyjątkiem pierwszego. Naprawdę nie rozumiem, co mówisz; dx <= n && dy <= njest dokładnym odwzorowaniem odległości na Manhattanie, prawda?
Klamka
Nie, odległość na Manhattanie wynosi | dx | + | dy | <= n.
Peter Taylor,
@PeterTaylor W porządku, dziękuję, naprawiłem to również.
Klamka
1
@stokastic Myślę, że „w odległości n / 2 pikseli” jest całkowicie poprawnym stwierdzeniem bez zaokrąglania / podłogi n / 2 w ogóle (tak efektywnie „myślę, że”).
Martin Ender,

Odpowiedzi:

14

Python 2 - 326 339 358

Pobiera dane od użytkownika. Najpierw złóż plik 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')

Prawdopodobnie można by grać w golfa o wiele więcej: P Dzięki @ SP3000 za pomysły na golfa!

Przykładowe dane wejściowe: (Windows)

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

Edycja : Naprawiono błąd, w którym propagowano niebieski (Martin z n = 20 nie jest już rzeką; _;)

Martin z n = 2:

wprowadź opis zdjęcia tutaj

Martin z n = 10:

wprowadź opis zdjęcia tutaj

Martin z n = 20:

wprowadź opis zdjęcia tutaj

FryAmTheEggman
źródło
3

Python 2 - 617 bajtów

EDYCJA: trochę grałem w golfa, wygląda na to, że FryAmTheEggMan mnie pobił :)

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")
stokastic
źródło
3

Java - 1009 bajtów

eh, myślałem, że mogę zrobić lepiej niż to ...

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 z n = 5:

wprowadź opis zdjęcia tutaj

n = 20:

wprowadź opis zdjęcia tutaj

Ja z 10:

wprowadź opis zdjęcia tutaj

Stretch Maniac
źródło
Minęło trochę czasu, odkąd java ja coś, ale nie możesz zrobić k&0xFF00? Ponadto, czy nie możesz użyć 255zamiast 0xFF?
FryAmTheEggman
3

C, 429 (391 + 38 dla definicji flag)

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

Format wejściowy: pamplik bez komentarzy lub dodatkowych białych znaków w nagłówku, treść przekazywana przez STDIN.

n argumenty są wymagane (mogą być dowolne).

Format wyjściowy: pamplik w STDOUT.

Kompilować:

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,33554432zwiększa rozmiar stosu; można to zmienić lub usunąć, w zależności od rozmiaru przetwarzanego obrazu (program wymaga rozmiaru stosu większego niż dwukrotność liczby pikseli razy 4).

-funsigned-charma wykorzystanie gcc unsigned charzamiast signed charza char. Standardy C pozwalają na jedną z tych opcji, a ta opcja jest potrzebna tylko tutaj, ponieważ gcc używa signed chardomyślnie.

Aby uruchomić (n = 5):

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

Uwaga: W przypadku kompilacji w systemie Windows stdio.h, fcntl.hi io.hmuszą być uwzględnione, a następujący kod dodany do początku main(), aby program do odczytu / zapisu do STDIN / STDOUT jako binarne, a nie tekst, strumieni (to jest bez znaczenia na Linuksie, ale System Windows używa \r\nzamiast \nstrumieni tekstowych).

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

Skomentowana wersja

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 z n = 10:

Martin z n = 10

Martin z n = 20:

Martin z n = 20

Martin z n = 100:

Martin z n = 100

es1024
źródło
1

R, 440 znaków

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

Z podziałami linii dla czytelności:

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

Przykładowe dane wejściowe: f(2,"avatar.png")

Wyniki przy n = 2

Mój awatar z n = 2

... przy n = 10

przy n = 10

... przy n = 20

przy n = 20

plannapus
źródło