MinGWでOpenCVをビルドしてCLionで使った話

CLionでOpenCVも使えるようにしたいので,MinGWでビルドした話とかをする.
なお,環境は下記

  • Windows10(64bit), Windows7(64bit)
  • OpenCV2.4.11
  • CLion1.2.1

MinGWとCMakeは既にインストールされてるものとする.

OpenCVをビルドする

必要なものは

OpenCVをダウンロードしてくる

公式サイトからダウンロードするsourceforge.net
好きな場所に展開する(僕はD:\OpenCVに展開)

CMakeでgenerate

CMake GUIを開いて"Where is source code"にソースの場所を入れ,"Where to build the binaries"にビルド出力先を指定する.
Where is souece codeにはopencv\sourceを
Where to build the binariesにはopencv\mingwを指定した.
f:id:i-hako:20151125191500p:plain

場所の指定が終わったら,Configureを選択.
するとまずは真っ赤になって色々出てくる
f:id:i-hako:20151125191337p:plain
この赤い色が消えるまでConfigure.
TeX環境が整ってない場合はBUILD_DOCSのチェックボックスをオフにしておくと良いらしい.)

赤い色がすべて消えたらGenerate
これでCMakeの出番は終わり.

MinGWのヘッダーを書き換える

CMakeでGenerateが終わったら本当はすぐにMinGWでビルドするのだけれど,OSのバージョンによってはmingw32-makeがエラーで途中で止まってしまう事がある.
そこでMinGWのヘッダーの一部を書き換える必要がある.
まずはMinGWがインストールされてる場所まで行き,includeの中の"commctrl.h"を開く
f:id:i-hako:20151125192342p:plain
commctrl.hの中に_WIN32_IEを定義してる場所があるので,そこを下図の様に書き換える
f:id:i-hako:20151125193303p:plain
よくわからないけれど,こうすることでmingw32-makeのエラーを回避できる.

MinGWでビルド

