Miyabiarts.net

一年に一度の更新頻度

カテゴリーアーカイブ: Programming

Boost.勉強会 #5 名古屋で発表してきました

  • 開催日時:2011/05/14 13:00~18:00
  • 開催場所:株式会社エイチーム(名古屋市西区牛島町6番1号 名古屋ルーセントタワー32F)
  • ハッシュタグ:#boostjp

先週の関西ゲームプログラミング勉強会に続いて、今度はBoost.勉強会で発表してきました。

発表内容は「OpenCVを使った画像処理」ということで、Boostは一切関係ありません(笑)

いやまぁ、一応Boost.GILは紹介しましたよ!

 

実際のところ、前日に研究室内の種々の資料作成などで、今回の発表スライドをまともに作り始めたのは前日の夜からでした。

大枠は作っていましたが、デモに至っては当日の勉強会の途中で作っていましたからね。

ただ、作ったのはよいですが、プロジェクタにPCの画面が映らずに結局デモは使えなかったという悲しさです。

 

発表終了後に色々な人から画像処理について聴かれたので、なかなか上手く行った感じがして良かったです。

まだまだ色々な内容について発表するような感じでBoost.勉強会で発表することになっているみたいなので、機会があれば、また何かしら話させていただきます。

運営・発表者・参加者の方々はお疲れ様でした。

広告

関西ゲームプログラミング勉強会で発表してきました

既に24時間以上経っていますが、昨日関西ゲームプログラミング勉強会で発表してきました。

  • ATND: http://atnd.org/events/14697
  • 日時:2011/05/07 10:00
  • 場所:エビスビル(AAホール本館) 6階 貸会議室 (大阪府大阪市中央区淡路町3丁目2番9号 エビスビル)
  • ハッシュタグ:#oustudy

秋猫(@akineko)さんが主催となって開催された関西ゲームプログラミング勉強会。
ブラウザ三国志などを開発している株式会社ONE-UPさんの後援で、会場設備なども充実していました。

午前中は、自分の発表のデモをもう少し直したかったので、コーディングしながら聴講。
ネットワークゲームを作る上でのノウハウなどを講演していただき、作業半分で聴いてはいたのですが、昔ネットワーク系も触ったことあるので、よい復習になりました。

ちなみに、私のゲームプログラミング経験ですが、高校の時にちょっとしたものを勢いで作ったっきりで、それ以降今まで完成させたものはありません。
大学の学部生時代に趣味で色々やってはいたのですが、グラフィックスを作る力がないくせに、良いものにしたいとこだわったせいで、結局何も作れていないというのが本当のところです。
というわけで、自分は断片的に技術を齧ってはいるものの、ゲームプログラマではありません。
だけど、発表者の、それもトリになっています。
わけがわからないよ。

発表の方ですが、時間的にはおよそ70分の遅れで、色々ばっさり切りながら発表しないといけないなと思っていましたが、なんだかんだで全部話しきることができました。
ただ、早めに話さないといけないという気持ちから、相当な早口だったことと、話すことが上手くまとまらずに何言っているかよく分からないところが多々あった点を反省しておきます。
どこかに動画存在しているようですので、見たい方は探してください(笑)

Twitterのツイートを見る限りでは、割と受けは良かったようなので安心しました。
特に前の@fadis_さんの発表が素晴らしかったので、なおさらどうしたものかと思っていました。
感想として、「触ってみたい」「やってみよう」と思ってくださる方が沢山おられたことは最高の褒め言葉です。
Bulletに限らず物理エンジンは開発期間の割にはドキュメントなどの情報が少ないため、ユーザが増えることでそれらが充実することを願っています。

今回くらいの粒度でなら、まだネタとしてはいくつか話せることがありますため、また話す機会があれば是非呼んでいただけると嬉しいです。
それと、名古屋で開いてくれる方がいればお願いします。
(自分で開きたい気持ちはありますが、ちょっと色々なことが身体的な限界を迎えていますため。。。)

資料は以下に置いておきます。
(DropBox上に置いていますが、後ほど場所を移動して、リンクを貼り直す予定です。)

