ofFboにofTextureから大きな画像の一部を斜めに切り出す方法
大きな画像から、任意の位置と角度で、適当な矩形を切り出す方法をメモしておきます。
注記:普通にやるならこちらです。
cvl-robot.hateblo.jp
画像サイズ1024×768。描画なしで800fps程度。描画ありだと、verticalSyncに引っ張られて60fps。
普通にOpenCVで書くのとどっちが速いだろう???
カーソル操作は自動車(戦車?)のように移動します。
← 左に1度旋回
→ 右に1度旋回
↑ 前進
↓ 後退
マウスは、ドラッグした位置に切り抜き中心が移動します。スクロール上で左に旋回、下で右に旋回します。
ofApp.cpp
#include "ofApp.h" //-------------------------------------------------------------- void ofApp::setup(){ // 描画の有無とフレームレートの設定 flag_draw = true; ofSetVerticalSync(flag_draw); ofSetFrameRate(0); // 切り抜き画像サイズ crop_size.x = 100.f; crop_size.y = 100.f; // 画像の読み込み ofLoadImage(pix, "Koala.jpg"); // 汎用性のためにPixelsで読み込み tex.allocate(pix); tex.setTextureWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_BORDER); // 切り抜き中心位置の初期化 pos.x = tex.getWidth() / 2.f; pos.y = tex.getHeight() / 2.f; // fboの準備 fbo.allocate((int)crop_size.x, (int)crop_size.y); // メインウィンドウの大きさ調整 ofSetWindowShape((int)ceil(tex.getWidth() + crop_size.x), (int)tex.getHeight()); flag_updated = true; // 更新フラグ } //-------------------------------------------------------------- void ofApp::update(){ // cout << "FrameRate: " << ofToString(ofGetFrameRate(), 0) << "\t\r"; } //-------------------------------------------------------------- // Texture tの中心位置p,角度aからFbo fにfのサイズで画像を切り出す関数 void ofApp::rotationalCrop(ofFbo& f, ofTexture& t, ofVec2f p, float a) { float w = f.getWidth(); float h = f.getHeight(); // float diag = sqrtf(powf(w, 2.f) + powf(h, 2.f)); // 対角線の長さ // 外接する長方形の長辺 float rad = ofDegToRad(a); float i = fabs(w*cos(rad)) + fabs(h*sin(rad)); float j = fabs(w*sin(rad)) + fabs(h*cos(rad)); float r = ceil((i>j)?i:j); f.begin(); ofClear(0.f); ofPushMatrix(); // Fboの中心で回転 ofTranslate(0.5f*w, 0.5f*h); ofRotate(a); ofTranslate(-0.5f*w, -0.5f*h); // 長辺長の正方形を位置pを中心にして描画 t.drawSubsection(-0.5f*(r-w), -0.5f*(r-h), r, r, p.x - 0.5f*r, p.y - 0.5f*r, r, r); ofPopMatrix(); f.end(); } //-------------------------------------------------------------- void ofApp::draw(){ if (tex.isAllocated() && fbo.isAllocated() && flag_updated) { rotationalCrop(fbo, tex, pos, angle); flag_updated = false; } if (!flag_draw) return; if (tex.isAllocated()) { // テクスチャの表示 tex.draw(0, 0); // カーソルの表示 ofPushStyle(); ofNoFill(); ofPushMatrix(); ofTranslate(pos.x, pos.y); ofRotate(-angle); ofDrawRectangle(-crop_size.x/2.f, -crop_size.y/2.f, crop_size.x, crop_size.y); ofPopMatrix(); ofPopStyle(); } if (fbo.isAllocated()) { // 切り抜き結果の表示 ofPushMatrix(); ofTranslate(tex.getWidth(), 0); fbo.draw(0, 0); ofPopMatrix(); } // フレームレートの表示 // ofDrawBitmapString(ofToString(ofGetFrameRate(), 0), 20, 20); // bug } //-------------------------------------------------------------- void ofApp::keyPressed(int key){ // 回転 if (key == OF_KEY_LEFT) { angle += 1.f; flag_updated = true; } else if (key == OF_KEY_RIGHT) { angle -= 1.f; flag_updated = true; } // 前進・後退 if (key == OF_KEY_UP) { float r = 2.f; float rad = ofDegToRad(angle + 90.f); ofVec2f d(r*cos(rad), -r*sin(rad)); pos = ofVec2f(ofClamp(pos.x + d.x, 0.f, tex.getWidth()), ofClamp(pos.y + d.y, 0.f, tex.getHeight())); flag_updated = true; } else if (key == OF_KEY_DOWN) { float r = 2.f; float rad = ofDegToRad(angle + 90.f); ofVec2f d(-r*cos(rad), r*sin(rad)); pos = ofVec2f(ofClamp(pos.x + d.x, 0.f, tex.getWidth()), ofClamp(pos.y + d.y, 0.f, tex.getHeight())); flag_updated = true; } // 切り出したFboをファイルに保存 // from here: http://www.atnr.net/how-to-save-fbo-screenshot-on-of/ if (key == 's') { ofImage img; ofPixels pixels; fbo.readToPixels(pixels); img.setFromPixels(pixels); char fileNameStr[255]; string date = ofGetTimestampString(); // タイムスタンプをファイル名にする sprintf(fileNameStr, "%s.png", date.c_str()); img.save(fileNameStr, OF_IMAGE_QUALITY_BEST); } } //-------------------------------------------------------------- void ofApp::keyReleased(int key){ } //-------------------------------------------------------------- void ofApp::mouseMoved(int x, int y ){ } //-------------------------------------------------------------- void ofApp::mouseDragged(int x, int y, int button){ pos = ofVec2f(ofClamp(x, 0, tex.getWidth()), ofClamp(y, 0, tex.getHeight())); flag_updated = true; } //-------------------------------------------------------------- void ofApp::mousePressed(int x, int y, int button){ } //-------------------------------------------------------------- void ofApp::mouseReleased(int x, int y, int button){ } //-------------------------------------------------------------- void ofApp::mouseEntered(int x, int y){ } //-------------------------------------------------------------- void ofApp::mouseExited(int x, int y){ } //-------------------------------------------------------------- void ofApp::windowResized(int w, int h){ } //-------------------------------------------------------------- void ofApp::gotMessage(ofMessage msg){ } //-------------------------------------------------------------- void ofApp::dragEvent(ofDragInfo dragInfo){ } //-------------------------------------------------------------- void ofApp::mouseScrolled(int x, int y, float scrollX, float scrollY) { angle += scrollY; flag_updated = true; }
ofApp.h
#pragma once #include "ofMain.h" #include "ofPixels.h" #include "ofTexture.h" #include "ofFbo.h" class ofApp : public ofBaseApp { public: void setup(); void update(); void draw(); void keyPressed(int key); void keyReleased(int key); void mouseMoved(int x, int y); void mouseDragged(int x, int y, int button); void mousePressed(int x, int y, int button); void mouseReleased(int x, int y, int button); void mouseEntered(int x, int y); void mouseExited(int x, int y); void windowResized(int w, int h); void dragEvent(ofDragInfo dragInfo); void gotMessage(ofMessage msg); void mouseScrolled(int x, int y, float scrollX, float scrollY); void rotationalCrop(ofFbo& f, ofTexture& t, ofVec2f p, float a); protected: ofPixels pix; ofTexture tex; ofFbo fbo; ofVec2f crop_size; ofVec2f pos; float angle; private: bool flag_updated; bool flag_draw; };
Lidarを使った2D SLAM実装のためのお勉強
Atsushi SakaiさんのブログMyEnigmaで紹介されているmatlabのコードをいくつかc++(openFrameworks環境)に移植してみました。
myenigma.hatenablog.com
とても勉強になり大変に有難いです。移植の目的は、matlabに慣れたかったのと、現実的な実行速度を確認したかった為です。matlabはpythonよりc++寄りで移植しやすいですね。
1. ofxGridMapSample.h
2. ofxParticleFilterLocalization.h
3. ofxICPSample.h
main()関数やsetup(), update(), draw()の呼び出しは、openFrameworksのテンプレートから適当に作ってください。
また追加のaddonとしてofMatrix2x2をプロジェクトに加えてください。
GitHub - naokiring/ofMatrix2x2: 2x2 matrix class for openFrameworks
Globally Optimalな点群位置合わせ手法の調査
2010年台ごろに入ってから、3次元点群位置合わせの手法として"Globally Optimal*1"な物の提案が増えてきました。理論はおいて置いて、どのくらい実用になるかをテストするために、実装が公開されているものを中心にリストにまとめておきたいと思います。
1. Go-ICP: A Globally Optimal Solution to 3D ICP Point-Set Registration
Jiaolong Yang, et. al. ICCV2013, PAMI
iitlab.bit.edu.cn
解説
2. Super4PCS: Fast Global Pointcloud Registration via Smart Indexing
Nicolas Mellado, Dror Aiger, Niloy J. Mitra CGF2014
SGP | UCL
github.com
つかってみた、試してみた解説
「 Super4PCS 」という点群結合のライブラリを試してみました - Natural Software
JVR ― 自腹でバーチャルリアリティ ― Super4PCS 速度面で実用的ではなさそう。
3. Fast Global Registration
Qian-Yi Zhou, Jaesik Park, Vladlen Koltun, ECCV2016
Fast Global Registration - Vladlen Koltun
github.com
入力が3次元点群+FPFHなどの3次元特徴量ベクトルなので、3次元特徴量の計算にも時間コストがかかることに留意。
速度的には、まだAlignment.exe(Indexed Imageを使った方法)で位置合わせした方が速そう。
読むべき論文多すぎて、サーベイがおっつかないよ。。。
*1:Globally Optimalの正しい和訳は知りませんが、端的な意訳は"初期位置あわせの要らない"だと思います。
初任給で買うと良いものの研究2017
初任給を貰ったら、まず親に御礼代わりのプレゼントを買うべきです。
が、自分で稼いだお金で自分の欲しいものを買うのも良いことです。
とくに、新生活が始まったばかりの人にとっては、今後の生活の潤いのためになるものを揃えておくのが良いでしょう。
というわけで、今自分が新社会人だったら何が欲しかったかなぁ、と考えてリストにまとめます。(仕事が手につかずに遊んでいる、ともいうが。。。)
物入りな時期でしょうから、予算は最大5万円をめどとします。
1. 大事なデータを保存しておくNAS
デジカメで撮りためた写真や書類など、日々溜まっていく重要なデータはほっておくと、すぐにどこかに行ってしまいなくして後悔します。
早めにデータの置き場所を決めて固めておいておく癖をつけておくとよいです。とくに、転勤などで引っ越しがあったときにも慌てずに済むので、オススメです。
HDDは時間が経つと壊れてしまうので、おすすめはミラーリングで良いのでRAID構成にしておくことです。
いろいろ調べた結果、性能値段比が一番いいのはQNAP TS-228のようです。
QNAP TS-228 専用OS QTS搭載 ARM デュアルコア1.1GHz CPU 1GBメモリ 2ベイ ホーム/SOHO向け プライベートクラウド機能対応 NAS 2年保証
- 出版社/メーカー: QNAP(キューナップ)
- 発売日: 2016/07/29
- メディア: Personal Computers
- この商品を含むブログを見る
東芝 MD04ACA400 4TB アマゾン限定モデル 2年保証 SATA 6Gbps対応3.5型内蔵ハードディスク
- 出版社/メーカー: 東芝
- 発売日: 2017/04/07
- メディア: Personal Computers
- この商品を含むブログを見る
2. 寝っ転がって本を読むタブレット端末
NASにデータを集める環境が作れたら、そのデータを簡単に閲覧する方法が欲しくなります。
PCがあればそれでも良いのですが、仕事で疲れているときには寝っ転がって写真を見たり本を読んだりしたくなります。
とくに仕事を始めると、眼の疲れを最小にすることの重要さにそのうち気が付きます。
タブレット端末は進化が早いので安いやつで良いのですが、ディスプレイの質の良いものがオススメです。
今選ぶなら、HuaweiのMedia T2 8.0 Proが2万未満で買えて、画面が奇麗でよいです。
Huawei 8インチ タブレット MediaPad T2 8.0 PRO ホワイト ※LTE,Wi-Fiモデル RAM 2GB/ROM 16GB【日本正規代理店品】
- 出版社/メーカー: Huawei
- 発売日: 2016/12/09
- メディア: Personal Computers
- この商品を含むブログを見る
3. 腰や肩を大事にするための敷布団マットレス
仕事中は自由に体を動かせず、毎日決まった姿勢をし続けなければならないような状況が起きてしまいます。
とくにPCを相手にする仕事の場合、腰に負担がかかります。
普通の布団では寝ていても腰に力が掛かってしまい、あまり疲れが取れないという状況が起きます。
良さげなマットレスが世の中にいっぱいありますが、お年寄向けのものも多く、ちょっと気が引けます。
その点、西川Airはオシャレです。価格の高いモデルもあり、更にかっこよいですが、エアー01で十分効果があります。
長年使っているうちに多少ヘタって来てしまいますので、標準体重ぐらいの男性はハード、女性はソフトが良いように思います。
東京西川 [エアー01] マットレス シングル ハード ネイビー
- 出版社/メーカー: AIR
- メディア: ホーム&キッチン
- クリック: 23回
- この商品を含むブログ (2件) を見る
東京西川 ラップシーツ シングル エアー マットレス専用 アウトラスト使用 ネイビー
- 出版社/メーカー: AIR
- メディア: ホーム&キッチン
- この商品を含むブログを見る
4. 首を大事にするための良い枕
首は、腰と同じように負担がかかります。
自分の体に合った枕を選ぶのが一番良いですが、西川Airのマットレスを買ったら、同じシリーズの枕で揃えるのも良いですね。
中のマットを抜くと高さを調整することができます。
東京西川 枕 [エアー3D] コンディショニングピロー 高め タフ ネイビー
- 出版社/メーカー: AIR
- メディア: ホーム&キッチン
- この商品を含むブログを見る
東京西川 枕カバー wrap ストレッチ素材 抗菌防臭 ダークブルー
- 出版社/メーカー: 西川産業
- メディア: ホーム&キッチン
- この商品を含むブログを見る
5. 快適な睡眠のためのゴアテックス羽毛掛け布団
敷布団は、西川Airがとても良いのですが、合わせる掛け布団に悩みます。
温かくて、軽くて、水分調整ができて、虫がわきにくい、そんな都合が良い羽毛掛け布団が西川にあります。
西川リビング シングル ゴアテックス 羽毛掛け布団(日本製) (ブルー色)
- 出版社/メーカー: 西川リビング
- メディア:
- この商品を含むブログを見る
掛け布団カバーは、デザイン重視でお好きなものを。
西川 リビング 掛けふとん カバー 150×210cm ON15 シングル ベージュ 2138-15137
- 出版社/メーカー: 西川リビング
- 発売日: 2013/03/14
- メディア: ホーム&キッチン
- この商品を含むブログを見る
結局、ほとんど睡眠用品になってしまいましたが、社会人にはそれだけ睡眠の質が重要だということ。
Emlid Navio2で動かすardupilotにxwindowを入れる
要らないものもあるかもしれないけれど、とりあえず起動するのでOK。
sudo apt-get update
sudo apt-get install lxde
sudo apt-get install lightdm
sudo apt-get install xinit
sudo apt-get install xutils
sudo apt-get install xserver-xorg
startxでLXDEというデスクトップが立ち上がります。
lxdeは古いので、新しいPIXELを使いたい、という場合はこちら。
sudo apt-get install raspberrypi-ui-mods
sudo apt-get install firefox-esr
単にxwindowを入れた状態ではlibEGLの設定がおかしな状態になっていて、openFrameworksやQtが立ち上がらないという問題があります。
[1]のサイトを参考に、libEGLのライブラリへのリンクを張りなおすと立ち上がるようになります。
raspi-configでGL DriverをLegacyに設定するのを忘れずに。
# sudo ln -fs /opt/vc/lib/libEGL.so /usr/lib/arm-linux-gnueabihf/libEGL.so
# sudo ln -fs /opt/vc/lib/libGLESv2.so /usr/lib/arm-linux-gnueabihf/libGLESv2.so
# sudo ldconfig
[1] raspbian - Qt applications don't work due to libEGL - Raspberry Pi Stack Exchange
掃除機の買い方の研究
掃除機は、多くの人には数年に一度しか買い替える機会がないものかと思います。
急に掃除機が欲しくなるというよりも、そろそろ買い替えたいなー、という気分になったときしばらく時間をかけて検討して買い替えするかと思います。
ということは、時々安くなるセールを狙って買えるということです!定期的に安くなるモデルを見つけたので、紹介します。
何を買うか
ダイソンのハンディのバッテリー駆動モデルと、ロボット掃除機のルンバを狙います。
ビックカメラの量販店モデル
ダイソンDC74 MH EX:
ダイソン 【国内正規品】 コードレスクリーナー 「Dyson V6 cord-free」 DC74 MH EX 【ビックカメラグループオリジナル】
- 出版社/メーカー: ダイソン
- メディア: エレクトロニクス
- この商品を含むブログを見る
iRobot ルンバ ロボット掃除機 631 【国内正規品】
- 出版社/メーカー: iRobot ルンバ
- メディア:
- この商品を含むブログを見る
ジャパネットたかたの量販店モデル
ルンバ626:
iRobot Roomba 自動掃除機 ルンバ626 ホワイト R626060 [ジャパネットオリジナルモデル]
- 出版社/メーカー: iRobot(アイロボット)
- メディア:
- この商品を含むブログを見る
どこで買うか
ビックカメラ・コジマか、ジャパネットたかたをチェックします。
店頭でもネットでも価格は同じでしたが、ポイントの付き方が違います。
アマゾンポイントが安く買えて使えるときは、アマゾンがお得かと思います。
いつ買うか
ジャパネットたかたのセールの日に、ビックカメラがえげつなくセールをぶつけてくることが多いので
半期に一度ぐらいのジャパネットたかたのセールをテレビで見かけたら、ビックカメラのセール品をチェックします。
いくらで買うか
半年に一度ぐらい、どちらも\29800で販売されることがあります。
去年の実績は10月ごろと3月ごろに、それぞれ一日だけその価格で販売されていました。
LAUNCHXL-F28069MとBOOSTXL-DRV8305EVMでSCIを使うとき、問題を避けるためにADCの割り込み優先順位を上げる方法
TiのC2000Piccoloの割り込みは、独自のPIEテーブルとかいうものに基づいたもので、とても分かりにくく使いにくいです。
C2000シリーズではPIEテーブルの順序の変更も容易ではなく(掲示板にはデキナイ、との書き込みも)、さらにその定義も小首を傾げたくなるような順序に並んでいます。
InstaSPINモータドライバを使うとき、ADCがフル稼働しているのですが、標準だとこの優先順位がSCI(UART)よりも低く設定されているため、SCI割り込みが入るとモータが動かせないという謎仕様です。
ただし、これは問題を知っていれば簡単に回避できます。
参考資料
このスレッドなどを参考に。
level interrupts in motorware_12 - InstaSPIN Motor Solutions Forum - C2000™ Microcontrollers - TI E2E Community
割り込みトリガーをADC_IntNumber_1からADC_IntNumber_1HP(High Priority)に変更
なぜか、同じADCに優先順位の設定が2つ割り当てられていて、10番(標準)と1番(優先)です。
デフォルトで10番に割り当てられているものを1番のPIEで駆動されるように変更します。
hal.c
void HAL_enableAdcInts(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; // enable the PIE interrupts associated with the ADC interrupts PIE_enableAdcInt(obj->pieHandle,ADC_IntNumber_1HP); // ADC_IntNumber_1 to ADC_IntNumber_1HP // enable the ADC interrupts ADC_enableInt(obj->adcHandle,ADC_IntNumber_1); // enable the cpu interrupt for ADC interrupts CPU_enableInt(obj->cpuHandle,CPU_IntNumber_1); // CPU_IntNumber_10 to CPU_IntNumber_1 return; } // end of HAL_enableAdcInts() function
hal.h
static inline void HAL_initIntVectorTable(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle; PIE_Obj *pie = (PIE_Obj *)obj->pieHandle; ENABLE_PROTECTED_REGISTER_WRITE_MODE; pie->ADCINT1_HP = &mainISR; // pie->ADCINT1 to pie->ADCINT1_HP //pie->SCIRXINTA = &sciarxISR; DISABLE_PROTECTED_REGISTER_WRITE_MODE; return; } // end of HAL_initIntVectorTable() function
hal.h
static inline void HAL_acqAdcInt(HAL_Handle handle,const ADC_IntNumber_e intNumber) { HAL_Obj *obj = (HAL_Obj *)handle; // clear the ADC interrupt flag ADC_clearIntFlag(obj->adcHandle,intNumber); // Acknowledge interrupt from PIE group 1 PIE_clearInt(obj->pieHandle,PIE_GroupNumber_1); // PIE_GroupNumber_10 to PIE_GroupNumber_1 return; } // end of HAL_acqAdcInt() function
これでも、SCITX割り込みがうまく動かない。なんでた”~。