画像の色相をトレースする


17

このスタックスニペットに画像をロードし、マウスをその上に移動します。カーソルポイントから始まる、色相角に続く黒い曲線が描画されます。

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

このスニペットはGoogle Chromeでのみテストしました。

たとえば、カーソルが赤の上にある場合、曲線の傾きは0°ですが、黄色の上にある場合、傾きは60°です。曲線は、指定された長さだけ継続し、色相に合わせて傾斜を連続的に変更します。

この画像をロードし、カーソルをパンすると、カーソルの周りの線が完全に反時計回りに回転します。

色相角

これこれは、試してみるのに適した他の画像です。(保存してからスニペットで読み込む必要があります。クロスオリジン制約のため、直接リンクすることはできません。)

スニペットの縮小されていないバージョンは次のとおりです。

チャレンジ

スニペットが実行していることを実行するプログラムを作成します。対話型ではありません。画像と画像の境界内の(x、y)座標、および最大曲線長を取得します。(x、y)から始まり、最大長に達するか、画像の境界に達すると終了する色相角に続く追加の黒い曲線を使用して、同じ画像を出力します。

具体的には、(x、y)で曲線を開始し、そこで色相角を測定します。その方向に1単位(1ピクセルの幅)移動します。新しい位置はおそらく整数座標ではないことに注意してください。曲線上の別の点をマークし、最も近いピクセルの色相を使用して再度移動しますfloorまたはのround、これを正確に確認しません)。曲線が範囲外になるか、最大長を超えるまでこのように続けます。終了するには、すべての曲線ポイントを画像上に重ねられた単一の黒いピクセル(再び、最も近いピクセルを使用)としてプロットし、この新しい画像を出力します。

「色相角」は色相です。

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

技術的に色相を持たないグレースケール値の場合、これは0を返しますが、それで問題ないことに注意してください。

(この式はatan2、ほとんどの組み込み数学ライブラリが持っているものを使用します。R、G、Bは0〜255ではなく、0〜1です。)

  • 一般的なロスレス画像ファイル形式だけでなく、画像ライブラリも使用できます。
  • stdinまたはコマンドラインから入力を取得するか、イメージファイル名、xおよびy、および最大長の引数を使用して関数を記述します。
  • 最大長とxおよびyは常に非負の整数です。xとyが範囲内にあると仮定できます。
  • 選択した名前で出力画像を保存するか、単に表示します。
  • 実装はスニペットと完全に一致する必要はありません。わずかに異なる丸め/計算方法により、わずかに異なる場所にあるいくつかのピクセルは問題ありません。(混chaとした場合、これは大きく異なるカーブにつながる可能性がありますが、視覚的に正しいように見える限り問題ありません。)

得点

バイト単位の最小の提出勝ちです。


1
このスニペットはFirefoxで完全に壊れています。
Ypnypn

SnippetはSafariでも機能しません。(しかし、クールな挑戦、+ 1)
アレックスA.

@ Calvin's Hobbiesチャットできますか?chat.stackexchange.com/rooms/22029/...
BrainSteel

回答:


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

@sanchisesからほとんどのセットアップなどをコピーしましたが、代わりstreamlineにパスの計算と描画に使用します。ただし、ラインをアンチエイリアスし、指定された最近傍ではなく双線形補間を使用します。


5

C、SDL、549 516バイト

このパーティーを始めましょう!なんらかの理由で、今夜ゴルフに挑戦したい気がしました。皆さんがしていることは難しいです...このサイトに見当たらないことが1つあるとしたら、それはSDLです。私はちょうどその理由を見つけたかもしれません。この特定のスニペットはSDL2とSDL1.2の両方に準拠していますが、ひどいです。と呼ばれf("imagename.bmp", xcoord, ycoord, max_length);ます。引数で指定された名前と同じ名前でファイルを保存します。出力はOPのコードスニペットに非常に似ているようですが、「ファジー」です。私はこれを少し後で修正しようとするかもしれません。

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

ここではすべて解かれています。

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

クロスプラットフォームにするために注意が払われたことに注意する必要があります-正直なところ、かなりのバイト数を切り捨てたとしても、私のマシン用にハードコードするのは気分が良くありませんでした。それでも、ここではいくつかの事柄が不必要だと感じています。後でもう一度見ていきます。

編集-------

結局のところ、これはグラフィカルな出力です...定期的に面白いと思う画像で更新します。

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

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)

サンプル出力: ここに画像の説明を入力してください

で呼び出す f("image.jpg", 400, 400, 300)

誰かがそれを改善する提案を持っているなら、私はインポートのために多くのキャラクターを無駄にしました。3.0では動作しない可能性があります


一目者:sqrt(3) -> 3**.5?ただし、インポートについては何も考えられません。
Sp3000

良いですね!これは将来役に立つでしょう。
-grovesNL

3

MATLAB、186 172

ゲームは 始まりました!コールt('YourImage.ext',123,456,100')(X、Y)=(123,456)から始まる任意のタイプのMATLAB支持体の画像、及び最大長さ100を初期位置にすることができない、正確のでに、(それは私の2つのバイトを要するであろう)右と下縁に端x=799.99から開始し、で開始するようなものを使用しx=800ます。インデックスは0ではなく1から始まります。

コード:

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)

改訂:

  • ラインがピクセルより長くなることはないので、ラインから前のピクセルから次のピクセルに変更して、ピクセルにドットを置くだけにしました! lineそれがピクセルを生成するために知っている最も短いコードであるので、まだ使用しています。
  • 色を黒から青に変更し、を使用Coして展開しますColor(MATLABはこれを自動的に行います)
  • 次の位置を計算して点を描画する順序を変更しました。これは、境界を確認していたので、実際に境界から描画していることに@grovesNLのおかげで気づいたからです。 変更しました。位置を変更した。
  • 線の描画から、rgbマトリックスを0に設定してから表示するように変更されました。

ブラックラインキャンディー


位置ではない、x=0またはy=0潜在的に有効な位置ですか?
-grovesNL

また、この166バイトはどうですか?
-grovesNL

@grovesNL申し訳ありませんが、誤ってfunctionヘッダーなしのテストバージョンをカウントしました。仕様はゼロベースまたは1ベースのインデックスを必要としなかったので、MATLABの1ベースのインデックスを使用しているため、このプログラムでは無効であるx=0か、y=0無効です。
-Sanchises

ああ、MATLABが1ベースだったことを忘れていました(しばらくの間)。しかし、私はそれを作ることを推測x=Xし、y=Y代わりに有効?
grovesNL

1
ハァッ!あなた自身のゲームであなたを打ち負かし私のMATLABソリューションはわずか135文字です!
-AJMansfield

1

処理中、323文字

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

空白あり:

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

色相トレース画像

これをさらに短縮できると確信していますが、今のところは機能します。


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}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.