関西ゲームプログラミング勉強会 #oustudy

ひたすら原稿執筆か発表資料作りしているばかりで、ブログは停滞の一途を辿っています。
仕様です。

明日は、いつのまにか発表することになっていた関西ゲームプログラミング勉強会 #oustudyに参加するために大阪に向かう予定です。
本業の進捗が気まずいことになっているので、進めるために徹夜で研究をしていたため、現在体力の限界を向かえています。
発表スライドはまだ完成していません。
さて、どうなることやら。

Luaの文字列とQStringの相互変換

Luaの文字列は、C++側ではstd::stringで受け取ってしまうのでQtの文字列QStringを引数にするような関数をLua側に公開するためには一工夫する必要があります。
luabindを用いると、以下のように書くことで、Luaの文字列とQStringを相互変換することができます。

namespace luabind
{
  template
  struct default_converter
    : native_converter_base
    {
      static int compute_score( lua_State *L, int index )
      {
        switch( lua_type( L, index) )
        {
          case LUA_TNIL:
          case LUA_TSTRING:
          {
            return 0;
         }
         default:
         {
           return -1;
         }
       }
    }

    QString from( lua_State *L, int index )
    {
      switch( lua_type( L, index ) ) 
      {
        case LUA_TNIL:
        {
          return QString();
        }
        case LUA_TSTRING:
        default:
        {
          return QString( lua_tostring( L, index ) );
       }
      }
    }

    void to( lua_State * L, QString const& x )
    {
      lua_pushstring( L, x.toStdString().c_str() );
    }
  };

  template
  struct default_converter
  : default_converter
  {};
}

つまり、下のような関数がLua側に公開できるということです。

void print( const QString &text )
{
  qDebug() << text;
}

わんくま同盟 名古屋勉強会 #17

わんくま同盟 名古屋勉強会 #17に行ってきました。
最近、節操無くあちこちに行っていますね。
とても楽しいです。
そして、いつも懇親会まで参加するため、財布の中身が本当に気まずいことになっています。

  • 10:30-11:10 「Kinect on Windows?」 こくぶんさん
    • Kinectでパワポ操作しようとして、思うようにいかない。どこかで見たデジャビュ。
    • 11:10-11:50 「これはモナドですか? はい、コンピュテーション式です」 bleis-tift さん
      • 一応Haskellはそれなりにやったことがあるけど、びっくりするほどF#分からなかった。
      • テライケメンさん。マイクロソフトMVPおめでとうございます!
  • 11:50-12:20 ライトニングトーク
    • コーヒーとか自動車の話。痛車の車検はとっても困る。
  • 13:10-13:40 TDD 道場
    • TDD(テスト駆動開発)は気になっていたけど、研究用プラグラムではそこまでやることはないですからね。ただ聞いていて、むしろ研究手法の1つではないんじゃないかと思っていた。成功例・失敗例をはっきりさせるという意味で。
  • 13:40-14:30 「IBM Rational Team Concert に触れてみた」 You&I さん
    • 色々なツールがあるものだ。
    • ごめんなさい。昨日あんまり寝ていなくて、半分うとうととしていました。
  • 14:40-15:30 「TDD のおさらい ~ どうやるんだっけ? なにが美味しいんだっけ?」 biac さん
    • ちぃ、なんとなく覚えた!
  • 15:40-16:30 「確率の不思議」 IIJIM@S さん
    • 一応、確率・統計は研究にも関係していることなので、内容に関しては大丈夫だ。問題ない。
    • 淡々と数学の話をされていたので、一部の人たちにラリホーがかかっていました。

ゲーム開発者を問い詰める会 in Twitter

Twitter上で、@cpp_akiraさんがなにやら「ゲーム開発者を問い詰める会 in Twitter」というものを7分後に始めると言って、楽しみに見ていたら、質問と回答がなかなかカオスなことになっていたので、見やすくしようかと思ってトゥギャってみました。

Togetter 「ゲーム開発者を問い詰める会 in Twitter」

