はじめに
- この記事はOpenCV Advent Calendar 2017 8日目の記事です。関連記事は目次にまとめられています。
キャリブレーションパターンの作り方
- キャリブレーションパターンを作るサイト、スクリプト、手順など、多数公開されており、その意味ではN番煎じも甚だしい記事です。
- ただし、通常と違うのは、今回は「バージョン管理も念頭に入れ」て、「ベクタ形式で生成する」ことです
後日談というか、今回のオチ
-
ビルドするとチェッカーパターンのパワーポイント(pptx)を生成するプログラムを公開しました
-
という具合にビルドするだけでパワーポイント用のバイナリファイルが作られます
-
あとはこれを、「倍率指定100%」で印刷する(用紙サイズ指定ではありません)と、誤差1mm以下の精度で印刷してくれます1
-
プリンタで印刷するとサイズが変わってしまう報告がありますが、私が試した限りでは、「用紙指定」ではなく「倍率指定」なのがキモ、という認識です。
中身の詳細
- 大まかに説明すれば
- xmlファイルを複数含むディレクトリをプログラムで生成
- ディレクトリを単一zipファイルに圧縮
- zipファイルをpptxにリネーム
- をしているだけです。
- Office は拡張子の末尾にxがつくようになってから、ファイルの実態は複数のxmlファイルを単一のファイルにZIP形式で圧縮したもの、となりました
- 今回はCMakeを使ってpptxファイルを生成しています
円形キャリブレーションパターンの方が精度良いんじゃないの?
-
はい、随所で円形パターンの方が精度が良いことが報告されています
-
なので、cmakeを使ってる理由はそこで、cmakeのコンフィグ時に、パターンの個数や長さの他に種類も変更できるようにしてあります
-
図中にも示しましたが、
MARKER_TYPES
にmarker_Chessboard
、marker_CircleSymmetrical
とmarkerCircleAsymmetrical
の3種類があり、それぞれ- チェッカーボード
- 円形パターン(格子)
- 円形パターン(互い違いに配置)
-
となっております
印刷がきれいになるだけなの?
- 最大の特徴が、キャリブレーションパターンの情報がヘッダファイルに生成される点です
- このプロジェクトをcmakeでコンフィグすると、buildディレクトリ直下にconfig.hというファイルが生成されます
#ifndef CONFIGURE_H_INCLUDED
#define CONFIGURE_H_INCLUDED
/* number of markers in column */
const int cNumMarkerCols = 4;
/* number of markers in row */
const int cNumMarkerRows = 9;
/* gap between markers in cm (= size of each box of chessboard) */
const float cMarkerGap = 1.0f; // in cm
/* diameter of the circle in cm (not used for chessboard) */
const float cSizeCircle = 0.5f; // in cm
/* offset from the edge in cm */
const float cOffset = 1.0f; // in cm
/* name of powerpoint slide file name */
#define DEFAULT_XML_FILENAME "slide1.xml"
/* name of thumbnail file */
#define THUMBNAIL_FILENAME "thumbnail.jpeg"
enum markerType
{
marker_Chessboard,
marker_CircleSymmetrical,
marker_CircleAsymmetrical,
};
const enum markerType cMarkerType = marker_Chessboard;
#endif // CONFIGURE_H_INCLUDED
- で、この中に先程のパターン数、パターンの種類、長さ、全ての情報が埋め込まれているわけです。
- cmakeのコマンド、
configure_file
があり、これよってファイルの中に埋め込んだ変数がcmakeで得られた実際の数値/文字列に置き換えられます - OpenCVの
HAVE_FFMPEG
とかWITH_OPENCL
を持つ、cvconfig.h
と同じ方法です
- cmakeのコマンド、
- 何が良いかというと、これのおかげでソースコードとキャリブレーションパターンが一意にバージョン管理することができるのが最大のウリです。
- キャリブレーションパターンとソースコード、別々に管理してたりしませんか?
- そもそもgit、ひいてはGithubはあまりバイナリの管理には向いていません
- 圧縮して全履歴を保存することが理由ですが、バイナリには圧縮がほとんどきかないため、Gitのリポジトリに入れると、容易にサイズが肥大化します
- そのような理由からGithubでも1コミットのサイズに制約がついています
You will not be allowed to push files larger than 100 MB.
- もちろんそれでもパワーポイントのpptxファイル、特にキャリブレーションパターン程度ならばkbオーダなので、無視してもいいぐらいのサイズです。
- しかしながら、あとから実験の記録を見返したときに、「あれ?このキャリブレーションパターンいつ使ったんだっけ?」とか、「この写真中のボード、間隔何cmだったかな?」とか、悩んだりしないでいいわけです!
- その時点の実験を再現するならば、ビルドするだけで、全く同じキャリブレーションパターンを生成できるからです!すごい!
このプログラムキャリブレーションパターン生成するだけ?
- キャリブレーションパターンを生成してそれでおしまいということはまず無いので、このソースコードを使いたい人は、何らかキャリブレーション用ソースコードとともに、このCMakeLists.txtを管理したいと考えていると思います
- ここでは、その応用した使い方を紹介したいと思います
- 直接埋め込む方法
- execute_process でcmake時点でビルドする方法
直接埋め込む方法
- 詳細は割愛します。公開したプロジェクトをforkなりダウンロードなりして改造してくれれば良いと思います
execute_process を使う方法
- CMakeにはexecute_processという強力な機能があります。
- cmakeするときに、裏側でソースのダウンロード、cmakeによるconfiguration、ビルド、実行までcmakeの裏側で行えます
- パターンを再生成するためには、cmakeからやり直す必要があります
- が現実問題パターンの生成をやり直すことはそうそうないのではないでしょうか。
- 以下のコードをご自身のCMakeLists.txtに追加するだけで、裏側で勝手にpptxが生成さる、手軽さがウリです。
-
pptx
はbuild\third-party\build\generated.pptx
に生成されます。 - 下記の例では
${TARGET_NAME}
ターゲットをmain.cpp
から生成して、その際にcalibrationPatternGenerator
が生成するconfig.h
をインクルードしています
set(PATTERN_GENERATOR_WORK "${CMAKE_BINARY_DIR}/third-party")
set(PATTERN_GENERATOR_BUILD "${PATTERN_GENERATOR_WORK}/build")
set(DOWNLOADED_ZIP "${CMAKE_BINARY_DIR}/patternGenerator.zip")
file(MAKE_DIRECTORY ${PATTERN_GENERATOR_WORK} ${PATTERN_GENERATOR_BUILD})
file(DOWNLOAD "https://github.com/tomoaki0705/calibrationPatternGenerator/archive/v1.0.zip" ${DOWNLOADED_ZIP})
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xz ${DOWNLOADED_ZIP} WORKING_DIRECTORY ${PATTERN_GENERATOR_WORK})
execute_process(COMMAND ${CMAKE_COMMAND} -G${CMAKE_GENERATOR} "../calibrationPatternGenerator-1.0/" WORKING_DIRECTORY ${PATTERN_GENERATOR_BUILD})
execute_process(COMMAND ${CMAKE_COMMAND} --build . --target ALL_BUILD --config Release WORKING_DIRECTORY ${PATTERN_GENERATOR_BUILD})
# executable
add_executable(${TARGET_NAME} main.cpp ${PATTERN_GENERATOR_BUILD}/config.h)
実際にやってみた
苦労した点
日本語に苦労(xml作成編)
- もちろん最初は手動でpptxファイルを作り、それと同じコンテンツをプログラムから出力しようとしました
- が、一向にエラーで開けない2
- 最終的にはバイナリエディタで比較したところ、「楕円1」という文字列がもとのpptxにあり、それをダイレクトに出力すると文字コードの関係でファイルのエンコードが破壊されていました
- なので、日本語を諦めて「ellipse 1」もしくは「box 1」と修正
圧縮プログラムに苦労
- 実はcmakeには、標準で複数ファイルを圧縮する機能がついています
-
cmake -E tar cf hoge.zip file1.xml file2.xml
とコマンドを叩くと、cmakeが圧縮ファイルを作ってくれます - が、これも何故かpptxとしては開けない。バイナリエディタで比較すると、どうにもファイルフォーマットがzipでない模様。
- で、コマンドが
tar
となってるので、ファイル名はzipでも、tar圧縮されたファイルが生成されていた、というオチ - 仕方ないので7zipの実行バイナリをcmake時にダウンロードして来て、裏で実行するスクリプトに改造したのですが、そのあとで、cmakeの3.3からzipフォーマットでの出力がサポートされたことを発見3
-
cmake -E tar cf hoge.zip --format=zip file1.xml file2.xml
と、formatオプションを渡すと、ちゃんとZIPファイルとして作ってくれる。
まとめ
- 筆者は以下の環境で検証しました
項目 | 環境1 | 環境2 | 環境3 |
---|---|---|---|
OS | Windows 7 Professional 64bit | Windows 10 Pro 64bit | Ubuntu 14.04 32bit |
Office | 2016 | 2016 | 20164 |
OpenCV | 3.3.0 | 3.2.0 | 3.1.0 |
コンパイラ | Visual Studio 2013 Update 5 | Visual Studio 2013 Update 5 | gcc 4.8.4 |
CMake | 3.9.1 | 3.10.0 | 3.5.1 |
CUDA | 8.0 | 8.0 | - |
- 明日はTaroYamadaさんの記事で、執筆時点でのタイトルは「仮) OpenCV と Intel Movidius Neural Compute Stick のSDKを連携させた。」です。楽しみ!
補足
pptxだけしかダメなの?docxは?
- 検証していませんが、docxも中身はzipファイルです。本プログラムを改造して、docxを出力するようにすれば申請書のフォーマットに則ってdocxファイルを出力したり、ネ申エクセルのフォーマットに則ったxlsxファイルを出力することも原理的には可能のはずです。うまくいけば、texファイルからdocxを生成できる夢もあるかも知れません(が、恐ろしく高い障壁が立っている気もします)
OpenCV関係なくね?CMakeだけじゃね?
- 非常に鋭いツッコミでありますが、OpenCVも必須であります。
- ZIPに圧縮するファイル群の中に、一つだけ、サムネイル画像としてthumbnail.jpegが必須です。このthumbnail.jpegも、xmlファイルを吐き出すときに合わせて生成しています
- 裏を返すと、このjpegを吐き出すためだけにOpenCVを使っています5
XMLを直書きしてるけれど、OpenCVのFileStorageクラスは使わなかったの?
- OpenCVにはxmlで行列やパラメータを書き出せる
cv::FileStorage
クラスが存在します - 実はこれで書き出すことも試したのですが、実は書き出す以前に読み込むことに失敗しました。
- ですので、どうやらOffice用のxmlとOpenCVがパースできるxmlのフォーマットのどこかに差異があるようです
- 今回はそこまで検証しておりません、あしからず
-
最近のプリンタはすごいですね。 ↩
-
誤ったフォーマットのpptxファイルをパワーポイントで開こうとすると、「ファイルが壊れています」というダイアログが表示され、無情にも真っ白なファイルが。。。 ↩
-
リンク先には「3.2から」と書かれているが、Windows版のバイナリで検証した結果、多分3.2では非対応で、3.3から対応が盛り込まれた ↩
-
Linuxで生成した後にWindowsに
pptx
ファイルだけ転送。この表には記載しなかったが、OpenOfficeでも開けることだけは確認した。印刷は試してないので不明。 ↩ -
検証していませんが、多分2.4系列でも動くのではないかと思います ↩