2012.02.13 | 

あと15分で月曜日。今回苦戦のため画像が準備できませんでした。
こんばんはmuchoです。

今回はGLSLでGaussian Blurの自作に挑戦しました。
作りたいというか欲しかったのが、とにかく高速で、大きくボケるフィルター。

ズバリ目指したのはこれ↓
http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
最初はquasimondoさんのソースをさっくり移植しようと思ったんですが、
商用で使ってる方もいるみたいで、二次利用を断念。

こちらのサイトを参考にしました。
http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/
英語なのでいまいちよく分かりませんが、
まず横にぼかしをかけて、
その結果画像をさらに縦にぼかすと
計算が少なくてすむということらしい。
9ピクセルぼかすとすると本来なら
9x9=81
それを横と縦で分けることで
9+9=18
この差は大きい!
実際9x9的な本来のブラーを作ってみましたが、OpenCVのGaussian Blurと比べて
高速化が感じられず、上記の横かけて、縦かけての2段階描画方式にしてみました。
まずはそのままコピペしてみたところ、大きくぼかすとおかしなことに。
というわけで、参考サイトでは9+9固定なのですが、ボカすサイズによって、
描画回数が変わるように書き直してみました。
以下がそのソース。

煮詰まりまくりで作ったので、微妙にソースに意味不明なところがあります。
さらにどうも正弦波の値の求め方がおかしいような?
おまけに、本来のブラーよりは高速化したとはいえ、大きくぼかすと
まだまだ実用には厳しい遅さ。。。
次回はquasimondoさんのソースをさらに読み解きつつ、
これをチューニングできたらと思います。できるのかなー。怪しいなー。



//horizontal Fragment Shader
#version 120
uniform sampler2D texture0;
uniform int width;
uniform int height;
uniform float blurSize;

void main()
{
	float v;
	float w_step = 1.0 / width;
	float h_step = 1.0 / height; 
	float radius = blurSize;
	if ( radius < 0 ) radius = 0;
	int steps = int(radius);
	float x = gl_TexCoord[0].x;
	float y = gl_TexCoord[0].y;
	float pi = 3.141592653589793;
	float t = 1/(steps*2+1);
	vec4 sum = texture2D(texture0, vec2(x, y))*t;
	int i;
	for(i = 1; i<=steps;i++){
		v = (cos(i/(steps+1)*pi)+1)*0.5;
		sum += texture2D(texture0, vec2(x + i*w_step, y))*v*t;
		sum += texture2D(texture0, vec2(x - i*w_step, y))*v*t;
	}
 
  gl_FragColor = sum;
	
}

//---------------------------------------------------------------
//vertical Fragment Shader

#version 120
uniform sampler2D texture0;
uniform int width;
uniform int height;
uniform float blurSize;

void main()
{
	float v;
	float w_step = 1.0 / width;
	float h_step = 1.0 / height; 
	float radius = blurSize;
	if ( radius < 0 ) radius = 0;
	int steps = int(radius);
	float x = gl_TexCoord[0].x;
	float y = gl_TexCoord[0].y;
	float pi = 3.141592653589793;
	float t = 1/(steps*2+1);
	vec4 sum = texture2D(texture0, vec2(x, y))*t;
	int i;
	for(i = 1; i<=steps;i++){
		v = (cos(i/(steps+1)/pi)+1)*0.5;
		sum += texture2D(texture0, vec2(x, y + i*h_step))*v*t;
		sum += texture2D(texture0, vec2(x, y - i*h_step))*v*t;
	}
 
  gl_FragColor = sum;
	
}



2012.02.03 | 

こんばんは。muchoです。
寒い日が続きますね。こんな日はおでんで一杯とか。
そんな夢のような枕詞を置いたところで
今日もはりきっていってみましょう。0時回ってます。

