Crie imagens de avatar geladas para a temporada de inverno

29

É inverno e chegou a época do ano para começar a esfriar (e para estranhos lenços de cabeça coloridos começarem a aparecer ... em breve). Vamos escrever um código para criar imagens de avatar e outras imagens congeladas, para se adequar ao tema!

Entrada

A entrada para os envios para esse desafio deve ser uma imagem (a imagem a congelar) e um número (o limite, que será explicado mais adiante).

Você pode inserir a imagem da maneira que o seu idioma suportar (um caminho de arquivo ou URL como argumento, retirá-la da área de transferência, arrastar e soltar uma imagem etc.) e em qualquer formato listado aqui que expresse cores em RGB (você pode suportar / exigir RGBA, se desejar, mas isso não é um requisito).

Você também pode inserir o número da maneira que desejar (argumento de linha de comando, STDIN, caixa de diálogo de entrada etc.), com a exceção de codificá-lo em seu programa (por exemplo n=10). Se você usar um caminho / URL de arquivo para a imagem, ela deverá ser inserida dessa maneira também.

Saída

O programa deve processar a imagem de acordo com a descrição abaixo e enviá-la da maneira que desejar (para um arquivo, mostrando-o na tela, colocando-o na área de transferência, etc.).

Descrição

As submissões devem processar a imagem com as três etapas a seguir. nrefere-se ao número que seu programa recebeu como entrada junto com a imagem.

  1. Aplique um desfoque de raio nà imagem de entrada, substituindo os valores de R, G e B de cada pixel pelos valores médios de R, G e B de todos os pixels a uma distância de npixels de Manhattan , ignorando todas as coordenadas fora dos limites. (Ou seja, todos os pixels em que a soma da diferença em X e a diferença em Y é menor ou igual a n.)

    (nota: usei um desfoque gaussiano para as imagens acima porque havia uma função interna conveniente para ela, para que suas imagens pudessem parecer um pouco diferentes.)

  2. Defina cada pixel como um pixel aleatório a uma distância de n/2pixels ("distância" é definida da mesma maneira que na etapa anterior).

    Isso deve ser feito percorrendo a imagem e definindo cada pixel para um pixel aleatório nesse intervalo, para que alguns pixels desapareçam completamente e outros possam ser duplicados.

    Todas as alterações devem ser aplicadas ao mesmo tempo. Em outras palavras, use os valores antigos dos pixels (após a etapa 1, mas antes desta etapa), não os novos valores após defini-los para um pixel aleatório.

  3. Multiplique o valor RGB "azul" de cada pixel por 1,5, limitando-o a 255 (ou qualquer que seja o valor máximo para uma faixa de pixels) e arredondando para baixo.

Regras

  • Você pode usar bibliotecas de imagens / funções relacionadas ao processamento de imagens incorporadas ao seu idioma; no entanto, você não pode usar nenhuma função que execute uma das três principais tarefas mencionadas na descrição. Por exemplo, você não pode usar uma blurfunção, mas uma getPixelfunção está correta.

  • Isso é , então o código mais curto em bytes vence!

Maçaneta da porta
fonte
11
O passo 1 tem dois pontos que precisam ser esclarecidos. Em primeiro lugar, qual métrica? Você diz Manhattan (L-1) e descreve L-infinito. Em segundo lugar, como os limites da imagem devem ser tratados: sem quebra, reduzindo o denominador à média apenas dos pixels dentro do limite? A etapa 2 tem um ponto que precisa ser esclarecido: a amostragem de uma cópia da imagem após a etapa 1 ou as alterações do início da etapa 2 podem se propagar? Para a etapa 3, limitar em 255 é apropriado apenas em um modelo de cores de 24 bits, e a pergunta não exige isso em nenhum lugar.
Peter Taylor
@ PeterTaylor Eu tentei esclarecer todos esses pontos, exceto o primeiro. Eu realmente não entendo o que você está dizendo; dx <= n && dy <= né uma representação precisa da distância de Manhattan, não é?
Maçaneta
Não, a distância de Manhattan é | dx | + | dy | <= n.
Peter Taylor
@ PeterTaylor Tudo bem, obrigado, eu também corrigi isso.
Maçaneta
11
@stokastic Eu acho que "a uma distância de n / 2 pixels" é uma afirmação perfeitamente válida sem arredondamentos / pisos n / 2 (de forma eficaz, "floored", eu acho).
Martin Ender

Respostas:

14

Python 2 - 326 339 358

Recebe informações do usuário. Arquivo primeiro, então 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')

Provavelmente, isso poderia ser muito mais praticado: P Graças ao @ SP3000 por idéias de golfe!

Entrada de amostra: (Windows)

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

Edit : Bug corrigido onde o azul estava sendo propagado (Martin com n = 20 não é mais um rio; _;)

Martin com n = 2:

insira a descrição da imagem aqui

Martin com n = 10:

insira a descrição da imagem aqui

Martin com n = 20:

insira a descrição da imagem aqui

FryAmTheEggman
fonte
3

Python 2-617 bytes

EDIT: jogou golfe, parece que FryAmTheEggMan me venceu :)

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
fonte
3

Java - 1009 bytes

eh, eu pensei que poderia fazer melhor que isso ...

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

insira a descrição da imagem aqui

n = 20:

insira a descrição da imagem aqui

Eu com 10:

insira a descrição da imagem aqui

Stretch Maniac
fonte
Já faz um tempo desde que eu java qualquer coisa, mas você não poderia fazer k&0xFF00? Além disso, você não poderia usar 255no lugar de 0xFF?
FryAmTheEggman
3

C, 429 (391 + 38 para definir sinalizadores)

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 de entrada: pam arquivo sem comentários ou espaço em branco extra no cabeçalho, conteúdo transmitido via STDIN.

n argumentos são necessários (eles podem ser qualquer coisa).

Formato de saída: pam arquivo em STDOUT.

Compilar:

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 o tamanho da pilha; isso pode ser alterado ou removido, dependendo do tamanho da imagem que está sendo processada (o programa requer um tamanho de pilha maior que o dobro do número de pixels vezes 4).

-funsigned-chartem o uso do gcc em unsigned charvez de signed charparachar . Os padrões C permitem qualquer uma dessas opções, e essa opção é necessária apenas aqui porque o gcc usa signed charpor padrão.

Para executar (n = 5):

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

Nota: Se a compilação no Windows, stdio.h, fcntl.he io.hdeve ser incluído, e o seguinte código adicionado ao início do main()fim para o programa de leitura / gravação para STDIN / STDOUT como binário, não texto, córregos (isso é irrelevante no Linux, mas Windows usa em \r\nvez de \npara fluxos de texto).

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

Versão comentada

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

Martin com n = 10

Martin com n = 20:

Martin com n = 20

Martin com n = 100:

Martin com n = 100

es1024
fonte
1

R, 440 caracteres

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

Com quebras de linha para legibilidade:

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

Entrada de amostra: f(2,"avatar.png")

Resultados com n = 2

Meu avatar com n = 2

... com n = 10

com n = 10

... com n = 20

com n = 20

plannapus
fonte