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; };