Создание ледяных аватаров для зимнего сезона


29

Сейчас зима, и пришло время года, чтобы оно стало холодным (и чтобы странные разноцветные головные уборы начали появляться ... скоро). Давайте напишем некоторый код, чтобы сделать картинки аватара и другие изображения замороженными, чтобы соответствовать теме!

вход

Входными данными для подачи заявки на участие в этом конкурсе должны быть изображение (изображение, которое нужно сделать замороженным) и число (порог, который будет объяснен позже).

Вы можете вводить изображение любым способом, которым поддерживает их ваш язык (путь к файлу или URL-адрес в качестве аргумента, извлечение его из буфера обмена, перетаскивание изображения и т. Д.), А также в любом из перечисленных здесь форматов, который выражает цвета в RGB (вы вместо этого может поддерживать / требовать RGBA, но это не является обязательным требованием).

Вы можете также ввести число любым удобным для вас способом (аргумент командной строки, STDIN, диалоговое окно ввода и т. Д.), За исключением жесткого кодирования его в вашей программе (например n=10). Если вы используете путь к файлу / URL для изображения, его также необходимо ввести таким же образом.

Выход

Программа должна обработать изображение в соответствии с описанием ниже, а затем вывести его любым удобным для вас способом (в файл, показать его на экране, поместить в буфер обмена и т. Д.).

Описание

Материалы должны обработать изображение с помощью следующих трех шагов. nотносится к числу, которое ваша программа получила в качестве входных данных вместе с изображением.

  1. Примените размытие радиуса nк входному изображению, заменив значения R, G и B каждого пикселя средними значениями R, G и B для всех пикселей на расстоянииn пикселей от Манхэттена , игнорируя все координаты за пределами границ. (Т.е. все пиксели, в которых сумма разности по X и разности по Y меньше или равна n.)

    (примечание: я использовал размытие по Гауссу для изображений выше, потому что для него была удобная встроенная функция, поэтому ваши изображения могут выглядеть немного иначе.)

  2. Установите для каждого пикселя случайный пиксель в пределах расстояния от n/2пикселей («расстояние» определяется так же, как и на предыдущем шаге).

    Это должно быть сделано путем циклического прохода по изображению и установки каждого пикселя на случайный пиксель в этом диапазоне, чтобы некоторые пиксели могли полностью исчезнуть, а некоторые могли бы дублироваться.

    Все изменения должны применяться одновременно. Другими словами, используйте старые значения пикселей (после шага 1, но до этого шага), а не новые значения после установки их в случайный пиксель.

  3. Умножьте «синее» значение RGB каждого пикселя на 1,5, ограничив его значением 255 (или любым другим максимальным значением для полосы пикселей) и округлив вниз.

правила

  • Вы можете использовать библиотеки изображений / функции, связанные с обработкой изображений, встроенные в ваш язык; тем не менее, вы не можете использовать какие-либо функции, которые выполняют одну из трех основных задач, упомянутых в описании. Например, вы не можете использовать blurфункцию, но getPixelфункция в порядке.

  • Это , поэтому выигрывает самый короткий код в байтах!


1
Шаг 1 имеет два момента, которые необходимо прояснить. Во-первых, какой показатель? Вы говорите Манхэттен (L-1) и описываете L-бесконечность. Во-вторых, как следует обрабатывать границы изображения: без переноса, уменьшая знаменатель до среднего только по пикселям внутри границы? У шага 2 есть один момент, который необходимо уточнить: является ли выборка из копии изображения после шага 1, или могут распространяться изменения с начала шага 2? Для шага 3 ограничение 255 подходит только для 24-битной цветовой модели, и вопрос нигде не требует этого.
Питер Тейлор

@PeterTaylor Я попытался прояснить все эти моменты, кроме первого. Я не очень понимаю, что вы говорите; dx <= n && dy <= nэто точное представление о расстоянии Манхэттена, не так ли?
Дверная ручка

Нет, Манхэттенское расстояние | dx | + | DY | <= п.
Питер Тейлор

@PeterTaylor Хорошо, спасибо, я тоже это исправил.
Дверная ручка

1
@stokastic Я думаю, что "на расстоянии n / 2 пикселя" - совершенно правильное утверждение без округления / наложения n / 2 вообще (так эффективно, я думаю, что "floored").
Мартин Эндер

Ответы:


14

Python 2 - 326 339 358

Принимает участие от пользователя. Сначала файл, потом 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')

Это, вероятно, может быть гораздо лучше: P Спасибо @ SP3000 за идеи гольфа!

Пример ввода: (Windows)

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

Редактировать : Исправлена ​​ошибка, когда синий размножался (Мартин с n = 20 больше не река; _;)

Мартин с n = 2:

введите описание изображения здесь

Мартин с n = 10:

введите описание изображения здесь

Мартин с n = 20:

введите описание изображения здесь


3

Python 2 - 617 байт

РЕДАКТИРОВАТЬ: игра в гольф некоторые, похоже, FryAmTheEggMan заставил меня победить, хотя

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 байт

да, я думал, что мог бы сделать лучше, чем это ...

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

Мартин с n = 5:

введите описание изображения здесь

п = 20:

введите описание изображения здесь

Мне с 10

введите описание изображения здесь


Я давно ничего не делал, но разве ты не мог k&0xFF00? Кроме того, вы не могли бы использовать 255вместо 0xFF?
FryAmTheEggman

3

C, 429 (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);}

Формат ввода: pamфайл без комментариев или лишних пробелов в заголовке, содержимое передается через STDIN.

n аргументы обязательны (они могут быть чем угодно).

Формат вывода: pamфайл в STDOUT.

Скомпилировать:

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,33554432увеличивает размер стека; это может быть изменено или удалено в зависимости от размера обрабатываемого изображения (программе требуется размер стека, превышающий число пикселей в 4 раза).

-funsigned-charимеет использование GCC unsigned charвместо signed charдля char. Стандарты C допускают любую из этих опций, и эта опция нужна только здесь, потому что gcc использует signed charпо умолчанию.

Для запуска (n = 5):

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

Примечание: Если компиляции на Windows, stdio.h, fcntl.hи io.hдолжны быть включены, и следующий добавляется в начале кода main()для того , чтобы программа для чтения / записи на STDIN / STDOUT в двоичный, а не текст, потоки (это не имеет значения , на Linux, но Windows использует \r\nвместо \nтекстовых потоков).

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

Комментируемая версия

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

Мартин с n = 10:

Мартин с n = 10

Мартин с n = 20:

Мартин с n = 20

Мартин с n = 100:

Мартин с n = 100


1

R, 440 символов

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

С разрывами строки для удобочитаемости:

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

Пример ввода: f(2,"avatar.png")

Результаты с n = 2

Мой аватар с n = 2

... с n = 10

с n = 10

... с n = 20

с n = 20

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.