Schwarzweiss-Regenbogen

60

Bei einem Bild mit nur schwarzen und weißen Pixeln und einer (x, y) -Position, die ein weißes Pixel ist, färben Sie die weißen Pixel basierend auf ihrem minimalen Manhattan-Abstand von (x, y) in einem Pfad, bei dem nur andere weiße Pixel durchlaufen werden.

Der Farbton der farbigen Pixel muss proportional zu ihrem Abstand von (x, y) sein, damit das Pixel bei (x, y) einen Farbton von 0 ° (reines Rot) hat und die Pixel am weitesten von (x, y) entfernt sind. hat einen Farbton von 360 ° (auch rot), wobei die anderen Farbtöne nahtlos und linear dazwischen übergehen. Die Sättigung und der Wert müssen beide 100% betragen.

Wenn ein weißes Pixel nicht über andere weiße Pixel mit (x, y) verbunden ist , muss es weiß bleiben.

Einzelheiten

  • Die Eingabe besteht aus dem Dateinamen des Bildes oder den Rohbilddaten sowie den Ganzzahlen x und y.
  • Das Ausgabebild kann in einer Datei gespeichert oder in einem beliebigen gängigen Bilddateiformat als Pipe-Rohdatei ausgegeben oder einfach angezeigt werden.
  • Der x-Wert ist 0 für die am weitesten links liegenden Pixel und steigt nach rechts. Der y-Wert ist in den obersten Pixeln 0 und steigt nach unten. (x, y) befindet sich immer innerhalb der Bildgrenzen.
  • Es sind sowohl vollständige Programme als auch Funktionen zulässig.

Der kürzeste Code in Bytes gewinnt.

Beispiele

Alle diese Bilder wurden aus Platzgründen verkleinert. Klicken Sie auf die Bilder, um sie in voller Größe anzuzeigen.

Eingabebild:

Beispiel 1 Eingang

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

Beispiel 1 Ausgang A Beispiel 1 Ausgang B


Eingabebild und Ausgabe mit (x,y) = (0,0):

Beispiel 5 Eingabe Beispiel 5 Eingabe A


Eingabebild und Ausgabe mit (x,y) = (600,350):

Beispiel 2 Eingabe Beispiel 2 Ausgabe


Eingabebild und Ausgabe mit (x,y) = (0,0):

Beispiel 3 Eingabe Beispiel 3 Ausgabe


Eingabebild und Ausgabe mit (x,y) = (0,0):

Beispiel 4 Eingabe Beispiel 4 Ausgabe


Optional -30% Bonus: Verwenden Sie die euklidische Distanz. Ein Vorschlag für Ihren Algorithmus lautet wie folgt (allgemeine Gliederung):

  1. Habe ein Startpixel.
  2. Fülle es von diesem Pixel aus.
  3. Für jedes Pixel, das in der Überflutungsfüllung erreicht wird,
  4. Bewegen Sie sich in Schritten von einer halben Einheit in einer geraden Linie von dem Startpixel zu diesem Pixel.
  5. Wenden Sie bei jedem Schritt int()die x- und y-Koordinaten an. Wenn das Pixel an diesen Koordinaten schwarz ist, halten Sie an. Andernfalls fahren Sie fort. (Dies ist eine Sichtlinienmethode.)
  6. Jedes erreichte Pixel, das an ein weißes Pixel angrenzt, und / oder ein Pixel, das zuvor mit einem signifikant höheren Abstand (dh +10) gekennzeichnet war, wird zu einem Startpixel.

In einem metaeren Sinn breitet sich dieser Algorithmus auf jedes Pixel aus, das in einer geraden Linie von den anfänglichen / bereits gefärbten Pixeln aus erreichbar ist, und dann "Zoll" um die Kanten herum. Das Bit "signifikant höherer Abstand" soll den Algorithmus beschleunigen. Ehrlich gesagt spielt es keine Rolle, wie Sie die euklidische Distanz implementieren, es muss nur so aussehen.

So sieht das erste Beispiel mit euklidischer Distanz aus, wobei der obige Algorithmus verwendet wird:

Eingabebild und (x,y) = (165,155)

Beispiel 1 Eingang Bildbeschreibung hier eingeben


Vielen Dank an Calvin'sHobbies und Trichoplax für die Unterstützung beim Schreiben dieser Herausforderung! Habe Spaß!

El'endia Starman
quelle
7
Ich habe nicht vor, Golf zu spielen, aber ich habe eine Javascript-Version erstellt, bei der Sie mit der Maus über das Bild fahren und die Farben sofort aktualisieren können. Die Testbilder hier sind zu groß, um schnell ausgeführt zu werden. Daher würde ich empfehlen, kleinere Bilder wie dieses oder jenes zu verwenden .
Calvins Hobbys
Das ist fantastisch! Ich vermute, es ist zu effizient, um eine gute Basis für eine Golfversion zu sein =)
flawr
2
Labyrinthe sind so viel einfacher zu lösen, wenn sie so gefärbt sind!
mbomb007
Das letzte Beispiel ist wirklich schön. Ist das Eingangsbild nur Rauschen?
Dylnan
@dylnan: Wenn Sie über das Beispiel direkt vor dem Bonus sprechen, ist das eigentlich ein Labyrinth. Sie können darauf klicken, um es in voller Größe zu sehen.
El'endia Starman

Antworten:

33

Matlab, 255 245 231 Bytes

Dies erwartet zuerst den Bildnamen yund dann 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),[])

Ich habe die Überflutungsfüllung (oder 'dijkstra for 4-neighborhoods', wenn Sie möchten) grob implementiert, indem ich zuerst eine Maske erstellt habe, in der das Startbildelement auf 1 gesetzt ist, und einen Abstandsakkumulator (beide Bildgrößen) verwendet und dann die folgenden Schritte wiederholt habe Schritte:

  • Falte die Maske mit einem 4-Viertel-Kernel (dies ist der sehr ineffiziente Teil)
  • Setze alle von Null verschiedenen Pixel der Maske auf 1
  • Setzen Sie alle schwarzen Pixel des Bildes auf Null
  • stellen sie alle werte im akku ein, bei denen sich die maske in diesem schritt geändert hat auf k
  • erhöhen, ansteigen k
  • Wiederholen, bis die Maske nicht mehr geändert wurde (ich überprüfe diese Bedingung nicht, sondern verwende nur die Anzahl der Pixel im Bild als Obergrenze, was normalerweise eine sehr schlechte Obergrenze ist, aber dies ist codegolf =)

Dies lässt uns die Manhattan-Abstände von jedem Pixel zu dem Startpixel in dem Abstandsakkumulator. Dann erstellen wir ein neues Bild, indem wir den vorgegebenen Farbbereich durchlaufen und den "ersten" Farbton auf den Wert Null und den "letzten" Farbton auf den maximalen Abstand abbilden.

Beispiele

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

Bildbeschreibung hier eingeben

Als Bonus hier ein hübsches Bild, wie die Distanz berechnet wird. heller = weiter weg.

Bildbeschreibung hier eingeben

fehlerhaft
quelle
3
Das ist die Art von Sachen, die ich ausdrucken möchte, damit meine Tochter darauf zeichnen kann.
rayryeng - Wiedereinsetzung von Monica
@ rayryeng Die Vorlagen sind El'endia Starmans Arbeit, nicht meine =)
Fehler
Sie haben den Bildern noch Farbe verliehen: D. Du hast den letzten Schritt getan.
rayryeng
4
Ich bin beeindruckt. Ich konnte kaum verstehen , die Herausforderung lol
zfrisch
Ehrlich gesagt, ich möchte damit Landschaften schaffen.
CorsiKa
3

Blitz 2D / 3D , 3068 × 0,7 = 2147,6

Dies ist die Referenzimplementierung für den euklidischen Algorithmus Golfed.

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

Eigentlich hasse ich es, wie unleserlich dies im Vergleich zum Original ist. (Das sind übrigens 5305 Bytes.) Eigentlich könnte ich ein paar Bytes mehr wegschneiden, indem ich für alles einstellige Variablennamen verwende, aber das ist schon lächerlich genug. Und es wird nicht so bald gewinnen. : P