一応、質問と回答がなるべく対応するようにまとめたのですが、タイムラインの流速があまりに速く、複数話題が同時に飛び交っていたため、抜けや誤りが多数含まれますが大体の内容は含まれているはずです。
全体的にまとまり感がなかったので、もっと深く聞きたい話もあったのですが、面白い話が見れて楽しかったです。
また、このような企画が勃発すれば良いですね。

最後の方は、一触即発の可能性のあるエディタ・キーボード論争に発展しかけていましたが(笑)。

OpenCVのcv::Mat / cv::Mat_の使い方(cv::Mat_編)

前回の続きで、今回はcv::Mat_に関してです。
内容はほぼ前回のコードの置き換えなので説明は少ないです。
記事の構成も同じです。

画像の作成

cv::Mat_は見たままですが、cv::Matに対して型Tを与えて用いるためのクラスです。
そのため、変数を定義する際に画素の型を与える必要があります。
cv::Matでは画素の型はOpenCVの定数でしたが、cv::Mat_ではC++の型のことです。

cv::Mat_< T > image( 高さ, 幅 );

// グレースケール画像(8bit)画像
cv::Mat_< unsigned char > image( height, width );

// RGB画像(24bit)画像
cv::Mat_< cv::Vec3b > image( height, width );

画像の入出力

画像の入力は、cv::Matと同様です。

// グレースケール画像(8bit)画像
cv::Mat_< unsigned char > image = cv::imread( "ファイル名", 0 );

// RGB画像(24bit)画像
cv::Mat_< cv::Vec3b > image = cv::imread( "ファイル名", 1 );

画像の出力も同様。

cv::imread( "ファイル名", image );

任意の画素へのアクセス

cv::Mat_だと、変数を定義する際に型を与えているため、任意の画素へとアクセスする際に型を与える必要がありません。
以下の例では、位置(x,y)の画素に0xffを代入して白画素にしています。

// グレースケール画像(8bit)画像
image( y, x ) = 0xff;

// RGB画像(24bit)画像
image( y, x )[ 0 ] = 0xff;
image( y, x )[ 1 ] = 0xff;
image( y, x )[ 2 ] = 0xff;

画像全体の走査

cv::Matの時と同様に3つのアクセス方法で画像全体を走査します。

任意の画素へのアクセスによる走査

// グレースケール画像(8bit)画像
for( int y = 0 ; y < image.rows ; ++y )
{
  for( int x = 0 ; x < image.cols ; ++x )
  {
    image( y, x ) = 0xff;
  }
}

// RGB画像(24bit)画像
for( int y = 0 ; y < image.rows ; ++y )
{
  for( int x = 0 ; x < image.cols ; ++x )
  {
    image( y, x )[ 0 ] = 0xff;
    image( y, x )[ 1 ] = 0xff;
    image( y, x )[ 2 ] = 0xff;
  }
}

ポインタアクセスによる走査

// グレースケール画像(8bit)画像
for( int y = 0 ; y < image.rows ; ++y )
{
  unsigned char *p = &image( y, 0 );
  for( int x = 0 ; x < image.cols ; ++x )
  {
    *p = 0xff;
    ++p;
  }
 }

// RGB画像(24bit)画像
for( int y = 0 ; y < image.rows ; ++y )
{
  cv::Vec3b *p = &image( y, 0 );
  for( int x = 0 ; x < image.cols ; ++x )
  {
    ( *p )[ 0 ] = 0xff;
    ( *p )[ 1 ] = 0xff;
    ( *p )[ 2 ] = 0xff;
    ++p;
  }
}

MatIterator_による走査

// グレースケール画像(8bit)画像
cv::MatIterator_ itr = image.begin();
for( ; itr != image.end() ; ++itr )
{
   *itr = 0xff;
}

// RGB画像(24bit)画像
cv::MatIterator_ itr = image.begin();
for( ; itr != image.end() ; ++itr )
{
   ( *itr )[ 0 ] = 0xff;
   ( *itr )[ 1 ] = 0xff;
   ( *itr )[ 2 ] = 0xff;
}

OpenCVのcv::Mat / cv::Mat_の使い方(cv::Mat編)

