Pelangi Hitam dan Putih


60

Mengingat gambar yang hanya memiliki piksel hitam dan putih dan lokasi (x, y) yang merupakan piksel putih, warnai piksel putih berdasarkan jarak Manhattan minimum dari (x, y) di jalur yang hanya melibatkan melintasi piksel putih lainnya.

The rona piksel berwarna harus sebanding dengan jarak mereka dari (x, y), sehingga piksel pada (x, y) akan memiliki rona 0 ° (merah murni) dan piksel terjauh dari (x, y) akan memiliki rona 360 ° (juga merah), dengan rona lainnya bercampur mulus dan linier di antaranya. The saturasi dan nilai keduanya harus 100%.

Jika piksel putih tidak terhubung ke (x, y) melalui piksel putih lainnya, maka piksel itu harus tetap putih.

Detail

  • Input akan terdiri dari nama file gambar atau data gambar mentah, ditambah bilangan x dan y.
  • Gambar output dapat disimpan ke file atau disalurkan mentah ke stdout dalam format file gambar umum, atau hanya ditampilkan.
  • Nilai x adalah 0 pada piksel paling kiri, dan meningkat ke kanan. Nilai y adalah 0 pada piksel paling atas dan naik turun. (x, y) akan selalu berada dalam batas gambar.
  • Program dan fungsi lengkap diizinkan.

Kode terpendek dalam byte menang.

Contohnya

Semua gambar ini telah dirampingkan untuk menghemat ruang. Klik untuk melihat ukuran penuh.

Input gambar:

contoh 1 input

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

contoh 1 output A contoh 1 output B


Input gambar dan output dengan (x,y) = (0,0):

contoh 5 input contoh 5 input A


Input gambar dan output dengan (x,y) = (600,350):

contoh 2 input contoh 2 output


Input gambar dan output dengan (x,y) = (0,0):

contoh 3 input contoh 3 output


Input gambar dan output dengan (x,y) = (0,0):

contoh 4 input contoh 4 output


Opsional -30% bonus: gunakan jarak Euclidean. Saran untuk algoritme Anda adalah sebagai berikut (garis besar umum):

  1. Memiliki piksel awal.
  2. Isi banjir dari piksel itu.
  3. Untuk setiap piksel yang dicapai dalam isi banjir,
  4. Pindah dari piksel awal ke piksel dalam setengah unit langkah, dalam garis lurus.
  5. Pada setiap langkah, terapkan int()pada koordinat x dan y. Jika piksel pada koordinat ini berwarna hitam, berhenti. Kalau tidak, lanjutkan. (Ini adalah metode line-of-sight.)
  6. Setiap piksel yang mencapai yang membatasi piksel putih dan / atau piksel yang sebelumnya diberi label dengan jarak yang jauh lebih tinggi (yaitu +10) menjadi piksel awal.

Dalam arti yang lebih meta, algoritma ini menyebar ke setiap piksel yang dapat dijangkau dalam garis lurus dari piksel awal / yang sudah berwarna, lalu "inci" di sekitar tepinya. Bit "jarak jauh lebih tinggi" dimaksudkan untuk mempercepat algoritma. Jujur, tidak masalah bagaimana Anda menerapkan jarak Euclidean, hanya saja harus terlihat seperti ini.

Inilah contoh pertama yang terlihat dengan jarak Euclidean, menggunakan algoritma di atas:

Masukkan gambar dan (x,y) = (165,155)

contoh 1 input masukkan deskripsi gambar di sini


Terima kasih banyak kepada Calvin Hobi dan trichoplax karena telah membantu menulis tantangan ini! Selamat bersenang-senang!


7
Saya tidak berencana untuk bermain golf tapi saya membuat versi Javascript di mana Anda dapat mengarahkan gambar dan warna diperbarui secara instan. Gambar uji di sini terlalu besar untuk berjalan cepat jadi saya sarankan mencoba gambar yang lebih kecil seperti ini atau ini .
Hobi Calvin

Ini luar biasa! Saya menduga itu terlalu efisien untuk menjadi basis yang baik untuk versi
golf

2
Labirin jauh lebih mudah dipecahkan saat diwarnai seperti ini!
mbomb007

Contoh terakhir sangat indah. Apakah gambar input hanya noise?
dylnan

@dylnan: Jika Anda berbicara tentang contoh tepat sebelum bonus, itu sebenarnya sebuah labirin. Anda dapat mengkliknya untuk melihatnya dalam ukuran penuh.
El'endia Starman

Jawaban:


33

Matlab, 255 245 231 byte

Ini mengharapkan nama gambar pertama, lalu ydan kemudian 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),[])

Saya menerapkan pengisian banjir (atau 'dijkstra untuk 4-lingkungan' jika Anda mau) secara kasar dengan terlebih dahulu membuat topeng di mana piksel benih diatur ke 1 dan dengan akumulator jarak (keduanya ukuran gambar) dan kemudian mengulangi mengikuti Langkah:

  • lilitkan topeng dengan kernel 4 lingkungan (ini adalah bagian yang sangat tidak efisien)
  • setel semua piksel bukan-nol dari topeng ke 1
  • atur semua piksel hitam gambar ke nol
  • setel semua nilai dalam akumulator tempat mask telah diubah pada langkah ini menjadi k
  • meningkatkan k
  • ulangi sampai tidak ada lagi perubahan pada mask (saya sebenarnya tidak memeriksa kondisi ini, tetapi cukup gunakan jumlah piksel pada gambar sebagai batas atas, yang biasanya batas atas sangat buruk, tetapi ini codegolf =)