El'endia Starman
quelle
2

C ++ / SFML: 1271 1235 1226 Bytes

-36 Bytes dank user202729 -9 Bytes dank 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));}

Der sf::ImageParameter ist auch die Ausgabe (wird geändert). Du kannst es so benutzen:

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

r(img, 0, 0);

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

Der erste Parameter ist die Bildeingabe (und -ausgabe), der zweite und der dritte Parameter sind die Parameter xund y, bei denen sie beginnen müssen

HatsuPointerKun
quelle
Der Schalterfall scheint so verschwenderisch, dass wahrscheinlich eine Makrodefinition sinnvoll wäre ... Ist auch das `` at setPixel(j, i,hsv2und FI(xm,ym) (std::find_ifwirklich notwendig?
user202729
Sie können das Leerzeichen zwischen G(d,a,b,c)und entfernen case d:. Auch der Abstand zwischen case d:und return C(a,b,c)ist nicht erforderlich. (b>m?b:m)erfordert keine Klammern und (t/60)%6=> t/60%6nach Operationsreihenfolge.
Zacharý
Sie sollten wahrscheinlich auch umbenennen xmund ymzu kürzeren Variablennamen
Zacharý
Ich denke , es ist möglich , den Raum zwischen zu entfernen G(d,a,b,c)und case, FI, tiund hsv2rgbkann jeweils mit einem kürzeren Namen ersetzt werden.
Zacharý
1

C ++, 979 969 898 859 848 Bytes

#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);}}}
  • Eingabe: RGB-Datendatei (enthalten in Datei: d)
  • Ausgabe: RGBA RGB- Datendatei ( Ausgabe in Datei: d)
  • Beispiel: konvertiere -tiefe 8 -größe "400x400" test.png d.rgb && mv -f d.rgb d && g ++ -o test main.c && ./test
  • HINWEIS: Die Bildgröße und der Start werden auf Quellenebene gesteuert. Wenn es sich um ein Problem handelt, fügen Sie 50 Bytes hinzu.

Nicht gerade ein direkter "ungolf", aber dies war ein C-Prototyp, den ich zuerst verspottet habe:

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

Viele Konzepte bleiben ähnlich, aber es gibt sicherlich unzählige kleine Änderungen. Um dies als C zu kompilieren, müssen Sie C11 verwenden (C99 wird wahrscheinlich funktionieren, aber ich habe es nur in C11 streng getestet).
Ich habe diese Herausforderung sehr genossen, danke, dass du mir die Idee gegeben hast, etwas Neues auszuprobieren :).
Edit: Golf wäre ein bisschen besser.
Edit2: Zwei Strukturen wurden zusammengeführt, so dass meine Pixelstruktur und Warteschlange identisch sind, ein bisschen mehr Makromissbrauch und die Verwendung von 255 als -1 definiert werden können, wenn eine Reihe von Zeichen ohne Vorzeichen definiert wird. Zuletzt wurde ein Funktionsaufruf entfernt.
Edit3: Wiederverwendung einiger weiterer Variablen, Optimierung der Operatorpräzision und Konvertierung der Ausgabe in RGB, wobei der Alpha-Kanal
gespeichert wird.

p4plus2
quelle
0

Python 3 und Matplotlib, 251 Bytes

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

Die Eingabe ist ein MxNx3-Numpy-Array, wie es von der matplotlib- imshow()Funktion zurückgegeben wird. Die Eingabe wird von der Funktion so geändert, dass sie vorher kopiert werden sollte. Es zeigt das Bild automatisch an, wenn sich matplotlib im "interaktiven" Modus befindet. Andernfalls sollte ein Aufruf show()für weitere 7 Byte hinzugefügt werden.

Die Ausgabe wird erstellt, indem zuerst das Originalbild und dann das darüberliegende Regenbogenbild angezeigt werden. Matplotlib behandelt inf und nan praktisch als transparent, sodass das Schwarzweißbild durchscheint.

Ryan McCampbell
quelle