Чорно-білі веселки


60

З огляду на зображення, які мають лише чорні та білі пікселі, та (x, y) розташування, яке є білим пікселем, розфарбуйте білі пікселі на основі їх мінімальної відстані на Манхеттені від (x, y) на шляху, який передбачає лише проходження інших білих пікселів.

Відтінок з кольорових пікселів повинна бути пропорційна відстані від (х, у), так що піксель в точці (х, у) буде мати колірної тон 0 ° (чистий червоний колір) і пікселі далі від (х, у) матиме відтінок 360 ° (також червоний), а інші відтінки змішуються плавно та лінійно між ними. І насиченість, і значення повинні бути 100%.

Якщо білий піксель не з'єднаний з (x, y) через інші білі пікселі, він повинен залишатися білим.

Деталі

  • Вхід буде складатися з назви файла зображення або необроблених даних зображення, плюс цілі числа x та y.
  • Вихідне зображення може бути збережене у файл або перероблене в необработному вигляді для будь-якого загального формату файлу зображень або просто відображатися.
  • Значення x дорівнює 0 на крайньому лівому пікселі, і збільшується, якщо йде справа. Значення y дорівнює 0 у найвищих пікселях і збільшується вниз. (x, y) завжди буде в межах зображення.
  • Дозволені як повні програми, так і функції.

Виграє найкоротший код у байтах.

Приклади

Усі ці зображення були зменшені для економії місця. Клацніть на них, щоб переглянути в повному розмірі.

Вхідне зображення:

приклад 1 вхід

(x,y) = (165,155) і (x,y) = (0,0)

приклад 1 вихід A приклад 1 вихід B


Вхідне зображення та вихід із (x,y) = (0,0):

приклад 5 введення приклад 5 вхід A


Вхідне зображення та вихід із (x,y) = (600,350):

приклад 2 введення приклад 2 вихід


Вхідне зображення та вихід із (x,y) = (0,0):

приклад 3 введення приклад 3 вихід


Вхідне зображення та вихід із (x,y) = (0,0):

приклад 4 введення приклад 4 виведення


Необов’язково -30% бонус: використовуйте евклідову дистанцію. Пропозиція щодо вашого алгоритму полягає в наступному (загальний контур):

  1. Мати стартовий піксель.
  2. Заливка з цього пікселя.
  3. На кожен піксель, досягнутий у заповненні,
  4. Перемістіться від стартового пікселя до цього пікселя кроком на пів-одиниці по прямій лінії.
  5. На кожному кроці застосовуйте int()до координат x і y. Якщо піксель у цих координатах чорний, зупиніться. В іншому випадку продовжуйте. (Це метод прямого бачення.)
  6. Будь-який досягнутий піксель, що межує з білим пікселем та / або пікселем, який раніше був позначений значно більшою відстані (тобто +10), стає піксельним початком.

У більш мета-сенсі цей алгоритм поширюється на кожен доступний піксель по прямій лінії від початкових / вже кольорових пікселів, потім "дюймів" по краях. Біт "значно більшої відстані" призначений для прискорення роботи алгоритму. Чесно кажучи, це не дуже важливо, як ви реалізуєте евклідову дистанцію, вона просто має виглядати приблизно так.

Ось як виглядає перший приклад з евклідовою дистанцією, використовуючи алгоритм, наведений вище:

Вхідне зображення і (x,y) = (165,155)

приклад 1 вхід введіть тут опис зображення


Велике спасибі Calvin'sHobbies та трихоплаксам за допомогу в написанні цього виклику! Веселіться!


7
Я не планую займатися гольфом, але я створив версію Javascript, де ви можете мишувати зображення та кольори миттєво оновлюватись. Тестові зображення тут занадто великі, щоб швидко працювати, тому я б радив спробувати менші зображення, подібні до цього чи цього .
Захоплення Кальвіна

Це круто! Я підозрюю, що це занадто ефективно, щоб бути хорошою базою для версії для гольфу =)
flawr

2
Лабіринти настільки простіше вирішити, коли вони кольорові такі!
mbomb007

Останній приклад справді прекрасний. Чи вхідне зображення є лише шумом?
dylnan

@dylnan: Якщо ви говорите про приклад перед бонусом, це насправді лабіринт. Ви можете натиснути на нього, щоб побачити його в повному розмірі.
El'endia Starman

Відповіді:


33

Матлаб, 255 245 231 байт

Це очікує спочатку ім'я зображення, потім, yа потім x.

