Arc-en-ciel noir et blanc


60

Pour une image comportant uniquement des pixels noirs et blancs et un emplacement (x, y) qui est un pixel blanc, colorez les pixels blancs en fonction de leur distance minimale de Manhattan à partir de (x, y) dans un tracé qui implique uniquement de traverser d'autres pixels blancs.

La teinte des pixels colorés doit être proportionnelle à leur distance par rapport à (x, y). Ainsi, le pixel situé en (x, y) aura une teinte de 0 ° (rouge pur) et les pixels les plus éloignés de (x, y). aura une teinte de 360 ​​° (également rouge), avec les autres teintes se mélangeant de manière transparente et linéaire entre les deux. La saturation et la valeur doivent être toutes deux 100%.

Si un pixel blanc n'est pas connecté à (x, y) via d'autres pixels blancs, il doit rester blanc.

Détails

  • L'entrée consistera en le nom de fichier de l'image ou des données d'image brutes, plus les entiers x et y.
  • L'image de sortie peut être enregistrée dans un fichier ou transférée brute sur stdout dans n'importe quel format de fichier d'image commun, ou simplement affichée.
  • La valeur x est 0 sur les pixels les plus à gauche et augmente en allant à droite. La valeur y est 0 dans les pixels les plus élevés et augmente en descendant. (x, y) sera toujours dans les limites de l'image.
  • Les programmes complets et les fonctions sont autorisés.

Le code le plus court en octets gagne.

Exemples

Toutes ces images ont été réduites pour gagner de la place. Cliquez dessus pour voir en taille réelle.

Image d'entrée:

exemple 1 entrée

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

exemple 1 sortie A exemple 1 sortie B


Image d'entrée et sortie avec (x,y) = (0,0):

exemple 5 entrée exemple 5 entrée A


Image d'entrée et sortie avec (x,y) = (600,350):

exemple 2 entrée exemple 2 sortie


Image d'entrée et sortie avec (x,y) = (0,0):

exemple 3 entrée exemple 3 sortie


Image d'entrée et sortie avec (x,y) = (0,0):

exemple 4 entrée exemple 4 sortie


Bonus optionnel de -30%: utilisez la distance euclidienne. Une suggestion pour votre algorithme est la suivante (aperçu général):

  1. Avoir un pixel de départ.
  2. Remplir de ce pixel.
  3. Pour chaque pixel atteint dans le remplissage d'inondation,
  4. Déplacez le pixel de départ vers ce pixel par demi-unités, en ligne droite.
  5. À chaque étape, appliquez int()les coordonnées x et y. Si le pixel à ces coordonnées est noir, arrêtez. Sinon, continuez. (Ceci est une méthode en ligne de mire.)
  6. Tout pixel atteint qui borde un pixel blanc et / ou un pixel précédemment étiqueté avec une distance beaucoup plus grande (+10) devient un pixel de départ.

Dans un sens plus méta, cet algorithme se propage à chaque pixel accessible en ligne droite à partir des pixels de départ / déjà colorés, puis en "pouces" autour des bords. Le bit "distance significativement plus élevée" est destiné à accélérer l'algorithme. Honnêtement, peu importe la manière dont vous mettez en œuvre la distance euclidienne, cela doit ressembler beaucoup à ceci.

Voici à quoi ressemble le premier exemple avec la distance euclidienne, en utilisant l'algorithme ci-dessus:

Image d'entrée et (x,y) = (165,155)

exemple 1 entrée entrez la description de l'image ici


Merci beaucoup à Calvin'sHobbies et à Trichoplax d’avoir aidé à écrire ce défi! S'amuser!


7
Je n’envisage pas de jouer au golf, mais j’ai créé une version Javascript où vous pouvez passer la souris sur l’image et les couleurs se mettre à jour instantanément. Les images de test ici sont trop volumineuses pour pouvoir fonctionner rapidement. Je vous conseillerais donc d'essayer de plus petites images comme celle-ci ou celle-ci .
Les passe-temps de Calvin

C'est génial! Je pense que c'est trop efficace pour être une bonne base pour une version
golfée

2
Les labyrinthes sont tellement plus faciles à résoudre quand ils sont colorés comme ça!
mbomb007

Le dernier exemple est vraiment magnifique. Est-ce que l'image d'entrée est juste du bruit?
Dylnan

@ Dylnan: Si vous parlez de l'exemple juste avant le bonus, c'est un labyrinthe. Vous pouvez cliquer dessus pour le voir en taille réelle.
El'endia Starman

Réponses:


33

Matlab, 255 245 231 octets

Cela attend le nom de l'image en premier, puis y, puis 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),[])

