jit.gl.pix でモルフォロジー処理を実装してみた : #max6 #jitter #cycling74

Before

スクリーンショット 2014-07-11 16.12.13

After

スクリーンショット 2014-07-11 16.12.10

モルフォロジー処理は、コバルト爆弾αΩのΔに教えてもらいました。ノイズを消すにはメディアンフィルターより良いとの事。エッジ抽出などにも使えるようです。アルゴリズムや使い道は、こちらが参考になりました。10個とか重ねて書けてもあまりfps落ちないので、シェーダー凄いっぽい。

CodeBox(モルフォロジー処理(収縮))


delta = 1/(dim+1);

outPix = in1;

for( i = 0 ; i < 9 ; i += 1) { x = ((i%3)-1) * delta.x; y = (floor(i/3) -1) * delta.y; pix = nearest(in1,vec( x,y ) + norm,boundmode="clamp"); outPix = switch(pix < 0.5, pix,outPix); } out1 = outPix;

pix < 0.5 を pix > 0.5 にすると膨張処理に変わります。

Max Patch

スクリーンショット 2014-07-11 16.22.09

Continue reading

jit.gl.pix でラプラシアンフィルターを実装してみた:#max6 #jitter #cycling74

Before-特大ゆっくり魔理沙(ニコニ・コモンズより)

スクリーンショット 2014-07-09 19.54.20

After ラプラシアンフィルターによるエッジ抽出

スクリーンショット 2014-07-09 19.54.12

メディアンフィルターに引き続き、ラプラシアンフィルターによるエッジ抽出をjit.gl.pix実装してみました。

jit.gl.pix – Codebox


//laplacian
filter = vec(0,1,0,1,-4,1,0,1,0);

//sharp
//filter = vec(0,-1,0,-1,5,-1,0,-1,0);

//mean
//filter = vec(1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9);

//mean2
//filter = vec(1/16,2/16,1/16,2/16,4/16,2/16,1/16,2/16,1/16);

//mean3
//filter = vec(1/3,0,0,0,1/3,0,0,0,1/3);

//sobel
//filter = vec(-1,0,1,-2,0,2,-1,0,1);

step = 1/(dim+1);

d = (vec( 0 % 3 , floor( 0 /3)) - 1) * step;
p0 = sample(in1,norm + d,boundmode="clamp");

d = (vec( 1 % 3 , floor( 1 /3)) - 1) * step;
p1 = sample(in1,norm + d,boundmode="clamp");

d = (vec( 2 % 3 , floor( 2 /3)) - 1) * step;
p2 = sample(in1,norm + d,boundmode="clamp");

d = (vec( 3 % 3 , floor( 3 /3)) - 1)* step;
p3 = sample(in1,norm + d,boundmode="clamp");

d = (vec( 4 % 3 , floor( 4 /3)) - 1) * step;
p4 = sample(in1,norm + d,boundmode="clamp");

d = (vec( 5 % 3 , floor( 5 /3)) - 1) * step;
p5 = sample(in1,norm + d,boundmode="clamp");

d = (vec( 6 % 3 , floor( 6 /3)) - 1)* step;
p6 = sample(in1,norm + d,boundmode="clamp");

d = (vec( 7 % 3 , floor( 7 /3)) - 1)* step;
p7 = sample(in1,norm + d,boundmode="clamp");

d = (vec( 8 % 3 , floor( 8 /3)) - 1)* step;
p8 = sample(in1,norm + d,boundmode="clamp");

sum = p0 * swiz(filter,0)
     + p1 * swiz(filter,1)
     + p2 * swiz(filter,2)
     + p3 * swiz(filter,3)
     + p4 * swiz(filter,4)
     + p5 * swiz(filter,5)
     + p6 * swiz(filter,6)
     + p7 * swiz(filter,7)
     + p8 * swiz(filter,8);

out1 = sum;

一番上のfilterの初期値を変える事で、いくつかのフィルターを試せるようにしてあります。

おまけ – jit.gl.pix の困ってるポイント

  • sample / nearest を function や for 文で、取得する位置を変更しながら繰り返し利用するとコンパイル通らない。
  • sample / nearest から取得した pixcel から swizしようとすると(例 : swiz(vec,0) ) コンパイルが通らない。
  • function と Param を同時に定義するとコンパイル出来ない事がある。

jit.gl.pix でメディアンフィルターを実装してみた:#max6 #jitter #cycling74

Before

lena noise

After – 3×3 メディアンフィルターで処理

lena median

ノイズが載った画像を綺麗にする必要が出てきたので、jit.gl.pix のシェーダーを使ってメディアンフィルター(Median Filter)を実装してみました。下の画像は、上記のノイズ画像をメディアンフィルターで処理した結果です。結構凄い!

jit.gl.pix で実装する上でのポイント

メディアンフィルターのアルゴリズムは、こちらにある通り、近傍の画素値を拾ってきて、並び替えた上で中央値を採用するという単純なものです。例えば、3×3で行うと中央のピクセルに対して周辺と自分を含めた9つの画素値を、明るさで並べ替えて、4番目の値を出力すればOK。

