Görüntünün Renk Tonlarını İzleme


17

Bu yığın snippet'ine bir resim yükleyin ve farenizi üzerinde hareket ettirin. İmleç noktanızdan başlayarak ton açısını takip eden siyah bir eğri çizilecektir:

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

Bu pasajı yalnızca Google Chrome'da test ettim.

Örneğin, imleç kırmızı üzerindeyken, eğrinin 0 ° eğimi vardır, ancak sarının üstünde olduğunda 60 ° eğimi vardır. Eğri, belirtilen uzunluk boyunca devam eder ve eğimini tonla eşleşecek şekilde sürekli değiştirir.

Bu görüntüyü yükleyin ve imleci üzerine kaydırdığınızda, imlecin hemen yanındaki çizgi saat yönünün tersine tam bir dönüş yapmalıdır:

renk tonu açıları

Bu ve bu denemek için diğer düzgün görüntüler. (Bunları kaydetmeniz ve ardından snippet ile yüklemeniz gerekir. Çapraz kaynak kısıtlamaları nedeniyle doğrudan bağlanamazlar.)

Snippet'in küçültülmemiş bir sürümü:

Meydan okuma

Parçacığın ne yaptığını yapan bir program yazın, sadece etkileşimli değil. Bir görüntü ve görüntünün sınırlarında (x, y) bir koordinat ve maksimum eğri uzunluğu alın. Aynı görüntüyü, (x, y) ile başlayan ve maksimum uzunluğa ulaştığında veya bir görüntü sınırına çarptığında biten renk tonlarını izleyen eklenen siyah eğri ile çıktılayın.

Özellikle, eğriyi (x, y) 'de başlatın ve oradaki renk tonu açısını ölçün. Yeni konumunuzun büyük olasılıkla bir tamsayı koordinatı olmadığını belirterek, bu yönde bir birim (bir piksel genişliği) kullanın . Eğrideki başka bir noktayı işaretleyin ve en yakın pikseldeki tonu kullanarak tekrar hareket ettirin ( floorveya gibi bir şey kullanarak roundbunu tam olarak kontrol etmeyeceğim). Eğri sınırların dışına çıkıncaya veya maksimum uzunluğu aşana kadar bu şekilde devam edin. İşlemi tamamlamak için, tüm eğri noktalarını görüntünün üzerine bindirilmiş tek bir siyah piksel olarak çizin (yine en yakın pikselleri kullanın) ve bu yeni görüntüyü çıktılayın.

"Ton açısı" sadece renk tonudur :

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

Teknik olarak renk tonu olmayan gri tonlamalı değerler için bu değerin 0 değerini döndürdüğünü, ancak sorun olmadığını unutmayın.

(Bu formülde, atan2yerleşik matematik kitaplıklarının çoğunun bulunduğu kullanılır. R, G, B, 0 ile 255 arasında değil, 0 ile 1 arasındadır.)

  • Herhangi bir yaygın kayıpsız görüntü dosyası biçiminin yanı sıra görüntü kitaplıklarını da kullanabilirsiniz.
  • Stdin veya komut satırından girdi alın veya resim dosyası adı, x ve y ve maksimum uzunluk için bağımsız değişkenler içeren bir işlev yazın.
  • Maksimum uzunluk ve x ve y her zaman negatif olmayan tamsayılardır. X ve y'nin menzil içinde olduğunu varsayabilirsiniz.
  • Çıktı görüntüsünü istediğiniz bir adla kaydedin veya basitçe görüntüleyin.
  • Uygulamanızın snippet ile tam olarak eşleşmesi gerekmez. Biraz farklı yuvarlama / hesaplama yöntemi nedeniyle biraz farklı yerlerde birkaç piksel iyi. (Kaotik durumlarda bu, büyük ölçüde farklı olan eğrilere yol açabilir, ancak görsel olarak doğru göründükleri sürece, sorun değil.)

puanlama

Bayt cinsinden en küçük gönderim kazanır.


1
Snippet, Firefox'ta tamamen bozuk.
Ypnypn

Snippet, Safari'de de çalışmaz. (Yine de harika bir meydan okuma, +1)
Alex A.

@ Calvin'in Hobileri Sohbet edebilir miyiz? chat.stackexchange.com/rooms/22029/…
BrainSteel

Yanıtlar:


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

Kurulumun çoğunu kopyaladı ve @sanchises'den, ancak bunun yerine streamlineyolu hesaplamak ve çizmek için kullanıyorum. Çizgiyi yumuşatır ve belirtildiği gibi en yakın komşu yerine bilinear enterpolasyon kullanır.