さて今回は前回の続きでnoiseです。
simplex noiseを何回もかけて複雑なnoiseにしようという試みです。
http://www.davidcornette.com/glsl/noise.html
上のサイトに参考画像があるので分かりやすいと思いますが、
ノイズの細かさを変更して何度も計算することで複雑なノイズになります。



	float k = 200;
	float n1 = simplexNoise(vec3(gl_TexCoord[0].x*k*0.005,gl_TexCoord[0].y*k*0.005,time));
	float n2 = simplexNoise(vec3(gl_TexCoord[0].x*k*0.01,gl_TexCoord[0].y*k*0.01,time));
	float n3 = simplexNoise(vec3(gl_TexCoord[0].x*k*0.02,gl_TexCoord[0].y*k*0.02,time));
	float n4 = simplexNoise(vec3(gl_TexCoord[0].x*k*0.03,gl_TexCoord[0].y*k*0.03,time));
	float n5 = simplexNoise(vec3(gl_TexCoord[0].x*k*1.0,gl_TexCoord[0].y*k*1.0,time));
	float n6 = (n1 + n2 + n3 + n4 + n5)*0.2;



こんな感じで5回かけてみました。
n1が一番ゆるくて、n5が一番こまかいです。

さすがに激重かなと思ったのですが、耐えれる速度で動きました。
前回と同じように雲模様的な動画にしてもよかったんですが、
より処理速度が分かるようにと思いカメラ映像に合成してみました。

結局パラメータを調整してノイズを飛ばし気味にしてしまったので、
フラクタル感がいまいちよく分からないですね・・・。

2011.06.10 | 

最近暑いですねー。こんばんはムーチョです。節電でがんばってます。
ドロネー三角形分割第3弾です。
前々回前回の続きです。

あれから、kaminalyと試行錯誤を繰り返し、
(主にkaminalyによって)最適化をほどこし、
さらに領域外の分割点も使うように変更しました。

その過程で衝撃の事実が発覚しましたのでご報告。
Cinderのgl::draw()やgl::drawLine()は遅い!
もうムーチョがっかりです。


前回と見た目は一緒ですが、速度は倍ぐらいに(当社比)

さらにちょっと遊んでみました。

画像を読み込んで、ポイントのばらつきをちょっと制御
この時点じゃなんだかよく分かりませんね。


さらに色も画像から引っ張ってみたり。どうでしょう?読めますかね?

ソースはこちらです。よろしければどうぞ。
DelauneayRectApp.cpp
さらにあわせ技でカメラ画像をキャプチャーしたりもしましたが、
それはまたの機会に。ムーチョでした。では皆さんよい週末を。

2011.06.05 | 

前回に引き続きドロネー図行ってみましょう。こんにちは。ムーチョです。
今回は面を塗りつぶします。
前回同様にOpenCVのソースに含まれるサンプルをもとに作成しました。
おおまかな流れはこんな感じです。

1.空のドロネー空間を作成
2.座標をドロネー空間に追加
3.面の座標3点を取得
4.描画

1.2.は前回と全く一緒なので飛ばして3.へ。
さすがはOpenCV!あっさり3点が取れる関数が平然と用意されてるッ!
そこにシビれる!あこがれるゥ!
って展開を思い切り期待していましたが、そんなことはありませんでした・・・。