I=@input;i=imread(I('','s'));[r,c]=size(i);m=zeros(r,c);m(I(''),I(''))=1;M=m;d=m;K=[1,2,1];for k=1:r*c;d(m&~M)=k;M=m;m=~~conv2(m,K'*K>1,'s');m(~i)=0;end;z=max(d(:));v=[1,1,3];imshow(ind2rgb(d,hsv(z)).*repmat(m,v)+repmat(~d&i,v),[])

Я реалізував заливку (або "dijkstra для 4-кварталів", якщо ви хочете) орієнтовно, спершу створивши маску, у якій насіннєвий піксель встановлений на 1, та з акумулятором відстані (обидва розміру зображення), а потім повторюючи наступне кроки:

  • скласти маску з 4 ядром сусідства (це дуже неефективна частина)
  • встановити всі ненульові пікселі маски на 1
  • встановити всі чорні пікселі зображення на нуль
  • встановіть усі значення в акумуляторі, куди маска змінилася на цьому кроці k
  • збільшити k
  • повторюйте, поки не буде більше змін у масці (я фактично не перевіряю цю умову, а просто використовую кількість пікселів на зображенні як верхню межу, яка зазвичай є дуже поганою верхньою межею, але це codegolf =)

Це залишає нам відстань кожного пікселя від манхеттена до насінного пікселя в акумуляторі відстані. Тоді ми створюємо нове зображення, проходячи через заданий діапазон кольорів і відображаємо відтінок "перший" до нульового значення та "останнього" відтінку до максимальної відстані.

Приклади

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

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

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

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

Як бонус, ось гарне уявлення про те, як розраховується відстань. світліше = далі.

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


3
Це такі речі, які я хотів би роздрукувати для своєї дочки.
rayryeng

@rayryeng Шаблони - це робота El'endia Starman, а не моя =)
flawr

Ви все одно додаєте кольори до зображень: D. Ви зробили останній крок.
rayryeng

4
Я вражений. Я ледве зрозумів виклик lol
zfrisch

Чесно кажучи, те, що я хочу використовувати, це створення пейзажів.
corsiKa

3

Бліц 2D / 3D , 3068 * 0,7 = 2147,6

Це опорна реалізація алгоритму Евкліда, гольфу.

image=LoadImage("HueEverywhere_example1.png")
Graphics ImageWidth(image),ImageHeight(image)
image=LoadImage("HueEverywhere_example1.png")
x=0
y=0
w=ImageWidth(image)
h=ImageHeight(image)
Type start
Field x,y
Field dis#
Field nex.start
End Type
Type cell
Field x,y
Field dis#
End Type
Type oldCell
Field x,y
Field dis#
End Type
initCell.start=New start
initCell\x=x
initCell\y=y
initCell\dis=1
Dim array#(w,h)
imgBuff=ImageBuffer(image)
LockBuffer(imgBuff)
s.start=First start
colr=col(0,0,0)
colg=col(0,0,1)
colb=col(0,0,2)
newcol=colr*256*256+colg*256+colb
WritePixelFast(s\x,s\y,newcol,imgBuff)
While s<>Null
c.cell=New cell
c\x=s\x
c\y=s\y
c\dis=s\dis
While c<>Null
For dy=-1To 1
For dx=-1To 1
If dx*dy=0And dx+dy<>0
nx=c\x+dx
ny=c\y+dy
ndis#=s\dis+Sqr#((nx-s\x)*(nx-s\x)+(ny-s\y)*(ny-s\y))
If nx >= 0And nx<w And ny >= 0And ny<h
If KeyHit(1)End
pixcol=ReadPixelFast(nx,ny,imgBuff)
If pixcol<>-16777216
If array(nx,ny)=0Or ndis<array(nx,ny)
check=1
steps=Ceil(dis)*2
For k=0 To steps
r#=k*1./steps
offx#=Int(s\x+(c\x-s\x)*r)
offy#=Int(s\y+(c\y-s\y)*r)
pixcol2=ReadPixelFast(offx,offy,imgBuff)
If pixcol2=-16777216
check=0
Exit
EndIf
Next
If check
array(nx,ny)=ndis
newCell.cell=New cell
newCell\x=nx
newCell\y=ny
newCell\dis=ndis
EndIf
EndIf
EndIf
EndIf
EndIf
Next
Next
o.oldCell=New oldCell
o\x=c\x
o\y=c\y
o\dis=c\dis
Delete c
c=First cell
Wend
For o.oldCell=Each oldCell
bordersWhite=0
For dy=-1To 1
For dx=-1To 1
If dx<>0Or dy<>0
nx=o\x+dx
ny=o\y+dy
If nx>=0And nx<w And ny>=0And ny<h
pixcol=ReadPixelFast(nx,ny,imgBuff)
If (pixcol=-1And array(nx,ny)=0)Or array(nx,ny)>o\dis+9
bordersWhite=1
Exit
EndIf
EndIf
EndIf
Next
If bordersWhite Exit
Next
If bordersWhite
ns.start=New start
ns\x=o\x
ns\y=o\y
ns\dis=o\dis
s2.start=First start
While s2\nex<>Null
If ns\dis<s2\nex\dis
Exit
EndIf
s2=s2\nex
Wend
ns\nex=s2\nex
s2\nex=ns
EndIf
Delete o
Next
EndIf
s2=s
s=s\nex
Delete s2
Wend
maxDis=0
For j=0To h
For i=0To w
If array(i,j)>maxDis maxDis=array(i,j)
Next
Next
For j=0To h
For i=0To w
dis2#=array(i,j)*360./maxDis
If array(i,j) <> 0
colr=col(dis2,0,0)
colg=col(dis2,0,1)
colb=col(dis2,0,2)
newcol=colr*256*256+colg*256+colb
WritePixelFast(i,j,newcol,imgBuff)
EndIf
Next
Next
UnlockBuffer(imgBuff)
DrawImage image,0,0
Function col(ang1#,ang2#,kind)
While ang1>360
ang1=ang1-360
Wend
While ang1<0 
ang1=ang1+360
Wend
While ang2>180
ang2=ang2-360
Wend
While ang2<-180
ang2=ang2+360
Wend
a3#=ang2/180.
If ang1>300
diff#=(ang1-300)/60.
r=255
g=0
b=255*(1-diff)
ElseIf ang1>240
diff#=(ang1-240)/60.
r=255*diff
g=0
b=255
ElseIf ang1>180
diff#=(ang1-180)/60.
r=0
g=255*(1-diff)
b=255
ElseIf ang1>120
diff#=(ang1-120)/60.
r=0
g=255
b=255*diff
ElseIf ang1>60
diff#=(ang1-60)/60.
r=255*(1-diff)
g=255
b=0
Else
diff#=(ang1-00)/60.
r=255
g=255*diff
b=0
EndIf
If a3>0
r2=r+a3*(255-r)
g2=g+a3*(255-g)
b2=b+a3*(255-b)
Else
r2=r+a3*r
g2=g+a3*g
b2=b+a3*b
EndIf
If r2>255
r2=255
ElseIf r2<0
r2=0
EndIf
If g2>255
g2=255
ElseIf g2<0
g2=0
EndIf
If b2>255
b2=255
ElseIf b2<0
b2=0
EndIf
If kind=0
Return r2
ElseIf kind=1
Return g2
ElseIf kind=2
Return b2
Else
Return 0
EndIf
End Function

Насправді я ненавиджу, як це нечитабельно порівняно з оригіналом. (Що, до речі, 5305 байт.) Насправді я міг би відключити ще декілька байтів, використовуючи одноіменні назви змінних для всього, але це вже досить смішно. І незабаром це не виграш. : P


2

C ++ / SFML: 1271 1235 1226 байт

-36 байт завдяки користувачу202729 -9 байт завдяки Zacharý

#include<SFML\Graphics.hpp>
#include<iostream>
#define V std::vector
#define P e.push_back
#define G(d,a,b,c) case d:return C(a,b,c);
#define FI(r,s)(std::find_if(e.begin(),e.end(),[&a](const T&b){return b==T{a.x+(r),a.y+(s),0};})!=e.end())
using namespace sf;using C=Color;struct T{int x,y,c;bool operator==(const T&a)const{return x==a.x&&y==a.y;}};int max(V<V<int>>&v){int m=INT_MIN;for(auto&a:v)for(auto&b:a)m=b>m?b:m;return m;}C hsv2rgb(int t){int ti=t/60%6;float f=t/60.f-ti,m=(1.f-f)*255,n=f*255;switch(ti){G(0,255,n,0)G(1,m,255,0)G(2,0,255,n)G(3,0,m,255)G(4,n,0,255)G(5,255,0,m)default:throw std::exception();}}void r(Image&a,int x,int y){auto d=a.getSize();V<V<int>>m(d.x,V<int>(d.y));int i=0,j,c=0,t;for(;i<d.y;++i)for(j=0;j<d.x;++j)m[j][i]=a.getPixel(j,i)==C::Black?-1:0;V<T>e{{x,y,1}};while(e.size()){V<T>t=std::move(e);for(auto&a:t){m[a.x][a.y]=a.c;if(a.x>0&&m[a.x-1][a.y]==0&&!FI(-1,0))P({a.x-1,a.y,a.c+1});if(a.y>0&&m[a.x][a.y-1]==0&&!FI(0,-1))P({a.x,a.y-1,a.c+1});if(a.x<m.size()-1&&m[a.x+1][a.y]==0&&!FI(1,0))P({a.x+1,a.y,a.c+1});if(a.y<m[0].size()-1&&m[a.x][a.y+1]==0&&!FI(0,1))P({a.x,a.y+1,a.c+1});}}c=max(m)-1;for(i=0,j;i<d.y;++i)for(j=0;j<d.x;++j)if(m[j][i]>0)a.setPixel(j,i,hsv2rgb(360.f*(m[j][i]-1)/c));}

sf::ImageПараметр також вихідний сигнал (буде змінено). Ви можете використовувати його так:

sf::Image img;
if (!img.loadFromFile(image_filename))
    return -1;

r(img, 0, 0);

if (!img.saveToFile(a_new_image_filename))
    return -2;

Перший параметр - це вхід зображення (і вихід), другий і третій параметри - це xта yпараметр, з якого його потрібно запустити


Корпус комутатора видається настільки марнотратним, що, ймовірно, буде корисним визначення макросу ... Також, чи є `` at setPixel(j, i,hsv2і FI(xm,ym) (std::find_ifдійсно необхідним?
користувач202729

Ви можете видалити пробіл між G(d,a,b,c)і case d:. Також простір між case d:і return C(a,b,c)також непотрібний. (b>m?b:m)не вимагає круглих дужок, і (t/60)%6=> t/60%6в порядку операцій.
Zacharý

Напевно, ви також повинні перейменовувати xmі ymскорочувати імена змінних
Zacharý

Я думаю , що це можливо , щоб видалити простір між G(d,a,b,c)та case, FI, ti, і hsv2rgbкожен може бути замінений більш коротким ім'ям.
Zacharý

1

C ++, 979 969 898 859 848 байт

#include<cstdio>
#include<cstdlib>
#define K 400
#define L 400
#define M (i*)malloc(sizeof(i))
#define a(C,X,Y)if(C&&b[Y][X].c){t->n=M;t=t->n;b[Y][X].d=d+1;t->n=0;t->c=X;t->d=Y;}
#define A(n,d)case n:d;break;
#define F fgetc(f)
#define W(A,B) for(A=0;A<B;A++){
struct i{int c;int d;int v;i*n;}b[L][K]={0},*h,*t;float m=0;int main(){FILE*f=fopen("d","r+b");int x,y,d=0;W(y,L)W(x,K)b[y][x].c=F<<16|F<<8|F;}}rewind(f);x=165,y=155;h=M;h->c=x;h->d=y;b[y][x].d=d;t=h;while(h){i*p=b[h->d]+h->c;if(p->v)h=h->n;else{p->v=1;x=h->c;y=h->d;d=p->d;m=d>m?d:m;a(x>0,x-1,y)a(x<K-1,x+1,y)a(y>0,x,y-1)a(y<L-1,x,y+1)}}W(y,L)W(x,K)i p=b[y][x];unsigned char n=-1,h=p.d/(m/n),R=h%43*6,Q=n*(n-(n*R>>8))>>8,t=n*(n-(n*(n-R)>>8))>>8,r,g,b;switch(h/43){A(0,n,t,0)A(1,Q,n,0)A(2,0,n,t)A(3,0,Q,n)A(4,t,0,n)A(5,n,0,Q)}d=h?r|g<<8|b<<16:p.c?-1:0;fwrite(&d,1,3,f);}}}
  • Вхід: файл даних RGB (міститься у файлі: d)
  • Вихід: RGBA файл даних RGB (виводиться у файлі: d)
  • Приклад: перетворити -depth 8 -розмір "400x400" test.png d.rgb && mv -f d.rgb d && g ++ -o тест main.c && ./test
  • ПРИМІТКА: розмір і початок зображення контролюються на рівні джерела, якщо це проблема, додайте 50 байт чи щось таке - мені просто не було бажання змінити його на чесність.

Не зовсім прямий "ungolf", але це був прототип С, який я знущався першим:

#include "stdio.h"
#include "stdlib.h"

struct i{
    unsigned int c;
    int d;
    int v;
}b[400][400]={0};

typedef struct q{
    int x;
    int y;
    struct q *n;
}q;
q *qu;
q *t;
float m=0;
int get_dist(int x, int y)
{
    int d = 0;

}

void flood(int x,int y,int d){
    qu=malloc(sizeof(q));
    qu->x=x;qu->y=y;b[y][x].d=d;
    t=qu;
    while(qu){
        struct i *p = &b[qu->y][qu->x];
        if(p->v){qu=qu->n; continue;}
        p->v=1;x=qu->x;y=qu->y;d=p->d;
        #define a(C,X,Y) if(C&&b[Y][X].c){t->n=malloc(sizeof(q));t=t->n;b[Y][X].d=d+1;t->n=0;t->x=X;t->y=Y;}
        a(x>0,x-1,y);
        a(x<399,x+1,y);
        a(y>0,x,y-1);
        a(y<399,x,y+1);
        m=p->d>m?p->d:m;
    }
}

unsigned int C(int h)
{
    int r=0,g=0,b=0;
    int s=255,v=255;
    unsigned char R, qq, t;

    R = h%43*6; 

    qq = (v * (255 - ((s * R) >> 8))) >> 8;
    t = (v * (255 - ((s * (255 - R)) >> 8))) >> 8;

    switch (h / 43){
        case 0: r = v; g = t; break;
        case 1: r = qq; g = v; break;
        case 2: g = v; b = t; break;
        case 3: g = qq; b = v; break;
        case 4: r = t; b = v; break;
        case 5: r = v; b = qq; break;
    }

    return r|(g<<8)|(b<<16)|255<<24;
}