しかしjit.gl.pixでは実装に問題がありました。for文を使って近傍画素を取得し配列へ保存したいのですが、配列が使えないです。そのため変数(m0 ~ m8)を9つ用意し、愚直にベタ書きをしました。また並べ替えに関しても同様の問題がありバブルソートをベタ書きしています。

この問題点は、jit.gl.pixの仕様なのか、シェーダーの仕様なのかはわからないですが、非線形な処理を書こうとすると苦労しそうです。もし、簡単・軽量・カッコよく実装する方法があれば、是非教えてください!

jit.gl.pix Codebox – 3×3 Median Filter


sort(x,y){

return min(x,y),max(x,y);
};

xmin = 1/(dim.x - 1);
ymin = 1/(dim.y - 1);

//近傍画素の取得
//0
x = (-1) * xmin;
y = (-1) * ymin;
m0 = sample(in1,norm + vec(x,y),boundmode="clamp");

//1
x = (0) * xmin;
y = (-1) * ymin;
m1 = sample(in1,norm + vec(x,y),boundmode="clamp");

//2
x = (1) * xmin;
y = (-1) * ymin;
m2 = sample(in1,norm + vec(x,y),boundmode="clamp");

//3
x = (-1) * xmin;
y = (0) * ymin;
m3 = sample(in1,norm + vec(x,y),boundmode="clamp");

//4
x = (0) * xmin;
y = (0) * ymin;
m4 = sample(in1,norm + vec(x,y),boundmode="clamp");

//5
x = (1) * xmin;
y = (0) * ymin;
m5 = sample(in1,norm + vec(x,y),boundmode="clamp");

//6
x = (-1) * xmin;
y = (1) * ymin;
m6 = sample(in1,norm + vec(x,y),boundmode="clamp");

//7
x = (0) * xmin;
y = (1) * ymin;
m7 = sample(in1,norm + vec(x,y),boundmode="clamp");

//8
x = (1) * xmin;
y = (1) * ymin;
m8 = sample(in1,norm + vec(x,y),boundmode="clamp");

//バブルソート
m0,m1 = sort(m0,m1);
m0,m2 = sort(m0,m2);
m0,m3 = sort(m0,m3);
m0,m4 = sort(m0,m4);
m0,m5 = sort(m0,m5);
m0,m6 = sort(m0,m6);
m0,m7 = sort(m0,m7);
m0,m8 = sort(m0,m8);

m1,m2 = sort(m1,m2);
m1,m3 = sort(m1,m3);
m1,m4 = sort(m1,m4);
m1,m5 = sort(m1,m5);
m1,m6 = sort(m1,m6);
m1,m7 = sort(m1,m7);
m1,m8 = sort(m1,m8);

m2,m3 = sort(m2,m3);
m2,m4 = sort(m2,m4);
m2,m5 = sort(m2,m5);
m2,m6 = sort(m2,m6);
m2,m7 = sort(m2,m7);
m2,m8 = sort(m2,m8);

m3,m4 = sort(m3,m4);
m3,m5 = sort(m3,m5);
m3,m6 = sort(m3,m6);
m3,m7 = sort(m3,m7);
m3,m8 = sort(m3,m8);

m4,m5 = sort(m4,m5);
m4,m6 = sort(m4,m6);
m4,m7 = sort(m4,m7);
m4,m8 = sort(m4,m8);

m5,m6 = sort(m5,m6);
m5,m7 = sort(m5,m7);
m5,m8 = sort(m5,m8);

m6,m7 = sort(m6,m7);
m6,m8 = sort(m6,m8);

m7,m8 = sort(m7,m8);

//中央値の出力
out1 = m4;

参考

上記画像は、画像処理の分野で良く使われているLenaという女性の画像です。

jit.gl.pix を jit.gl.lua 内で利用する

スクリーンショット 2014-06-06 16.27.18


autowatch = 1
gc = 1

local mov = jit.new("jit.qt.movie",this.drawto)
mov.adapt = 1;
mov:read("bball.mov");

local frame = jit.matrix();
local plane = jit.new("jit.gl.videoplane",this.drawto);
local pix = jit.new("jit.gl.pix",this.drawto)
pix.gen = "aer.line.genjit"; -- readでは無く、genでファイルを読み込みます。
 

function draw()

    mov:matrixcalc(frame.name,frame.name)

    pix:jit_matrix({frame.name})
    pix:draw()

    plane:jit_gl_texture(pix.out_name)
    plane:draw();

end

ピクセルシェーダ jit.gl.pix による光るリングの描画 : #jitter #maxmsp

スクリーンショット 2014-05-20 19.25.52 jit.gl.pix を使ったシェーダーによる画像描画や処理を少しづつ学んで行こうと思います。今回は以下の参考サイトにあったコードを参考に光る輪っかを描画してみました。

コード

スクリーンショット 2014-05-20 19.26.28

  • snormで -1 ~ 1 に正規化した座標を取得
  • length によって原点からの距離に変換
  • !- 0.5 とabs により半径0.5の円周上の最も近い点から座標との距離に変換
  • !/ 0.02 により、座標における光の量を決定(半径0.5の円に近い点ほど、数値が高くなるため光が強くなる)
  • out 1 に光の強さを送る。自動的に vec 4 (R G B A)に変換されている

参考サイト

wgld.org – 時間経過とマウスカーソル座標