トップ 差分 一覧 ソース 検索 ヘルプ PDF RSS ログイン

独り言日記(2007/07)

独り言日記

メルセンヌツイスター(2007/07/30)

かなり昔から使っていた擬似乱数ルーチンがあるのですが(数学書に載っていたFORTRANのものをC++に移植したものです。少なくともANSI Cのrandよりは散らばりがある)、最近の作業にて周期的な部分が出てしまう、ってのが発生していました。今まで(自前)GIレンダラでも使ってたくらいなので、そんな変えるまでもないかなぁと思ってたのですが・・・。こんなこともあるもんですね。私用でも仕事でも10年くらい使っていたルーチンなんですが、今までお世話になりました。

ということで、もっと精度のいいメルセンヌツイスターに置き換えるようにしました。

http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/mt.html

これで散らばりがさらに出てきた感じです。周期も目立たなくなったかな。

しかし、なかなか原因が見つからずに追いかけていたものが、根本の擬似乱数ルーチンの周期問題とは思ってもみませんでした。よく、再現性のあるツボにはまったもんだなぁと。

OpenCV(2007/07/27)

息抜きにお遊びを。OpenCVにて画像処理を行うことができ、顔検出が結構簡単にできそうでしたので試してみました。以下がOpenCVのご本家です。

http://sourceforge.net/projects/opencvlibrary/

サンプルソースの「facedetect」より、最低限使う部分だけ抜き出して日本語コメントを入れてみました。

#include "cv.h"
#include "highgui.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

static CvMemStorage *storage = 0;
static CvHaarClassifierCascade *cascade = 0;

void detect_and_draw(IplImage *image);

/**
 * メイン関数
 */
int main( int argc, char** argv )
{
    const char *cascade_name;

    if(argc < 2) {
        printf("引数に画像ファイル名を指定してください。\n");
        return -1;
    }

    // 認識で使用するパターン
    cascade_name = "../data/haarcascades/haarcascade_frontalface_alt2.xml";

    cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
    
    if(!cascade) {
        printf("認識のパターンファイルが読み込めませんでした。\n");
        return -1;
    }

    // メモリ領域を生成
    storage = cvCreateMemStorage(0);

    const char *filename = argv[1];
    // イメージを読み込む。第二引数は色を有効にしている。
    IplImage *image = cvLoadImage(filename, 1);
    if(!image) {
       char szStr[256];
       sprintf(szStr, "画像 [%s] の読み込みに失敗しました。\n", argv[1]);
    }

    // 画像解析
    detect_and_draw(image);

    // 画像を解放
    cvReleaseImage(&image);

    cvClearMemStorage(storage);

    return 0;
}

/**
 * 顔認識を行う関数
 */
void detect_and_draw(IplImage *img)
{
    double scale = 1.3;     // 若干縮小
    CvPoint p1, p2;
    CvScalar col;
    int penSize = 3;
    int i;
    double t;

    // カラの画像を生成する
    IplImage *gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );

    // 8bpp(グレイスケール保持用)の画像を生成する
    IplImage *small_img = cvCreateImage(cvSize( cvRound (img->width/scale),
                         cvRound (img->height/scale)),
                     8, 1 );

    // RGBの画像をグレイスケールに変換(img ==> gray)
    cvCvtColor(img, gray, CV_BGR2GRAY);

    // 画像のリサイズ(gray ==> small_img)
    cvResize(gray, small_img, CV_INTER_LINEAR);

    // グレースケール画像のヒストグラムを均一化
    cvEqualizeHist(small_img, small_img);

    cvClearMemStorage(storage);

    if(cascade) {
       t = (double)cvGetTickCount();

       // 画像中のオブジェクト(ここではcascadeの情報であらわされる顔)を検出
       CvSeq* faces = cvHaarDetectObjects(small_img, cascade,
            storage, 1.1, 2, 0   /*CV_HAAR_DO_CANNY_PRUNING*/,
            cvSize(30, 30) );

       t = (double)cvGetTickCount() - t;

       printf( "cvHaarDetectObjectsでの計算時間 %gms\n",
           t / ((double)cvGetTickFrequency()*1000.0));

       for(i = 0; i < (faces ? faces->total : 0); i++) {
           // 顔を囲むバウンディングボックスを取得
           CvRect* r = (CvRect*)cvGetSeqElem(faces, i);

           // 矩形を描画する
           p1.x = (int)((r->x) * scale);
           p1.y = (int)((r->y) * scale);
           p2.x = (int)(((r->x) + (r->width)) * scale);
           p2.y = (int)(((r->y) + (r->height)) * scale);
           col.val[0] = 0;             // Blue
           col.val[1] = 255;           // Green
           col.val[2] = 255;           // Red
           cvRectangle(img, p1, p2, col, penSize);
       }
   }

   cvSaveImage("out.jpg", img);            // 画像を保存

   // 使用した情報を解放する
   cvReleaseImage(&gray);
   cvReleaseImage(&small_img);
}

実行時にコマンドライン引数で画像ファイル名を指定すると、その画像から顔の部分だけ矩形で囲って「out.jpg」に出力するものです。OpenCVのサンプルではWebカメラ対応とUIがあったのでそれは除外してます(といっても扱いは非常に簡単。Webカメラ制御はDirectShowが複雑怪奇なのに比べてスマートです)。

「haarcascade_frontalface_alt2.xml」というのが識別パターンらしく、別に顔でなくてもこれを作ることで他の物体のみを検出したり、とかできそうです。

で、サンプルの「haarcascade_frontalface_alt2.xml」で正面からの顔は検出できるのですが、少し斜めを向く、首をかしげる、などするとアウトになります。もしかしたら、そのパターンを登録してあげるともっと精度上がるのかなぁ。

ただ、集合写真などで認識させると結構な確率で顔の部分を選択できますね(「集合写真」でググッたらいろいろ実験できそうな写真が出てきました)。何もない空間を囲うことがあるのですが、、、微妙に顔の模様でも出てるのかな。後、アニメでも試しましたが、、、写真でないと判別が弱いですねぇ。これもサンプリング次第?

OpenCV自身は顔認識以外でも汎用的に2D画像を解析できるライブラリですので、使い方次第で面白いものができそうではあります。何よりも簡単に扱えるってのがすばらしいです(Microsoft(特にCOM関連のもの。DirectShowとかIEコンポーネント制御とか)もみならってほしぃ)。

続続・重ならないUV展開(2007/07/24)

バグチェックおよび最適化を行い、以下のように展開できました。顔の例ではあまり重なりがないため、ウサギで。

6万ポリゴンくらいのスケルトン(DirectX9に付属)にてPentium4 2.8GHzマシンにて600msくらいでUV設定してます。ただ、スケルトンもそうですが複雑な形状だとやはり細かくなりすぎて不正が出てしまいますね。

