Miyabiarts.net

一年に一度の更新頻度

月別アーカイブ: 2月 2011

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

ウィンドウのみのスクリーンショット

あるウィンドウのみのスクリーンショットが欲しいために、画面全体のスクリーンショットを取ってから、ペイントで切り出している人がいたので、「Alt+Print Screen」でフォーカスのあるウィンドウのみのスクリーンショットを取れるよ。と教えたら感動されました。

WindowsでもLinuxでも共通して、「Alt+Print Screen」でフォーカスのあるウィンドウのみのスクリーンショットを取れます。

GLGE入門

最近WebGLが流行りだし、Webブラウザで3Dモデルを表示することができるようになりました。
表示を簡単にするライブラリがいくつか出ていますが、GLGEを試してみました。

ダウンロード&インストール

GLGEからGLGEv0.8.zip(2011/2/15現在)をダウンロードします。
この圧縮ファイルを展開したら、中にはドキュメントやサンプルが入っていますが、当面必要なのは、トップ階層にあるglge-compiled-min.jsだけです。
このファイルに対してパスを通すなり、使う場所にコピーするなりしてください。

サンプル

赤色の平面を表示するだけのサンプルです。

ファイル構成は以下のようになります。

[cc width=”650″ lines=”100″]
– index.html HTMLページ
– glge-compiled-min.js GLGEスクリプト
– scene.xml シーン定義XML
[/cc]

scene.xmlで表示するシーンを定義してやり、それをindex.html内のスクリプトで呼び出しています。
それぞれのファイルの中身を以下に示します。

index.html

[cc lang=”html” width=”650″ lines=”100″]

GLGE

var canvas = document.getElementById( ‘canvas’ )
var renderer = new GLGE.Renderer( canvas );

var doc = new GLGE.Document();

doc.onLoad = function()
{
var scene = doc.getElement( “mainscene” );
renderer.setScene( scene );
renderer.render();

setInterval( function(){ renderer.render();}, 15 ); }
doc.load(“scene.xml”);

[/cc]

scene.xml

[cc lang=”html” width=”650″ lines=”100″]

-100.0,0.0,-100.0,
100.0,0.0,-100.0,
100.0,0.0, 100.0,
-100.0,0.0, 100.0

0,1,2,
0,2,3

[/cc]

第4回 名古屋CV・PRML勉強会

第4回 名古屋CV・PRML勉強会開催しました。
気持ちよく起きるために早めに布団には入ったのですけど、結局眠れずに明け方まで起きていたので、3時間しか眠れなくてつれー。眠れなくてつれー。
まぁ実際はそれほど眠気を感じることなく元気でした。

内容としては、私が所属する研究室から私を含めて3人が発表。
最初に、後輩が「超解像」に関して基礎から詳しく話してくれました。
次に、私が「類似画像検索と画像カテゴリ分類」について話しました。
会場のネットワークがつながらなかったため、作ったデモは不発に終わり、デモを頑張っていた分、スライドを色々端折ってしまったので、それが残念でした。
最後に、私の同期が「クラウドでCV ~一般物体認識をしよう~」というタイトルで発表しました。

今回は、事前に発表者がなかなか集まらずに、私が所属する研究室中心でやることにはなったのですが、なかなか面白いものになったのではないかと思います。
次回は、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を参考すると良いです。

類似画像検索

最近ちまちまと類似画像検索システムを作っているのですが、なかなか良い結果がでません。
まぁそんなに簡単にでたら、もっと沢山のサービスが実用化されているでしょうね。
今のところ、コマンドライン上で動くプログラムとなっているので、サーバとして動くように開発していきたいと思います。

今作っているもののは以下の本を主に参考にしています。

[amazon asin=”4915851400″]

ちなみにこの内容を第4回 名古屋CV・PRML勉強会で話す予定です。

研究者のターゲットOS

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

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

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

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

第1回 入門自然言語処理読書会 参加してきました

第1回 入門自然言語処理読書会に参加してきました。
コンピュータ・ビジョンの分野でも自然言語処理の技術は色々と使えるので、良い機会です。
予定が合う限り、今後も参加していきたいと思います。

参加者全員の自己紹介を行った後、1章全部と、とりあえずということで12章を各自で回しながら読みました。

途中、動的計画法について説明したのですが、即席過ぎて上手く説明できなくて残念。
後で考え直したら、分りやすい説明思いつきました。

[amazon asin=”4873114705″]

しょぼーん(´・ω・`) (`・ω・´)シャキーン

Twitterやチャットなどの文字ベースで感情表現のために顔文字使う人も多いと思います。
そこで、各々お気に入りの顔文字なんかがあるかと思いますが、自分が気に入っているものは以下の2つです。

しょぼーん(´・ω・`)

(`・ω・´)シャキーン

「しょぼーん(´・ω・`) 」は、悲しいときや自分の期待が外れたときに使います。

「(`・ω・´)シャキーン」はドヤ顔をしたいときやこれからやってやるぜ!みたいなときに使います。

元々の使い方は、上のような感じですが、最近は割と意味もなく乱発しております。
ちなみに、上の2つにあてはまらない場合は、「(・ω・)」を使うことが多いです。

これらの顔文字は、特に自分だけがお気に入りというわけではなく、多くの人に気に入られているようで、クッションにもなっています。
これをいつ買おうかと虎視眈々と狙っている毎日であります。
[amazon asin=”B004JM5GOA”]
[amazon asin=”B004K7EKOG”]