Kış sezonu için buzlu avatar görüntüleri oluşturun


29

Kış mevsimi ve yılın soğumaya başlaması için geldi (ve garip renkli saçların ortaya çıkmaya başlaması ... yakında). Avatar resimlerini ve diğer görüntüleri donmuş yapmak için temaya uydurmak için biraz kod yazalım!

Giriş

Bu zorluğa katılacak girdiler bir resim (dondurulacak resim) ve bir sayı (daha sonra açıklanacak eşik) olmalıdır.

Resmi, dilinizin desteklediği herhangi bir şekilde (bir dosya yolu veya argüman olarak bir URL, panodan alarak, bir resmi sürükleyip bırakarak, vb.) Ve burada renkleri RGB olarak ifade eden herhangi bir formatta girebilirsiniz. isterseniz RGBA'yı destekleyebilir / talep edebilir, ancak bu bir gereklilik değildir.

Numarayı istediğiniz şekilde (komut satırı argümanı, STDIN, giriş diyalogu, vb. n=10) Programınıza kodlama haricinde girebilirsiniz (ör. ). Görüntü için bir dosya yolu / URL kullanıyorsanız, bu şekilde de girilmelidir.

Çıktı

Program, görüntüyü aşağıdaki açıklamaya göre işlemeli ve sonra istediğiniz şekilde (bir dosyaya, ekranda göstererek, panoya koyarak vb.) Çıkarmalıdır.

Açıklama

Gönderimler, görüntüyü aşağıdaki üç adımda işlemelidir. nprogramınızın resimle birlikte girdi olarak aldığı sayı anlamına gelir.

  1. Yarıçapın bir bulanıklık uygulama nortalama R, G, ve içindeki bütün pikseller B değerleri, her bir pikselin R, G ve B değerleri değiştirilerek giriş görüntüsüne Manhattan mesafe arasında n, piksel her dışı sınırları koordinatları dikkate almaz. (Yani, X'deki farkın toplamı ve Y'deki farkın toplamının ona eşit veya daha küçük olduğu tüm pikseller n.)

    (not: Yukarıdaki resimler için Gauss bulanıklığı kullandım, çünkü bunun için uygun bir yerleşik işlev vardı, bu yüzden resimleriniz biraz farklı görünebilir.)

  2. Her pikseli piksel mesafesindeki rastgele bir piksele ayarlayın n/2("mesafe", önceki adımdakiyle aynı şekilde tanımlanır).

    Bu, görüntüde dolaşarak ve her pikseli bu aralıkta rastgele bir piksele ayarlayarak yapılmalıdır, böylece bazı pikseller tamamen kaybolabilir ve bazıları çoğaltılabilir.

    Tüm değişiklikler aynı anda uygulanmalıdır. Başka bir deyişle, piksellerin eski değerlerini kullanın (adım 1'den sonra ancak bu adımdan önce), yeni değerleri rastgele bir piksele ayarladıktan sonra kullanmayın.

  3. Her pikselin "mavi" RGB değerini 1,5 ile çarpın, 255'te kapatın (veya bir piksel bandı için maksimum değer ne olursa olsun) ve aşağı yuvarlayın.

kurallar

  • Dilinizde yerleşik olan görüntü kitaplıklarını / görüntü işleme ile ilgili işlevleri kullanabilirsiniz; ancak, açıklamada belirtilen üç ana görevden birini gerçekleştiren işlevleri kullanamazsınız. Örneğin, bir blurişlevi kullanamazsınız , ancak bir getPixelişlev iyidir.

  • Bu , yani bayttaki en kısa kod kazanır!


1
1. adımda netleştirilmesi gereken iki nokta vardır. İlk olarak, hangi metrik? Manhattan (L-1) diyor ve L-sonsuzluğunu açıklıyorsun. İkincisi, görüntü sınırları nasıl ele alınmalıdır: sarma yok, paydayı sınırın içindeki piksellerin üzerinde ortalamaya indirgemek için? 2. adımda netleştirilmesi gereken bir nokta vardır: 1. adımdan sonra görüntünün bir kopyasından örnekleme mi, yoksa 2. adımın başından itibaren değişebilir mi? 3. adım için, 255'te sınırlama yalnızca 24 bit renk modelinde uygundur ve soru hiçbir yerde bunu gerektirmez.
Peter Taylor

@PeterTaylor Birincisi dışındaki tüm bu noktaları açıklığa kavuşturmaya çalıştım. Ne dediğini anlamıyorum; dx <= n && dy <= nManhattan mesafesinin doğru bir temsili, değil mi?
Doorknob

Hayır, Manhattan mesafesi | dx | + | dy | <= n.
Peter Taylor

@ PeterTaylor Tamam, teşekkürler, ben de düzelttim.
Doorknob

1
@stokastic Bence "n / 2 piksel mesafesi içinde" n / 2'yi yuvarlama / döşeme yapmadan mükemmel bir şekilde ifade ediyor (çok etkili, "döşeme", sanırım).
Martin Ender

Yanıtlar:


14

Python 2 - 326 339 358

Kullanıcıdan girdi alır. Önce dosya, sonra 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')

Bu muhtemelen çok daha fazla golf oynayabilir: P Golf fikirleri için @ SP3000'e teşekkürler!

Örnek giriş: (Windows)

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

Düzenleme : Mavinin yayıldığı yerdeki hata giderildi (n = 20 olan Martin artık bir nehir değil; _;)

N = 2 olan Martin:

görüntü tanımını buraya girin

Martin, n = 10 ile:

görüntü tanımını buraya girin

N = 20 olan Martin:

görüntü tanımını buraya girin


3

Python 2 - 617 Bayt

EDIT: golf oynadı, FryAmTheEggMan beni dövdü gibi görünüyor :)

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 bayt

