Créez des images d'avatar glacées pour la saison d'hiver

29

C'est l'hiver, et le moment de l'année est venu pour qu'il commence à faire froid (et que d'étranges couvre-chefs colorés commencent à apparaître ... bientôt). Écrivons du code pour faire des images d'avatar et d'autres images gelées, pour s'adapter au thème!

Contribution

La contribution aux soumissions à ce défi devrait être une image (l'image à faire figée) et un nombre (le seuil, qui sera expliqué plus loin).

Vous pouvez saisir l'image de n'importe quelle manière que votre langue prend en charge (un chemin de fichier ou une URL comme argument, la retirer du presse-papiers, faire glisser et déposer une image, etc.) et dans n'importe quel format répertorié ici qui exprime les couleurs en RVB (vous peut prendre en charge / exiger RGBA à la place si vous le souhaitez, mais ce n'est pas une exigence).

Vous pouvez également saisir le numéro de la manière que vous souhaitez (argument de ligne de commande, STDIN, boîte de dialogue de saisie, etc.), à l'exception de le coder en dur dans votre programme (ex. n=10). Si vous utilisez un chemin de fichier / URL pour l'image, il doit également être saisi de cette manière.

Sortie

Le programme doit traiter l'image selon la description ci-dessous, puis la restituer comme vous le souhaitez (dans un fichier, l'afficher à l'écran, la mettre dans le presse-papiers, etc.).

La description

Les soumissions doivent traiter l'image avec les trois étapes suivantes. nfait référence au numéro que votre programme a reçu en entrée avec l'image.

  1. Appliquez un flou de rayon nà l'image d'entrée en remplaçant les valeurs R, G et B de chaque pixel par les valeurs moyennes R, G et B de tous les pixels dans une distance Manhattan de npixels, en ignorant toutes les coordonnées hors limites. (C'est-à-dire tous les pixels où la somme de la différence en X et de la différence en Y est inférieure ou égale à n.)

    (Remarque: j'ai utilisé un flou gaussien pour les images ci-dessus car il y avait une fonction intégrée pratique pour cela, donc vos images pourraient avoir un aspect légèrement différent.)

  2. Définissez chaque pixel sur un pixel aléatoire à une distance de n/2pixels (la "distance" est définie de la même manière qu'à l'étape précédente).

    Cela doit être fait en parcourant l'image et en définissant chaque pixel sur un pixel aléatoire dans cette plage, de sorte que certains pixels peuvent disparaître complètement et certains peuvent être dupliqués.

    Toutes les modifications doivent s'appliquer en même temps. En d'autres termes, utilisez les anciennes valeurs des pixels (après l'étape 1 mais avant cette étape), pas les nouvelles valeurs après les avoir définies sur un pixel aléatoire.

  3. Multipliez la valeur RVB "bleue" de chaque pixel par 1,5, en la plafonnant à 255 (ou quelle que soit la valeur maximale pour une bande de pixels) et en arrondissant vers le bas.

Règles

  • Vous pouvez utiliser des bibliothèques d'images / des fonctions liées au traitement d'images intégrées dans votre langue; cependant, vous ne pouvez pas utiliser de fonctions exécutant l'une des trois tâches principales mentionnées dans la description. Par exemple, vous ne pouvez pas utiliser une blurfonction, mais une getPixelfonction est très bien.

  • C'est le , donc le code le plus court en octets gagne!

Poignée de porte
la source
1
L'étape 1 comporte deux points qui doivent être clarifiés. Premièrement, quelle métrique? Vous dites Manhattan (L-1) et décrivez L-infinity. Deuxièmement, comment gérer les limites de l'image: pas de recouvrement, réduisant le dénominateur à la moyenne uniquement sur les pixels à l'intérieur de la limite? L'étape 2 a un point à clarifier: l'échantillonnage à partir d'une copie de l'image après l'étape 1, ou les changements du début de l'étape 2 peuvent-ils se propager? Pour l'étape 3, le plafonnement à 255 n'est approprié que dans un modèle de couleur 24 bits, et la question ne l'exige nulle part.
Peter Taylor
@PeterTaylor J'ai essayé de clarifier tous ces points, sauf le premier. Je ne comprends pas vraiment ce que vous dites; dx <= n && dy <= nest une représentation précise de la distance de Manhattan, n'est-ce pas?
Poignée de porte
Non, la distance de Manhattan est | dx | + | dy | <= n.
Peter Taylor
@PeterTaylor Très bien, merci, j'ai également corrigé cela.
Poignée de porte
1
@stokastic Je pense que "dans une distance de n / 2 pixels" est une déclaration parfaitement valable sans arrondir / plancher n / 2 du tout (donc effectivement, "parqueté", je pense).
Martin Ender

Réponses:

14

Python 2 - 326 339 358

Prend l'entrée de l'utilisateur. File d'abord, puis 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')

Cela pourrait probablement être joué beaucoup plus: P Merci à @ SP3000 pour les idées de golf!

Exemple d'entrée: (Windows)

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

Edit : Bug corrigé où le bleu se propageait (Martin avec n = 20 n'est plus une rivière; _;)

Martin avec n = 2:

entrez la description de l'image ici

Martin avec n = 10:

entrez la description de l'image ici

Martin avec n = 20:

entrez la description de l'image ici

FryAmTheEggman
la source
3

Python 2 - 617 octets

EDIT: joué au golf, on dirait que FryAmTheEggMan m'a bien battu :)

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
la source
3

Java - 1009 octets

eh, je pensais que je pouvais faire mieux que ça ...

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

entrez la description de l'image ici

n = 20:

entrez la description de l'image ici

Moi avec 10:

entrez la description de l'image ici

Stretch Maniac
la source
Cela fait un moment que je n'ai rien java, mais tu ne peux pas faire k&0xFF00? De plus, ne pourriez-vous pas utiliser 255à la place de 0xFF?
FryAmTheEggman
3

C, 429 (391 + 38 pour définir des drapeaux)

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 d'entrée: pamfichier sans commentaire ni espace supplémentaire dans l'en-tête, contenu transmis via STDIN.

n des arguments sont requis (ils peuvent être n'importe quoi).

Format de sortie: pamfichier en STDOUT.

Compiler:

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,33554432augmente la taille de la pile; cela peut être modifié ou supprimé, selon la taille de l'image en cours de traitement (le programme nécessite une taille de pile supérieure au double du nombre de pixels multiplié par 4).

-funsigned-charutilise gcc unsigned charau lieu de signed charfor char. Les normes C autorisent l'une ou l'autre de ces options, et cette option est uniquement nécessaire ici car gcc utilise signed charpar défaut.

Pour exécuter (n = 5):

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

Remarque: Si la compilation sous Windows, stdio.h, fcntl.het io.hdoit être inclus, et le code suivant ajouté au début de main()afin que le programme de lecture / écriture à STDIN / STDOUT sous forme binaire, pas de texte, les flux (ce qui est hors de propos sur Linux, mais Windows utilise \r\nau lieu de \npour les flux de texte).

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

Version commentée

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

Martin avec n = 10

Martin avec n = 20:

Martin avec n = 20

Martin avec n = 100:

Martin avec n = 100

es1024
la source
1

R, 440 caractères

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

Avec des sauts de ligne pour plus de lisibilité:

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

Exemple d'entrée: f(2,"avatar.png")

Résultats avec n = 2

Mon avatar avec n = 2

... avec n = 10

avec n = 10

... avec n = 20

avec n = 20

plannapus
la source