いろいろアイデアを考えるのはいいけど、結構実装の面で詰まることも多かったので詰まったところをメモ。主にC++の基本的なところとちょっとした小技(?)、忘れると1〜数日潰す可能性あり。
参考資料 : ググって出てきた様々なページ。ヤフー知恵袋、stackoverflow
1.vectorのvectorの作り方とvectorのきほん
vector<vector<double> > ←最後の「>」の手前に半角スペース入れないとだめ(環境に因るかも)
2.vectorの要素の追加
(vector).push_back(入れたい値) でvectorの最後尾に新しい要素を入れる。
カラのvectorの定義だけして vector[n]=値 とかで代入しようとするとエラーになる。
まずvector.push_back=値 またはassign()とかresize()適当なサイズと初期値を設定する。
vectorのvectorならvector.push_back=2層目vector<〜〜> みたいな感じで使う 。
pythonのリストなら適当でなんとかなるのにね。不便だね。
3.opencvのROIの使い方
Rect roirect=Rect(0,0,150,150);// まず四角を定義してROIの設定
Mat imgroi=img;// ←ここでimg(roirect) にすると定義した四角がROIになったimgをimgroiとして定義できる。
ここまではいいがROIのオフセット(ROIの四角の起点になる座標)が(0,0)じゃないときオフセットを考慮する必要がある。 やらないと例えばROIが画面中心らへんだった時検出したキーポイントが画面中心じゃなくて左上とかにずれて表示される。
↓こんな感じ
for(int i=0;i<keypoint.size();i++){
keypoint.pt.x += roirect.x; ←検出したキーポイントの座標をオフセット分だけずらす
keypoint.pt.y += roirect.y; ←キーポイント構造体の座標取り出し方法
(〜.pt.x, 〜.pt.y)も意外に忘れやすいので注意
}
↑キーポイントはROIの中だけで検出されるけどキーポイント座標(pt.x pt.y)もROIのローカル座標でが決定されるのでオフセット分ずらす必要がある(オフセットが(0,0)なら別にずらさなくていい)。
4.文字扱いの数字を数値として取り出す方法
ファイルとかから読み込んだ数値をちゃんとintなりdoubleで読み込む(変換する)コツ。stringstream を使うだけ。これもpythonなら意識する必要すらない部分。C++万歳!(皮肉)
↓以下やり方。
stringstream ss; ←stringstreamのインスタンスをつくる
string str; ←stringと任意の形式(この例ではdouble)を定義
double dbl;
ss << str;// ←stringstreamにstringをぶち込む
ss >>dbl; ←stringstreamからdoubleに取り出す。これで変換完了。
ss.clear(); ←ssの中身をクリア、しないとろくなことにならないよ。ループで使う時とか。
5.opencv:任意の座標の色情報の取り出し方
意外に手こずった部分。Vec3bという型を作って以下の書式で取り出す。
Vec3b color = img.at<Vec3b>(Y座標,X座標); ←.at<Vec3b>はおそらくY座標、X座標の順で定義されている。普通と違うので注意(環境やimgの種類によってちがうかも)。
また、取り出した色情報((B,G,R),0〜256の数字)はデフォルトだと多分charで入ってるので
intへのキャストが必要↓
(int)ccolor[0]+100 ; ←例えば取り出した色の青色成分に100足すとき
今日のところはとりあえず終了。
2012年12月1日土曜日
2012年11月18日日曜日
しょぼいけど特定物体認識できたよ〜(´∀`)〜
苦節数カ月、やっとここまで来たよ・・・(つд`)
考えうるもっともしょぼい方法だけど、FAST(キーポイント検出)、FREAK(特徴量記述)を使った特定物体認識(というほどのものでもないかもしれないが)に成功したのでメモ。
・・・と思ったけど、今日はとても疲れたので実行結果だけ↓
特徴量を記述、指標化して(参考資料:FREAKの論文)総当り比較(画像が増えてくると間違いなく遅くなる)で、ひげ剃りとかカロリーメイトとか本棚(上段、下段)をまあだいたい識別できるようになった。ちなみに左上の数字はFPS。その横が似ている画像ファイル名。
↓比較用ひげ剃り画像、こんな感じで写真をフォルダに入れまくることで、どれに一番近いかを判別してくれる。
まだ課題も多いけど、これをラジコンと接続して目的の物まで向かわせるとかは頑張れば出来そう。
〜おわり〜
考えうるもっともしょぼい方法だけど、FAST(キーポイント検出)、FREAK(特徴量記述)を使った特定物体認識(というほどのものでもないかもしれないが)に成功したのでメモ。
・・・と思ったけど、今日はとても疲れたので実行結果だけ↓
特徴量を記述、指標化して(参考資料:FREAKの論文)総当り比較(画像が増えてくると間違いなく遅くなる)で、ひげ剃りとかカロリーメイトとか本棚(上段、下段)をまあだいたい識別できるようになった。ちなみに左上の数字はFPS。その横が似ている画像ファイル名。
↓比較用ひげ剃り画像、こんな感じで写真をフォルダに入れまくることで、どれに一番近いかを判別してくれる。
まだ課題も多いけど、これをラジコンと接続して目的の物まで向かわせるとかは頑張れば出来そう。
〜おわり〜
2012年11月17日土曜日
opencvでAi-Ball(小型WiFiカメラ)を使う
わかってしまえば簡単だが、わからないと一生わからない気がするのでメモ
※重要※
今回のコードによって発生した問題につきましては一切の責任を負いかねますのでご注意の上ご利用ください(トリセツとかに載っていない使い方の為)。
今回(3週間くらい前だが)は、Ai-Ball(公式サイト?)をopwncvで普通に使う方法をメモっておきます。
主な参考資料
・Ai-Ballの取説
・海外の質問掲示板(ここの情報がメインだが、場所を失念)
・九州工業大学 宮本研究室HP様(ttp://www.brain.kyutech.ac.jp/~miyamo/index.php/)
要約
c++:
VideoCapture cap("http://(Ai-BallのIPアドレス)/?action=stream.mjpeg");
python:
capture=cv.CaptureFromFile("http://(Ai-BallのIPアドレス)/?action=stream.mjpeg")
↑ちなみに普通のwebカメラだと
capture = cv.CaptureFromCAM(0) pythonでは微妙に使う関数が違うので注意
それぞれのカメラ動画使うサンプル見ればわかると思いますけど、変化点は↑だけです。
なかなか分からなかったのがアドレスの最後の「.mjpeg」の部分(どこかの海外掲示板の丸パクリ、もうどうやって検索したのか思い出せない)。
こうすることでリアルタイム(うちのPCでは18fpsくらいしか出ないが)で普通のウェブカメラとして使えます。
ちなみに宮本研究室さんの公開されているプログラムは動画(mjpeg)としてではなくスナップショット(jpg)として画像を取り込んでいるためfpsが落ちます(環境により異なると思いますが筆者環境では4fpsくらい)
今現在(2012年11月)、使いやすそうな小型無線カメラもあんまりないし、もしかしたらこの情報が役に立つ人がいるといいな・・・と思いつつ終了。
※重要※
今回のコードによって発生した問題につきましては一切の責任を負いかねますのでご注意の上ご利用ください(トリセツとかに載っていない使い方の為)。
今回(3週間くらい前だが)は、Ai-Ball(公式サイト?)をopwncvで普通に使う方法をメモっておきます。
主な参考資料
・Ai-Ballの取説
・海外の質問掲示板(ここの情報がメインだが、場所を失念)
・九州工業大学 宮本研究室HP様(ttp://www.brain.kyutech.ac.jp/~miyamo/index.php/)
要約
c++:
VideoCapture cap("http://(Ai-BallのIPアドレス)/?action=stream.mjpeg");
python:
capture=cv.CaptureFromFile("http://(Ai-BallのIPアドレス)/?action=stream.mjpeg")
↑ちなみに普通のwebカメラだと
capture = cv.CaptureFromCAM(0) pythonでは微妙に使う関数が違うので注意
それぞれのカメラ動画使うサンプル見ればわかると思いますけど、変化点は↑だけです。
なかなか分からなかったのがアドレスの最後の「.mjpeg」の部分(どこかの海外掲示板の丸パクリ、もうどうやって検索したのか思い出せない)。
こうすることでリアルタイム(うちのPCでは18fpsくらいしか出ないが)で普通のウェブカメラとして使えます。
ちなみに宮本研究室さんの公開されているプログラムは動画(mjpeg)としてではなくスナップショット(jpg)として画像を取り込んでいるためfpsが落ちます(環境により異なると思いますが筆者環境では4fpsくらい)
今現在(2012年11月)、使いやすそうな小型無線カメラもあんまりないし、もしかしたらこの情報が役に立つ人がいるといいな・・・と思いつつ終了。
2012年10月28日日曜日
ハンドジェスチャによるラジコン操縦システムの開発
無駄に格調高いタイトルだけど、ただこれまでのプログラムを全混ぜしただけ
まずラジコンの話↓
先週どうにかxbeeが使えるようになったのでラジコンでも作ってみた(有給2日取って)。
同僚「ラジコン作ったんだって?」
筆者「おう!テンション上って動画まで撮ってきたぜ!!」
同僚「マジかよ見せて」
筆者「もちろん!」
↓
同僚「え・・・ああ、なんか微妙だな・・・」
筆者「そうか、まあこんなもんだよ実際・・・(´・ω・)」
しょうがないよね。単三電池4本でArduinoとxbeeとDCモータ2つ動かしてるからね(´・ω・)
〜材料〜
タミヤのキット(これ)の下半分
Arduino uno
xbee ZBのやつ
モータドライバ(TA7291P)✕2
ブレッドボード
電池ボックス、単三✕4
100均の使い捨てお弁当箱
ジャンプワイヤ✕多分14本くらい
〜操作インターフェース(上の動画はこれで操作してた)〜
2本のスライダで前後と左右(回転)を制御する極めて洗練された(必要な機能まで削ぎ落した)インターフェース。
・一旦止まらないと曲がれない酷い仕様。
・PWMで速度は無駄に細かく(最大1024段階)調整できる。
上半分はテスト用のGUIなので今回の話とは無関係
ラジコンの話 〜おわり〜
過去に作ったopencvのプログラム(過去記事)にラジコン操作プログラムをぶち込んで、
特定の指の状態のとき上のインターフェースのスライダの値を変化するようにしてみた。
手の形:動作
パー:前進
親指曲げたパー:後退
グー:停止
チョキ:左回転(回転は人差し指基準に左右の指を立てるイメージ)
指でっぽう:右回転
でやってみた結果、当然ながら成功。ラジコンの動きは上の動画と同じで、手の認識は過去記事と同じ。気分は超能力者 (´д`)ノシ ミ凸
これでとりあえず、カメラ→PCで画像処理、判断→無線→Arduino→モータの流れが実装出来た。
しばらくはコードの最適化、高速化(一部をboost.pythonでC++にしただけでフレームレートが5fps増えた) でもやりながら、機械学習やら制御やらを勉強する予定。
〜おわり〜
まずラジコンの話↓
先週どうにかxbeeが使えるようになったのでラジコンでも作ってみた(有給2日取って)。
同僚「ラジコン作ったんだって?」
筆者「おう!テンション上って動画まで撮ってきたぜ!!」
同僚「マジかよ見せて」
筆者「もちろん!」
↓
同僚「え・・・ああ、なんか微妙だな・・・」
筆者「そうか、まあこんなもんだよ実際・・・(´・ω・)」
しょうがないよね。単三電池4本でArduinoとxbeeとDCモータ2つ動かしてるからね(´・ω・)
〜材料〜
タミヤのキット(これ)の下半分
Arduino uno
xbee ZBのやつ
モータドライバ(TA7291P)✕2
ブレッドボード
電池ボックス、単三✕4
100均の使い捨てお弁当箱
ジャンプワイヤ✕多分14本くらい
〜操作インターフェース(上の動画はこれで操作してた)〜
2本のスライダで前後と左右(回転)を制御する極めて洗練された(必要な機能まで削ぎ落した)インターフェース。
・一旦止まらないと曲がれない酷い仕様。
・PWMで速度は無駄に細かく(最大1024段階)調整できる。
上半分はテスト用のGUIなので今回の話とは無関係
ラジコンの話 〜おわり〜
過去に作ったopencvのプログラム(過去記事)にラジコン操作プログラムをぶち込んで、
特定の指の状態のとき上のインターフェースのスライダの値を変化するようにしてみた。
手の形:動作
パー:前進
親指曲げたパー:後退
グー:停止
チョキ:左回転(回転は人差し指基準に左右の指を立てるイメージ)
指でっぽう:右回転
でやってみた結果、当然ながら成功。ラジコンの動きは上の動画と同じで、手の認識は過去記事と同じ。気分は超能力者 (´д`)ノシ ミ凸
これでとりあえず、カメラ→PCで画像処理、判断→無線→Arduino→モータの流れが実装出来た。
しばらくはコードの最適化、高速化(一部をboost.pythonでC++にしただけでフレームレートが5fps増えた) でもやりながら、機械学習やら制御やらを勉強する予定。
〜おわり〜
2012年10月20日土曜日
arduino-xbee-firmata-python連携キター(´∀`)ー
いろいろ参考にしまくってどうにかxbee(簡単に無線でシリアル通信できるユニット)でいつも通りにarduino動かせるようになったので要点をメモ(忘れると1日潰れる箇所あり。注意)
筆者環境:ubuntu 12.04 (32bit) pythonはeclipse(PyDev) 他はふつうのはず
主な参考文献、ソフトなどの入手先
1、ubuntuでのxbeeのソフト設定方法を参考にさせて頂きました。
ttp://d.hatena.ne.jp/abikounso/20100506/1273106924
2、オライリーの「XBeeで作るワイヤレスセンサネットワーク」、今回の話の基盤になる書籍。
3、FTDI(PCとxbeeをつなぐUSBコネクタのドライバ)
ttp://www.ftdichip.com/FTDrivers.htm(目次的なページ)
http://www.ftdichip.com/Drivers/VCP.htm(ubuntuはこっち)
ページにあるTN-101という資料に具体的な入れ方が書いてあるから見ながら入れる(英語)
■xbeeを使えるようにする
上記3のドライバを入れる → xbeeをエクスプローラ(xbee-USBコネクタ)に装着
→ PCのUSBに挿し込む
→ 参考資料1や2を参考にwineでX-CTUを起動 、ファームウェア(〜ATのバージョン最新のやつ、バージョンは16進数なので注意)をxbeeに書き込む
→picocom(コマンドラインでxbeeの通信設定できるソフト) を導入
apt-get でも入れられるがバージョンが古い(1.4)ため参考資料のやり方でできない。
最新のtar玉落としてきて 「cd (最新版のフォルダ) ./picocom」で起動
これを使ってATコマンドでネットワークIDなどの登録、設定を行う。無いと詰む
→ 順序は変わるが、ここでボーレートをデフォルトの9600から57600に変更する。
やらないとfirmata使えない(解決に半日)やり方は以下
ファームウェアの設定画面のSerial〜 のBaud Rateを57600にする。
メイン画面の右上のBaudも57600にしておく
2個目のxbeeも同様に設定する(USB引っこ抜いて、アダプタのxbeeを載せ替え)。ファームウェアは片方はコーディネータ(AT)、片方はルータ(AT)になるようにしておく。あと、ATDH、ATDLのシリアルは相手側の番号を入力する。
コーディネータをPC(USBコネクタで)に繋ぎ、ルータの方をarduino(xbeeシールド)に載せる。
図は配線後の写真(サンプルスケッチでLEDを光らせてみた)
シールドを使うときの 注意点として、arduinoにスケッチ(arduinoに書き込むプログラムのおしゃれな言い方)を書き込むときはシールド上「serial select」スイッチをUSBに、書き込み終わって実際に無線で動かすときはMICROにすること。間違えると動かないし、スケッチ書き込みでバグる。
arduinoにstandardfirmataのスケッチ(サンプルの中にある)を書き込む。
pythonでpyfirmata(ググる→githubらへんから入手→setup.pyでインストール→pythonのインクルードパスにフォルダ登録しとく)を使って普通にプログラム書く。使い方はpyfirmataのサンプル参照。そのうち自分でまとめるかもしれないけど。
→以前に作ったfirmata用テストプログラムの接続ポートだけ変えてサーボモータを動かすことに成功。スライドバーの動きに応じてサーボが動く、楽しすぎワロタ
上がテストGUI(作りが雑)、下が実機の構成(arduino、電池、サーボ、ブレッドボード )。
ブレッドボードに今回の話と関係ないセンサが刺さってるのはご愛嬌
明日と来週で適当にラジコンでも作ってみるか。
・・・書き忘れがあったら嫌だな(;´д`)。ああ、無線モノは認識に時間かかる(X-CTUとか)から気長に待つべし。連打するとろくなことにならない。
筆者環境:ubuntu 12.04 (32bit) pythonはeclipse(PyDev) 他はふつうのはず
主な参考文献、ソフトなどの入手先
1、ubuntuでのxbeeのソフト設定方法を参考にさせて頂きました。
ttp://d.hatena.ne.jp/abikounso/20100506/1273106924
2、オライリーの「XBeeで作るワイヤレスセンサネットワーク」、今回の話の基盤になる書籍。
3、FTDI(PCとxbeeをつなぐUSBコネクタのドライバ)
ttp://www.ftdichip.com/FTDrivers.htm(目次的なページ)
http://www.ftdichip.com/Drivers/VCP.htm(ubuntuはこっち)
ページにあるTN-101という資料に具体的な入れ方が書いてあるから見ながら入れる(英語)
■xbeeを使えるようにする
上記3のドライバを入れる → xbeeをエクスプローラ(xbee-USBコネクタ)に装着
→ PCのUSBに挿し込む
→ 参考資料1や2を参考にwineでX-CTUを起動 、ファームウェア(〜ATのバージョン最新のやつ、バージョンは16進数なので注意)をxbeeに書き込む
→picocom(コマンドラインでxbeeの通信設定できるソフト) を導入
apt-get でも入れられるがバージョンが古い(1.4)ため参考資料のやり方でできない。
最新のtar玉落としてきて 「cd (最新版のフォルダ) ./picocom」で起動
これを使ってATコマンドでネットワークIDなどの登録、設定を行う。無いと詰む
→ 順序は変わるが、ここでボーレートをデフォルトの9600から57600に変更する。
やらないとfirmata使えない(解決に半日)やり方は以下
ファームウェアの設定画面のSerial〜 のBaud Rateを57600にする。
メイン画面の右上のBaudも57600にしておく
2個目のxbeeも同様に設定する(USB引っこ抜いて、アダプタのxbeeを載せ替え)。ファームウェアは片方はコーディネータ(AT)、片方はルータ(AT)になるようにしておく。あと、ATDH、ATDLのシリアルは相手側の番号を入力する。
コーディネータをPC(USBコネクタで)に繋ぎ、ルータの方をarduino(xbeeシールド)に載せる。
図は配線後の写真(サンプルスケッチでLEDを光らせてみた)
シールドを使うときの 注意点として、arduinoにスケッチ(arduinoに書き込むプログラムのおしゃれな言い方)を書き込むときはシールド上「serial select」スイッチをUSBに、書き込み終わって実際に無線で動かすときはMICROにすること。間違えると動かないし、スケッチ書き込みでバグる。
arduinoにstandardfirmataのスケッチ(サンプルの中にある)を書き込む。
pythonでpyfirmata(ググる→githubらへんから入手→setup.pyでインストール→pythonのインクルードパスにフォルダ登録しとく)を使って普通にプログラム書く。使い方はpyfirmataのサンプル参照。そのうち自分でまとめるかもしれないけど。
→以前に作ったfirmata用テストプログラムの接続ポートだけ変えてサーボモータを動かすことに成功。スライドバーの動きに応じてサーボが動く、楽しすぎワロタ
上がテストGUI(作りが雑)、下が実機の構成(arduino、電池、サーボ、ブレッドボード )。
ブレッドボードに今回の話と関係ないセンサが刺さってるのはご愛嬌
明日と来週で適当にラジコンでも作ってみるか。
・・・書き忘れがあったら嫌だな(;´д`)。ああ、無線モノは認識に時間かかる(X-CTUとか)から気長に待つべし。連打するとろくなことにならない。
2012年10月14日日曜日
boost python の導入
C/C++でglade使ってGTKのUI作ってOPENCVも使って、同時にArduinoも(firmataで)動かせればいいな〜と思いつつここ2週間ほど足掻いてきたけど
「もうむりぽ・・・(´ω`)、いまのぼくではpythonでしかopencvとarduinoを繋げないお・・」
な感じになってきたので、やっぱりpythonで諸問題の解決に当たることにしました。
pythonにおける実行速度の問題解決方法はだいたい以下の路線になります。
1,cpython
2,pypy
3,boost python
4,そもそものアルゴリズムを変更
今回は3の「boost python」とかいうのに(C++勉強したのがもったいなかったので)挑戦したのでメモ
boost python・・・C++のコードを普通にpythonにimportできる神ライブラリ(boostっていうのはC++の準標準ライブラリ群のことらしい)
これでやたら計算時間がかかるベクトルの角度計算のとこだけ高速化できればめでたくHappyENDを迎えることができる。
で、Boostのインストールから(ubuntu 12.04 32bit)
synapticで「boost」で検索→libboost-python1.46.1(2012年10月現在)を インストール(依存関係にあるものも全部)。ほかの方法(apt-getとかtar玉から手動でインストールとかはなぜかうまく行かなかった(インストールはうまく行ったがその後が・・・)。ふつうはうまく行くはずなのでそちらで行けるならどうぞ)
おわり
使い方:
参考文献:
1.「[c++][python][boost]boost::pythonを使ってC++のPythonラッパーを作る」: ttp://d.hatena.ne.jp/sleepy_yoshi/20111120/p1
2.Boost.Python の機能をざっと紹介してみる :
ttp://d.hatena.ne.jp/moriyoshi/20091214/1260779899
参考文献を参考にさせていただきながら、どうにかhello world的な行為に成功。
□まずc++のソースを書く(ほぼ参考文献2からの引用、コードの解説はそちらでどうぞ)
#define BOOST_PYTHON_STATIC_LIB
#include <string>
#include <boost/python.hpp>
using namespace std;
string add_hello( string s )
{
return "Hello, " + s;
}
int square( int n )
{
return n * n;
}
BOOST_PYTHON_MODULE(kakudo)
{
// C++のadd_hello関数を、greetという名前でpython用に公開
boost::python::def( "greet", add_hello );
// C++のsquare関数を、squareという名前でpython用に公開
boost::python::def( "square", square );
}
流れとしては、ヘッダ書く→関数書く(クラスもいけるらしい)→pythonの関数名との対応関係を記入という感じ。これだけ見るとわかりやすくて簡単そうだが・・・
□これをpythonで動かす
g++でコンパイル(コンパイルのオプションなんかは参考文献1からのパクr引用)
g++ -I`python -c 'from distutils.sysconfig import *; print get_python_inc()'` -DPIC -shared -fPIC -o kakudo.so kakudo.cpp -lboost_python
↑何がなんだかわからない。ちょっと調べて簡略化(太字部分)
g++ -I/usr/include/python2.7 -DPIC -shared -fPIC -o kakudo.so kakudo.cpp -lboost_python
どうやらここはこの前の`pkg-config 〜`みたいな感じで「python.h」のおいてあるフォルダの位置(だいたいpythonのインストールフォルダ)と思われる(他のページでpython.hがいるって書いてたきがする) 。
次に、 -DPIC -shared -fPIC の部分。-DPICはよく分からなかった(削除してもとりあえず問題なかった) -shared -fPIC は共用ファイル(〜.so)を作るのにセットで必要なオプションっぽい(-fpicはなくても機能したけど直感的に入れといたほうが良い気がする)
その次は -o (出力ファイル名) (入力ファイル名)
最後に -lboost_python は-l(ライブラリの検索) とboost_pythonなのでインクルードパス(どこだかしらないけどboostを入れた時にg++のデフォルト探索範囲に設定されてるはず)からboost_pythonを探してくるコマンド。もし無いと
ImportError:〜.so: undefined symbol: _ZN5boost6python6detail11init_moduleEPKcPFvvE
↑python側でこんなエラーが出る(知らずにこんなエラーが出たら泣くね。ライブラリ忘れには注意したいところ)。
〜python側の処理(筆者のオリジナルコード)〜
pythonのインクルードパスにkakudo.so (名前は↑のコマンドで自由に変更できる)のあるフォルダを入れてから以下の高度なpythonプログラムを記述し、実行する。
import kakudo
a=kakudo.greet("hello")
print a
〜出力〜
Hello, hello
以上、おわり。
来週はベクトルの角度求める関数でも書いて見る予定。これで高速化出来なかったら精神的ダメージを受けそうだわ・・・わりとその可能性もあるし
「もうむりぽ・・・(´ω`)、いまのぼくではpythonでしかopencvとarduinoを繋げないお・・」
な感じになってきたので、やっぱりpythonで諸問題の解決に当たることにしました。
pythonにおける実行速度の問題解決方法はだいたい以下の路線になります。
1,cpython
2,pypy
3,boost python
4,そもそものアルゴリズムを変更
今回は3の「boost python」とかいうのに(C++勉強したのがもったいなかったので)挑戦したのでメモ
boost python・・・C++のコードを普通にpythonにimportできる神ライブラリ(boostっていうのはC++の準標準ライブラリ群のことらしい)
これでやたら計算時間がかかるベクトルの角度計算のとこだけ高速化できればめでたくHappyENDを迎えることができる。
で、Boostのインストールから(ubuntu 12.04 32bit)
synapticで「boost」で検索→libboost-python1.46.1(2012年10月現在)を インストール(依存関係にあるものも全部)。ほかの方法(apt-getとかtar玉から手動でインストールとかはなぜかうまく行かなかった(インストールはうまく行ったがその後が・・・)。ふつうはうまく行くはずなのでそちらで行けるならどうぞ)
おわり
使い方:
参考文献:
1.「[c++][python][boost]boost::pythonを使ってC++のPythonラッパーを作る」: ttp://d.hatena.ne.jp/sleepy_yoshi/20111120/p1
2.Boost.Python の機能をざっと紹介してみる :
ttp://d.hatena.ne.jp/moriyoshi/20091214/1260779899
参考文献を参考にさせていただきながら、どうにかhello world的な行為に成功。
□まずc++のソースを書く(ほぼ参考文献2からの引用、コードの解説はそちらでどうぞ)
#define BOOST_PYTHON_STATIC_LIB
#include <string>
#include <boost/python.hpp>
using namespace std;
string add_hello( string s )
{
return "Hello, " + s;
}
int square( int n )
{
return n * n;
}
BOOST_PYTHON_MODULE(kakudo)
{
// C++のadd_hello関数を、greetという名前でpython用に公開
boost::python::def( "greet", add_hello );
// C++のsquare関数を、squareという名前でpython用に公開
boost::python::def( "square", square );
}
流れとしては、ヘッダ書く→関数書く(クラスもいけるらしい)→pythonの関数名との対応関係を記入という感じ。これだけ見るとわかりやすくて簡単そうだが・・・
□これをpythonで動かす
g++でコンパイル(コンパイルのオプションなんかは参考文献1からのパクr引用)
g++ -I`python -c 'from distutils.sysconfig import *; print get_python_inc()'` -DPIC -shared -fPIC -o kakudo.so kakudo.cpp -lboost_python
↑何がなんだかわからない。ちょっと調べて簡略化(太字部分)
g++ -I/usr/include/python2.7 -DPIC -shared -fPIC -o kakudo.so kakudo.cpp -lboost_python
どうやらここはこの前の`pkg-config 〜`みたいな感じで「python.h」のおいてあるフォルダの位置(だいたいpythonのインストールフォルダ)と思われる(他のページでpython.hがいるって書いてたきがする) 。
次に、 -DPIC -shared -fPIC の部分。-DPICはよく分からなかった(削除してもとりあえず問題なかった) -shared -fPIC は共用ファイル(〜.so)を作るのにセットで必要なオプションっぽい(-fpicはなくても機能したけど直感的に入れといたほうが良い気がする)
その次は -o (出力ファイル名) (入力ファイル名)
最後に -lboost_python は-l(ライブラリの検索) とboost_pythonなのでインクルードパス(どこだかしらないけどboostを入れた時にg++のデフォルト探索範囲に設定されてるはず)からboost_pythonを探してくるコマンド。もし無いと
ImportError:〜.so: undefined symbol: _ZN5boost6python6detail11init_moduleEPKcPFvvE
↑python側でこんなエラーが出る(知らずにこんなエラーが出たら泣くね。ライブラリ忘れには注意したいところ)。
〜python側の処理(筆者のオリジナルコード)〜
pythonのインクルードパスにkakudo.so (名前は↑のコマンドで自由に変更できる)のあるフォルダを入れてから以下の高度なpythonプログラムを記述し、実行する。
import kakudo
a=kakudo.greet("hello")
print a
〜出力〜
Hello, hello
以上、おわり。
来週はベクトルの角度求める関数でも書いて見る予定。これで高速化出来なかったら精神的ダメージを受けそうだわ・・・わりとその可能性もあるし
2012年10月10日水曜日
eclipseでC++でGTKで動かす(その1)
先月末ごろ
筆者「じゃんけんマシンの基礎キターーー(略」
筆者「・・・でもどう頑張っても20fpsくらいしか出ない。
しゃーなしC++やってみるか。死ぬほど嫌だけど。」
ということでC++の 勉強を始めました。今回はそのメモ
eclipseだとCDT(C Develop tool(?))というのをいれるとC/C++が使えるようになる。
CDT入れるとこまではググってどうにか・・・・
で、問題はここからだよ。先週の土日を消費しても間に合わず今日(いまさっき)どうにか到達
1,gtkmm(pythonでいうところのpygtkにあたるもの)の導入
筆者「じゃんけんマシンの基礎キターーー(略」
筆者「・・・でもどう頑張っても20fpsくらいしか出ない。
しゃーなしC++やってみるか。死ぬほど嫌だけど。」
ということでC++の 勉強を始めました。今回はそのメモ
eclipseだとCDT(C Develop tool(?))というのをいれるとC/C++が使えるようになる。
CDT入れるとこまではググってどうにか・・・・
で、問題はここからだよ。先週の土日を消費しても間に合わず今日(いまさっき)どうにか到達
1,gtkmm(pythonでいうところのpygtkにあたるもの)の導入
sudo apt-get install libgtkmm-3.0-dev
sudo apt-get install libgstreamermm-0.10-dev sudo apt-get install libgdamm4.0-dev
という感じでインストールするだけ(ubuntu12.04)。
2,gtkmmの動作を確認
ようつべにて
「Creating a simple GUI programm with C++ and GTKMM with a Button」という偉大な動画からテスト用のコードを拝借#include <gtkmm.h>
int main( int argc, char *argv[] )
{
Gtk::Main kit( argc, argv );
Gtk::Window window;
Gtk::Main::run( window );
return 0;
}
これでウィンドウが表示できるぜ!!ってなればよかったんだけどね・・・
当然コンパイラが<gtkmm.h>とかいうのをどここから探して
持ってこないといけないわけでして・・・
ここでeclipseの設定をいじらないといけなくなりました。
まあ当然と言われるとそうなんだが。
以下設定のしかた。
1,プロジェクトのプロパティから下のような設定画面を出す。
ここでC/C++ビルドの「設定」をクリック
2,この中の 「〜C++ Compiler」の「その他」をクリック
で、「その他のフラグ」に`pkg-config --libs --cflags gtkmm-3.0`と書いておく
(かいせつ)
「`」はshift+@キーで出る(shift+7キーじゃないよ)
pkg-config はいつの間にか入ってたがアプリっぽい。もし無いなら入れるべし。
--libs --cflags はpkg-configのオプション。C++(多分Cも)にインクルードする関連の
ファイルのパスを全部表示してくれる便利な奴。
これでgtkmm使うに当って必要なファイルは全部リンク出来る感じになる。多分他のツール
(opencvとか)使うときにも活用できる。
その他の3つほど上に「インクルード」とかいうのがあってそれで
参照するパスを入れることもできるが(多分そっちが普通か?)
gtkmmは参照ファイルが多いので止めた方がいい。 日が暮れるので。
これで使えたらいいんだけどまだやることがある。
今まで触ってた項目の親である「GCC C++ Compiler」をクリックして「エキスパート設定
コマンド行パターン」とかいう難しそうなところに注目。
どうやらここでコンパイル時のコマンドラインの入力順を規定しているっぽい。
eclipseも所詮はコマンドライン入力を自動でやってくれるだけの存在でしかない。
ここで「g++ (ファイル名)(オプション)(出力ファイル名)(なんとか〜)」の()の
順番をいろいろ入れ替えられるようになってる(はず)。
デフォルトだとgtkmm込のコンパイルが通らないのでここの順番を
${COMMAND} ${FLAGS} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS}
から
${COMMAND} ${OUTPUT_FLAG} ${OUTPUT_PREFIX}${OUTPUT} ${INPUTS} ${FLAGS}
に変更(ここの丸写し。いいのだろうか:スタックオーバーフロー)
でビルド→実行→窓出現
ビルドで警告出るし、実行で「必要なプロジェクトにエラーがあります」とか出るけど
無視して実行(そのうち解決できるといいね)。
結果↓
pythonなら10分くらいで出来そうな話だったけどさすがC++。そらみんな別の言語使うわ。
気軽にGUI作れるgladeっていうソフトで作れるようになるとこまで持っていくので次回へ
続く(諦めてpythonに戻ったら続かない)
登録:
投稿 (Atom)











