Buat gambar avatar dingin untuk musim dingin

29

Ini musim dingin, dan waktu tahun telah datang untuk mulai menjadi dingin (dan untuk jilbab warna-warni yang aneh untuk mulai muncul ... segera). Mari kita menulis beberapa kode untuk membuat gambar avatar dan gambar lain yang membeku, agar sesuai dengan temanya!

Memasukkan

Input untuk pengajuan tantangan ini harus berupa gambar (gambar untuk dibekukan) dan angka (ambang, yang akan dijelaskan nanti).

Anda dapat memasukkan gambar dengan cara apa pun bahasa Anda mendukungnya (jalur file atau URL sebagai argumen, mengambilnya dari clipboard, menyeret dan menjatuhkan gambar, dll.) Dan dalam format apa pun yang tercantum di sini yang mengekspresikan warna dalam RGB (Anda dapat mendukung / membutuhkan RGBA sebagai gantinya jika Anda inginkan, tetapi ini bukan keharusan).

Anda dapat memasukkan nomor dengan cara apa pun yang Anda inginkan (argumen baris perintah, STDIN, dialog input, dll.), Dengan pengecualian hardcoding ke dalam program Anda (mis. n=10). Jika Anda menggunakan jalur file / URL untuk gambar, itu harus dimasukkan dengan cara ini juga.

Keluaran

Program harus memproses gambar sesuai dengan deskripsi di bawah ini dan kemudian menampilkannya dengan cara apa pun yang Anda inginkan (ke file, menunjukkannya di layar, meletakkannya di clipboard, dll.).

Deskripsi

Pengajuan harus memproses gambar dengan tiga langkah berikut. nmengacu pada nomor yang diterima program Anda sebagai input bersama dengan gambar.

  1. Oleskan blur radius nke gambar masukan dengan mengganti R setiap pixel ini, G, dan nilai-nilai B dengan rata-rata R, G, dan nilai-nilai B dari semua piksel dalam jarak Manhattan dari npiksel, mengabaikan semua out-of-batas koordinat. (Yaitu semua piksel dengan jumlah selisih X dan selisih Y kurang dari atau sama dengan n.)

    (catatan: Saya menggunakan blur Gaussian untuk gambar di atas karena ada fungsi bawaan yang nyaman untuk itu, sehingga gambar Anda mungkin terlihat sedikit berbeda.)

  2. Atur setiap piksel ke piksel acak dalam jarak n/2piksel ("jarak" didefinisikan dengan cara yang sama seperti pada langkah sebelumnya).

    Ini harus dilakukan dengan mengulang gambar dan mengatur setiap piksel ke piksel acak dalam rentang ini, sehingga beberapa piksel mungkin hilang seluruhnya dan beberapa mungkin akan diduplikasi.

    Semua perubahan harus berlaku secara bersamaan. Dengan kata lain, gunakan nilai-nilai lama piksel (setelah langkah 1 tetapi sebelum langkah ini), bukan nilai baru setelah mengaturnya ke piksel acak.

  3. Lipat gandakan nilai "biru" RGB dari setiap piksel dengan 1,5, membatasi pada 255 (atau apa pun nilai maksimum untuk pita piksel) dan membulatkan ke bawah.

Aturan

  • Anda dapat menggunakan pustaka gambar / fungsi terkait pemrosesan gambar yang ada dalam bahasa Anda; namun, Anda tidak dapat menggunakan fungsi apa pun yang melakukan salah satu dari tiga tugas utama yang disebutkan dalam deskripsi. Misalnya, Anda tidak dapat menggunakan blurfungsi, tetapi getPixelfungsi itu baik-baik saja.

  • Ini adalah , jadi kode terpendek dalam byte menang!