J'ai implémenté le remplissage par inondation (ou «dijkstra pour 4 quartiers» si vous le souhaitez) en créant d'abord un masque où le pixel de départ est défini sur 1 et avec un accumulateur de distance (à la fois de la taille de l'image) et en répétant ensuite pas:

  • convolute le masque avec un noyau à 4 voisinage (c'est la partie très inefficace)
  • définir tous les pixels non nuls du masque sur 1
  • régler tous les pixels noirs de l'image à zéro
  • définir toutes les valeurs dans l'accumulateur où le masque a changé dans cette étape à k
  • augmenter k
  • répéter jusqu'à ce qu'il n'y ait plus de modifications dans le masque (en fait, je ne vérifie pas cette condition, mais j'utilise simplement le nombre de pixels de l'image comme limite supérieure, ce qui correspond généralement à une très mauvaise limite supérieure, mais c'est codegolf =)

Cela nous laisse avec les distances de manhattan de chaque pixel jusqu'au pixel d'origine dans l'accumulateur de distance. Ensuite, nous créons une nouvelle image en parcourant la plage de couleurs donnée et en mappant la "première" teinte à la valeur zéro et la "dernière" teinte à la distance maximale.

Exemples

entrez la description de l'image ici

entrez la description de l'image ici

entrez la description de l'image ici

entrez la description de l'image ici

En prime, voici une jolie image de la manière dont la distance est calculée. plus lumineux = plus loin.

entrez la description de l'image ici


3
C’est le genre de choses que je voudrais imprimer pour que ma fille s’en inspire.
Rayryeng - Réintégrer Monica

@rayryeng Les modèles sont le travail d'El'endia Starman, pas le mien =)
flawr

Vous mettez toujours de la couleur aux images: D. Vous avez fait la dernière étape.
Rayryeng

4
Je suis impressionné. Je comprenais à peine le défi. Lol
zfrisch

Honnêtement, je veux l'utiliser pour créer des paysages.
CorsiKa

3

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

Ceci est l'implémentation de référence de l'algorithme euclidien, 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

En fait, je déteste à quel point cela est illisible par rapport à l'original. (Ce qui est, par ailleurs, 5305 octets.) En fait, je pourrais supprimer encore quelques octets en utilisant des noms de variable à un caractère pour tout, mais c'est déjà assez ridicule. Et ce n'est pas gagner de sitôt. : P


2

C ++ / SFML: 1271 1235 1226 octets

-36 octets grâce à user202729 -9 octets grâce à 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));}

Le sf::Imageparamètre est également la sortie (sera modifié). Vous pouvez l'utiliser comme ça:

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

r(img, 0, 0);

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

Le premier paramètre est l'image d'entrée (et de sortie), les deuxième et troisième paramètres sont les paramètres xet yoù il doit commencer


Le cas de commutation semble tellement inutile qu'une définition macro serait probablement utile ... Est-ce que le «at setPixel(j, i,hsv2et FI(xm,ym) (std::find_ifvraiment nécessaire?
user202729

Vous pouvez supprimer l'espace entre G(d,a,b,c)et case d:. En outre, l'espace entre case d:et return C(a,b,c)est également inutile. (b>m?b:m)ne nécessite pas les parenthèses, et (t/60)%6=> t/60%6par ordre d'opération.
Zacharý

Vous devriez probablement aussi renommer xmet ym
utiliser

Je pense qu'il est possible de supprimer l'espace entre G(d,a,b,c)et case, FI, tiet hsv2rgbpeuvent chacun être remplacé par un nom plus court.
Zacharý

1

C ++, 979 969 898 859 848 octets

#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);}}}
  • Entrée: fichier de données RVB (contenu dans le fichier: d)
  • Sortie: fichier de données RVB RGBA (sortie dans le fichier: d)
  • Exemple: convert -depth 8 -size "400x400" test.png d.rgb && mv -f d.rgb d && g ++ -o test main.c &&. ./Test
  • REMARQUE: la taille et le début de l'image sont contrôlés au niveau de la source. S'il s'agit d'un problème, ajoutez 50 octets ou quelque chose de ce genre. Je ne voulais simplement pas le changer pour être honnête.

Ce n'est pas exactement un "ungolf" direct, mais c'était un prototype en C que je me suis d'abord maquillé:

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

De nombreux concepts restent similaires, mais il y a certainement une myriade de changements minimes. Pour compiler cela en tant que C, vous devez utiliser C11 (C99 fonctionnera probablement, mais je n’ai testé strictement que dans C11).
J'ai vraiment apprécié ce défi, merci de m'avoir donné l'idée d'essayer quelque chose de nouveau :).
Edit: Golf serait un peu mieux.
Edit2: Fusion de deux structures pour que ma structure et ma file de pixels soient identiques, un peu plus de macro-abus et des utilisations de 255 telles que l'on puisse la définir en tant que -1 lors de la définition d'une série de caractères non signés, et enfin supprimer un appel de fonction.
Edit3: Réutilisation de quelques variables supplémentaires, ajustements de la priorité des opérateurs et sortie convertie au
format RVB en enregistrant le canal alpha Edit4: Je pense que j'en ai terminé avec cela, quelques modifications arithmétiques de pointeur et de légers ajustements du flux de contrôle.


0

Python 3 et matplotlib, 251 octets

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

L'entrée est un tableau numpy MxNx3 renvoyé par la imshow()fonction matplotlib . L'entrée est modifiée par la fonction, elle doit donc être copiée au préalable. Il affiche automatiquement l'image si matplotlib est en mode "interactif"; sinon, un appel à show()devrait être ajouté pour 7 octets supplémentaires.

La sortie est créée en affichant d'abord l'image d'origine, puis en superposant l'image arc-en-ciel. Matplotlib traite idéalement inf et nan comme étant transparent, de sorte que l'image en noir et blanc transparaisse.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.