黑色和白色的彩虹


60

给定一个图像,该图像仅包含黑白像素,并且(x,y)位置是白色像素,请根据白色像素与(x,y)的最小曼哈顿距离为它们着色,该路径仅涉及遍历其他白色像素。

彩色像素的色相必须与其与(x,y)的距离成正比,因此(x,y)处的像素的色相为0°(纯红色),而距(x,y)的像素最远将具有360°的色相(也为红色),其他色相之间无缝且线性地混合。的饱和度和值都必须是100%。

如果白色像素未通过其他白色像素连接到(x,y),则它必须保持白色。

细节

  • 输入将包含图像的文件名或原始图像数据,以及x和y整数。
  • 可以将输出图像保存到文件中,或以任何常见图像文件格式将其原始传输到stdout,或简单地显示出来。
  • 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和trichoplax帮助编写此挑战!玩得开心!


7
我不打算打高尔夫球,但我制作了Javascript版本,您可以将鼠标悬停在图像上,并且颜色会立即更新。这里的测试图像太大它跑得快,所以我会建议尝试较小的图像,像这样这样
加尔文的爱好2015年

这太棒了!我怀疑它太高效率了,无法成为高尔夫版本的良好基础=)
瑕疵的

2
当迷宫这样着色时,它们很容易解决!
mbomb007

最后一个例子真的很漂亮。输入图像仅仅是噪声吗?
dylnan '17

@dylnan:如果您在谈论奖金之前的例子,那实际上是一个迷宫。您可以单击它以查看完整尺寸。
El'endia Starman

Answers:


33

Matlab,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),[])

我大致通过首先创建一个将种子像素设置为1并使用距离累加器(均为图像大小)的蒙版来大致实现洪水填充(如果需要,可以使用“ dijkstra for 4 eighbourhoods”)。脚步:

  • 用4个邻域内核对掩码进行卷积(这是效率很低的部分)
  • 将遮罩的所有非零像素设置为1
  • 将图像的所有黑色像素设置为零
  • 将在此步骤中掩码已更改的累加器中的所有值设置为 k
  • 增加 k
  • 重复进行操作,直到蒙版中没有更多更改为止(我实际上不检查这种情况,而是仅使用图像中的像素数作为上限,这通常是一个非常糟糕的上限,但这是codegolf =)

这就给我们留下了距离累积器中每个像素到种子像素的曼哈顿距离。然后,我们通过遍历给定的颜色范围来创建新图像,并将“第一个”色相映射为零值,将“最后一个”色相映射为最大距离。

例子

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

另外,这里还提供了如何计算距离的漂亮图片。更亮=更远。

在此处输入图片说明


3
我想把这种东西打印出来,供女儿借鉴。
rayryeng

@rayryeng模板是El'endia Starman的作品,不是我的=)
瑕疵的

您仍然为图像添加颜色:D。您完成了最后一步。
rayryeng

4
我印象深刻 我几乎无法理解挑战,哈哈
zfrisch

老实说,我想用它来创建风景。
corsiKa

3

闪电战2D / 3D,3068 * 0.7 = 2147.6

这是Euclidean算法的参考实现。

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字节归功于user202729 -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;

第一个参数是图像输入(和输出),第二个和第三个参数是需要启动的xand y参数


开关的情况下,似乎这样的浪费,可能在宏定义将是有益的......也就是``在setPixel(j, i,hsv2FI(xm,ym) (std::find_if真的有必要?
user202729 '17

您可以删除之间的空间G(d,a,b,c)case d:。此外,之间的空间case d:return C(a,b,c)是不必要的为好。(b>m?b:m)不需要括号,并且(t/60)%6=> t/60%6按操作顺序。
扎卡里

你或许应该重新命名也xmym较短的变量名
扎卡里

我认为这是可以消除之间的空间G(d,a,b,c)caseFIti,并且hsv2rgb都可以设置一个较短的名称所取代。
扎卡里

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)
  • 示例:convert -depth 8 -size“ 400x400” test.png d.rgb && mv -f d.rgb d && g ++ -o test main.c && ./test
  • 注意:图像大小和开始是在源级别上控制的,如果这是一个问题,请添加50个字节或其他内容-老实说,我只是不在乎更改它。

不完全是直接的“ ungolf”,但这是我首先模拟的C原型:

#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,从而保存了Alpha通道
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')

输入是由matplotlib imshow()函数返回的MxNx3 numpy数组。输入已由功能修改,因此应事先复制。如果matplotlib处于“交互”模式,它将自动显示图像。否则,show()应添加对另外7个字节的调用。

通过首先显示原始图像,然后在其顶部显示彩虹图像来创建输出。Matplotlib方便地将inf和nan视为透明,因此黑白图像可以通过。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.