Crea imágenes de avatar heladas para la temporada de invierno

29

Es invierno, y ha llegado la época del año para que comience a enfriarse (y para que pronto aparezcan extraños y coloridos sombreros). ¡Escribamos un código para hacer que las imágenes de avatar y otras imágenes se congelen, para que se ajusten al tema!

Entrada

La entrada a las presentaciones para este desafío debe ser una imagen (la imagen que se congelará) y un número (el umbral, que se explicará más adelante).

Puede ingresar la imagen de cualquier manera que su idioma los admita (una ruta de archivo o URL como argumento, tomándola del portapapeles, arrastrando y soltando una imagen, etc.) y en cualquier formato enumerado aquí que exprese colores en RGB (usted puede admitir / requerir RGBA en su lugar si lo desea, pero esto no es un requisito).

También puede ingresar el número de la forma que desee (argumento de línea de comando, STDIN, diálogo de entrada, etc.), con la excepción de codificarlo en su programa (ej. n=10). Si utiliza una ruta / URL de archivo para la imagen, también debe ingresarse de esta manera.

Salida

El programa debe procesar la imagen de acuerdo con la descripción a continuación y luego enviarla de la forma que desee (a un archivo, mostrándola en la pantalla, colocándola en el portapapeles, etc.).

Descripción

Las presentaciones deben procesar la imagen con los siguientes tres pasos. nse refiere al número que recibió su programa como entrada junto con la imagen.

  1. Aplique un desenfoque de radio na la imagen de entrada reemplazando los valores R, G y B de cada píxel con los valores R, G y B promedio de todos los píxeles dentro de una distancia de npíxeles de Manhattan , ignorando todas las coordenadas fuera de los límites. (Es decir, todos los píxeles donde la suma de la diferencia en X y la diferencia en Y es menor o igual que n).

    (nota: utilicé un desenfoque gaussiano para las imágenes de arriba porque tenía una función incorporada conveniente, por lo que sus imágenes pueden verse un poco diferentes).

  2. Establezca cada píxel en un píxel aleatorio dentro de una distancia de n/2píxeles ("distancia" se define de la misma manera que en el paso anterior).

    Esto se debe hacer recorriendo la imagen y estableciendo cada píxel en un píxel aleatorio en este rango, de modo que algunos píxeles puedan desaparecer por completo y otros puedan duplicarse.

    Todos los cambios deben aplicarse al mismo tiempo. En otras palabras, use los valores antiguos de los píxeles (después del paso 1 pero antes de este paso), no los valores nuevos después de establecerlos en un píxel aleatorio.

  3. Multiplique el valor RGB "azul" de cada píxel por 1.5, limitándolo a 255 (o lo que sea el valor máximo para una banda de píxeles) y redondeando hacia abajo.

Reglas

  • Puede usar bibliotecas de imágenes / funciones relacionadas con el procesamiento de imágenes integradas en su idioma; sin embargo, no puede usar ninguna función que realice una de las tres tareas principales mencionadas en la descripción. Por ejemplo, no puede usar una blurfunción, pero una getPixelfunción está bien.

  • Este es el , por lo que gana el código más corto en bytes.

Pomo de la puerta
fuente
1
El paso 1 tiene dos puntos que deben aclararse. En primer lugar, ¿qué métrica? Usted dice Manhattan (L-1) y describe L-infinito. En segundo lugar, ¿cómo deben manejarse los límites de la imagen: sin ajuste, reduciendo el denominador para promediar solo sobre píxeles dentro del límite? El paso 2 tiene un punto que necesita aclaración: ¿se propaga el muestreo de una copia de la imagen después del paso 1 o los cambios desde el principio del paso 2? Para el paso 3, el límite en 255 solo es apropiado en un modelo de color de 24 bits, y la pregunta no lo requiere en ninguna parte.
Peter Taylor
@PeterTaylor He intentado aclarar todos esos puntos, excepto el primero. Realmente no entiendo lo que estás diciendo; dx <= n && dy <= nes una representación precisa de la distancia de Manhattan, ¿no es así?
Pomo de la puerta
No, la distancia de Manhattan es | dx | + | dy | <= n.
Peter Taylor
@PeterTaylor Muy bien, gracias, también lo arreglé.
Pomo de la puerta
1
@stokastic Creo que "dentro de una distancia de n / 2 píxeles" es una declaración perfectamente válida sin redondear / poner el piso n / 2 en absoluto (de manera efectiva, "con piso", creo).
Martin Ender

Respuestas:

14

Pitón 2 - 326 339 358

Toma aportes del usuario. Archivo primero, luego 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')

Esto probablemente podría ser mucho más golf: P ¡Gracias a @ SP3000 por ideas de golf!

Entrada de muestra: (Windows)

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

Editar : error corregido donde se propagaba el azul (Martin con n = 20 ya no es un río; _;)

Martin con n = 2:

ingrese la descripción de la imagen aquí

Martin con n = 10:

ingrese la descripción de la imagen aquí

Martin con n = 20:

ingrese la descripción de la imagen aquí

FryAmTheEggman
fuente
3

Python 2 - 617 bytes

EDITAR: golfed algunos, parece que FryAmTheEggMan me ha vencido :)

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")
estocástico
fuente
3

Java - 1009 bytes

eh, pensé que podría hacerlo mejor que esto ...

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:

ingrese la descripción de la imagen aquí

n = 20:

ingrese la descripción de la imagen aquí

Yo con 10:

ingrese la descripción de la imagen aquí

Estiramiento Maniaco
fuente
Ha pasado un tiempo desde que java'd algo, pero ¿no podrías hacer k&0xFF00? Además, ¿no podrías usarlo 255en lugar de 0xFF?
FryAmTheEggman
3

C, 429 (391 + 38 para definir banderas)

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: pamarchivo sin comentarios o espacios en blanco adicionales en el encabezado, contenido pasado a través de STDIN

n Se requieren argumentos (pueden ser cualquier cosa).

Formato de salida: pamarchivo en 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 el tamaño de la pila; esto puede cambiarse o eliminarse, dependiendo del tamaño de la imagen que se procesa (el programa requiere un tamaño de pila mayor que el doble de píxeles por 4).

-funsigned-chartiene uso de gcc en unsigned charlugar de signed charfor char. Los estándares C permiten cualquiera de estas opciones, y esta opción solo es necesaria aquí porque gcc usa signed charde forma predeterminada.

Para ejecutar (n = 5):

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

Nota: Si la compilación en Windows, stdio.h, fcntl.hy io.hdebe ser incluido, y el código añadido al inicio del siguiente main()con el fin de que el programa de lectura / escritura a STDIN / STDOUT como binario, no en el texto, arroyos (esto es irrelevante en Linux, pero Windows usa en \r\nlugar de \nsecuencias de texto).

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

Versión 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 con n = 10:

Martin con n = 10

Martin con n = 20:

Martin con n = 20

Martin con n = 100:

Martin con n = 100

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

Con saltos de línea para legibilidad:

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

Resultados con n = 2

Mi avatar con n = 2

... con n = 10

con n = 10

... con n = 20

con n = 20

plannapus
fuente