studyの最近のブログ記事

秋の夜長、うんこでも載せないとやってられません。

画像処理ライブラリの OpenCV を用いて顔検出を行い、頭にうんこを載せるソフトウェア UnkoNose を作りました。

UnkoNose をダウンロード

【はじめに】
.NET Framework 2.0 がインストールされていないと実行できません。
Windows Update からインストールできます。

【使い方】
上でダウンロードした UnkoNose.zip を解凍し、UnkoNose.exe をダブルクリックして、出現したフォームにお好みの画像ファイルをドロップするだけです。
UnkoNose01.PNG

すると・・・

UnkoNose02.PNG
あら、はしたない!
頭に うんこ 載ってますよー!!!


顔検出ミスると、わけのわからんところに うんこ が出現しますが、それは サプライズうんこ ということで。
あと、フォルダ内の"unko.bmp"ファイルを差し替えると他の画像も頭に載せることができます。
なお、白画素(R=255,G=255,B=255)は透明扱いになりますので。

あなたも頭にいろいろ載っけてみよう!
Wikipediaの"数学"のページ( http://ja.wikipedia.org/wiki/%E6%95%B0%E5%AD%A6 )をなんとなく見てたら、
数学は、量、構造、変化、空間といったものを対象として、いくつかの仮定から始めて、決められた演繹的推論をすすめることで得られる事実(定理)のみからなる体系を研究する学問である。
って、書いてあった。

あれ?そういえば、数学的帰納法とかいうのあったなぁ・・・と高校のころの記憶がよみがえった。
数学は、"演繹的推論をすすめることで得られる事実(定理)のみからなる体系を研究する学問"なら、数学的帰納法ってなんなの?という疑問が沸いた。
で、Wikipediaでいろいろ見てみた。

演繹 ( http://ja.wikipedia.org/wiki/%E6%BC%94%E7%B9%B9 )
演繹法 は、一般的・普遍的な仮定からより個別的・特殊的な結論を得る推論方法である。対義語は帰納法。帰納の導出関係は蓋然的に正しいのみだが、演繹の導出関係は前提を認めるなら絶対的、必然的に正しい。

帰納 ( http://ja.wikipedia.org/wiki/%E5%B8%B0%E7%B4%8D )
帰納法 とは、個別的・特殊的な事例から一般的・普遍的な規則を見出そうとする推論の方法である。対義語は演繹法。演繹においては前提が真であれば結論も必然的に真であるが、帰納では前提が真であるからといって結論が必ずしも真であることは保証されない。
...(中略)...一般的にいって帰納は、あくまでも確率・確度といった蓋然性の導出に留まる。
...(中略)...帰納とは、個別・特殊的事実の多さから結論がどのくらい確からしいものかを導くための推理といえる。

数学的帰納法 ( http://ja.wikipedia.org/wiki/%E6%95%B0%E5%AD%A6%E7%9A%84%E5%B8%B0%E7%B4%8D%E6%B3%95 )
数学的帰納法 とは、有限回の議論で可算無限個の対象に対する命題を証明するための数学の論法である。


帰納法は確率的規則を導くのだけれど、数学的帰納法は対象としている範囲(可算無限個)では絶対的に正しい。
ということは、数学的帰納法は帰納法ではないじゃんか。

あとで調べたら、はてなキーワード( http://d.hatena.ne.jp/keyword/%BF%F4%B3%D8%C5%AA%B5%A2%C7%BC%CB%A1 )にも書いてあった。
...(中略)...余録であるが数学的帰納法は、哲学的に言えば演繹法(Deduction)であって、帰納法(Induction)ではない。


数学的帰納法って、最後に"帰納法"って書いてあるから帰納法みたいだ。
でも、数学的帰納法は帰納法的な考え方を用いているが演繹法である。
こんな名前だと、みんな勘違いするよ!
だから、帰納的演繹法 とかに名前変えたほうがいいんじゃないかな。
主成分分析(PCA)とは、特徴量の次元がバカでかくなりすぎた場合に行われる次元収縮の手法である。
参考: http://www-pse.cheme.kyoto-u.ac.jp/~kano/document/text-PCA.pdf
   http://aoki2.si.gunma-u.ac.jp/lecture/PCA/index.html
主成分分析は広く知られている手法で、統計学で習った人も多いかもしれない。

パターン認識の分野では、この主成分分析と組み合わせて、独立成分分析(ICA)がしばしば使われる。

独立成分分析と主成分分析の処理は似ている。だが、主成分分析は(主成分の)軸は直交しなければいけないのに対して、独立成分分析では軸は直交しなくてもよいという点が違う。独立成分分析では、データ分布の独立性を見るのだ。

独立成分分析は fastICA ( http://www.cis.hut.fi/projects/ica/fastica/ ) で簡単に計算できる。

以下では、fastICA の例をもって説明する。

画像ファイルの全画素値を配列にコピーする場合の速度比較を行った。

比較するのは以下の3手法。

・方法1: C#
 - C# で Bitmap クラスの GetPixel メソッドを使った
 - 普通の方法
・方法2: C#(unsafe)
 - C# で unsafe を使った
 - ちょっと工夫した方法
・方法3: C++
 - C++ のクラスライブラリを作成し、C# から参照して使った
 - 画像処理ライブラリとして、OpenCV を用いた

一応、比較用に書いたソースは記事末に載っけときました。

557x850 の 24ビットカラー JPEG画像の場合
方法1: 21.6388260748251 (秒)
方法2: 5.06153430618396 (秒)
方法3: 0.0533208579219269 (秒)

方法1の20秒は、ありえないぐらい遅い。
unsafe を用いた方法2で処理時間は1/4になったが、C++を用いた方法3と比べると100倍近く遅い。

方法1はポインタが使えないから遅いというのは分かるような気がするが、ポインタが使える方法2と方法3がこんなに違うのは不思議だ。

JPEG のデコードで時間が掛かってるのか?と思って、ビットマップ画像でも比較。

557x850 の 24ビットカラー ビットマップ画像の場合
方法1: 21.81745337468 (秒)
方法2: 5.01866893115639 (秒)
方法3: 0.0364773279243997 (秒)

あれ?方法1と方法2があんまり変わらんのに、方法3がますます速くなってるし。


まとめ
・大量の画像を相手にしなければいけないときは C++ を使おう。


【追記(2007/11/24)】
Bitmap.Width, Bitmap.Height は意外にコストが高い(内部的にDllImportしたgdiplus.dllを利用している)ので、forループ前に一旦変数に入れてやると多少パフォーマンスが改善されるそうです。(コメントからの情報)

(真上から見たイメージの)おっぱいを標本化する場合。
おっぱいの周波数の2倍以上の点で、標本化しなければならない。
さもないと、おっぱいが、2つではなくなるかもしれない(2倍以上の点でも標本点が少ないとカップ数は変わる場合がある)。

また、おっぱいをフーリエ変換し、パワー(振幅)スペクトルを求めることにより、おおよそのカップ数が、推定できる。

さらに、おっぱいにローパスフィルタを適用することにより、高周波成分である乳頭が排除でき、R-18指定から、R-15指定に次元を落とすことができる。
MP3からボーカルを抜いてカラオケ状態にするボーカルリデューサー
http://www.ringolab.com/note/daiya/archives/004666.html

ボーカルリデューサーとは
・音楽ファイルからボーカル部分を自動認識技術で発見し、除去する。

特徴
・音楽のほとんどが、ボーカルが中央に定位していることを利用し、ボーカル部分を除去。
・つまり、ボーカルは左右のスピーカで同じ音が流れるが、楽器音は左右のスピーカで違う音が流れるということを利用

アルゴリズム概要
・1. フーリエ変換、ハートレー変換などで周波数解析
・2. 両チャンネルの振幅スペクトル・位相スペクトルを比較し、非常に近いもののみをリデュース

まとめ
・CDのようなにちゃんとステレオを意識して作ってある音楽ファイルではないと適応できない。
・なので、汎用性はあまりない。

たぶん、音を研究している人が自分が欲しいからという目的だけで作ったものだろう。
VS2005 C++/CLI で、アンマネージなライブラリを使う場合、ライブラリの関数の引数がアンマネージな文字列型(char*, wchar_t*, LPSTR, LPWSTR)の時がある。そんな時に必要な変換。
using namespace System::Runtime::InteropServices;	//Marshal使うから

//変換元
String ^srcStr = "Hello";

//char*
char* dstChar;
dstChar = (char*)(void*)Marshal::StringToHGlobalAnsi(srcStr);

//wchar_t*
wchar_t *dstWchar_t;
int strLen = srcStr->Length;
dstWchar_t = (wchar_t*)malloc((strLen+1)*sizeof(wchar_t));
for(int i = 0 ; i < strLen ; i++) {
  dstWchar_t[i] = srcStr[i];
}
dstWchar_t[strLen] = '\0';

//LPSTR
LPSTR dstLPSTR;
dstLPSTR = (LPSTR)dstChar;

//LPWSTR
LPWSTR dstLPWSTR;
dstLPWSTR = (LPWSTR)dstWchar_t;
wchar_t* への変換だが、文字数が高々知れてるのならば、malloc を使わずに
wchar_t dstWchar_t[100];
ってすればよい。
SmartOCR とは
・日本語対応OCRソフト。
 (OCRとは、光学文字認識(Optical Character Recognition) のこと。つまり、画像の中の文字をテキストとして認識してくれるもの)
・認識率の高さと Lite Edition がフリーなことで、有名になった。
・Lite Edition の他に Professional Edition や SmartOCR Library SDK の販売も行っていた。
・しかし、開発元である スマートリーディング が解散してしまったために今では手に入らない。


SmartOCR Lite Edition を試しに使ってみた。
ちなみに設定はすべてデフォルト(文字位置や文字方向は自動認識)。

SmartOCR01.jpgスクリーンショット(クリックで拡大)
左が元画像で右が認識結果。
"一時的に"が"一時的促"になっているが、その他は正しく認識されている。

SmartOCR02.jpgスクリーンショット(クリックで拡大)
メインの文字の"飲めないのに、お中元でビール・・・・・・いくらで売れる?"は正しく認識されている。
右の"今も、誰かがトクしてる。"とか"オークション"という文字は認識できていない。
あと、傾いた"お中元"という文字や、スロットが回ってるところを、わけの分からん文字として誤認識している。

あと、他にも10枚ぐらい試した。


まとめ
・割と認識率はよいようだ。
・小さい文字は認識しにくい。
・やっぱ、漢字は誤認識がどうしても起こるようだ。
・背景と文字のコントラストが低いと文字として認識できない時がる。
・背景の周波数が激しい箇所が、わけの分からん文字として誤認識する。
・フォントが特殊だと誤認識しやすい。


これだけのものをフリーで提供しているのはすごい。
オープンソースで開発されている OCR があるようだが、どれも日本語に対応していないし。

SDK を販売していたそうだが、今は手に入らないのが悔やまれる(いくらで売ってたのかは知らないけど)。
他の 日本語対応OCRソフト の SDK は、くそ高い(20万円以上とか)ので手が出ない。
個人で OCR 組み込んだプログラム作るのは無理ってことかー?!
サポートベクターマシン(以下 SVM) とは
・ニューラルネットワークの一種
・教師ありクラスタリング

SVM の基本的な考え方
・元々2クラスの線形分離手法として提案される
・単層パーセプトロンに似ているが、SVM はマージン最大化という手法をとっているのがポイント。
・マージン最大化とは、超平面と学習データの隙間となるマージンをなるべく大きく取ろうというもの。
 (ここでいう超平面とは、2つのクラスにぶった切る平面のこと)
・ちなみに超平面と、ちょうどマージンの分だけ離れている学習データをサポートベクトルという。
・このマージン最大化という考えを取り入れることによって、テストデータの識別精度を高めている。


SVM の発展
・線形分離不可能な問題への対応
 - ソフトマージン(学習データが多少マージンにくい込んだり、反するクラスの空間にくい込んだりしても許す)で対応
  (↑まだ、超平面自体は線形であることに注意)
・非線形問題への対応
 - カーネルトリックにより非線形な問題も対応
  (ちなみに、PCA(主成分分析)や部分空間法もカーネルトリックにより、非線形に拡張可能)
 - このカーネルトリックにより SVM の精度が飛躍的に向上し、SVM がメジャーになった。
・2クラスより多いクラスタリング問題への対応
 - 複数のSVMを組み合わせることにより対応


SVM の利点
・データの特徴量の次元が大きくなっても識別精度がよい(マージン最大化のおかげ)
 - 一般的にデータの特徴量の次元をむやみに増やすと識別精度が悪くなる(ヒューズの現象、球面集中現象)。
  なので、本来次元数の数倍の学習データを用意しなければいけないとされている。
  しかし、SVM は特徴量の次元数が大きくても対応できるため、画像認識の分野で頻繁に使われる。
  (文字認識の問題では、元の画像をグレースケールにして 20x20Pixel に正規化して、そのまま400次元の特徴量として SVM にぶち込んでやるという手法もとられている。)
・最適化するべきパラメータが少ない
 - ニューラルネットワークでは、良い精度を得るためにパラメータを試行錯誤して決定する必要があるが、SVM では割と簡単に最適なパラメータが求められる。

SVM の欠点
・学習データが増えると計算量が膨大となる
 - 特徴量の次元は大きくても対応できるが、学習データ数が増えるとタイヘン。
・基本は2クラスの識別の手法
 - 複数のSVMを組み合わせることで多クラスの識別が可能だが、多クラスを考慮に入れた識別関数の最適化をすることができない。

参考 : 前田英作, "痛快! サポートベクトルマシン ~古くて新しいパターン認識手法~", 情報処理学会誌, Vol.42, No.7, pp.676-683, (2001).
    http://www.neuro.sfc.keio.ac.jp/~masato/study/SVM/index.htm
    とか、あといろいろ見たよ。



実際に計算してみよう!
パッケージとしては、"LIBSVM"と"SVMlight"が有名なようだ。
http://www.bi.a.u-tokyo.ac.jp/~tak/svm.html
R(オープンソースの統計処理ソフトウェア) のインタフェースが用意されているということで、LIBSVM を選択。
http://www.csie.ntu.edu.tw/%7Ecjlin/libsvm/
LIBSVM は、R の"e1071"というパッケージに入っています。

パラメータをどのように設定したらいいかは以下の pdf を参照。
http://www.csie.ntu.edu.tw/~cjlin/papers/guide/guide.pdf

e1071 の仕様は以下の pdf を参照。
http://cran.r-project.org/doc/packages/e1071.pdf

e1071 を使ったサンプル
http://www.csie.ntu.edu.tw/%7Ecjlin/libsvm/R_example
(↑とか、e1071.pdf のサンプルとかを実際に入力して練習してみるといいよ)

LIBSVM の FAQ
http://www.csie.ntu.edu.tw/%7Ecjlin/libsvm/faq.html


最適なパラメータの探し方
・主に精度の良し悪しを決めるのは kernel の選び方と γ(gamma) と C(cost) の設定である。
・上の guide.pdf を参考にすると設定法は以下となる
 - kernel はデフォルトの RBF 一択でOK。
 - γとC は、grid serch により最適な値をヒューリスティックに探す。
  grid serch は、例えば調べる値を γ=(0.5, 0.25) C=(1, 2, 4)として入力したら、
  (γ,C) = (0.5, 1),(0.5, 2),(0.5, 4),(0.25, 1),(0.25, 2),(0.25, 4)
  の 6 種類すべて、cross-validation(または、bootstrap) で性能評価し、一番制度の良いものを提示してくれる。
  (e1071 では、grid serch を tune という関数で行う。)
 - 最初は大雑把な値で、次に詳細な値で、探すといいよ(coarse to fine(祖から密へ) の考え方で)。
 - ただし、特徴量の次元がバカでかい(数千次元)などの特別な場合は、他の手法を取る必要があるよ。

その他のパラメータについて
・type について
 - "C-classification" と "nu-classification" の違い
  FAQに該当箇所がある
  http://www.csie.ntu.edu.tw/%7Ecjlin/libsvm/faq.html#f411
  基本的には同じということだし、デフォルトが"C-classification"だし、教科書的な方法は"C-classification"みたいだし(詳しくは以下の pdf 参照)、デフォルトままでよさそう。
  http://www.csie.ntu.edu.tw/~cjlin/papers/libsvm.pdf
・scale について
 - デフォルトのTRUE だと、すべての特徴量の次元ごとでスケーリング(正規化)を行う。
 - 特徴量の次元ごとに重みを変えたい場合は、scale を FALSE にして、自分で重みを考慮したスケーリングすると調整するとできるのかな?
・class.weights について
 - クラスの重みを変えることができる。
 - 例えば、犬の画像と猫の画像をクラスタリングすることを考える。
  自分は犬の画像が大好きなので、犬の画像にクラスタリングされる画像が欲しいのだが、
  一枚の犬の画像も見逃したくはない、という場合に犬のクラスタの重みを大きくする。
  すると、犬の画像が猫の画像だと誤認識される確率は減り、犬の画像の再現率が上がる。
  でも、猫の画像が紛れ込む可能性が上がるけどね。
  という感じにクラスの重みを調整できる。


type パラメータについてもっと詳しく
・"C-classification" (or "nu-classification") (分類)について
 - 普通のクラスタリング問題の時に使う。
 - 例えば、犬の画像と猫の画像のクラスタリング問題を考えると
  テストデータの予測(predictの)結果は、犬クラスか猫クラスかという2値(2クラスタなので)で出力される。
・"eps-regression" (or "nu-regression") (回帰)について
 - 上の"C-classification"では、テストデータの予測結果は、犬クラスか猫クラスかという2値で与えられるが、
  このパラメータを使用すると、予測結果は数値として出力される。
  つまり、そのテストデータがどれくらい犬クラス(猫クラス)として尤もらしいかを知りたい時に使用する。
 - ラベルは数値で与える。
 - 例えば、学習データの犬の画像に -1、猫の画像に 1 のラベルを与えたとする。
  すると予測(predictの)結果は -0.10516366 や -0.80516366 という値として出力される。
  両方とも犬クラスとして判定されたことになるが、前者(-0.10516366)より後者(-0.80516366)の方が、犬の画像として尤もらしいことが分かる。
  なお、0 より小さい値を犬クラス、0 より大きい値を猫クラスと判定すれば、"C-classification" と同じことになる。
  たぶん。
・"one-classification" (1クラスSVM)について
 - 1つのクラスとその他にクラスタリングしたいときに使用する。
 - 例えば、種々雑多な画像群から犬の画像だけ取って来たい場合
  犬の画像のみで学習し、犬の画像とそれ以外の画像にクラスタリングする。
 - e1071 では、ラベルの引数を与えずに 関数svm でモデルを作れば、
  自動的に type="one-classification" となり、1クラスSVM となる。


SVM 使った感想
・精度タケー!
FFmpeg とは、オープンソースで開発されている動画エンコーディングパッケージである。
動画のエンコーディング/コーデック変換をする ffmpeg、動画再生をする ffplay、動画配信のためのサーバーである ffserver を提供する。
http://ffmpeg.mplayerhq.hu/index.html

ffmpeg の利点
・エンコードが速く、対応フォーマットも多い。
・コマンドラインから使えるために自作のアプリケーションから呼び出して使える。
 ("携帯動画変換君"や"Riva FLV Encoder"の中でも使われている。)
・動画のエンコーディング/デコーディングを担当するライブラリである libavcodec も直接利用可能。
参考 : http://megaui.net/oss4art/wiki/FFmpeg
    http://www.xucker.jpn.org/pc/ffmpeg_install.html


試しに使ってみた。
自分でコンパイルするのが面倒なので、"携帯動画変換君"をダウンロードして、その中から ffmpeg.exe を引っこ抜いてきた。

コマンドラインで
ffmpeg -i input.avi -f mov output.mov
と入力。
avi形式である input.avi を mov形式の output.mov に変換できた。
うおー!
参考 : http://www.nurs.or.jp/~calcium/wiki/index.php?ffmpeg%20usage

でも、wmv → avi に変換しようとしたら、エラーが起きて実行できなかった。
どうやら、パラメータとかちゃんと指定してやらないといけないらしい?
自己組織化マップとは
・ニューラルネットワークの一種
・教師なしクラスタリング(k-means法に動作が似ている)
・多次元のデータを圧縮して低次元(2次元)にマッピングするもの。(そういう意味では、非線形の主成分分析+クラスター分析とも言える。)
・多次元データを2次元にマッピングできることから、多次元データの可視化にも使われる。


実際に計算するには
・文献などでは、パッケージとして SOM_PAK が有名だが、R(オープンソースの統計処理ソフトウェア)の方が日本語のドキュメントも多く、分かりやすい。
RでSOM(自己組織化マップ) の関連リンクにある pdf の "Rと自己組織化マップ" というのが分かりやすい。


学習のパラメータについて
以下、コホネン先生著の"自己組織化マップ"より、ものすごくテキトーに抜粋
・単調減少関数は、線形的でも反比例的でも指数的でもさほど問題ではない。
・学習回数は、最低でもユニット数の500倍。
・学習回数はユニットの数に依存し、学習データの数には依存しない。
・半径の初期値は、マップが断片的にならないようにネットワーク全体の直径以上。
・フェーズを2つに分けて学習する場合(マップの断片化を防ぐために)
 -最初のフェーズでは、大域的な学習を行う。1000ステップぐらいで α=0.9 など α は 1 に近い値がよい。
 -次のフェーズで、微調整を行う。学習回数は長めに設定する必要がある。α は 0.02 より小さな値に達するようにする
・ユニットの初期値が乱数ではなく大まかな入力密度関数に適応した初期値(順序付けられた状態)で開始できる場合、近傍関数が狭く、かつ α=0.2 とか 0.1 のような低い値であっても、学習過程は急速に収束する。
画像処理やってると、ある画像の画素値を見たくなるときがあります。

でも、いちいちプログラミングで座標を指定して画素値を取り出すのは面倒です。
PhotoShop などの画像編集ソフトのスポイトを使えば取れるのですが、だいたい RGB表色系 にしか対応していません。

そこで、表示されている画像の画素をクリックすると、その画素値を取り出し、RGB,HSV,Lab,YCrCb の値として出力するビューアを作りました。
というか、自分用に作っただけです。

pix_viewer.jpgスクリーンショット(クリックで拡大)
(x,y) は、画像の座標。RGB,HSV,Lab,YCrCb のそれぞれの値は 0~255 の値に正規化されています。ただし、HSV の H のみ 0~360。


ビューアをダウンロード
.Net FrameWork 2.0 がないと動きません。Windows Update でダウンロードできます。

みじめなソースも置いときます。
みじめなソース (開発環境: VS2005Pro(C++/CLI),OpenCVb5)
Visual Studio 2005 (Professional Edition) で画像処理ライブラリである OpenCV(beta5) を使うときのメモです。

基本は以下を参考にします。
OpenCV@Chihara-Lab -> インストール。

OpenCV(beta5) のヘッダファイルには間違いがあります。(cvaux.hの1137行目 : "*/" でコメントを終了しなければいけないところが、"・/" になっていて、次の行までコメントアウトされてしまっている。)気づいてくれてありがとう、Chihara-Lab の人。

VS2003 では、上のページにしたがってやれば、導入できるのですが、
VS2005 では、コンパイルしようとすると私の環境では、以下のようなエラー・警告がでます。

VS2005_OpenCV.JPG(クリックで拡大)
1~3つ目のエラーは、"cxtypes.h"内 の 関数"cvRound()"の定義で、"__asm"を使っているからエラーが出ているようです。よって、"cvRound()"を一番安全そうなコードでコンパイルするように変更しましょう。
CV_INLINE  int  cvRound( double value )
{
    double temp = value + 6755399441055744.0;
    return (int)*((uint64*)&temp);
}
たぶん、これで大丈夫です。

4つめの警告は、"cvcompat.h"の該当箇所
    data[2] = A[2]; data[3] = A[5];
    data[2] = A[2];
    data[3] = A[5];
に変更したら、警告はでなくなりました。プログラム詳しくないので、なんでかは分かりません。

このアーカイブについて

このページには、過去に書かれたブログ記事のうちstudyカテゴリに属しているものが含まれています。

前のカテゴリはetcです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

プロフィール

profile.jpg

モローチョ(moro-tyo)

Webエンジニア。

詳しいプロフィール

このblogのはてブ

Powered by Movable Type 4.1