[[FrontPage]]


*この記事について [#c6a6e3ac]
-この記事は[[Computer Vision Advent Calendar 2012>http://partake.in/events/13622c9b-3ada-4dd8-a967-56fe8927541b]]の1日目&note{cv-advent-calendar:[[Computer Vision Advent Calendar 2012>http://partake.in/events/13622c9b-3ada-4dd8-a967-56fe8927541b]], 2012-12-01閲覧};の担当記事
-本来は「ブログに書く」のがルールなのですが、主催者からWikiでも良いとのお言葉&note{twitter-sakanazensen-tweet:[[Twitter / sakanazensen: @tomoaki_teshima ...>https://twitter.com/sakanazensen/status/270502633926713344]], 2012-12-01閲覧};を頂いたので、wikiの記事に書きます。

*はじめに [#xc25ce7e]
-Computer Vision のプログラミングをしていると、連結関係を心配することが多々あります。
--例えば、複数フレームにわたって特徴点の追跡を行うとき。
--例えば、複数フレームにわたって動物体のラベルの追跡を行うとき。
--例えば、複数フレームにわたって人物の追跡を行うとき。
--ありますよね?
--あ り ま す よ ね ?
--''あ り ま す よ ね ?''
--''少なくとも私はありました。''
-とすると、ここらへんの対応関係がうまく行ってるかどうかは結局目で見比べるか、正解データを作る必要があります。
-しかし、この対応関係を目視で確認するのは結大変だったりします。
-当然正解データを作って、それに対する結果を自動的に評価することも大事ですが、
結構目視で確認する事態が発生したりします。


-さて、そんな時に、特徴点の追跡を可視化しようとすると、結構大変だったりします。
-そう、今更ですが、今日のテーマは''可視化''です。

*可視化のツール [#x03f10c8]
-当然、可視化も自前でやればいいわけですが、ちょっと微妙なこともあります。
-なので、[[Graphviz>http://www.graphviz.org/]]&note{graphviz-official:[[Graphviz>http://www.graphviz.org/]], 2012-12-01閲覧};を使ってみましょう。
-このGraphvizはdot言語というものをかけば、それ相応の対応関係を作ってくれます。
んで配置と配線を自動的にやってくれるという、ありがたいものです。


*dot言語について [#y6fceef3]
-dot言語についてはまとめてある[[便利なサイト>http://tessy.org/wiki/index.php?Graphviz%A5%E1%A5%E2]]があるのでそちらを参照&note{tessy.org:[[Graphvizメモ - AkiWiki>http://tessy.org/wiki/index.php?Graphviz%A5%E1%A5%E2]]};%%(ステマ)%%。
-こんな感じのソースコードを入れると
#geshi(dot){{
digraph sample {
	rankdir=LR;
	A->B->C;
	A[shape=circle,label="A"]
	B[shape=box,label="B"]
	C[shape=box,label="C"]
}
}}
-こんな感じの画像が生成されます。
#ref(sample1.png)
-連結グラフなので、ノードとエッジにより実現されます
-本稿の中ではノードはラベルとも呼ぶことにします。

*さて、デバッグ [#o98dc55b]
-これを一工夫入れると、結構便利になります。
**特徴点たちの羅列 [#qe97dc90]
-特徴点たちを複数フレーム追跡するとなると、結構な数になります。
-できるなら一つの特徴点を1つのラベルとして書き出したいですよね。
-しかし、dot言語の仕様から、以下の制約があります
--1つの特徴点をユニークなラベルとして出力するためにはユニークなラベル名を付ける必要がある
--ラベル名はアルファベットで始まる必要がある
-というわけで、今度は特徴点1つ1つをユニークなラベルとして記述するために、メモリの番地を使うことにします。
-例えば、特徴点が cv::Point に格納されているとして
-例えば、その特徴点の集合が std::vector<cv::Point> に格納されているとして、その番地はユニークであるはず!
-あ、ジョジョの放送が始まる。
-ジョジョの放送が終わった。
-こ、こいつ、死んでいる!
-番地はユニークであっても、ラベル名に番地をそのまま使うことはできない。
-そこで、適当にアルファベットを1文字付け加えることにする。
#geshi(c++){{
std::cout << " A" << &(arrayOfPoints[i]) << "[shape=box,label=\"" << i << "\"]" << std::endl;
}}
-こんな感じのdotファイルができる
#geshi(dot){{
digraph sample {
	rankdir=LR;
	A0027F760[shape=box,label="1"]
	A0027F762[shape=box,label="2"]
	A0027F764[shape=box,label="3"]
	A0027F760->A0027F762->A0027F764;
	A0027F764->A0027F762->A0027F760;
}
}}
-このdotファイルを処理することで、こんな画像ができる
#ref(sample2.png)
-無事特徴点の連結関係が記述できましたね。
**特徴点の詳細を記述する [#y6a49982]
-この特徴点には、特徴量や、位置なんか、他のプロパティもあります
-そのプロパティをlabelに埋め込んでやることができます
#geshi(dot){{
digraph sample {
	rankdir=LR;
	A0027F760[shape=record,label="(122,110)|{0|1}"];
	A0027F762[shape=record,label="(124,112)|{1|1}"];
	A0027F764[shape=record,label="(127,114)|{1|0}"];
	A0027F760->A0027F762->A0027F764;
	A0027F764->A0027F762->A0027F760;
}
}}
-shape属性をrecordにし、label内で {} で括って "|" 記号で区切ることで、複数情報をまとめることができます
-こんな感じに
#ref(sample3.png)
-ちなみに、位置に関してはGraphvizが適切にやってくれるので、位置を動かす必要はない
-位置を細かく調整する必要がある場合はもう諦めよう。Graphvizはそういう時に使うツールではない
**特徴点をフレームごとにまとめる [#dd64cd73]
-細かい位置調整は諦めようとは言え、同じフレームの情報は当然近くに配置されていて欲しいと思うのは人の常
-これのためにはsubgraphという機能を使うと、ラベル同士をまとめてグルーピングできます
#geshi(dot){{
digraph sample {
	rankdir=LR;
	subgraph cluster_frame_100 {
		label="Frame 100";
		A0027F760[shape=record,label="(122,110)|{0|1}"];
		A0027F750[shape=record,label="(232,210)|{0|1}"];
		A0027F740[shape=record,label="(180,130)|{0|1}"];
	}
	subgraph cluster_frame_101 {
		label="Frame 101";
		A0027F762[shape=record,label="(124,112)|{1|1}"];
		A0027F752[shape=record,label="(235,210)|{1|1}"];
		A0027F742[shape=record,label="(184,132)|{1|1}"];
		A0027F800[shape=record,label="(110,234)|{0|0}"];
	}
	subgraph cluster_frame_102 {
		label="Frame 102";
		A0027F764[shape=record,label="(127,114)|{1|0}"];
		A0027F754[shape=record,label="(240,211)|{1|0}"];
		A0027F744[shape=record,label="(190,134)|{1|0}"];
	}
	A0027F760->A0027F762->A0027F764;
	A0027F764->A0027F762->A0027F760;
	A0027F754->A0027F752->A0027F750;
	A0027F750->A0027F752->A0027F754;
	A0027F740->A0027F742->A0027F744;
	A0027F744->A0027F742->A0027F740;
}
}}
-ちなみに、subgraphは clusterで始まる名前のsubgraphにしないと、グルーピングしてくれないので注意です
-こんな感じの画像ができます
#ref(sample4.png)

**プログラムから呼び出す [#fb776c15]
-C++なんかだとsystem関数でコールして上げると、一発でpngファイルを生成できます
#geshi(dot){{
system("path/to/graphviz/dot -T png debug.dot > debug.png");
debugImage = cv::imread("debug.png");
cv::imshow("debug", debugImage);
}}
-やっぱりデバッグは分かりやすいことが何よりですよね

*最後に [#z0935a19]
-Advent Calendar Event って準備とネタ選びに頭を悩ませた
-本当は空いてる枠の分も発表したいんだが、仕事との兼ね合いが・・・
-参加できてよかった。企画者の [[@sakanazensen>https://twitter.com/sakanazensen/]]&note{twitter-sakanazensen:[[@sakanazensen>https://twitter.com/sakanazensen/]], 2012-12-01閲覧}; くんに感謝!

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS