Czarno-białe tęcze

60

Biorąc pod uwagę obraz, który ma tylko czarno-białe piksele i lokalizację (x, y), która jest białym pikselem, pokoloruj białe piksele na podstawie ich minimalnej odległości na Manhattanie od (x, y) na ścieżce, która obejmuje tylko przemieszczenie innych białych pikseli.

Odcienia barwnego pikseli muszą być proporcjonalne do odległości od (x, y), a więc na pikselu (x, y) będą miały odcień w zakresie od 0 ° (czysty kolor czerwony), a piksele najdalej z (x, y), będzie miał odcień 360 ° (także czerwony), a pozostałe odcienie będą płynnie i liniowo mieszać się między nimi. Nasycenia i wartość musi być zarówno 100%.

Jeśli biały piksel nie jest podłączony do (x, y) przez inne białe piksele, musi pozostać biały.

Detale

  • Dane wejściowe będą składały się z nazwy pliku obrazu lub nieprzetworzonych danych obrazu oraz liczb całkowitych xiy.
  • Obraz wyjściowy można zapisać do pliku lub przesłać strumieniowo na standardowe wyjście w dowolnym standardowym formacie pliku obrazu lub po prostu wyświetlić.
  • Wartość x wynosi 0 na skrajnych lewych pikselach i zwiększa się w prawo. Wartość y wynosi 0 w najwyższych pikselach i rośnie w dół. (x, y) zawsze będzie w granicach obrazu.
  • Dozwolone są zarówno pełne programy, jak i funkcje.

Najkrótszy kod w bajtach wygrywa.

Przykłady

Wszystkie te obrazy zostały zmniejszone, aby zaoszczędzić miejsce. Kliknij je, aby wyświetlić w pełnym rozmiarze.

Obraz wejściowy:

przykład 1 wejście

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

przykład 1 wyjście A przykład 1 wyjście B


Obraz wejściowy i wyjściowy za pomocą (x,y) = (0,0):

przykład 5 danych wejściowych przykład 5 wejście A


Obraz wejściowy i wyjściowy za pomocą (x,y) = (600,350):

przykład 2 wejście przykład 2 wyjście


Obraz wejściowy i wyjściowy za pomocą (x,y) = (0,0):

przykład 3 wejście przykład 3 wyjście


Obraz wejściowy i wyjściowy za pomocą (x,y) = (0,0):

przykład 4 wejście przykład 4 wyjście


Opcjonalny bonus -30%: użyj odległości euklidesowej. Sugestia dla twojego algorytmu jest następująca (ogólny zarys):

  1. Mają piksel początkowy.
  2. Wypełnienie z tego piksela.
  3. Dla każdego piksela osiągniętego w wypełnieniu powodziowym
  4. Przejście od piksela początkowego do tego piksela w krokach co pół jednostki, w linii prostej.
  5. Na każdym kroku zastosuj int()do współrzędnych xiy. Jeśli piksel na tych współrzędnych jest czarny, zatrzymaj się. W przeciwnym razie kontynuuj. (Jest to metoda widoczności.)
  6. Każdy osiągnięty piksel, który otacza biały piksel i / lub piksel, który był wcześniej oznaczony znacznie większą odległością (tj. +10), staje się pikselem początkowym.

W bardziej meta sensie, algorytm ten rozciąga się na każdy piksel osiągalny w linii prostej od pikseli początkowych / już kolorowych, a następnie „cali” wokół krawędzi. Bit „znacznie większej odległości” ma na celu przyspieszenie algorytmu. Szczerze mówiąc, tak naprawdę nie ma znaczenia, w jaki sposób wdrażasz odległość euklidesową, po prostu musi wyglądać mniej więcej tak.

Tak wygląda pierwszy przykład z odległością euklidesową przy użyciu powyższego algorytmu:

Wprowadź obraz i (x,y) = (165,155)

przykład 1 wejście wprowadź opis zdjęcia tutaj


Bardzo dziękuję Calvin'sHobby i trichoplax za pomoc w napisaniu tego wyzwania! Baw się dobrze!

El'endia Starman
źródło
7
Nie planuję gry w golfa, ale stworzyłem wersję Javascript, w której można najechać myszką na obrazek, a kolory natychmiast się aktualizują. Obrazy testowe są tu zbyt duże na to, aby uruchomić szybko, więc radzę próbując mniejszych obrazów jak ten lub ten .
Calvin's Hobbies
To jest niesamowite! Podejrzewam, że jest zbyt wydajny, aby być dobrą bazą dla wersji
golfowej
2
Labirynty są o wiele łatwiejsze do rozwiązania, gdy mają takie kolory!
mbomb007,
Ostatni przykład jest naprawdę piękny. Czy obraz wejściowy to po prostu szum?
dylnan
@dylnan: Jeśli mówisz o przykładzie tuż przed premią, to właściwie labirynt. Możesz go kliknąć, aby zobaczyć w pełnym rozmiarze.
El'endia Starman,

Odpowiedzi:

33

Matlab, 255 245 231 bajtów

Oczekuje to najpierw nazwy obrazu, a potem yi potem 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),[])

Zaimplementowałem wypełnienie zalewowe (lub `` dijkstra dla 4 dzielnic '', jeśli chcesz) z grubsza, najpierw tworząc maskę, w której piksel początkowy jest ustawiony na 1, i z akumulatorem odległości (oba wielkości obrazu), a następnie powtarzając następujące kroki:

  • skręć maskę za pomocą 4 sąsiedzkiego jądra (jest to bardzo nieefektywna część)
  • ustaw wszystkie niezerowe piksele maski na 1
  • ustaw wszystkie czarne piksele obrazu na zero
  • ustaw wszystkie wartości w akumulatorze, w którym maska ​​zmieniła się w tym kroku, na k
  • zwiększać k
  • powtarzaj, aż nie będzie już żadnych zmian w masce (faktycznie nie sprawdzam tego warunku, ale po prostu używam liczby pikseli na obrazie jako górnej granicy, która zwykle jest bardzo złą górną granicą, ale jest to kodegolf =)

To pozostawia nam manhattan odległości każdego piksela do piksela nasion w akumulatorze odległości. Następnie tworzymy nowy obraz, przechodząc przez podany zakres kolorów i odwzorowując „pierwszy” odcień na wartość zero, a „ostatni” odcień na maksymalną odległość.

Przykłady

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Jako bonus, tutaj jest ładny obraz tego, jak obliczana jest odległość. jaśniejszy = dalej.

wprowadź opis zdjęcia tutaj

wada
źródło
3
Tego rodzaju rzeczy chciałbym wydrukować dla mojej córki.
rayryeng
@rayryeng Szablony są dziełem El'endii Starman, a nie moje =)
flawr
Nadal nadajesz kolor obrazom: D. Zrobiłeś ostatni krok.
rayryeng
4
Jestem pod wrażeniem. Ledwo mogłem zrozumieć wyzwanie lol
zfrisch
Szczerze mówiąc, chcę to wykorzystać do tworzenia krajobrazów.
corsiKa,
3

Blitz 2D / 3D , 3068 * 0,7 = 2147.6

Jest to referencyjna implementacja algorytmu euklidesowego, golfa.

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

Właściwie to trochę nienawidzę tego, jak nieczytelne w porównaniu do oryginału. (Nawiasem mówiąc, 5305 bajtów.) Właściwie, mógłbym odciąć jeszcze kilka bajtów, używając do tego wszystkiego jednoznakowych nazw zmiennych, ale to już dość śmieszne. I wkrótce nie wygrywa. : P

El'endia Starman
źródło
2

C ++ / SFML: 1271 1235 1226 bajtów

-36 bajtów dzięki user202729 -9 bajtów dzięki 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));}

Ten sf::Imageparametr jest również wyjściem (zostanie zmodyfikowany). Możesz użyć tego w następujący sposób:

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

r(img, 0, 0);

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

Pierwszym parametrem jest wejście obrazu (i wyjście), drugim i trzecim parametrem jest parametr xi ytam, gdzie musi się rozpocząć

HatsuPointerKun
źródło
Obudowa przełącznika wydaje się tak marnotrawstwem, że prawdopodobnie przydałaby się definicja makra ... Czy też `` jest setPixel(j, i,hsv2i FI(xm,ym) (std::find_ifnaprawdę konieczne?
user202729,
Możesz usunąć spację między G(d,a,b,c)i case d:. Również przestrzeń między case d:i nie return C(a,b,c)jest potrzebna. (b>m?b:m)nie wymaga nawiasów i (t/60)%6=> t/60%6według kolejności operacji.
Zacharý
Prawdopodobnie powinieneś także zmienić nazwę xmi ymskrócić nazwy zmiennych
Zacharý
Myślę, że to możliwe, aby usunąć przestrzeń między G(d,a,b,c)i case, FI, ti, i hsv2rgbkażdy może być zastąpiona krótszą nazwą.
Zacharý
1

C ++, 979 969 898 859 848 bajtów

#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);}}}
  • Dane wejściowe: plik danych RGB (zawarty w pliku: d)
  • Wyjście: plik danych RGBA RGB (wyprowadzony w pliku: d)
  • Przykład: konwersja -depth 8 -size „400x400” test.png d.rgb && mv -f d.rgb d && g ++ -o test main.c&& ./test
  • UWAGA: rozmiar obrazu i początek są kontrolowane na poziomie źródła, jeśli jest to problem, dodaj 50 bajtów lub coś - po prostu nie chciałem go zmieniać, aby być szczerym.

Nie do końca bezpośredni „niepozorny”, ale był to prototyp C, z którego najpierw wyszydzałem:

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

Wiele koncepcji pozostaje podobnych, ale z pewnością istnieje mnóstwo drobnych zmian. Aby skompilować to jako C, musisz użyć C11 (C99 prawdopodobnie będzie działać, ale ja tylko ściśle przetestowałem w C11).
Bardzo podobało mi się to wyzwanie, dziękuję za pomysł, aby spróbować czegoś nowego :).
Edycja: Golf był trochę lepszy.
Edycja2: Scaliłem dwie struktury, aby moja struktura pikseli i kolejka były takie same, nieco więcej nadużyć makr, i ponownie wykorzystałem 255, tak że można go zdefiniować jako -1 podczas definiowania serii niepodpisanych znaków, a na koniec usunąć wywołanie funkcji.
Edycja3: Ponownie wykorzystałem kilka dodatkowych zmiennych, ulepszenia pierwszeństwa operatora i dane wyjściowe przekonwertowane na RGB, zapisując kanał alfa.
Edit4: Myślę, że już to zrobiłem, pewne zmiany arytmetyczne wskaźnika i drobne poprawki przepływu sterowania.

p4plus2
źródło
0

Python 3 i matplotlib, 251 bajtów

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')

Dane wejściowe to tablica liczb MxNx3 zwracana przez imshow()funkcję matplotlib . Dane wejściowe są modyfikowane przez funkcję, dlatego należy je wcześniej skopiować. Wyświetla obraz automatycznie, jeśli matplotlib jest w trybie „interaktywnym”; w przeciwnym razie show()należy dodać wywołanie do kolejnych 7 bajtów.

Dane wyjściowe są tworzone poprzez wyświetlenie oryginalnego obrazu, a następnie wyświetlenie nad nim obrazu tęczy. Matplotlib dogodnie traktuje inf i nan jako przezroczyste, dzięki czemu widać czarno-biały obraz.

Ryan McCampbell
źródło