Cầu vồng đen và trắng


60

Cho một hình ảnh chỉ có các pixel đen trắng và một vị trí (x, y) là pixel trắng, tô màu các pixel trắng dựa trên khoảng cách Manhattan tối thiểu của chúng từ (x, y) trong một đường dẫn chỉ đi qua các pixel trắng khác.

Các màu sắc của các điểm ảnh màu phải tương xứng khoảng cách của họ từ (x, y), do đó pixel tại (x, y) sẽ có một màu từ 0 ° (đỏ nguyên chất) và các điểm ảnh xa xa (x, y) sẽ có màu sắc 360 ° (cũng màu đỏ), với các màu khác được trộn liền mạch và tuyến tính ở giữa. Độ bão hòa và giá trị phải là 100%.

Nếu một pixel trắng không được kết nối với (x, y) thông qua các pixel trắng khác thì nó phải giữ nguyên màu trắng.

Chi tiết

  • Đầu vào sẽ bao gồm tên tệp của hình ảnh hoặc dữ liệu hình ảnh thô, cộng với số nguyên x và y.
  • Hình ảnh đầu ra có thể được lưu vào một tệp hoặc được dẫn thô đến thiết bị xuất chuẩn ở bất kỳ định dạng tệp hình ảnh phổ biến nào, hoặc hiển thị đơn giản.
  • Giá trị x là 0 trên các pixel ngoài cùng bên trái và tăng dần sang phải. Giá trị y là 0 trong các pixel trên cùng và tăng dần xuống. (x, y) sẽ luôn nằm trong giới hạn hình ảnh.
  • Cả hai chương trình và chức năng đầy đủ đều được cho phép.

Mã ngắn nhất tính bằng byte thắng.

Ví dụ

Tất cả những hình ảnh này đã được thu nhỏ để tiết kiệm không gian. Nhấp vào chúng để xem ở kích thước đầy đủ.

Hình ảnh đầu vào:

ví dụ 1 đầu vào

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

ví dụ 1 đầu ra A ví dụ 1 đầu ra B


Hình ảnh đầu vào và đầu ra với (x,y) = (0,0):

ví dụ 5 đầu vào ví dụ 5 đầu vào A


Hình ảnh đầu vào và đầu ra với (x,y) = (600,350):

ví dụ 2 đầu vào ví dụ 2 đầu ra


Hình ảnh đầu vào và đầu ra với (x,y) = (0,0):

ví dụ 3 đầu vào ví dụ 3 đầu ra


Hình ảnh đầu vào và đầu ra với (x,y) = (0,0):

ví dụ 4 đầu vào ví dụ 4 đầu ra


Phần thưởng tùy chọn -30%: sử dụng khoảng cách Euclide. Một gợi ý cho thuật toán của bạn như sau (phác thảo chung):

  1. Có một pixel bắt đầu.
  2. Lấp đầy từ pixel đó.
  3. Đối với mỗi pixel đạt được trong vùng lấp lũ,
  4. Di chuyển từ pixel bắt đầu sang pixel đó theo các bước nửa đơn vị, theo một đường thẳng.
  5. Ở mỗi bước, áp dụng int()cho tọa độ x và y. Nếu pixel ở các tọa độ này là màu đen, dừng lại. Nếu không, tiếp tục. (Đây là một phương pháp tầm nhìn.)
  6. Bất kỳ pixel nào đạt được viền giáp pixel trắng và / hoặc pixel được gắn nhãn trước đó với khoảng cách cao hơn đáng kể (ví dụ: 10) sẽ trở thành pixel bắt đầu.

Theo nghĩa siêu thực hơn, thuật toán này trải đều đến mọi pixel có thể tiếp cận theo một đường thẳng từ các pixel bắt đầu / đã được tô màu, sau đó "inch" xung quanh các cạnh. Bit "khoảng cách cao hơn đáng kể" được dự định để tăng tốc thuật toán. Thành thật mà nói, việc bạn thực hiện khoảng cách Euclide thực sự không quan trọng , nó chỉ phải trông khá giống như thế này.

Đây là ví dụ đầu tiên trông giống với khoảng cách Euclide, sử dụng thuật toán ở trên:

Hình ảnh đầu vào và (x,y) = (165,155)

ví dụ 1 đầu vào nhập mô tả hình ảnh ở đây


Rất cám ơn Calvin'sHob sở thích và trichoplax đã giúp viết thử thách này! Chúc vui vẻ!


7
Tôi không có kế hoạch chơi golf nhưng tôi đã tạo một phiên bản Javascript nơi bạn có thể di chuột qua hình ảnh và màu sắc cập nhật ngay lập tức. Các hình ảnh thử nghiệm ở đây quá lớn để nó chạy nhanh, vì vậy tôi khuyên bạn nên thử những hình ảnh nhỏ hơn như thế này hoặc thế này .
Sở thích của Calvin

Điều này thật tuyệt! Tôi nghi ngờ rằng nó quá hiệu quả để trở thành một cơ sở tốt cho phiên bản chơi gôn =)
flawr

2
Mazes rất dễ giải quyết khi chúng có màu như thế này!
mbomb007

Ví dụ cuối cùng thực sự rất đẹp. Là hình ảnh đầu vào chỉ là nhiễu?
dyl Nam

@dylnan: Nếu bạn đang nói về ví dụ ngay trước phần thưởng, đó thực sự là một mê cung. Bạn có thể nhấp vào nó để xem nó ở kích thước đầy đủ.
El'endia Starman

Câu trả lời:


33

Matlab, 255 245 231 byte

Điều này mong đợi tên hình ảnh đầu tiên, sau đó yvà sau đó 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),[])

Tôi đã triển khai việc lấp lũ (hoặc 'dijkstra cho 4 vùng lân cận' nếu bạn muốn) bằng cách trước tiên tạo mặt nạ trong đó pixel hạt giống được đặt thành 1 và với bộ tích khoảng cách (cả hai kích thước của hình ảnh) và sau đó lặp lại theo sau các bước:

  • kết hợp mặt nạ với kernel 4 lân cận (đây là phần rất kém hiệu quả)
  • đặt tất cả các pixel khác không của mặt nạ thành 1
  • đặt tất cả các pixel đen của hình ảnh về 0
  • đặt tất cả các giá trị trong bộ tích lũy trong đó mặt nạ đã thay đổi trong bước này thành k
  • tăng k
  • lặp lại cho đến khi không có thêm thay đổi nào trong mặt nạ (tôi thực sự không kiểm tra điều kiện này, mà chỉ sử dụng số pixel trong ảnh làm giới hạn trên, thường là giới hạn trên rất xấu, nhưng đây là codegolf =)

Điều này để lại cho chúng ta khoảng cách manhattan của mỗi pixel đến pixel hạt trong bộ tích khoảng cách. Sau đó, chúng tôi tạo ra một hình ảnh mới bằng cách đi qua dải màu đã cho và ánh xạ màu sắc "đầu tiên" thành giá trị 0 và màu sắc "cuối cùng" đến khoảng cách tối đa.

Ví dụ

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây

Như một phần thưởng, đây là một bức tranh đẹp về cách tính khoảng cách. sáng hơn = xa hơn.

nhập mô tả hình ảnh ở đây


3
Đây là loại nội dung tôi muốn in ra để con gái tôi vẽ.
rayryeng - Phục hồi Monica

@rayryeng Các mẫu là tác phẩm của El'endia Starman, không phải của tôi =)
flawr

Bạn vẫn đặt màu cho hình ảnh: D. Bạn đã làm bước cuối cùng.
rayryeng - Phục hồi Monica

4
Tôi rất ấn tượng. Tôi hầu như không thể hiểu được thử thách lol
zfrisch

Thành thật mà nói, những gì tôi muốn sử dụng nó là tạo cảnh quan.
corsiKa

3

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

Đây là triển khai tham chiếu cho thuật toán Euclide, được đánh gôn.

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

Trên thực tế, tôi ghét việc không thể đọc được điều này so với bản gốc. (Đó là, tình cờ, 5305 byte.) Trên thực tế, tôi có thể loại bỏ thêm một vài byte bằng cách sử dụng tên biến một ký tự cho mọi thứ, nhưng điều này đã đủ kỳ cục rồi. Và nó không chiến thắng bất cứ lúc nào sớm. : P


