ComputerVisionまとめの部屋

役に立った情報や調査結果をまとめています

コーナー検出とは

画像内における「エッジ」は一方向にのみ輝度勾配が大きい点の集合と考えられるが、「コーナー」はそのエッジが交差する部分、すなわち二方向に輝度勾配が大きい部分と考えられる。例えばチェスボードのような直行する白黒の模様を考えると、x方向の勾配とy方向の勾配が、同時に最大になる点がコーナーであるとみなせる。

 

これを一般化するには「分散共分散行列」を考えるとうまくいく。
xの1次微分"Ix"とyの1次微分"Iy"に対する分散共分散行列は、対角成分に分散(Ix^2とIy^2)が並び、非対角成分に共分散(Ix*Iy)を配置する。この行列の固有値固有ベクトルを計算すると、1次微分が最大化する方向(エッジに直交する方向)と、その方向に軸をとったときの分散値Ix^2が分かるのだ。

また1次微分に対してガウシアンフィルタを適用してから分散共分散行列を求めることにより、異方性を解消することができる。

 

固有値を使うコーナー検出法をまとめると

  1. Sobelフィルタにより各ピクセルのx方向、y方向の1次微分画像を求める
  2. 各ピクセルごとに注目領域を決める
  3. ガウシアンフィルタを適用して分散共分散行列Mを組み立てる
  4. Mの固有値固有ベクトルを求めて大きいほうを(λmax, xmax)、小さいほうを(λmin, xmin)とする
  5. λminがしきい値より大きくなる点を特徴点とする

このコーナー検出法は回転不変性はあるが変形に対する不変性はない。OpenCVのcv::cornerEigenValsAndVecsは、この固有値計算をすることでコーナーを求めるAPIである。

CString から char* への変換 

文字型にはいつも悩まされています。プログラミングの都合上、色んな表現の仕方があるみたいです。それらの違いや特徴を理解した上で、合理的な(ただ動けばいいというのではない)プログラミングをする必要があります。 

 

文字列を引数に取る関数の引数の種類は以下の2通りがあります。

  1. char*型
    引数に渡した変数を書き換える関数
  2. const char*型
    引数に渡す変数は読み取り専用でそれを使ってある操作をする関数

2.の読み取り専用の引数の場合、CString型の変数をconst char*型で定義した引数にそのまま渡すことができます。これはCStringに備わっている機能として「CStringからconst char*型へのキャストが自動的に呼んで、LPCSTR型に変換する」というものがあるからです。


一方、1.の場合は注意を要します。

C++言語で用いるCString型文字列は、どんな長さの文字列でも適切にメモリ領域を確保してくれるというとても便利な型です。CStringクラスでは、プログラムが実行される時に動的にメモリ領域を確保してくれます。なので、char*型の引数を代入するように定義された関数にCString型の文字列を代入するときは、メモリ領域をどれだけ確保したらよいのかプログラム実行時まで分かりません。

このような場合どうするかというと、CStringクラスのGetBuffer()メンバ関数を用います。GetBuffer()は、引数に確保するメモリ領域のサイズを渡し、戻り値として確保されたメモリの先頭アドレスを渡します。

なのでchar*型の引数には、func( tmpStr.GetBuffer(10) )のように渡してやればよいです。

 

LTPSTRとは

文字型と言ってもいろいろある。

世界中にはいろんな言語があり、アルファベットだけで表されるものではない。
そうするとchar型の配列を使用した文字列だけと1文字=2^3=8ビット=1バイト=256通りの文字しか表わすことができない。

そのため日本語などでは、1文字=2^6=16ビット=2バイトとして、65536通りの文字を表わせるようにしている。これをダブルバイト文字という。

2バイトで表される文字列の中でUnicodeと呼ばれるものがあり、世界中のあらゆる文字を表すのに規格化されたコードである。

Unicodeが定義されているかどうかはOSなどシステムに依存している。プログラムがどんなシステムでも動くようにするためには、システムによる違いを吸収できるような仕組みが必要である。

それがLPTSTR型とかLPCTSTR型というものだ。
この文字型で変数を定義しておけば、システムごとに表示する段階で、Unicodeが定義されているなら2バイト文字のWCHAR型、そうでなければchar型にするなどを勝手にやってくれる。

文字型の定義

文字型の定義、変換が理解しにくいのでまとめ。

C言語はメモリを意識してプログラミングする必要がある。

整数型の定義は分かりやすい。
int型で定義すれば、変数には32ビット=4バイト、
数字にすると-2,147,483,648~2,147,483,647の値を入れられる。
その範囲内でのみ値を変えられ、それ以外の値を入れると確保したメモリ領域以外の部分を読み取ろうとして、不正なメモリアクセスが生じる。

文字型の定義はどうなるだろう。
char型はintと同じく整数型を格納するための型である。
整数型よりも小さくて、1文字に対して8ビット=1バイトのサイズが確保される。

char型もint型と同じく整数を格納する型と考えると分かりやすい。
char型の変数にAという文字を入れると、Aに対応する整数値が格納される。
どの文字がどの値に対応するかはASCII文字コードの一覧で確認できる。

_T("")マクロとは

プログラムの中で_T("")マクロが頻繁に使われている。

_T("")マクロは、ユニコードとマルチバイトの差異を解消するためのマクロ。

_T("文字列")としたときのの実際の動きを考えると、ユニコード設定ならL"文字列"として展開し、マルチバイト設定なら従来どおり"文字列"と展開される。

例えば _T("ABC")とプログラム中に書いた場合、
Unicodeが定義されたシステム内では、L"ABC"と書かれたのと同じ16ビットのワイド文字型になり、Unicodeが定義されていなければ、ただの"ABC"で書かれたのと同じ、8ビットのANSI文字列となる。


ではなぜ_T("")マクロを使う必要があるのか?

VisualC++ではビルド設定によって使用する文字セットをANSIにするかUnicodeにするかを切り替えることができる。

例えばUnicodeを使うなら、文字列定数は全て L"ABC"などのように定義する必要がある。マルチバイト文字セットを使用するなら、この「L」は必要ない。
そのどちらでも対応できるようにするのがTCHAR型の文字配列であり、TCHAR型に変換処理してくれるのが_T("")マクロである。

結局、どうすればいいのか?というと、Windowsプログラミングをするとき、文字列定数は"ABC"ではなく、常に_T("ABC")としておけばOKということだろう。

シングルクオーテーションとダブルクオーテーションの使い分け

文字のときは「’」(シングルクオーテーション)
文字列のときは「”」(ダブルクオーテーション)を使う


サイズの違い

ダブルクオーテーションの場合、
最後にNULL(\0)がつくので、”a”のデータサイズは「2バイト」となる。なので
char data[1] = "a" 
とするのは2バイトの文字列があるので誤り。’a’であれば1バイトなのでOK。

文字列の最後には必ずNULLがつく。
文字列を出力するときにNULLがないと終わりかわからないので、使われていないメモリも読み込まれて文字化けする。