Ini meninggalkan kita dengan jarak manhattan dari setiap piksel ke piksel awal dalam akumulator jarak. Kemudian kita membuat gambar baru dengan pergi ke kisaran warna yang diberikan dan memetakan rona "pertama" ke nilai nol dan rona "terakhir" ke jarak maksimal.

Contohnya

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Sebagai bonus, di sini gambar cantik tentang bagaimana jarak dihitung. lebih terang = lebih jauh.

masukkan deskripsi gambar di sini


3
Ini adalah jenis barang yang ingin saya cetak untuk dipakai anak saya.
rayryeng

@rayryeng Templatnya adalah karya El'endia Starman, bukan milikku =)
flawr

Anda masih memberi warna pada gambar: D. Anda melakukan langkah terakhir.
rayryeng

4
Saya terkesan. Saya hampir tidak bisa memahami tantangannya lol
zfrisch

Sejujurnya, apa yang ingin saya gunakan untuk menciptakan lanskap.
corsiKa

3

Blitz 2D / 3D , 3068 * 0.7 = 2147.6

Ini adalah implementasi referensi untuk algoritma Euclidean, golf.

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

Sebenarnya, saya agak benci betapa tidak terbacanya ini dibandingkan dengan aslinya. (Yaitu, kebetulan, 5305 byte.) Sebenarnya, saya bisa memotong beberapa byte lagi dengan menggunakan nama variabel satu karakter untuk semuanya, tapi ini sudah cukup konyol. Dan itu tidak akan menang dalam waktu dekat. : P


2

C ++ / SFML: 1271 1235 1226 byte

-36 bytes terima kasih ke user202729 -9 bytes berkat 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));}

The sf::Imageparameter juga output (akan dimodifikasi). Anda bisa menggunakannya seperti itu:

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

r(img, 0, 0);

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

Parameter pertama adalah input gambar (dan output), parameter kedua dan ketiga adalah xdan yparameter di mana ia harus memulai


Switch case sepertinya sangat boros sehingga mungkin sebuah definisi makro akan berguna ... Juga apakah `` at setPixel(j, i,hsv2dan FI(xm,ym) (std::find_ifbenar-benar diperlukan?
user202729

Anda dapat menghapus ruang antara G(d,a,b,c)dan case d:. Juga, ruang antara case d:dan return C(a,b,c)tidak dibutuhkan juga. (b>m?b:m)tidak memerlukan tanda kurung, dan (t/60)%6=> t/60%6atas perintah operasi.
Zacharý

Anda mungkin juga harus mengganti nama xmdan ymuntuk nama
Zacharý

Saya pikir itu mungkin untuk menghapus ruang antara G(d,a,b,c)dan case, FI, ti, dan hsv2rgbmasing-masing dapat diganti dengan nama yang lebih pendek.
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);}}}
  • Input: File data RGB (terkandung dalam file: d)
  • Output: File data RGBA RGB (dihasilkan dalam file: d)
  • Contoh: konversi -depth 8 -ukuran "400x400" test.png d.rgb && mv -f d.rgb d &&g ++ -o uji main.c && ./test
  • CATATAN: ukuran dan mulai gambar dikontrol pada tingkat sumber, jika ini merupakan masalah, tambahkan 50 byte atau sesuatu - saya hanya tidak peduli untuk mengubahnya jujur.

Bukan "ungolf" langsung tetapi ini adalah prototipe C yang saya tiru pertama kali:

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

Banyak konsep yang tetap serupa, tetapi tentu saja ada banyak sekali perubahan kecil. Untuk mengkompilasi bahwa sebagai C Anda perlu menggunakan C11 (C99 mungkin akan bekerja tetapi saya hanya benar-benar diuji di C11).
Saya cukup menikmati tantangan ini, terima kasih telah memberi saya ide untuk mencoba sesuatu yang baru :).
Sunting: Golf sedikit lebih baik.
Sunting2: Menggabungkan dua struct sehingga pixel saya dan antriannya sama, sedikit lebih banyak penyalahgunaan makro, dan menggunakan 255 yang direfleksikan sehingga dapat didefinisikan sebagai -1 ketika mendefinisikan serangkaian karakter yang tidak ditandai, dan terakhir menghapus panggilan fungsi.
Sunting3: Digunakan kembali beberapa variabel lagi, tweak diutamakan operator, dan output dikonversi ke RGB menghemat saluran alpha
Edit4: Saya pikir saya sudah selesai dengan ini sekarang, beberapa perubahan aritmatika pointer dan tweak aliran kontrol sedikit.


0

Python 3 dan 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')

Input adalah array numpy MxNx3 yang dikembalikan oleh imshow()fungsi matplotlib . Input dimodifikasi oleh fungsi sehingga harus disalin sebelumnya. Ini menampilkan gambar secara otomatis jika matplotlib dalam mode "interaktif"; jika tidak, panggilan ke show()harus ditambahkan selama 7 byte lainnya.

Output dibuat dengan pertama-tama menampilkan gambar asli dan kemudian menampilkan gambar pelangi di atasnya. Matplotlib dengan mudah memperlakukan inf dan nan transparan sehingga gambar hitam putih terlihat.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.