[work 34] Fourier Transform
Movie
Source code
about
- フーリエ変換して線を波形の合成で表す
- 参考(https://thecodingtrain.com/CodingChallenges/125-fourier-series.html)
- マウスで絵を描く
- 線の座標を取得する
- フーリエ変換を行う
- 波形の合成で1で描いた絵を再描画する
file
- 上部にあるファイル名が表示されているボタンを押すと、表示されるファイルが切り替わります
- 別ウィンドウ表示したい時や行番号などが無いRawMode表示したい時は、コード内右上のボタンを押してください(ボタンはマウスオーバーすると表示されます)
#include "ofMain.h" #include "ofApp.h" //================================ int main( ){ // 4K:4096x2160 // 2K:2048x1080 // FullHD:1920x1080 // HD:1440x1080 // HD720p:1280x720 // DVD:720x480 // setup the GL context ofSetupOpenGL(1280,720, OF_WINDOW); // this kicks off the running of my app // can be OF_WINDOW or OF_FULLSCREEN // pass in width and height too: ofRunApp( new ofApp()); }
#pragma once #include "ofMain.h" #include "Fourier.hpp" class ofApp : public ofBaseApp{ public: ofApp(); ~ofApp(); 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); private: std::vector<float> pointsX; std::vector<float> pointsY; unique_ptr<FourierTransform> ftX; unique_ptr<FourierTransform> ftY; std::vector<ofVec2f> traces; std::vector<ofVec2f> org; // mouse dragged points bool traceStart; };
#include "ofApp.h" ofApp::ofApp(){ } ofApp::~ofApp(){ } //-------------------------------------------------------------- void ofApp::setup(){ double fps = 30; ofSetFrameRate(fps); ofBackground(0); ofSetBackgroundAuto(true); ofSetVerticalSync(true); traceStart = false; } //-------------------------------------------------------------- void ofApp::update(){ if (traceStart) { ftX->update(); ftY->update(); if (ftX->isLoop()) { traces.clear(); } else { traces.push_back(ofVec2f(ftX->getLocation().x, ftY->getLocation().y)); } } } //-------------------------------------------------------------- void ofApp::draw(){ if (traceStart) { ftX->display(); ftY->display(); ofPushMatrix(); ofNoFill(); ofSetLineWidth(5); ofSetColor(255); ofBeginShape(); for (auto itr = traces.begin(); itr != traces.end(); ++itr) { ofVertex(*itr); } ofEndShape(); ofPopMatrix(); ofNoFill(); ofSetLineWidth(1); ofSetColor(255); ofDrawLine(ftX->getLocation().x, ftX->getLocation().y, traces.back().x, traces.back().y); ofNoFill(); ofSetLineWidth(1); ofSetColor(255); ofDrawLine(ftY->getLocation().x, ftY->getLocation().y, traces.back().x, traces.back().y); } else { ofPushMatrix(); ofNoFill(); ofSetLineWidth(5); ofSetColor(255); ofBeginShape(); for (auto itr = org.begin(); itr != org.end(); ++itr) { ofVertex(*itr); } ofEndShape(); ofPopMatrix(); } } //-------------------------------------------------------------- void ofApp::keyPressed(int key){ if (key == 's') { ofImage img; img.grabScreen(0, 0, ofGetWidth(), ofGetHeight()); img.save("screenshot.png"); } else if (key == 'c') { org.clear(); pointsX.clear(); pointsY.clear(); traces.clear(); traceStart = false; } } //-------------------------------------------------------------- void ofApp::keyReleased(int key){ } //-------------------------------------------------------------- void ofApp::mouseMoved(int x, int y){ } //-------------------------------------------------------------- void ofApp::mouseDragged(int x, int y, int button){ traceStart = false; org.push_back(ofVec2f(x, y)); pointsX.push_back(x - ofGetWidth() / 2); pointsY.push_back(y - ofGetHeight() / 2); } //-------------------------------------------------------------- void ofApp::mousePressed(int x, int y, int button){ } //-------------------------------------------------------------- void ofApp::mouseReleased(int x, int y, int button){ ftX = make_unique<FourierTransform>(pointsX); ftX->setup(); ftX->setPosition(ofVec2f(ofGetWidth() / 2, 100)); ftX->setRotation(0); ftY = make_unique<FourierTransform>(pointsY); ftY->setup(); ftY->setPosition(ofVec2f(100, ofGetHeight() / 2)); ftY->setRotation(PI / 2); traceStart = true; } //-------------------------------------------------------------- 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){ }
#ifndef Fourier_hpp #define Fourier_hpp #include <stdio.h> #include "ofMain.h" struct ComplexPlane { double re; // real double im; // imaginary int freq; // frequency double amp; // amplitude double phase; // phase(radian) bool operator< (const ComplexPlane &cp) const { return amp < cp.amp; }; bool operator> (const ComplexPlane &cp) const { return amp > cp.amp; }; }; class FourierTransform { public: FourierTransform(std::vector<float> p); ~FourierTransform(); void setup(); void update(); void display(); ofVec2f getLocation(); void setPosition(ofVec2f p); void setRotation(float r); bool isLoop(); private: void dft(); // discrete Fourier transform void epiCycles(); std::vector<float> points; // Input std::vector<ComplexPlane> cps; // complex plane settings std::vector<ofVec2f> locations; // Output ofVec2f position; // center of epicycle float rotation; // direction of epicycle double time; // differentiation bool loop; }; #endif /* Fourier_hpp */
#include "Fourier.hpp" FourierTransform::FourierTransform(std::vector<float> p) { points = p; time = 0; position = ofVec2f(0, 0); rotation = 0; loop = false; } FourierTransform::~FourierTransform() { } void FourierTransform::setup() { dft(); } void FourierTransform::update() { epiCycles(); } void FourierTransform::display() { ofPushMatrix(); ofFill(); ofSetLineWidth(1); ofSetColor(255); ofDrawCircle(locations[0], 2); for (int i = 0; i < locations.size() - 1; i++) { ofNoFill(); ofSetLineWidth(1); ofDrawLine(locations[i], locations[i+1]); ofDrawCircle(locations[i+1], 2); ofNoFill(); ofSetLineWidth(1); ofSetColor(ofColor(255), 100); ofDrawCircle(locations[i].x, locations[i].y, (locations[i+1]-locations[i]).length()); } ofPopMatrix(); } ofVec2f FourierTransform::getLocation() { return locations.back(); } void FourierTransform::setPosition(ofVec2f p) { position = p; } void FourierTransform::setRotation(float r) { rotation = r; } bool FourierTransform::isLoop() { return loop; } void FourierTransform::dft() { ComplexPlane cp; int n_max = points.size(); for (int n = 0; n < n_max; n++) { double re = 0; double im = 0; for (int k = 0; k < n_max; k++) { float theta = float(TWO_PI * k * n) / (float)n_max; re += points[k] * std::cos(theta); im -= points[k] * std::sin(theta); } re = re / n_max; im = im / n_max; cp.re = re; cp.im = im; cp.freq = n; cp.amp = std::sqrt(cp.re * cp.re + cp.im * cp.im); cp.phase = std::atan2(im, re); cps.push_back(cp); } std::sort(cps.begin(), cps.end(), std::greater<ComplexPlane>()); } void FourierTransform::epiCycles() { ofVec2f p = position; locations.clear(); locations.push_back(p); for (int i = 0; i < cps.size(); i++) { int freq = cps[i].freq; double radius = cps[i].amp; double phase = cps[i].phase; p.x += radius * std::cos(freq * time + phase + rotation); p.y += radius * std::sin(freq * time + phase + rotation); locations.push_back(p); } double dt = TWO_PI / cps.size(); time += dt; if (time > (double)TWO_PI) { time = 0; loop = true; } else { loop = false; } }
Link to the reference page
ソースコードで使用したAPIの中から要点になりそうなものをいくつか選んでリストアップしました。
category | API/Lib |
c++ | std::vector |
c++ | std::sort |
Development environment
- openframeworks 0.10.1
- c++
- macOS
- Xcode