OpenCVのC++インタフェースで行列、および画像を扱うためのcv::Mat / cv::Mat_ですが、主要なクラスの割にはまとまった情報が少ないので、基本的な使い方を紹介します。
ここでは、通常の行列として用いる方法ではなく、あくまで画像として扱うものとします。

今回は、cv::Matの方の使い方について書きます。
次回は、cv::Mat_について書きますが、内容としては少し扱い方が違うだけでほぼ同じです。

cv::Matとcv:Mat_

まずは、今回の対象であるcv::Matとcv::Mat_について説明します。
いずれも行列、および画像を扱うための二次元配列を表します。
cv::Matは、行列の1つの要素を型なしとして扱い、アクセスする際に型を与えます。
cv::Mat_は、定義する際に型を与え、要素にアクセスする際には型を必要としません。

これらのクラスを利用するためには、以下のようにヘッダファイルをインクルードします。
パスはちゃんと通しておいてください。

#include <opencv2/opencv.hpp>

画像の作成

任意のサイズ・画素の型で初期化する場合は、 以下のように書きます。
さっきcv::Matは、画素を型なしで扱うと書きましたが、あくまでC++の型のことで、1画素をどのように表現するかの型は必要となります。
この型は、OpenCVの定数で与えます。

cv::Mat image( 高さ, 幅, 画素の型 );

// グレースケール画像(8bit)画像
cv::Mat image( height, width, CV_8UC1 );

// RGB画像(24bit)画像
cv::Mat image( height, width, CV_8UC3 );

ここで、widthとheightを与える順番に気をつけてください。

画像の入出力

画像の入力は、読み込んだ画像をどのような型で扱うかで引数が異なります。

// グレースケール画像(8bit)画像
cv::Mat image = cv::imread( "ファイル名", 0 );

// RGB画像(24bit)画像
cv::Mat image = cv::imread( "ファイル名", 1 );

画像の出力は簡単で、以下のようにするだけです。

cv::imread( "ファイル名", image );

任意の画素へのアクセス

任意の位置の画素へのアクセスは以下のようにします。
cv::Matでは、画素の実際の値を読み書きするため、cv::Mat::atに対して型を与える必要があります。
以下の例では、位置(x,y)の画素に0xffを代入して白画素にしています。

// グレースケール画像(8bit)画像
image.at( y, x ) = 0xff;

// RGB画像(24bit)画像
cv::Vec3b &p = image.at( y, x );
p[ 0 ] = 0xff;
p[ 1 ] = 0xff;
p[ 2 ] = 0xff;

画像全体の走査

画像処理では、画像全体を画素毎にアクセスして処理を行うことが多々ありますが、上記の方法だと呼び出しのオーバヘッドが大きいので、ポインタを利用してアクセスする方法が多く取られます。
ただ、それでは範囲外アクセスの危険があるので、なるべくMatIterator_経由でアクセスすることをお勧めします。

やり方は以下のとおりです。
この例では、全画素に0xffを代入して白画素にしています。

加筆・修正(2011/2/24)(アクセス速度などに関する調査不足があったので、修正しました。)

任意の画素にアクセスする仕方は前述の通りですが、画像全体を走査して処理を行う場合は色々なアクセスの仕方があります。
ここでは、3つのアクセス方法を紹介します。
例では、全画素に0xffを代入して白画素にしています。

任意の画素へのアクセスによる走査

前述した任意の画素へのアクセスを行う方法です。

// グレースケール画像(8bit)画像
for( int y = 0 ; y < image.rows ; ++y )
{
  for( int x = 0 ; x < image.cols ; ++x )
  {
    image.at( y, x ) = 0xff;
  }
}

// RGB画像(24bit)画像
for( int y = 0 ; y < image.rows ; ++y )
{
  for( int x = 0 ; x < image.cols ; ++x )
  {
    cv::Vec3b &p = image.at( y, x );
    p[ 0 ] = 0xff;
    p[ 1 ] = 0xff;
    p[ 2 ] = 0xff;
  }
}

ポインタアクセスによる走査