5

SDL'li C, 549 516 bayt

Bu partiye başlayacağım! Nedense, bu gece golf elimi denemek gibi hissettim. Yaptığınız şey zor ... Bu sitede hiç görmediğim bir şey varsa, SDL. Nedenini yeni öğrenmiş olabilirim. Bu özel snippet, hem SDL2 hem de SDL1.2 ile uyumludur, ancak iğrençtir. Gibi denir f("imagename.bmp", xcoord, ycoord, max_length);. Bağımsız değişkenlerde verilenle aynı ada sahip bir dosya kaydeder. Çıktı, OP'nin kod snippet'ine çok benziyor, ancak "daha karmaşık". Bunu biraz sonra düzeltmeye çalışabilirim.

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

İşte hepsi çözülmüş:

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

Çapraz platform yapmak için özen gösterildiğine dikkat etmeliyim - dürüstlük açısından, önemli sayıda bayt kesmiş olsa bile makinem için sabit kodlamak iyi hissetmiyordu. Yine de, burada birkaç şeyin gereksiz olduğunu hissediyorum ve daha sonra tekrar bakacağım.

DÜZENLE-------

Sonuçta bu Grafiksel Çıktı ... Periyodik olarak ilginç bulduğum görüntülerle güncelleyeceğim.

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

HueTest1.bmp

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

HueTest2.bmp

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

HueTest3.bmp


3

Piton, 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)

Örnek çıktı: resim açıklamasını buraya girin

İle ara f("image.jpg", 400, 400, 300)

Herhangi birinin geliştirmek için önerileri varsa, içe aktarma için çok fazla karakter harcadım. 3.0 sürümünde çalışmayabilir


Bir bakışta Gönderen: sqrt(3) -> 3**.5? İthalat için hiçbir şey düşünemiyorum.
Sp3000

Güzel! Bu gelecekte faydalı olacaktır.
grovesNL

3

MATLAB, 186 172

Oyun başladı ! Çağrı olarak t('YourImage.ext',123,456,100')herhangi bir Matlab desteklerin bir görüntü için, (x, y) = (123,456) ve 100 ilk pozisyonları olamaz maksimum uzunluk başlayarak tam sağ ve alt kenarlarında böylece için, (yani bana iki bayt mal olacak) kenar gibi kullanım şeye başlamak x=799.99başlamak x=800. Endeksleme 0'da değil 1'de başlar.

Kod:

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)

Düzeltmeler:

  • Çizgi asla pikselden daha uzun olmayacağından, önceki pikselden sonraki piksele doğru bir piksele nokta koymaya değiştirildi! Hala linebir piksel üretmek için bildiğim en kısa kod olduğundan kullanıyorum .
  • Kullanarak rengi siyahtan maviye değiştirdi CoGenişletmeyi değiştirdi Color(MATLAB otomatik olarak yapar)
  • @GrovesNL sayesinde sınırları kontrol ettiğim için aslında sınırlardan çektiğimi fark ettiğimden, bir sonraki pozisyonu hesaplama ve bir nokta çizme sırası değişti pozisyonu değiştirdikten sonra .
  • Çizgi çizmekten rgb matrisini 0 olarak ayarlayıp daha sonra görüntülemeye değiştirildi.

Siyah çizgi şeker


Geçerli değil x=0veya y=0potansiyel olarak geçerli pozisyonlar mı?
grovesNL

Ayrıca, bu 166 bayt nasıl?
grovesNL

@grovesNL Üzgünüm, test sürümümü functionbaşlık olmadan yanlışlıkla saydım . Spec sıfır tabanlı veya tek tabanlı indeksleme gerektirmedi, bu yüzden MATLAB'ın tek tabanlı kullanıyorum, bu yüzden hayır x=0veya y=0bu programda geçerli değil.
Mart'ta Sanchises

Ah, MATLAB'ın tek tabanlı olduğunu unuttum (bir süredir). Ama sanırım bu geçerli x=Xve y=Ygeçerli olabilir mi?
grovesNL

1
Hah! Kendi oyununda yen, MATLAB çözümüm sadece 135 karakter!
AJMansfield

1

İşleniyor, 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");}

Boşluk ile:

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

renk tonlu izlenen görüntü

Eminim bunu daha da kısaltabilirim, ama şimdilik işe yarıyor.


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}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.