#define F fgetc(f)
int main()
{
    FILE *f=fopen("d", "r+b");
    for(int y=0; y<400; y++){
        for(int x=0; x<400; x++){
            b[y][x].c = (F<<24)|(F<<16)|(F<<8);
        }
    }
    rewind(f);
    flood(165,155,1);
    m/=255.f;
    for(int y=0; y<400; y++){
        for(int x=0; x<400; x++){
            struct i p = b[y][x];
            unsigned int h = C(p.d/m);
            int o = p.c?-1:255<<24;
            if(p.d)fwrite(&h,4,1,f);
            else fwrite(&o,4,1,f);
        }
    }
}

Багато концепцій залишаються схожими, але, безумовно, є безліч крихітних змін. Щоб скласти це як C, вам потрібно використовувати C11 (C99, ймовірно, спрацює, але я лише строго перевірений у C11).
Мені дуже сподобався цей виклик, дякую за те, що ви дали мені спробувати щось нове :).
Редагувати: Гольф трохи краще.
Edit2: Об'єднано дві структури, так що моя піксельна структура та черга однакові, трохи більше зловживань макрокомандами та поновлене використання 255 таким чином, що її можна визначити як -1 при визначенні ряду непідписаних символів, і нарешті видалено функцію виклику.
Edit3: Повторно використані ще кілька змінних, налаштування пріоритетності оператора та вихідний сигнал, перетворений на RGB, зберігаючи альфа-канал
Edit4: Я думаю, що я зараз з цим завершив, деякі арифметичні зміни вказівника та незначні налаштування потоку управління.


0

Python 3 та matplotlib, 251 байт

from pylab import*
def f(i,p):
    h,w,_=i.shape;o=full((h,w),inf);q=[p+(0,)]
    while q:
        x,y,d=q.pop(0)
        if w>x>=0and h>y>=0and i[y,x,0]:o[y,x]=d;i[y,x]=0;d+=1;q+=[(x-1,y,d),(x+1,y,d),(x,y-1,d),(x,y+1,d)]
    imshow(i);imshow(o,'hsv')

Вхід - це масивний масив MxNx3, повернутий функцією matplotlib imshow(). Вхід модифікується функцією, тому його слід попередньо скопіювати. Він відображає зображення автоматично, якщо matplotlib знаходиться в «інтерактивному» режимі; в іншому випадку show()слід додати дзвінок ще на 7 байт.

Вихід створюється шляхом спочатку відображення вихідного зображення, а потім відображення зображення веселки над ним. Matplotlib зручно ставиться до інф та нан як до прозорих, так що чорно-біле зображення видно наскрізь.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.