Bundan daha iyisini yapabileceğimi düşündüm.

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

görüntü tanımını buraya girin

N = 20:

görüntü tanımını buraya girin

Benimle 10:

görüntü tanımını buraya girin


Bir şeyleri java ettiğimden bu yana bir süre geçti, ama yapamaz k&0xFF00mısın? Ayrıca, yerine kullanamaz 255mıydınız 0xFF?
FryAmTheEggman

3

C, 429 (bayrakları tanımlamak için 391 + 38)

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

Giriş formatı: pamyorum içermeyen veya başlıkta fazla boşluk bırakılan dosya, içerik STDIN'den geçirildi.

n Argümanlar gereklidir (herhangi bir şey olabilir).

Çıkış formatı: pamSTDOUT dosya.

Derlemek için:

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,33554432yığın boyutunu artırır; bu, işlenmekte olan resmin boyutuna bağlı olarak değiştirilebilir veya kaldırılabilir (program, piksel sayısının 4 katından iki kat daha büyük bir yığın boyutu gerektirir).

-funsigned-chargcc kullanımı vardır unsigned charyerine signed chariçin char. C standartları bu seçeneklerden herhangi birine izin verir ve bu seçenek sadece burada gereklidir, çünkü gcc signed charvarsayılan olarak kullanır .

Çalıştırmak için (n = 5):

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

Not: Windows üzerinde derleme, varsa stdio.h, fcntl.hve io.hdahil edilmelidir ve başlangıcına eklenen aşağıdaki kod main()ikili, değil metin, dereler gibi program için sırayla STDIN / STDOUT okuma / yazma (bu, Linux üzerinde alakasız ama Windows, metin akışları \r\nyerine kullanır ( \n).

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

Yorumlanan sürüm

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

Martin, n = 10

N = 20 olan Martin:

Martin, n = 20

N = 100 olan Martin:

N = 100 olan Martin


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

Okunabilirlik için satır sonları ile:

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

Örnek giriş: f(2,"avatar.png")

N = 2 ile sonuçlanan

N = 2 olan avatarım

... n = 10 ile

n = 10 ile

... n = 20 olan

n = 20 olan

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.