スキャンラインごとに先頭画素のポインタを取得し、そのポインタ経由で画素にアクセスします。
次の画素へはポインタをインクリメントします。

// グレースケール画像(8bit)画像
for( int y = 0 ; y < image.rows ; ++y )
{
  unsigned char *p = &image.at( y, 0 );
  for( int x = 0 ; x < image.cols ; ++x )
  {
    *p = 0xff;
    ++p;
  }
 }

// RGB画像(24bit)画像
for( int y = 0 ; y < image.rows ; ++y )
{
  cv::Vec3b *p = &image.at( y, 0 );
  for( int x = 0 ; x < image.cols ; ++x )
  {
    ( *p )[ 0 ] = 0xff;
    ( *p )[ 1 ] = 0xff;
    ( *p )[ 2 ] = 0xff;
    ++p;
  }
}

MatIterator_による走査

画像全体をMapIterator_というIteratorを用いて走査することができます。

// グレースケール画像(8bit)画像
cv::MatIterator_ itr = image.begin();
for( ; itr != image.end() ; ++itr )
{
   *itr = 0xff;
}

// RGB画像(24bit)画像
cv::MatIterator_ itr = image.begin();
for( ; itr != image.end() ; ++itr )
{
   ( *itr )[ 0 ] = 0xff;
   ( *itr )[ 1 ] = 0xff;
   ( *itr )[ 2 ] = 0xff;
}

任意の画素を処理する際に隣接画素から値を求めたい場合には、その画素の位置情報が必要となります。
この位置情報については、以下のように取得できます。

for( ; itr != image.end() ; ++itr )
{
   // 画素の位置を取得
   const cv::Point &pos = itr.pos();

   // 隣接画素へアクセス可能
   image.at( pos.y - 1, pos.x - 1 );
}

アクセス速度

3つのアクセス方法を紹介しましたが、それぞれの方法でアクセス速度が異なります。
詳しくは「画像ピクセル値へのアクセスと計算速度」を参照してください。

Shogunのインストール

Shogunは、大規模なデータに対する機械学習のツールです。
何かの略というわけではなく、そのまんま”将軍”です。
しかも作っているのは日本ではないという訳の分からなさ。

名前は変わっていますが、やれることは素晴らしく、識別器であるSVMの複数の実装やMKL(Multiple Kernel Learing)など他にはない機能が多々あります。
また、C++をはじめとしてPythonやMatlabといった色々な環境で使うことがあります。

今回は、Shogunのソースコードからのインストールについて書きます。
ただし、Linuxを対象としています。

インストールと言っても普通にソースコードからインストールする時と一緒で、違うのはディレクトリの位置がほんの少し違うだけです。
ダウンロードから含めて、以下のようにシェルでインストールします。
今回対象としたものは、最新バージョンの0.10(2011/2/10現在)です。

[cc width=”650″]
wget http://shogun-toolbox.org/archives/shogun/releases/0.10/sources/shogun-0.10.0.tar.bz2
tar xvfj shogun-0.10.0.tar.bz2
cd shogun-0.10.0/src
./configure
make
make install
[/cc]

実際の使い方などはTutorialExampleを参考すると良いです。

研究者のターゲットOS

1週間前からtsunotterで、「研究者のターゲットOS」というアンケートをとっていました。

回答していただいた方は、画像処理な人が多かったのですが、基本的にWindows上でC++を用いて開発しており、別の環境でもなるべく動くように標準命令やクロスプラットフォームに対応したライブラリを用いるというものでした。

私の普段使っている環境はLinux(Fedora)ですが、研究室の他の人は主にWindowsを用いており、プログラムを渡すときに一度Windowsで動くように動作確認をとっています。
この作業が割と面倒くさいので、はじめからWindowsで作ったほうが良いかと思うことが多々ありました。

他の研究室ではどのような状況かと、ふと気になったので、今回のようなアンケートを取ることにしました。
アンケート結果は概ね予想通りで、やはりWindows環境はメインターゲットとして考えるべきですね。
あとは、標準命令でできない面倒な処理をライブラリに投げたいので、みんなQtかboostあたりを標準として使わないですかな。