Menelusuri Corak Gambar

17

Muat gambar ke potongan tumpukan ini dan gerakkan mouse Anda ke atasnya. Kurva hitam yang mengikuti sudut rona , mulai dari titik kursor Anda, akan ditarik:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><style>canvas{border:1px solid black;}</style>Load an image: <input type='file' onchange='load(this)'><br><br>Max length <input id='length' type='text' value='300'><br><br><div id='coords'></div><br><canvas id='c' width='100' height='100'>Your browser doesn't support the HTML5 canvas tag.</canvas><script>function load(t){if(t.files&&t.files[0]){var e=new FileReader;e.onload=setupImage,e.readAsDataURL(t.files[0])}}function setupImage(t){function e(t){t.attr("width",img.width),t.attr("height",img.height);var e=t[0].getContext("2d");return e.drawImage(img,0,0),e}img=$("<img>").attr("src",t.target.result)[0],ctx=e($("#c")),ctxRead=e($("<canvas>"))}function findPos(t){var e=0,a=0;if(t.offsetParent){do e+=t.offsetLeft,a+=t.offsetTop;while(t=t.offsetParent);return{x:e,y:a}}return void 0}$("#c").mousemove(function(t){function e(t,e){var a=ctxRead.getImageData(t,e,1,1).data,i=a[0]/255,r=a[1]/255,o=a[2]/255;return Math.atan2(Math.sqrt(3)*(r-o),2*i-r-o)}if("undefined"!=typeof img){var a=findPos(this),i=t.pageX-a.x,r=t.pageY-a.y;$("#coords").html("x = "+i.toString()+", y = "+r.toString());var o=parseInt($("#length").val());if(isNaN(o))return void alert("Bad max length!");for(var n=[i],f=[r],h=0;n[h]>=0&&n[h]<this.width&&f[h]>=0&&f[h]<this.height&&o>h;)n.push(n[h]+Math.cos(e(n[h],f[h]))),f.push(f[h]-Math.sin(e(n[h],f[h]))),h++;ctx.clearRect(0,0,this.width,this.height),ctx.drawImage(img,0,0);for(var h=0;h<n.length;h++)ctx.fillRect(Math.floor(n[h]),Math.floor(f[h]),1,1)}});</script>

Saya hanya menguji cuplikan ini di Google Chrome.

Misalnya, ketika kursor di atas merah, kurva memiliki kemiringan 0 °, tetapi ketika itu di atas kuning, ia memiliki kemiringan 60 °. Kurva berlanjut untuk panjang yang ditentukan, terus menerus mengubah kemiringannya agar sesuai dengan rona.

Memuat gambar ini dan ketika Anda menggeser kursor di atasnya, garis tepat di sekitar kursor harus melakukan putaran berlawanan arah jarum jam:

sudut rona

Ini dan ini adalah gambar rapi lainnya untuk dicoba. (Anda harus menyimpannya dan memuatnya dengan snippet. Mereka tidak dapat dihubungkan secara langsung karena kendala lintas-asal.)

Ini adalah versi cuplikan yang tidak diperkecil:

Tantangan

Tulis sebuah program yang melakukan apa yang snippet lakukan, hanya saja tidak secara interaktif. Ambil gambar dan koordinat (x, y) dalam batas gambar, dan panjang kurva maksimum. Keluarkan gambar yang sama dengan kurva hitam yang ditambahkan yang mengikuti sudut rona mulai dari (x, y) dan berakhir ketika mencapai panjang maksimum atau menyentuh batas gambar.

Secara khusus, mulailah kurva di (x, y) dan ukur sudut rona di sana. Pergi satu unit (lebar satu piksel) ke arah itu, perhatikan bahwa posisi baru Anda kemungkinan besar bukan koordinat bilangan bulat . Tandai titik lain pada kurva dan bergerak lagi, menggunakan rona dari piksel terdekat (menggunakan sesuatu seperti flooratau round, saya tidak akan memeriksa ini dengan tepat). Lanjutkan seperti ini sampai kurva melampaui batas atau melebihi panjang maksimum. Untuk menyelesaikan, plot semua titik kurva sebagai piksel hitam tunggal (sekali lagi, gunakan piksel terdekat) yang dilapis pada gambar, dan hasilkan gambar baru ini.

"Rona sudut" hanyalah rona :

hue = atan2(sqrt(3) * (G - B), 2 * R - G - B)

Perhatikan bahwa untuk nilai skala abu-abu yang secara teknis tidak memiliki rona, ini mengembalikan 0, tapi tidak masalah.

(Rumus ini menggunakan atan2yang dimiliki sebagian besar perpustakaan matematika bawaan. R, G, B adalah dari 0 hingga 1, bukan 0 hingga 255.)

  • Anda dapat menggunakan format file gambar lossless yang umum serta pustaka gambar apa pun.
  • Ambil input dari stdin atau baris perintah, atau tulis fungsi dengan argumen untuk nama file gambar, x dan y, dan panjang maks.
  • Panjang maks dan x dan y selalu bilangan bulat tidak negatif. Anda dapat menganggap x dan y berada dalam kisaran.
  • Simpan gambar keluaran dengan nama pilihan Anda atau cukup tampilkan.
  • Implementasi Anda tidak harus sama persis dengan cuplikan. Beberapa piksel di tempat yang sedikit berbeda karena metode pembulatan / perhitungan yang sedikit berbeda baik-baik saja. (Dalam kasus kacau ini dapat menyebabkan kurva yang berakhir sangat berbeda, tetapi selama mereka terlihat benar secara visual, itu baik-baik saja.)

Mencetak gol

Pengajuan terkecil dalam byte akan menang.

Hobi Calvin
sumber
1
Cuplikan tersebut benar-benar rusak di Firefox.
Ypnypn
Cuplikan juga tidak berfungsi di Safari. (Tantangan keren, +1)
Alex A.
@Hobi Calvin Bisakah kita mengobrol? chat.stackexchange.com/rooms/22029/…
BrainSteel

Jawaban:

2

MATLAB, 136

function t(g,x,y,l)
m=imread(g);imshow(m); h=2*pi*rgb2hsv(m);h=h(:,:,1);s=streamline(cos(h),-sin(h),x,y,[1,l]);set(s,'LineW',1,'Co','k');

Menyalin sebagian besar pengaturan dan semacamnya dari @sanchises, tapi saya malah menggunakan streamlineuntuk menghitung dan menggambar path. Ini memang antialias garis, dan menggunakan interpolasi bilinear, bukan tetangga terdekat seperti yang ditentukan.

AJMansfield
sumber
5

C dengan SDL, 549 516 byte

Saya akan memulai pesta ini! Untuk beberapa alasan, saya ingin mencoba bermain golf malam ini. Apa yang kalian lakukan sulit ... Jika ada satu hal yang tidak saya lihat di situs ini, itu SDL. Saya mungkin baru tahu mengapa. Cuplikan khusus ini sesuai dengan SDL2 dan SDL1.2, tetapi mengerikan. Disebut seperti f("imagename.bmp", xcoord, ycoord, max_length);. Ini menyimpan file dengan nama yang sama seperti yang diberikan dalam argumen. Output tampaknya sangat mirip dengan potongan kode OP, tetapi "lebih fuzzier." Saya mungkin mencoba memperbaikinya sedikit kemudian.

#include"SDL.h"
f(char*C,x,y,m){SDL_Surface*P=SDL_LoadBMP(C);int p=P->pitch,i=P->format->BytesPerPixel,q=0;double X=x,Y=y,f=255,R,G,B,h;Uint8*Q,d=1,r,g,b,k;while(d){Q=P->pixels+y*p+i*x;SDL_GetRGB(i==4?*(Uint32*)Q:i==3?SDL_BYTEORDER==4321?*Q<<16|Q[1]<<8|Q[2]:*Q|Q[1]<<8|Q[2]<<16:i==2?*(Uint16*)Q:*Q,P->format,&r,&g,&b);R=r/f;G=g/f;B=b/f;h=atan2(sqrt(3)*(G-B),2*R-G-B);for(k=0;k<i;k++)Q[k]=0;X+=cos(h);Y-=sin(h);if((int)X-x|(int)Y-y)q++;x=X;y=Y;d=x<0|x>=P->w|y<0|y>=P->h|q>=m?0:1;}SDL_SaveBMP(P,C);SDL_FreeSurface(P);}

Di sini semuanya terurai:

#include"SDL.h"
f(char*C,x,y,m){
    SDL_Surface*P=SDL_LoadBMP(C);
    int p=P->pitch,i=P->format->BytesPerPixel,q=0;
    double X=x,Y=y,f=255,R,G,B,h;
    Uint8*Q,d=1,r,g,b,k;
    while(d){
        Q=P->pixels+y*p+i*x;
        SDL_GetRGB(i==4?*(Uint32*)Q:i==3?SDL_BYTEORDER==4321?*Q<<16|Q[1]<<8|Q[2]:*Q|Q[1]<<8|Q[2]<<16:i==2?*(Uint16*)Q:*Q,P->format,&r,&g,&b);
        R=r/f;
        G=g/f;
        B=b/f;
        h=atan2(sqrt(3)*(G-B),2*R-G-B);
        for(k=0;k<i;k++)Q[k]=0;
        X+=cos(h);
        Y-=sin(h);
        if((int)X-x|(int)Y-y)q++;
        x=X;y=Y;
        d=x<0|x>=P->w|y<0|y>=P->h|q>=m?0:1;
    }
    SDL_SaveBMP(P,C);
    SDL_FreeSurface(P);
}

Saya harus mencatat bahwa kehati-hatian diambil untuk membuatnya lintas platform - demi kepentingan kejujuran, rasanya tidak enak untuk meng-hardcode-nya untuk mesin saya, bahkan jika itu memotong sejumlah besar byte. Namun, saya merasa ada beberapa hal yang berlebihan di sini, dan saya akan melihatnya lagi nanti.

Sunting -------

Ini IS Keluaran Grafis, setelah semua ... Saya akan memperbarui dengan gambar yang menurut saya menarik secara berkala.

f("HueTest1.bmp", 270, 40, 200);

HueTest1.bmp

f("HueTest2.bmp", 50, 50, 200);

HueTest2.bmp

f("HueTest3.bmp", 400, 400, 300);

HueTest3.bmp

BrainSteel
sumber
3

Python, 203 172

from scipy.misc import*
def f(i,x,y,l):
 a=imread(i);Y,X,_=a.shape;o=a.copy()
 while(X>x>0<y<Y<[]>l>0):r,g,b=a[y,x]/255.;o[y,x]=0;l-=1;x+=2*r-g-b;y-=3**.5*(g-b);imsave(i,o)

Output sampel: masukkan deskripsi gambar di sini

Telepon dengan f("image.jpg", 400, 400, 300)

Saya sudah membuang banyak karakter untuk impor, jika ada yang punya saran untuk memperbaikinya. Mungkin tidak berfungsi di 3.0

grovesNL
sumber
Dari sekilas: sqrt(3) -> 3**.5? Saya tidak bisa memikirkan apa pun untuk impor.
Sp3000
Yang bagus! Itu akan berguna di masa depan.
grovesNL
3

MATLAB, 186 172