コマンドプロンプトを開いてCMakeでGenerateした場所まで行く.(僕の場合D:/OpenCV/opencv_2-4-11/mingw
続いて下記コマンドを入力

mingw32-make

makeが終わったら続いてinstall

mingw32-make install

こうするとOpenCV/opencv_2-4-11/mingw/install下にインストールされる.
後は環境変数にbinとlibのパスを追加して終了.

CLionでOpenCVを使う

CMakeLists.txtを編集

CLionでプロジェクトを開いたら,CMakeLists.txtを編集して,下記を追加する

find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(<project name> ${OpenCV_LIBS})

おそらくこれで本当はちゃんと使えるはずだけれど,僕は上手く行かなかったので上手く行かなかった時のための方法も下記しておく

CMakeLists.txtを編集してもうまく行かなかった場合

CLionとCMakeの連携が取れていないのかも知れないけれど,たまに正しいディレクトリが反映されない事がある.
そういう場合はCLionのGUI上でCMakeListsを編集すると良い.
まず[View]->[Tool Buttons]を選択し,ツールボタンを表示させる.すると,CLionの下部に変なボタンが幾つか現れる.
f:id:i-hako:20151125194743p:plain
この中のCMakeを選択し,Cacheを選ぶとCMakeで設定されているパスとかが表示されるので,その中から

を探し,ここの値にMinGWでビルドしたパスを入れる.(僕の場合は画像の通り)
f:id:i-hako:20151125195511p:plain
あとは,左側の保存マークを押して完了*1
f:id:i-hako:20151125195526p:plain
おそらくこれでちゃんと使える様になるはず.

OpenCVとマウスでお絵かきできるミニアプリを作った

試しにLenna*2さんを表示するのは皆やってるので,とりあえずマウスポインタでお絵かきできる奴を作ってみた.

コード

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace std;

bool drawing = false;
cv::Point point;

void drawLine(cv::Mat* img, cv::Point points){
    cv::circle(*img, points, 3, cv::Scalar(255,255,255), -1, CV_AA);
}


void onMouse(int event, int x, int y, int flag, void* params){
    cv::Mat* image = static_cast<cv::Mat*>(params);

    switch(event){
        case cv::EVENT_MOUSEMOVE:
            if(drawing){
                point.x = x;
                point.y = y;
            }
            drawLine(image, point);
            break;

        case cv::EVENT_LBUTTONDOWN:
            drawing = true;
            point.x = x;
            point.y = y;
            drawLine(image, point);
            break;

        case cv::EVENT_LBUTTONUP:
            drawing = false;
            break;
    }
}

int main() {
    string name = "canvas";

    cv::Mat black_image = cv::Mat::zeros(cv::Size(800, 600), CV_8UC3);
    cv::Mat temp = black_image.clone();

    cv::namedWindow(name, CV_WINDOW_AUTOSIZE);

    cv::setMouseCallback(name, onMouse, (void *)&black_image);

    while(1){
        black_image.copyTo(temp);

        if(drawing)
            drawLine(&temp, point);

        cv::imshow(name, temp);

        if(cv::waitKey(100) == 27)
            break;
    }

    return 0;
}

実行画面
f:id:i-hako:20151125200649p:plain
ちゃんと動いた.

エラーコード0xC0000135で落ちる

CLionつかってると,たまにエラーコード0xC0000135とかいうのが出て実行ができない事がある.
そういう場合はとりあえずCLionを終了して,管理者として実行してみると割りと上手く行く事がわかったのでおすすめ.

*1:そういえば今だにフロッピーマークなのかと気づいた

*2:レナ (画像データ) - Wikipedia

*3:2015/11/25 21:00追記

CLionでBoost

最近、JetBrainsという所が作ってるCLionというC/C++IDEを導入した。
学生ならば*1一年間無料で利用できる。学生特権バンザイ。www.jetbrains.com

CLlionではCMakeとMinGWを使うので、これらもインストールする必要がある。

今回はCLionでBoostを使うための手順を書いていく。

Windowsにboostを入れる

boostをダウンロード

まずは、Boostを本家からダウンロードしてくる必要がある。

最新版で良い。
ダウンロードしたら、展開して好きな場所に置く。(僕は D:\boost に置いた。)

ビルド

boostはそのままでも使えるらしいが、一部はビルドしないと使えないらしい。
ビルドは主にVisual Studioを使ったビルドとMinGWを使ったビルドがある。
今回はMinGWを使ったビルドを行ったのでその方法を書く。
とは言っても何も大したことではなく、まずコマンドプロンプトを開いてBoostを置いたディレクトリまで移動する。
ここで下記コマンドを入力して実行

bootstrap.bat gcc

これで、b2.exeなる実行ファイルが出来上がる。
この実行ファイルが出来上がったら続いて下記コマンドを入力して実行する。
このコマンドでprefixの値は自分がライブラリを展開したい場所、-j 12はビルド時の並列処理のスレッド数なので各自自分のマシンに合わせた値を入れる。

b2.exe install --prefix=D:\boost\stage toolset=gcc link=static,shared threading=multi variant=debug,release runtime-link=shared -j 12

しばらくすると(ぼくの場合)D:\boost\stageにライブラリが出来上がる。

PAHT通し

システムの環境変数に値を追加する。
(CPLUS_INCLUDE_PATHの値はboostをインストールしたディレクトリ)

変数名
CPLUS_INCLUDE_PATH D:\boost\stage\include\boost-1_59\boost
LIBRARY_PATH D:\boost\stage\lib

これでwindowsにboostを入れる処理はおしまい。

CLionでBoostを読めるようにする。

…書こうとしたけど、微妙に上手く行ってないから上手くいった部分まで。*2

CMakeLists.txt編集

cmake_minimum_required(VERSION 3.3)
project(cpptest)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

set(SOURCE_FILES main.cpp)
add_executable(cpptest ${SOURCE_FILES})

include_directories(D:/boost/stage/include/boost-1_59)

target_link_libraries(cpptest ${Boost_LIBRARIES})

という感じで

  • include_directories()にヘッダーファイルの場所
  • target_link_libraries()にリンクしたいライブラリ

を書く。
ソースコード[C++] Windows での Boost 環境構築まとめ (Visual Studio 2012, MinGW) - クソネミ( ˘ω˘ ) から拝借した物を使ってみた。

#include <iostream>
#include <boost/version.hpp>

using namespace std;

int main() {
    cout << (BOOST_VERSION / 100000) << "." << (BOOST_VERSION / 100 % 1000) << "." << (BOOST_VERSION % 100) << endl;
    return 0;
}

実行結果

C:\Users\Home\.CLion12\system\cmake\generated\ba481e8e\ba481e8e\Debug\cpptest.exe
1.59.0

Process finished with exit code 0

ちゃんと正しいバージョンが出てる。

CLionでBoostがちゃんと動かない

「何を言っているんだこいつは…」と思うかもしれないけれど、動かなかったのだ。
詳しく言うと、上記のboost/version.hppではなくboost/thread/thread.hppを使ってマルチスレッド処理を書こうとした所、

CMakeFiles\cpptest.dir/objects.a(main.cpp.obj): In function `_static_initialization_and_destruction_0':
D:/boost/include/boost-1_59/boost/system/error_code.hpp:221: undefined reference to `boost::system::generic_category()'
D:/boost/include/boost-1_59/boost/system/error_code.hpp:222: undefined reference to `boost::system::generic_category()'
D:/boost/include/boost-1_59/boost/system/error_code.hpp:223: undefined reference to `boost::system::system_category()'
collect2.exe: error: ld returned 1 exit status
CMakeFiles\cpptest.dir\build.make:96: recipe for target 'cpptest.exe' failed
CMakeFiles\Makefile2:66: recipe for target 'CMakeFiles/cpptest.dir/all' failed
mingw32-make.exe[2]: *** [cpptest.exe] Error 1
mingw32-make.exe[1]: *** [CMakeFiles/cpptest.dir/all] Error 2
mingw32-make.exe: *** [all] Error 2
Makefile:82: recipe for target 'all' failed

と出てしまい、上手く動かなかった。
どうやらgccのオプションで -lboost_systemを付けると良いらしいがよくわからない。
またこの辺は後日。
(それより早くOpenCVの記事書かなきゃ…)

*1:ac.jpドメインのメールアドレスを持ってるならば

*2:後述

windows10にアップグレードしたら死んだ話①

経緯

7/29から一般リリースされたwindows10が気になって、アップグレード通知が来るまで待てなかったので手動でアップグレードした。
元のOSはwindows7 Pro。
なお手動アップグレードの方法はこれ
http://www.microsoft.com/ja-jp/software-download/windows10
手順通りにやったらwindows10にアップグレードは出来たもののなんだか色々ぶっ壊れてた。
「何もしてないのにこわれた!」
という気持ち。

何が死んだのか。何が壊れているのか。

具体的には、以下の通り

  • 僕のグラボのドライバがwindows10に対応していなかった*1(そしてこれが大本の原因)
  • windows10からwindows7にもどせなくなった。*2
  • explorer周りが完全に死んでいる。
  • OSのブートマネージャが死んだ*3

おそらく他にも気づいてない細かい点があると思うけど、多分クリティカルなのはこれぐらい。

それぞれの原因と時系列

原因

上記の問題はそれぞれ下記の原因によって起こっているらしい。*4

  • ドライバがwindows10に対応していなかった
  • 何らかの原因でwindows7のバックアップが作成されなかった
  • インストールが正しく行われていない。あるいはインストール後に何らかの原因で破損した。
  • BCDがプライマリディスク*5から何故か消失している。

実はこれらの問題は僕のとある動作によって引き起こされている可能性が高い。

時系列

windows10にインストール後ディスプレイドライバが死んでるのでドライバ入れなおす(nVidia)
-> 対応したハードウェアが見つからないと言われる(大本のドライバがぶっ壊れている)
-> win7の時に使用したドライバディスクでドライバインストール
-> OSがHDDブートしなくなる(ブルスク)
-> USBでレスキューディスク作ってスタートアップ修復(何回やっても失敗)
-> 何故かUSBを挿せばブート出来るようになった(何故かBCDがUSBに作られてしまった。)
-> explorer周りが死んでる事に気づく。
-> windows7に戻せなくなってる事に気づく。

という感じ。

解決方法

以上の問題の解決方法について数回に分けて書いていく。*6
今回はディスプレイドライバの話とOSがHDDブートできなくなった事に対する解決案みたいな話。

ディスプレイドライバ

僕が使ってるPCのグラボGeForce GTS450という割と古い物で、標準のドライバだとwin10に対応してないっぽい。
これはnVidiaがwin10リリース後に配布したドライバソフトをインストールする事で解決した。
http://www.geforce.com/drivers/results/87789
上記URLのドライバをインストールしたらちゃんと機能したので、グラフィック周りがおかしい人は試してみると良いかもしれない*7

OSがHDDブートできなくなった事について

今回は原因とMSのサポートに聞いた解決案についてだけ。*8

原因

windowsは起動に関してどのディスクのどこにwindowsがインストールされているのかという事を記録しているファイルが存在する。
これはBCD(Boot Configuration Data)と言うファイルで、このファイルにパラメータが記述されているらしい。
通常はC:\windows\Boot下に存在するが、何故か僕のwindowsではBCDのみが消えていた。

解決案①

幾つか試してみたがとりあえずMSサポートに言われた内容を記載。
とてもシンプルだが、今回僕のケースではUSBからブート出来るという事で、USBにBCDがある事がわかった。
そこで、プライマリHDDにUSBにある"Boot"というフォルダと"bootmgr"をコピーしてスタートアップ修復を2回行えとの事だった。
(試してみたが、結論から言うとだめだった。どうやらbootmgrがブートするディスクを読みに行けないらしい。)

解決案②

ちょいと技術的な話。このページに掲載されていた。pcsupport.about.com

~> bootrec /rebuildbcd

ここでwindowsが見つかればwindowsがインストールされているディスクをBCDに設定しておしまい。
見つからなければ。

  • 現在設定されているBCDのバックアップをとる
~> bcdedit /export C:\bcdbackup

なお、ここでのドライブはCかどうかは自分のパソコンに合わせて。

  • 続いてBCDのアクセス権を自由にする。
~> attrib C:\boot\bcd -h -r -s
  • BCDをリネームする。
~> ren C:\boot\bcd bcd.old
~> bootrec /rebuildbcd

見つかればwindowsBCDに設定して終了。
どうやらwindowsが見つけられる*9状態であれば、BCDwindowsに設定しそこねているだけらしいので、おそらくこれでうまくいくらしい。

やっぱりだめっぽい

ブルスクになった段階で結構変なところを弄ってしまったらしく、僕のPCは現在windowsがインストールされている領域が何故かロックされているとみなされてしまう。
そのため、上記の解決策ではどちらも上手く行かなかった…

次回

まだ今回の事が結論出てないので、まずはもう少し試してみる。
解決したら次のexplorerの問題とダウングレードできない問題を解決していくつもり。



はー…なんでぶっ壊れるかなぁ…

*1:現在は対応済み

*2:大変つらい

*3:一番でかい!

*4:MSサポート曰く

*5:windowsがインストールされてるディスク

*6:僕もまだ全部解決できてない。

*7:自己責任で

*8:解決できてない

*9:bootrec.exeがOSが入っているディスクにアクセス出来る

dpkgのlock解除

最近全くブログ書いてない事に気づいた。*1
研究が忙しかったということにしておこう。

今回はVirtualBoxの話。というかUbuntuの話。

普段研究室でUbuntu使ってて、家で作業の続きをする時には家のWindowsPCにVirtualBox入れて仮想マシンとしてubuntuで作業をしてる。
また、個人的なファイルとかはDropboxで共有してるのだけれど家のUbuntuに入れてなかった事に気づいたので先日インストールしようとしたところ、なんか失敗した。*2

結論からいうと、インストール中にフリーズしたため強制的に再起動した所apt-get updateとかができなくなった。

E: /var/lib/apt/lists/lock が取得できませんでした - open (11: リソースが一時的に利用できません)
E: ディレクトリ /var/lib/apt/lists/ をロックできません
E: ロック /var/lib/dpkg/lock が取得できませんでした - open (11: リソースが一時的に利用できません)
E: 管理用ディレクトリ (/var/lib/dpkg/) をロックできません。これを使う別のプロセスが動いていませんか?

って感じの事言われた。


今回はこれの解除方法とかを書こうとおもう。
早速ググってみたらドンピシャな事書いてあった記事があった。ankyo.blog.so-net.ne.jp

大変ありがたいので、備忘録的に書いていく。

方法

まずリカバリーモードで立ち上げる。
shiftキー押しながら起動するとリカバリーモードになる。

リカバリーモードでrootを選択し、以下のコマンドを入力する。

rm /var/lib/apt/lists/lock
rm /var/lib/dpkg/lock
apt-get update
apt-get install -f

あとは再起動。

怒られた

僕が上記の方法でlockファイル削除しようとしたら「Read Onlyだから消せない」って怒られた。
これも調べてみると再マウントする事で解決出来るらしいということがわかった。qiita.com
大変ありがたい。いんたーねっとは偉大である。

というわけでこちらに書いてある通りに下記コマンドを入力してリマウント

mount -o remount,rw /

あとは上に書いたコマンドでlockファイルを削除して、アップデートと強制インストールをしたら再起動しておしまい。

ちゃんと上手くいった。
大変ありがたいので、今後忘れないようにしよう。

*1:めっちゃツイートしてるくせにブログ更新してない

*2:面倒臭がってソフトウェアセンター使ったのが問題

std::stringstreamをクリアする

やり方

すごく初歩的な事だけど、最近知ったので。
std::stringstreamに格納されてる値をクリアにして別の値を入れる時に必要な処理

#include <iostream>
#include <sstream>

using namespace std;
int main(int argc, char* argv[]){
  stringstream ss;
  ss << "hoge";

  cout << ss.str() << endl;

  //ssをクリアする
  ss.str("");
  ss.clear(stringstream::goodbit);

  ss << "fuga";
  cout << ss.str() << endl;

  return 0;
}
hoge
fuga

ソースコードから複数のディレクトリに入ってるファイルを逐次参照するプログラムとかに使える。

使ってみた

data
  L dir1
      L file1.dat
    dir2
      L file2.dat
    dir3
      L file3.dat
    dir4
      L file4.dat

みたいなディレクトリ階層を作って、各ディレクトリのfile*.datを見るプログラムを作ってみた。
各file*.datにはファイルパスを書いておく。

#include <iostream>
#include <sstream>
#include <fstream>

using namespace std;
int main(int argc, char* argv[]){
  stringstream dir;
  string path = "./data/dir";
  string file = "file"

  for(int i = 0; i < 4; i++){
    dir << path << i+1 << "/" << file << i+1 << ".dat";
    ifstream ifs(dir.str().c_str());
    string line;
    while(getline(ifs, line)){
      cout << line << endl;
    }
    dir.str("");
    dir.clear(stringstream::goodbit);
  }

  return 0;
}
./data/dir1/file1.dat
./data/dir2/file2.dat
./data/dir3/file3.dat
./data/dir4/file4.dat

といった感じ。
OpenCVとかで作った行列データをyamlにして別々のディレクトリに保存したり読みだしたりする場合とかに使える。
(std::ifstreamのところはdir.str().c_str()としててちょっとアレだけど…)

参考HP

stringstreamのクリアの仕方 - りんでん記


[追記 2015/3/18]
ファイル逐次読み出しのソースをちょっと改変

謹賀新年

あけましておめでとうございます。

去年は色々有りました。幾つかイベントに参加したし、いっぱい勉強になりました。
まだまだいっぱいやることあって未熟者ですが、いっぱい頑張っていきたいと思います。
今年2015年は過去のいくつものSF作品などの時代設定で使用されている年でもあるので、僕もいい感じの事を出来るように色々やっていきたいですね。(適当)

今年もよろしくお願いします。

出かける前に予定とかを教えてくれるシステムを作った話

この記事はお家ハックAdvent Calendar 2014の17日目の記事です。

今回は朝の外出前に予定とか天気とか携行品を通知してくれるシステムを作った話です。(実は今年の8月ぐらいに作ったというのは内緒)

コンセプト

忙しい現代人は朝ゆっくりする時間が無い人が多い*1
僕も朝は決まってドタバタしてる。しかも急いで色々準備するもんだから忘れ物などをよくする。*2
忘れ物は人によっては結構深刻な問題に発展しかねない。
そういう失敗を起こさないための予防策として、外出前に今日の携行品とか予定を確認できる様なシステムがあればすごく嬉しいなーと思い、そういうサポートをしてくれるシステムを作りました。

概要

前提

朝の行動として以下の行動が考えられる

  • 起床
  • 洗顔など
  • 朝食
  • 気象情報確認
  • 気象情報に基づいた着替え
  • 予定確認
  • 携行品準備
  • 消灯
  • 外出

上記のうち太字の行動に何らかのサポートを行う事で外出前に効率的かつ失敗の少ない行動を行うことが出来ると考えました。

システムについて

必要要件
  • 当日の予定をメール通知
  • 持ち物を音声で通知
  • 天候情報を音声で通知
  • 消灯機構

以上を行う

システム概略図

基本はPCとUSBカメラとマイクとスピーカーがあれば出来る様にしたいと考え下図のようにした。(ちょっとわかりにくいけど・・・)
f:id:i-hako:20141217222005p:plain
天気情報や予定、持ち物などを各種APIを使用してウェブから取得してくる。
また、ユーザインターフェースとして音声を用いることにした。
音声UIとしてrospeexというクラウド音声合成サービスを使用した。*3

動作概要

システムの動作の概要は下図の通り
f:id:i-hako:20141217230615p:plain

  • 事前作業として、ユーザはgoogleカレンダーに事前に予定と必要物品を登録しておく。
  • ユーザが音声で予定を尋ねると、それを認識しgoogleカレンダーに予め登録されている予定を読みだしてメールで送信する。
  • 更にその後ユーザが外出準備に取り掛かり、携行品を準備しようとすると、動体を検出してその日必要な携行品を音声で通知してくれる。
  • また、外出直前に天気などを尋ねると、yahoo! weatherから天気情報を取得してその日の天候について教えてくれる。
  • 最後に、「電気を消して」と言うと電気を消す。

という感じです。


まとめ

感想

実際にやった場所は研究室だったので、厳密な意味でのお家ハックかと言われるとちょっとあれな感じはあるけれど*4、カメラとスピーカーとマイクがあれば好きな所で必要な情報をサポートしてくれるので、割りと便利かも知れない。
むしろ頼りすぎて余計に物忘れが激しくなりそうな感じはある。
一番きつかったのは各状態の制御をrosmessageでやってるので、ちょっと同期などが難しかった感じがあります。
(ROSについてはググってください。僕はあまり説明出来ません…(申し訳ない))

今後について

結局リマインダーの強化版みたいな感じで、事前にgoogleカレンダーに手動で予定や必要物品を登録しなきゃいけないのでもうちょっと賢い感じで予定とか立ててくれると嬉しいなーとか…

*1:早起きすればいいとかそういう話もあるけど…

*2:予定をすっぽかす事も有ります

*3:画像はhttp://rospeex.org/top-ja/より拝借

*4:まぁでもほとんど住んでるも同然だし良いよね!!!!!