2

C ++ / SFML: 1271 1235 1226 byte

-36 byte nhờ người dùng202729 -9 byte nhờ 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));}

Các sf::Imagetham số cũng là sản phẩm (sẽ được sửa đổi). Bạn có thể sử dụng nó như thế:

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

r(img, 0, 0);

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

Tham số đầu tiên là đầu vào hình ảnh (và đầu ra), tham số thứ hai và thứ ba là xytham số cần bắt đầu


Trường hợp chuyển đổi có vẻ lãng phí đến mức có lẽ một định nghĩa vĩ mô sẽ hữu ích ... Ngoài ra, đó là `` tại setPixel(j, i,hsv2FI(xm,ym) (std::find_ifthực sự cần thiết?
dùng202729

Bạn có thể loại bỏ khoảng trống giữa G(d,a,b,c)case d:. Ngoài ra, không gian giữa case d:return C(a,b,c)là không cần thiết là tốt. (b>m?b:m)không yêu cầu dấu ngoặc đơn và (t/60)%6=> t/60%6theo thứ tự các thao tác.
Zacharý

Có lẽ bạn cũng nên đổi tên xmvà đổi tên ymngắn hơn
Zacharý

Tôi nghĩ rằng nó có thể loại bỏ các khoảng trống giữa G(d,a,b,c)case, FI, ti, và hsv2rgbcó thể từng được thay thế bằng một tên ngắn hơn.
Zacharý

1

C ++, 979 969 898 859 848 byte

#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);}}}
  • Dữ liệu vào: Tệp dữ liệu RGB (có trong tệp: d)
  • Đầu ra: Tệp dữ liệu RGBA RGB (xuất ra trong tệp: d)
  • Ví dụ: convert -depth 8 -size "400x400" test.png d.rgb && mv -f d.rgb d && g ++ -o test main.c && ./test
  • LƯU Ý: kích thước hình ảnh và bắt đầu được kiểm soát ở mức nguồn, nếu đây là vấn đề thêm 50 byte hoặc thứ gì đó - tôi chỉ không quan tâm đến việc thay đổi nó thành trung thực.

Không chính xác là một "ungolf" trực tiếp nhưng đây là nguyên mẫu C tôi đã chế giễu trướ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);
        }
    }
}

Nhiều khái niệm vẫn tương tự, nhưng chắc chắn có vô số thay đổi nhỏ. Để biên dịch rằng như C, bạn cần sử dụng C11 (C99 có thể sẽ hoạt động nhưng tôi chỉ kiểm tra nghiêm ngặt trong C11).
Tôi khá thích thử thách này, cảm ơn vì đã cho tôi ý tưởng thử một cái gì đó mới :).
Chỉnh sửa: Golf'd tốt hơn một chút.
Edit2: Đã hợp nhất hai cấu trúc để cấu trúc pixel và hàng đợi của tôi giống nhau, lạm dụng macro hơn một chút và sử dụng 255 để có thể được định nghĩa là -1 khi xác định một loạt các ký tự không dấu và cuối cùng loại bỏ lệnh gọi hàm.
Edit3: Đã sử dụng lại một vài biến số, các điều chỉnh ưu tiên toán tử và đầu ra được chuyển đổi thành RGB lưu kênh alpha
Edit4: Tôi nghĩ rằng tôi đã hoàn thành việc này bây giờ, một số thay đổi số học con trỏ và điều chỉnh dòng điều khiển nhẹ.


0

Python 3 và matplotlib, 251 byte

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

Đầu vào là một mảng numpy MxNx3 được trả về bởi matplotlib imshow() hàm . Đầu vào được sửa đổi bởi chức năng vì vậy nó cần được sao chép trước. Nó tự động hiển thị hình ảnh nếu matplotlib ở chế độ "tương tác"; nếu không, một cuộc gọi show()sẽ được thêm vào cho 7 byte khác.

Đầu ra được tạo ra bằng cách đầu tiên hiển thị hình ảnh gốc và sau đó hiển thị hình ảnh cầu vồng phía trên nó. Matplotlib thuận tiện xử lý inf và nan trong suốt để hình ảnh đen trắng hiển thị xuyên suốt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.