サンプルをみる限り、線の時とほぼ同じで、
まずは1辺を取り、右隣の接する辺を取得してそれで3点にたどり着くという手法。
そこだけ抜粋するとこんな感じです。


	CvSeqReader  reader;
	cvStartReadSeq( (CvSeq*)(subdiv->edges), &#038;reader, 0 );

// 線の時と同じ形でなぜか総当たり
	for( i = 0; i < total; i++ ){
		CvQuadEdge2D* edge = (CvQuadEdge2D*)(reader.ptr);
		if( CV_IS_SET_ELEM( edge )){

// 辺から2点を取得
			pt0 = cvSubdiv2DEdgeOrg((CvSubdiv2DEdge)edge);
			pt1 = cvSubdiv2DEdgeDst((CvSubdiv2DEdge)edge);

// 右隣の辺を取得
			t = cvSubdiv2DGetEdge((CvSubdiv2DEdge)edge, CV_NEXT_AROUND_LEFT );
			pt2 = cvSubdiv2DEdgeDst(t);

		}
		CV_NEXT_SEQ_ELEM( elem_size, reader );
	}


その3点からTriMeshを作成して塗りつぶし。
とりあえずアルファ10%で塗ってみたところ、あれ?


これはこれでありか?いやいや。

という訳で塗れてない面やら何度も塗ってる面やらバラバラ。
サンプルをよくよく見直してみると、1辺から二つの面を取得してました。
という訳で以下を追加してたところ・・・


// 基準にしてる辺を反転
			e = cvSubdiv2DRotateEdge( (CvSubdiv2DEdge)edge, 2 );
// 辺から2点を取得
			pt0 = cvSubdiv2DEdgeOrg(e);
			pt1 = cvSubdiv2DEdgeDst(e);
// 反転させた辺の右隣の辺を取得
			t = cvSubdiv2DGetEdge(e, CV_NEXT_AROUND_LEFT );
			pt2 = cvSubdiv2DEdgeDst(t);



均質にはなったが、なんか濃いです・・・。

当然ながら辺総当たりなので、面1つにたいして辺が3つあるため
3倍塗ってるご様子。
どうもサンプルソースもそれっぽい。
そこでやや強引ですが、重複を削除することを決意。
C++初心者のムーチョはここでハマりまくり。

単純にソート&ユニーク化は効果なし・・・。

ソート時に比較しやすいように座標で持つのをあきらめ、
前回追加してたflagを3点のIDとして持った構造体に変更。
アンド、ID(int)3点の大小でソートできるように比較関数を用意。

比較関数がコンパイル時にエラーはきまくり。クラスにすることで回避。

と思ったのもつかの間、それ用に定義した構造体を渡すと、比較関数がエラー。
構造体をあきらめ、配列にするもエラー。C++の配列ってホント使いにくい。

vectorにしたら無事動くがややもっさり。
やっぱり構造体的なものの方がいいのか?と
省力化を兼ねてCinderが元々持ってるVec3iに3点のIDを格納しちゃえと変更。

再びエラーで動かなくなる。Vec3iをVec3fに変更。
もうかなりやけっぱち。後々わかりにくくなりそうだけど、エコですよ。エコ。

これでどうにか動くように。vectorを使ってた時より少し速くもなりました。
基本がないってつらいですね。



// まずは並べ替え
	polys.sort(comparePolyKey());

// 重複を削除
	list<Vec3f>::iterator last_it = unique(polys.begin(), polys.end());
	polys.erase(last_it, polys.end());

// 並べ替え用のクラス
class comparePolyKey {
public:
	bool operator()(const Vec3f&#038; left, const Vec3f&#038; right)
	{
		return (left.x < right.x)
		 || (left.x == right.x &#038;& left.y < right.y)
		 || (left.x == right.x &#038;& left.y == right.y &#038;& left.z < right.z);
	}
};


そんなこんなでようやくキレイに塗れました。

ぱっと見が退屈なのが非常に残念。

おまけにソートとユニーク化をかける前より高速化したので、
面倒でしたがこちらの方がいいですね。
そもそも3倍まわさないようにしたいのですが、
どう書くのがいいのか思いつかず・・・。
かなりいっぱいいっぱいなドロネー図でした。

さらに画像を解析して分割・塗りつぶしをしようと思っていましたが、
リアルタイムでは処理落ちしそうです。

2011.06.04 | 

先日、4時前に空が明るくなっててびっくりしました。
夏がまたやって来ますね。マサラ・ムーチョことムーチョです。こんばんは。
さてさて、Flash界では流行ともいえるドロネー図
Cinder+OpenCVで逆輸入してみました。
つたないソースですが、ソースコードも公開します。

座標群をドロネー三角形分割化し、出力するわけですが、
出力で必要なのは線だとつながる2点、面だと3点が必要になります。
今回は線の出力です。


おおおつながってるよ! 今回座標の数は2000。60fpsでもギュンギュン。

(続きを読む...)