Kinect x openFrameworks x Delaunay ver.0 from rettuce on Vimeo.
Kinect x openFrameworks x Delaunay ver.0-b from rettuce on Vimeo.
Vimeoがタダアカウントなので1週間に1個しか上げれない。。(´・_・`)
あと、映像に入ってるインターレースノイズは僕がPremireで書き出し設定ミスってるだけの話で、
実際にはキレイです。。(´;ω;`)ブワッ
今回たまたま案件で映像エフェクトのデザインが必要な部分があって、
止まり絵から考えるのとかあんまり現実的じゃないし実装しながら自分で表現考えますよー。
って割と好き勝手任せてもらえる感じで、一番テンション上がる開発方法とらせてもらったんで、
ちょっとそこからもうちょっとかっこよくできそうだなーって色々ブラッシュアップしてったよメモ。
初期の依頼は怪しい無機質な世界観で、それを映像として撮れればいいという内容だったので、
じゃあ映像素材としてKinect使った表現にしてみたら割とサイバーな感じでかっこいいんじゃない?ってことで
Kinect使ってデモってみた。散々見た表現だけどもやっぱ割といい感じ。でKinect使った表現でおkでた。ワーイ
こーやって自分で手を動かしながら表現と実装同時にディティール詰めて行くみたいな開発手法って、
デザインと実装同時にやりたい自分には一番自然だし、改めてその辺り、時代や流行に合わせて自分の仕事のやり方も
自分で作ってかないとなーて思ってた。何よりやっぱそれが一番テンション上がるし。あー話脱線した。
ということでやるやる詐欺になりつつあったoFとかKinectとかで映像素材作ってみためも。
KinectもoFも結局2年ぶりくらいにちゃんと触るなぁ。。(遠い目
でもまー、一歩目としてはoFとかxcodeとかようやくがっつり触れたので
これからどんどんweb以外もつくって行けそう。超楽しい。ワクワク感しかない。
で、今回oF内でやったことはこんな感じ。
(1)平面上にランダムPoint生成
(2)Kinectからのカメラ入力
(3)特定の深度域を抽出
(4)抽出部分内に重なるランダムPointを取得
(5)そのポイントをdelaunay分割
(6)3点ごとの頂点indexと3軸座標の抜き出し
(7)このポイントと面情報を使ってMesh生成
(8)三角形3点の中心座標にあたる部分の色をカメラ情報から取得
(9)三角形の面として描画
まーこれでポリゴンぽくなるだろ。って感じでつくった。
3D表現に使われてるのはこんな感じ。
Point → 頂点毎の3軸座標にそれぞれofCircleで描画
wire → ofDlaunayでのwire描画
face → ofVboMeshのaddVerticesとaddColorを使った描画
これはたまたま勉強過程で進んでいったらこの道筋が楽だっただけで、
わかってる人はたぶんMesh単体だけで全部できちゃいそう。
僕はKinectの設定とかXcodeの設定とか、新規プロジェクトの複製方法とか、
addonの追加方法とか、OSバージョンの違いとかで諸々くっそハマったんだけど、
今なら最新oF(v0073)とか落としてくれば projectGenerator っていう
新規プロジェクト簡単につくれるappついてくるので、それで追加したいaddonとかぽちぽち選んでって、
generateすれば新規projectすぐ作れるよ!くっそ!
まず何はともあれ Kinect の Hello World.
お決まりの Point Cloud。よく見るけどやっぱ未来感(現在だけどな)出ていいよね。うん。
//// setup //// kinect.init(); kinect.open(); // 0-300の部分だけ深度取る ここ割と細かく設定できると精度上がる気がした kinect.setDepthClipping(0,300); // これでColorの通常カメラと深度カメラのズレ修正できた kinect.setRegistration(true); // Kinect 初期の首角度 kinect.setCameraTiltAngle(22);
//// update //// kinect.update();
//// draw //// // OpenGLの設定。ここ忘れるとz深度が正しい順番にならない glEnable(GL_DEPTH_TEST); int step = int(space); for (int j = 0; j < kinect.height; j+=step) { for (int i = 0; i < kinect.width; i+=step) { // (x,y)のz位置取得 float distance = kinect.getDistanceAt(i, j); // 欲しいz深度範囲だけ描画 if(distance>50 && distance<1000) { // 色取得 ofSetColor(kinect.getColorAt(i,j)); ofPushMatrix(); ofTranslate(i-kinect.width, j-kinect.height, distance*-2.0); ofCircle(0, 0, int(radius)); ofPopMatrix(); } } }
※ spaceとかradiusとかは外部変数でGUIからの調整値。
と、まあこんな感じ。やり始めは訳分かんなかったけど、
やってみたら特に説明する所もないな。。w
ちなみにこの辺りの説明だったりoFの基礎的な部分はたどころせんせの授業資料読み漁れば完璧だと思うw
で、できたのこんなん。よく見るやつね。
次に3Dのポリゴンにするにはって考えて、3点情報持った多重配列みたいなことがしたくていろいろ調べて見る。
ちなみにポインタの概念は分かったのだけどこの時点では余裕なかったのでポインタとかバッサリ無視。
3点情報はofVec3fを、色情報はofColorをつっこむことにした。
oFのArrayは配列の長さ自動で変更されないとか、なんか使い勝手悪かったのでVectorで。
そいえばoFでもやっぱVectorの方が早いのかな。
//// header //// ofMesh mesh; // ofVboMesh vector< vector> points; vector< vector > colors; vector< vector > indexs;
こんな感じで多重配列は用意できた。
ofMesh使うよりofVboMesh使う方がよさげってどっかで見たので
途中からはofVboMesh使ってたんだけど、特に三点情報もたせてそれらに点、線、面が
描画できればそれでよかったので使い方は一緒。
//// update //// //clear mesh.clear(); points.clear(); colors.clear(); indexs.clear(); // 3点情報と色情報取得 int step = int(5 + int(scaledVol*15)); int total = 0; for (int j = 0; j < kinect.height; j+=step) { vectortemppoints; vector tempcolors; points.push_back(temppoints); colors.push_back(tempcolors); for (int i = 0; i < kinect.width; i+=step) { float distance = kinect.getDistanceAt(i, j); if(distance>50 && distance<1000) { ofVec3f tempPoint; ofColor tempColor; tempPoint = ofVec3f(i, j, distance*-2.0 ); tempColor = ofColor(kinect.getColorAt(i,j)); points[j/step].push_back(tempPoint); colors[j/step].push_back(tempColor); total++; }else{ ofVec3f tempPoint2; ofColor tempColor2; tempPoint2 = ofVec3f(i,j,0); //範囲外には深度0 tempColor2 = ofColor(0); points[j/step].push_back(tempPoint2); colors[j/step].push_back(tempColor2); } } } // 深度情報をindexを付与 int ind = 0; for (int m = 0; m < kinect.height; m+=step) { vector tempindexs; indexs.push_back(tempindexs); for (int n = 0; n < kinect.width; n+=step) { if(points[m/step][n/step].z != 0){ // cout << points[m][n] << endl; mesh.addColor(colors[m/step][n/step]); mesh.addVertex(points[m/step][n/step]); indexs[m/step].push_back(ind); ind++; }else{ indexs[m/step].push_back(-1); } } } // meshにTriangle追加 int W = int(kinect.width/step); for (int b = 0; b < kinect.height-step; b+=step){ for (int a = 0; a < kinect.width-1; a+=step) { if( (indexs[int(b/step)][int(a/step)]!=-1 && indexs[int(b/step)][int(a/step+1)]!=-1) && (indexs[int(b/step+1)][int(a/step+1)]!=-1 && indexs[int(b/step+1)][int(a/step)]!=-1) ){ mesh.addTriangle(indexs[int(b/step)][int(a/step)],indexs[int(b/step)][int(a/step+1)],indexs[int(b/step+1)][int(a/step+1)]); mesh.addTriangle(indexs[int(b/step)][int(a/step)],indexs[int(b/step+1)][int(a/step+1)],indexs[int(b/step+1)][int(a/step)]); } } }
//// draw //// mesh.setMode(OF_PRIMITIVE_TRIANGLES); glLineWidth(int(LINE_WEIGHT)); mesh.drawWireframe();
なんというかこの辺りは以前flashで触ったAlternativa3dとかと概念一緒やから楽チン。
こいうときに触っててよかったってなるね。:)
ワイヤーでいけた。
ここからメモがない。。汗
。。で、2ポリゴンに対して1つだけ塗ってみる。
両方。この時はまだポリゴンの頂点部分の色を取ってるだけなので
なんだか色の段差が激しい感じ。
あとやっぱり規則正しく並ぶとポリゴン感が安っぽくなるので、
ランダムポイントにしてDelaunayアルゴリズムで結んでみる。
五角形モチーフで遊んでみたり。
で、色の取り方はポリゴン三点の(だいたい)中央の色情報を面の色として使うようにした。
白が頂点で赤がその面に使用する色取得点。
これで完成。:)
実際のん。
声の音量に合わせてポリゴンブロック数削ってZ深度に変化与えたり。
で、この案件では人の個性を消したかったので、これはこれで終了。
でもこれだとランダムなんだけど結局ポリゴン面のサイズがどうしても
均一になるのが嫌なんだよなぁと悩んで風呂入ってるとふと下の一作業を思いついて、
最終的には目鼻口とかのポリゴン細かい部分も描画できるようになったので映像うp!
(0)OpenCVのCannyアルゴリズムで輪郭線抽出してPoint追加
これで細かい部分と何もない部分の描画で変化つけれるようになった。:)
あとは関係ないけど、背景とかに使われてた音声イコライザーみたいなんもoFで作ったりしてますた。
基本的にはoFアプリとAIRアプリしか作らない2ヶ月間だったなー。超楽しかった!
さてさて次は春に向けてまた楽しいもん作りますよーっと。:)
you
追記。
お知り合いの先輩からわざわざアフィリエイトの存在を教えてもらったので速攻作りました!w
ありがとうございます!:)
追記2。
JAYPEGにもアップしたらPopular入りしたー!!嬉しい。:)
これって、プログラムでも一種のデザインとして認められるってことよね。:)
追記3。
あ、これ単体のソースコードじゃないけど、この表現を2台のKinect使って人をキャプチャして
3Dデータ、gifアニ、pngなどのデータ群に変換するってプロジェクトをこれの半年後くらいにやって、
その時のソースコードは以下からgithubに上げてるのでよろしければそちらからどーぞご自由にお使いくださいませ。
この時のソースコードよりは幾分かマシなハズ。。。
.hito project つくりました。