Game ini aktif ! Sebutlah sebagai t('YourImage.ext',123,456,100'), untuk gambar jenis apa pun yang didukung MATLAB, mulai dari (x, y) = (123.456) dan panjang maksimum 100. Posisi awal tidak dapat persis di tepi kanan dan bawah (yang akan memakan biaya dua byte), jadi untuk mulai dari tepi, gunakan sesuatu x=799.99untuk memulai x=800. Pengindeksan dimulai pada 1, bukan 0.

Kode:

function t(g,x,y,l)
m=imread(g);[Y,X,~]=size(m);h=2*pi*rgb2hsv(m);while(x>0&x<X&y>0&y<Y&l)
p=ceil(x);q=ceil(y);m(q,p,:)=0;a=h(q,p);x=x+cos(a);y=y-sin(a);l=l-1;end
imshow(m)

Revisi:

  • Berubah dari garis dari piksel sebelumnya ke piksel berikutnya menjadi hanya menempatkan titik pada piksel, karena garis tersebut tidak akan pernah lebih lama dari satu piksel! Masih menggunakan linekarena itu adalah kode terpendek yang saya tahu menghasilkan piksel.
  • Mengubah warna dari hitam menjadi biru, gunakan Countuk memperluas ke Color(yang MATLAB tidak secara otomatis)
  • Mengubah urutan penghitungan posisi berikutnya dan menggambar suatu titik, karena saya menyadari terima kasih kepada @grovesNL bahwa saya sebenarnya menarik keluar batas karena saya memeriksa batas setelah mengubah posisi.
  • Berubah dari garis gambar ke pengaturan rgb matrix ke 0 dan ditampilkan setelah.

Permen garis hitam

Sanchises
sumber
Bukankah x=0atau y=0berpotensi posisi yang valid?
grovesNL
Juga, bagaimana ini 166 byte?
grovesNL
@ grovesNL Maaf, secara tidak sengaja menghitung versi pengujian saya tanpa functionheader. Spec tidak memerlukan pengindeksan berbasis nol atau satu, jadi saya menggunakan MATLAB berbasis satu, jadi tidak, x=0atau y=0tidak valid dalam program ini.
Sanchises
Ah, saya lupa bahwa MATLAB berbasis satu (sudah lama). Tapi saya kira itu bisa jadi x=Xdan y=Yvalid saja?
grovesNL
1
Hah! Mengalahkan Anda di gim Anda sendiri, solusi MATLAB saya hanya 135 karakter!
AJMansfield
1

Memproses, 323 karakter

void h(String f,float x,float y,float m){PImage i=loadImage(f);PImage i2=loadImage(f);while(m>0){color c=i.get((int)x,(int)y);float r=red(c)/255;float g=green(c)/255;float b=blue(c)/255;float h=atan2(sqrt(3)*(g-b),2*r-g-b);float dx=cos(h);float dy=-sin(h);m-=1;x+=dx;y+=dy;i2.set((int)x,(int)y,color(0));}i2.save("o.png");}

Dengan spasi putih:

void h(String f, float x, float y, float m) {
  PImage i = loadImage(f);
  PImage i2 = loadImage(f);

  while (m > 0) {

    color c = i.get((int)x, (int)y);
    float r = red(c)/255;
    float g = green(c)/255;
    float b = blue(c)/255;
    float h = atan2(sqrt(3) * (g - b), 2 * r - g - b);

    float dx = cos(h);
    float dy = -sin(h);

    m-= 1;
    x += dx;
    y += dy;

    i2.set((int)x, (int)y, color(0));
  }

  i2.save("o.png");
}

rona gambar yang dilacak

Saya yakin saya bisa mempersingkat ini lebih jauh, tetapi itu bekerja untuk saat ini.

Kevin Workman
sumber
0

JavaScript 414

function P(G,x,y,l){
I=new Image()
I.onload=function(){d=document,M=Math,C=d.createElement('canvas')
d.body.appendChild(C)
w=C.width=I.width,h=C.height=I.height,X=C.getContext('2d')
X.drawImage(I,0,0)
D=X.getImageData(0,0,w,h),d=D.data,m=255,i=0
for(;l--;i=(w*~~y+~~x)*4,r=d[i]/m,g=d[i+1]/m,b=d[i+2]/m,H=M.atan2(M.sqrt(3)*(g-b),2*r-g-b),d[i]=d[i+1]=d[i+2]=0,x+=M.cos(H),y-=M.sin(H))
X.putImageData(D,0,0)}
I.src=G}
wolfhammer
sumber