ということで、UV展開に関してはこれで終止符です(どこで使うかは内緒。UV展開のため、ではありません(^^;;)。

続・重ならないUV展開(2007/07/23)

意外と実装の都合で速度に影響する部分もありそうです。

Cube的に投影した三角形をそれぞれ比較していては抜群に時間がかかりますので、ちょっと小細工。再配置しても5万ポリくらいですとUV割り当てに1秒もかからないようにしてみました。ただ、複雑な形状だと重なりが出てしまう(DirectXのガイコツとか)・・なんか間違ってますね・・。

でも、いずれにしてもこの展開では後でテクスチャを塗るのは難しそう・・・。

重ならないUV展開(2007/07/21)

http://www.interq.or.jp/aquarius/ikeda3dr/tutorials/html/texture8.htm

に書いてある「オートマティックプロジェクション」というのがUVがかぶってない感じですね。理論として考えられるのは・・・

  • 各ポリゴンの法線をみてCubeとして6方向に投影し、完全に描画されているもの(一切隠れていない)をリストアップ。このときの各投影面はUVともに0.0〜1.0を与える。
  • 個々の投影面にて陸続きになっている部分をボックスで囲む(ひとつの投影面で複数のボックスができることあり)。
  • できた複数の「矩形範囲(UVに相当)と内包されるポリゴン番号(頂点ごとにUVを保持)」をスタックにプッシュ(ここで処理されたポリゴンはリストから除去)。
  • 再び6面に投影し、ポリゴンがなくなるまで再帰的に繰り返す。

で、スタック上に複数の異なるサイズの矩形情報(ポリゴンが内包されている)ができるので、これを並び替えて一枚のテクスチャに入れるようにします。格納手順は以下のとおり。

  • 矩形の高さが大きい順に並び替える。
  • テクスチャの左上から順番に入れていく。横方向(U)が一定範囲を超えた場合は下段に折り返し(可能な限り、最終的には正方形になるような形に落とし込んだほうがいいかも)。
  • 全体のUVが0.0〜1.0に収まるように各矩形のUVおよび内包されているポリゴンのUVを補正する。

これで、重ならないUV展開は完成、するかな。ポリキューブマップは論文を見てみて、どうもピクセルシェーダーでないと実現できないような気がしたので(たとえば、セルサイズよりも大きなポリゴンがある場合には分割しないといけない、というか、シェーディング時に実オブジェクト上での交点をボクセル空間に投影してからピクセルごとにテクスチャ色を求めている?)またもや方向転換。

たぶん、上のオートマティックプロジェクション理論(論文があるかは不明です。上のサイトの画像だけ見て適当にでっちあげてみました(^_^;;)でいけるでしょう・・・。

OBBの再帰(2007/07/20)

よく考えると「オブジェクトの特徴を見て複数の形状に分解できる場合は」ってのは、OBBを再帰したものとなんら変わらない結果になりそうな気がしてきました(汗)。

上記はShade9のパーティクルフィジックスのボックス分解ですが、やってることはオブジェクト全体を囲むOBBを求めてからそれを二分割して、左と右をOBB計算して2つの直方体の傾きとサイズを求める、で再帰で繰り返すという単純な作業です。

で、ここからOBBごとにUV展開しても、、無駄が多いというかそもそもUV自身が使い手向けにできないよなぁと。やはり今のところは切れ目を入れて開くLSCMが妥当なところなんでせうか。。。

ということで、時間も厳しいので普通にポリキューブマップすることにします(^_^;;。

http://vcg.isti.cnr.it/polycubemaps/

OpenCV(2007/07/20)

いずれ使えるかもしれないのでメモです。PCA(主成分分析)あたりを調べていて、たまたま見つけたライブラリです。「OpenCV」はインテルのオープンソースプロジェクトで、画像の特徴検出ができるとのこと。

http://sourceforge.net/projects/opencvlibrary/

Webカメラで顔だけリアルタイム検出とか、できそうです。

http://www.masayashi.com/labs/laughing_man/

の内容が何が出来るかわかりやすかったです。

先日の日記内容であるUV展開で奮闘しています。オブジェクトの特徴を見て複数の形状に分解できる場合は特徴検出でOBBに分解しよう、としてるのですが・・・・これが難しい。sphere-treeの論文を読んでいると、ボロノイ図とか出てきますね。Octreeで試した場合に無駄が多い、的な記載が論文内にありました。もうちょっと別理論を考えてみるか・・・。

UV展開(2007/07/19)

話題を変えて、復習もかねてUV展開です。

を円筒投影してマッピング(ShadeのUVマッピングエディタは使ってません。なぜかというと、実験したいことがあるから。これは後々解説入れていきます)。

顔の前と後ろが両方ほしいため、1枚に収まるようにOBBで傾きを求めて補正しました。実際はアゴの部分が重なってしまうのですが、この場合はなんとか重なりがないようになってる模様。ただ、おそらく鼻の部分は重なってる部分がある予感がします。

円筒投影の場合は上と下はUVが割り当てられない状態になるのですが、各面の法線を見て、Y軸方向成分の絶対値が大きい場合は別途平行投影して別テクスチャで持つとゆがみは抑えられるかなぁと。(球投影だとゆがみが気になるので考えてません)

で、やりたいことは「ポリゴンの重なりがないUVを与えるには?」というテーマです。確保したいのは

  • 速度(LSCMはちと時間がかかるため、対象からはずしました。というか、理解できてません・・・。Blenderのソースを読めばいいんですけど)
  • ポリゴン同士の重なりが極力ないようにする
  • できうるかぎり、隣り合うポリゴンはそのままの配置で展開したい
  • 全自動

です。

のような形状だと、普通の投影マッピングではアウトになります(オブジェクトとして分けてしまえばいいけど、シームレスにつながっている可能性もありうるので極力一まとめで扱いたい)。

で「ポリキューブ展開もどき」を考えてます。kd-treeで要点を絞ってそこだけ取り出し、かつOBBで傾きも考慮してやると、sphere-treeのボックス版ができる、かな。sphere-treeは以下のサイトにソースがあります。

http://isg.cs.tcd.ie/spheretree/

で、求まったOBBごとに円筒投影を行ってあげるとどうだろう?

もう一つ考えているUV展開法があるのですが(陸続きな凹凸が入り組んだ形状でもテクスチャ展開時に重なりを出さない。投影処理は行いません)、ちょっと開発時間がかかるのでこれはスルー。

なぜこんなことをしているのかは秘密ですが(UVマップツールを作るわけじゃありません)、LSCMをBlenderで試してみて思いの外時間がかかるのと、切れ目を入れる処理はいずれにしても必要になる、ってのが気になって妄想炸裂模索中です。

CEDEC 2007(2007/07/18)

ひさしぶりの更新。

http://cedec.cesa.or.jp/

ゲーム技術の祭典「CEDEC 2007」の案内が来ておりました。09/26〜09/28の3日間です。今年は東大にて開催されてます。早期割引は8/24までなので速めに申し込むべし(<自分)。

ちょっと今年は仕事の都合上忙しい合間を縫ってなので、いくつかの講演を見るだけになるかなぁ。物理エンジン系がいくつかあるので聞きに行く予定。後、五十嵐先生の講演があるじゃないですか。ほか、某セッションにて見たことある名前があるなぁというのがあったのですが、、、あれ、学生さんじゃなかったっけ?いずれにしても聞きにいこうと思ってます(物理系なもので)。気になったのは、やっぱりハードウェアの物理エンジン(PPU)は消えたのかな?AGEIAのセッションがない。。。

さて、今までやっていたこととして、とある3次元空間内の物体の「大きさ」と「傾き」を行列がない状態から求める、というのにトライしていたのですが、OBB(Jacobi法)ではなんとなく求まるのですがくるっと反転するときとかありますね。

「最小二乗法」でできるかと思ったのですが(これを気になんとなく理解はできるようになりました(^_^;;)、線形にできるのか・・・・?今回は時間をかけられないので、制限として逃げるしかないか・・・。理想は、頂点の順番が変わってしまっても一部欠損しても大きさと傾きが4x4行列で算出できる、なんですが、、、もうちょいのところでうまくいかない。推論は難しいっすね。

ヘアーサロンのパフォーマンステスト(2007/07/02)

DirectX9 SDKのXファイルとしてガイコツがあるのですが、これに毛を生やしてみようと思い立って少し遊んでみました。

「Xファイル形式→3Dアトリエ→DXF形式→Shade」と形状を持ってきました。

板ポリっぽくない表現ということで。コツは、

  • ヘアテクスチャの密度を少し疎(間を空ける)にする。
  • ヘアテクスチャに色のばらつきを与える。
  • ヘアテクスチャは一色でなく茶色の毛を混ぜてみた。
  • ヘア設定ダイアログにて、レイヤーカット(ヘア用語です)のごとく多段にする。
  • イメージウィンドウの「その他」の視線追跡レベルを10以上に(デフォルトの5では透過の回数が足りませんので)。

とするといい感じです。

ヘア設定ダイアログでは以下のようにヘアガイドが配置されてます。

Shade9.1でのヘアーサロンのパフォーマンスを調べる意味で、60307ポリゴンのガイコツを使ったのですが、これくらいの速度が出るとだいじょぶかな?

ccSvcHst.exe(2007/07/01)

WinXPマシンの起動時にCPUの半分以上を使って延々と何かしているプログラムがいる、と思って監視していると「Norton 360」で使っている「ccSvcHst.exe」が占有しているでないですか。5分くらい何もできなくしている原因はこいつか!!

後、OS終了時にアプリケーションエラーを引き起こしているのもNortonの模様(OS終了よりも長い処理をNortonが行っている、という回答がネット上の掲示板に書いてました)。

・・・ええかげん軽くなってくれと思います。特にアンチウイルスは必須ソフトですので、挙動として軽くなくては他の処理に負荷がかかってしまい、アンチウイルスソフト自身がウイルスかよ、と突っ込みたくなってしまいます。

Future's Laboratory 技術格納庫 2004-2013 Yutaka Yoshisaka.