Gagang pintu
sumber
1
Langkah 1 memiliki dua poin yang perlu diklarifikasi. Pertama, metrik yang mana? Anda mengatakan Manhattan (L-1) dan menggambarkan L-infinity. Kedua, bagaimana seharusnya batas gambar ditangani: tidak ada pembungkus, mengurangi penyebut menjadi rata-rata hanya piksel di dalam batas? Langkah 2 memiliki satu poin yang perlu diklarifikasi: apakah pengambilan sampel dari salinan gambar setelah langkah 1, atau dapatkah perubahan dari awal pada langkah 2 menyebar? Untuk langkah 3, pembatasan pada 255 hanya sesuai dalam model warna 24-bit, dan pertanyaannya tidak mengharuskan.
Peter Taylor
@PeterTaylor Saya sudah mencoba mengklarifikasi semua poin itu, kecuali yang pertama. Saya tidak begitu mengerti apa yang Anda katakan; dx <= n && dy <= nadalah representasi jarak Manhattan yang akurat, bukan?
Gagang Pintu
Tidak, jarak Manhattan adalah | dx | + | dy | <= n.
Peter Taylor
@ PeterTaylor Baiklah, terima kasih, saya sudah memperbaikinya juga.
Gagang Pintu
1
@stokastic Saya pikir "dalam jarak n / 2 piksel" adalah pernyataan yang benar-benar valid tanpa pembulatan / lantai n / 2 sama sekali (sangat efektif, "berlantai", saya pikir).
Martin Ender

Jawaban:

14

Python 2 - 326 339 358

Mengambil input dari pengguna. File pertama, lalu 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')

Ini mungkin bisa bermain golf lebih banyak: P Terima kasih kepada @ SP3000 untuk ide golf!

Input sampel: (Windows)

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

Sunting : Bug diperbaiki di mana biru sedang diperbanyak (Martin dengan n = 20 bukan lagi sungai; _;)

Martin dengan n = 2:

masukkan deskripsi gambar di sini

Martin dengan n = 10:

masukkan deskripsi gambar di sini

Martin dengan n = 20:

masukkan deskripsi gambar di sini

FryAmTheEggman
sumber
3

Python 2 - 617 Bytes

EDIT: bermain golf beberapa, sepertinya FryAmTheEggMan telah mengalahkan saya :)

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")
stokastik
sumber
3

Java - 1009 byte

eh, saya pikir saya bisa melakukan lebih baik dari ini ...

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

masukkan deskripsi gambar di sini

n = 20:

masukkan deskripsi gambar di sini

Saya dengan 10:

masukkan deskripsi gambar di sini

Regangkan Maniac
sumber
Sudah lama sejak saya melakukan sesuatu java, tapi tidak bisa Anda lakukan k&0xFF00? Selain itu, tidak bisa Anda gunakan 255di tempat 0xFF?
FryAmTheEggman
3

C, 429 (391 + 38 untuk mendefinisikan 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 input: pamfile tanpa komentar atau spasi kosong di header, konten diteruskan melalui STDIN.

n diperlukan argumen (bisa berupa apa saja).

Format output: pam file dalam STDOUT.

Untuk mengkompilasi:

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,33554432meningkatkan ukuran tumpukan; ini dapat diubah atau dihapus, tergantung pada ukuran gambar yang sedang diproses (program membutuhkan ukuran tumpukan lebih besar dari dua kali jumlah piksel kali 4).

-funsigned-charmemiliki penggunaan gcc unsigned charalih-alih signed charuntuk char. Standar C memungkinkan untuk salah satu dari opsi ini, dan opsi ini hanya diperlukan di sini karena penggunaan gccsigned char secara default.

Untuk menjalankan (n = 5):

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

Catatan: Jika kompilasi pada Windows, stdio.h, fcntl.hdan io.hharus disertakan, dan kode ditambahkan ke awal berikut main()agar program untuk membaca / menulis ke STDIN / STDOUT sebagai biner, tidak teks, sungai (ini tidak relevan di Linux, tapi Penggunaan Windows \r\nalih-alih \nuntuk stream teks).

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

Versi yang dikomentari

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

Martin dengan n = 10

Martin dengan n = 20:

Martin dengan n = 20

Martin dengan n = 100:

Martin dengan n = 100

es1024
sumber
1

R, 440 karakter

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

Dengan jeda baris untuk keterbacaan:

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 sampel: f(2,"avatar.png")

Hasil dengan n = 2

Avatar saya dengan n = 2

... dengan n = 10

dengan n = 10

... dengan n = 20

dengan n = 20

plannapus
sumber