ESP  0.1
The Example-based Sensor Predictions (ESP) system tries to bring machine learning to the maker community.
ofApp.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <cstdint>
4 #include <thread>
5 
6 // of System
7 #include "ofMain.h"
8 #include "ofxDatGui.h"
9 #include "ofxGrt.h"
11 
12 // custom
13 #include "calibrator.h"
14 #include "iostream.h"
15 #include "plotter.h"
16 #include "training.h"
17 #include "training-data-manager.h"
18 #include "tuneable.h"
19 
20 #define ESP_EVENT(s) \
21  ofLogVerbose() << "[" << ofGetTimestampString() << "] " << (s)
22 
23 class ofApp : public ofBaseApp, public GRT::Observer<GRT::ErrorLogMessage> {
24  public:
25  ofApp();
26  void setup() final;
27  void update() final;
28  void draw() final;
29  void exit() final;
30 
31  void keyPressed(int key) final;
32  void keyReleased(int key) final;
33  void mouseMoved(int x, int y ) final;
34  void mouseDragged(int x, int y, int button) final;
35  void mousePressed(int x, int y, int button) final;
36  void mouseReleased(int x, int y, int button) final;
37  void mouseEntered(int x, int y) final;
38  void mouseExited(int x, int y) final;
39  void windowResized(int w, int h) final;
40  void dragEvent(ofDragInfo dragInfo) final;
41  void gotMessage(ofMessage msg) final;
42 
44  tuneable_parameters_.push_back(t);
45  }
46 
47  void reloadPipelineModules();
48 
49  // GRT error log observer callback: we simply display it as status text.
50  virtual void notify(const ErrorLogMessage& data) final {
51  status_text_ = data.getMessage();
52  }
53 
54  void setBufferSize(uint32_t buffer_size) {
55  buffer_size_ = buffer_size;
56  }
57 
58  private:
59  enum class AppState {
60  kCalibration,
61  kPipeline,
62  kTraining,
63  kTrainingRenaming,
64  kTrainingHistoryRecording,
65  kTrainingRelabelling,
66  kAnalysis,
67  kPrediction,
68  kConfiguration,
69  };
70  AppState state_;
71  AppState last_state_;
72 
73  string getAppStateInstruction() const;
74 
75  enum Fragment {
76  CALIBRATION,
77  PIPELINE,
78  TRAINING,
79  ANALYSIS,
80  PREDICTION,
81  CONFIGURATION
82  };
83  Fragment fragment_;
84 
85  inline Fragment getAppView(AppState state) {
86  switch (state) {
87  case AppState::kCalibration:
88  return CALIBRATION;
89  case AppState::kPipeline:
90  return PIPELINE;
91  case AppState::kTraining:
92  case AppState::kTrainingRenaming:
93  case AppState::kTrainingHistoryRecording:
94  case AppState::kTrainingRelabelling:
95  return TRAINING;
96  case AppState::kAnalysis:
97  return ANALYSIS;
98  case AppState::kPrediction:
99  return PREDICTION;
100  case AppState::kConfiguration:
101  return CONFIGURATION;
102  default:
103  // Should never be here.
104  assert(false);
105  }
106  }
107 
108  void drawInputs(uint32_t, uint32_t, uint32_t, uint32_t);
109  void drawLiveFeatures(uint32_t, uint32_t, uint32_t, uint32_t);
110 
111  void drawCalibration();
112  void drawLivePipeline();
113  void drawTrainingInfo();
114  void enableTrainingSampleGUI(bool);
115  void drawAnalysis();
116  void drawPrediction();
117 
119  void usePipeline(GRT::GestureRecognitionPipeline& pipeline);
120  void useIStream(InputStream& stream);
121  void useOStream(OStream& stream);
122  void useOStream(OStreamVector& stream);
124  void useTrainingDataAdvice(string advice);
125  void useLeaveOneOutScoring(bool enable) {
126  use_leave_one_out_scoring_ = enable;}
127 
128  friend void useCalibrator(Calibrator &calibrator);
129  friend void usePipeline(GRT::GestureRecognitionPipeline &pipeline);
130  friend void useInputStream(InputStream &stream);
131  friend void useOutputStream(OStream &stream);
132  friend void useOutputStream(OStreamVector &stream);
133  friend void useStream(IOStream &stream);
134  friend void useStream(IOStreamVector &stream);
135  friend void useTrainingSampleChecker(TrainingSampleChecker checker);
136  friend void useTrainingDataAdvice(string advice);
137  friend void useLeaveOneOutScoring(bool enable);
138  friend void setTruePositiveWarningThreshold(double threshold);
139  friend void setFalseNegativeWarningThreshold(double threshold);
140 
141  // This variable is a guard so that code can check its status and made to be
142  // executed only once. Because we are loading the user code ::setup()
143  // function multiple times during the execution, this may cause input- or
144  // output-streams initialized multiple times. This boolean variable is
145  // useful there.
146  bool setup_finished_ = false;
147 
148  // Currently, we support labels (stored in label_) from 1 to 9.
149  const uint32_t kNumMaxLabels_ = 9;
150  uint8_t label_;
151 
152  // kBufferSize_ controls the number of points in the plot. Note: This is not
153  // the buffer size used for training/prediction.
154  uint32_t buffer_size_ = 256;
155 
156  //========================================================================
157  // Pipeline, tuneables and all data
158  //========================================================================
159  GRT::GestureRecognitionPipeline *pipeline_;
160 
161  // The number of pipeline stages will control the UI layout. The number is
162  // obtained during setup() and used in draw().
163  uint32_t num_pipeline_stages_;
164 
165  // These two variables just track the number of pre-processing modules and
166  // feature extraction modules so that we can control what data to read for
167  // getLastStageProcessedData.
168  uint32_t num_preprocessing_modules_;
169  uint32_t num_feature_modules_;
170  vector<double> getLastStageProcessedData() const;
171 
172  vector<Tuneable*> tuneable_parameters_;
173  Calibrator* calibrator_;
174  TrainingDataManager training_data_manager_;
175  TrainingSampleChecker training_sample_checker_ = 0;
176 
177  GRT::MatrixDouble sample_data_;
178  GRT::MatrixDouble input_data_;
179  std::mutex input_data_mutex_; // input_data_ is written by istream_ thread
180  // and read by GUI thread.
181  GRT::MatrixDouble test_data_;
182 
183  //========================================================================
184  // Analysis
185  //========================================================================
186  float training_accuracy_;
187  int predicted_label_; CircularBuffer<int> predicted_label_buffer_;
188  vector<double> predicted_class_distances_;
189  CircularBuffer<vector<double>> predicted_class_distances_buffer_;
190 
191  vector<double> predicted_class_likelihoods_;
192  CircularBuffer<vector<double>> predicted_class_likelihoods_buffer_;
193 
194  vector<UINT> predicted_class_labels_;
195  CircularBuffer<vector<UINT>> predicted_class_labels_buffer_;
196 
197  vector<UINT> test_data_predicted_class_labels_;
198 
199  vector<double> class_distance_values_;
200  vector<double> class_likelihood_values_;
201 
202  //========================================================================
203  // Input/Output streams
204  //========================================================================
205  InputStream *istream_;
206  void onDataIn(GRT::MatrixDouble in);
207  vector<OStream *> ostreams_;
208  vector<OStreamVector *> ostreamvectors_;
209 
210  //========================================================================
211  // Application states
212  //========================================================================
213  bool is_recording_; // When button 1-9 is pressed, is_recording_ will be
214  // set and data will be added to sample_data_.
215  bool enable_history_recording_ = false;
216  bool is_in_feature_view_ = false;
217 
218  //========================================================================
219  // rename
220  //========================================================================
221  int rename_target_ = -1;
222  string rename_title_;
223  string display_title_; // Display title is rename_title_ plus a blinking
224  // underscore.
225 
226  //========================================================================
227  // relabel
228  //========================================================================
229  uint32_t relabel_source_;
230  string relabel_source_title_;
231 
232  //========================================================================
233  // visual: status message
234  //========================================================================
235  string status_text_;
236  void setStatus(const string& msg) {
237  ESP_EVENT(msg);
238  status_text_ = msg;
239  }
240 
241  ofxDatGui gui_;
242 
243  //========================================================================
244  // visual: input stream
245  //========================================================================
246  ofxDatGuiDropdown *serial_selection_dropdown_;
247  void onSerialSelectionDropdownEvent(ofxDatGuiDropdownEvent e);
248 
249  //========================================================================
250  // visual: live plots are across all tabs
251  //========================================================================
252  InteractiveTimeSeriesPlot plot_inputs_;
253  vector<ofxGrtTimeseriesPlot> plot_live_features_; // live features
254  ofxGrtTimeseriesPlot plot_inputs_snapshot_; // a spectrum of the most
255  // recent input vector, shown
256  // only if the number of input
257  // dimensions is greater than
258  // kTooManyFeaturesThreshold
259  void onInputPlotRangeSelection(InteractivePlot::RangeSelectedCallbackArgs);
260  void onInputPlotValueSelection(
262 
263  //========================================================================
264  // visual: calibration
265  //
266  // Raw input + plotter for each calibrators
267  //========================================================================
268  ofxGrtTimeseriesPlot plot_raw_;
269  vector<Plotter> plot_calibrators_;
270 
271  //========================================================================
272  // visual: pipeline
273  //
274  // live data (above) + pre_processed + features
275  //========================================================================
276  vector<ofxGrtTimeseriesPlot> plot_pre_processed_;
277  vector<vector<ofxGrtTimeseriesPlot>> plot_features_;
278 
279  //========================================================================
280  // visual: test
281  //
282  // live (above) + window + overview
283  //========================================================================
284  ofxGrtTimeseriesPlot plot_testdata_window_;
285  Plotter plot_testdata_overview_;
286  void onTestOverviewPlotSelection(InteractivePlot::RangeSelectedCallbackArgs);
287  void updateTestWindowPlot();
288  void runPredictionOnTestData();
289 
290  //========================================================================
291  // visual: training
292  //
293  // live + samples + features
294  //========================================================================
295  vector<Plotter> plot_samples_;
296  vector<Plotter> plot_samples_snapshots_;
297  vector<std::string> plot_samples_info_;
298  void onPlotRangeSelected(InteractivePlot::RangeSelectedCallbackArgs arg);
299  void updatePlotSamplesSnapshot(int num, int row = -1);
300  void onPlotSamplesValueHighlight(InteractivePlot::ValueHighlightedCallbackArgs arg);
301 
302  bool is_final_features_too_many_ = false;
303  vector<vector<Plotter>> plot_sample_features_;
304  void toggleFeatureView();
305  void populateSampleFeatures(uint32_t sample_index);
306  vector<pair<double, double>> sample_feature_ranges_;
307 
308  vector<int> plot_sample_indices_; // the index of the currently plotted
309  // sample for each class label
310  vector<pair<ofRectangle, ofRectangle>> plot_sample_button_locations_;
311 
312  vector<ofxDatGui *> training_sample_guis_;
313  void renameTrainingSample(int num);
314  void renameTrainingSampleDone();
315  void deleteTrainingSample(int num);
316  void trimTrainingSample(int num);
317  void relabelTrainingSample(int num);
318  void deleteAllTrainingSamples(int num);
319  void doRelabelTrainingSample(uint32_t from, uint32_t to);
321 
322  //========================================================================
323  // theme
324  //========================================================================
325  void onBackgroundColorPickerEvent(ofxDatGuiColorPickerEvent e) {
326  background_color_ = e.color;
327 
328  // Also change every plot background
329  plot_inputs_.setBackgroundColor(background_color_);
330  for (auto& p : plot_live_features_) {
331  p.setBackgroundColor(background_color_);
332  }
333  plot_inputs_snapshot_.setBackgroundColor(background_color_);
334  plot_raw_.setBackgroundColor(background_color_);
335  for (auto& p : plot_calibrators_) {
336  p.setBackgroundColor(background_color_);
337  }
338  for (auto& p : plot_pre_processed_) {
339  p.setBackgroundColor(background_color_);
340  }
341  for (auto& ps : plot_features_) {
342  for (auto& p : ps) {
343  p.setBackgroundColor(background_color_);
344  }
345  }
346  plot_testdata_window_.setBackgroundColor(background_color_);
347  plot_testdata_overview_.setBackgroundColor(background_color_);
348 
349  for (auto& p : plot_samples_) {
350  p.setBackgroundColor(background_color_);
351  }
352  for (auto& p : plot_samples_snapshots_) {
353  p.setBackgroundColor(background_color_);
354  }
355  for (auto& ps : plot_sample_features_) {
356  for (auto& p : ps) {
357  p.setBackgroundColor(background_color_);
358  }
359  }
360  plot_class_likelihoods_.setBackgroundColor(background_color_);
361  for (auto& p : plot_class_distances_) {
362  p.setBackgroundColor(background_color_);
363  }
364  }
365  ofColor background_color_;
366 
367  void onTextColorPickerEvent(ofxDatGuiColorPickerEvent e) {
368  text_color_ = e.color;
369 
370  // Also change every plot text
371  plot_inputs_.setTextColor(text_color_);
372  for (auto& p : plot_live_features_) {
373  p.setTextColor(text_color_);
374  }
375  plot_inputs_snapshot_.setTextColor(text_color_);
376  plot_raw_.setTextColor(text_color_);
377  for (auto& p : plot_calibrators_) {
378  p.setTextColor(text_color_);
379  }
380  for (auto& p : plot_pre_processed_) {
381  p.setTextColor(text_color_);
382  }
383  for (auto& ps : plot_features_) {
384  for (auto& p : ps) {
385  p.setTextColor(text_color_);
386  }
387  }
388  plot_testdata_window_.setTextColor(text_color_);
389  plot_testdata_overview_.setTextColor(text_color_);
390 
391  for (auto& p : plot_samples_) {
392  p.setTextColor(text_color_);
393  }
394  for (auto& p : plot_samples_snapshots_) {
395  p.setTextColor(text_color_);
396  }
397  for (auto& ps : plot_sample_features_) {
398  for (auto& p : ps) {
399  p.setTextColor(text_color_);
400  }
401  }
402  plot_class_likelihoods_.setTextColor(text_color_);
403  for (auto& p : plot_class_distances_) {
404  p.setTextColor(text_color_);
405  }
406  }
407  ofColor text_color_;
408 
409  void onGridColorPickerEvent(ofxDatGuiColorPickerEvent e) {
410  ofColor grid_color(e.color.r, e.color.g, e.color.b, 0x20);
411 
412  // Also change every plot text
413  plot_inputs_.setGridColor(grid_color);
414  for (auto& p : plot_live_features_) {
415  p.setGridColor(grid_color);
416  }
417  plot_inputs_snapshot_.setGridColor(grid_color);
418  plot_raw_.setGridColor(grid_color);
419  for (auto& p : plot_calibrators_) {
420  p.setGridColor(grid_color);
421  }
422  for (auto& p : plot_pre_processed_) {
423  p.setGridColor(grid_color);
424  }
425  for (auto& ps : plot_features_) {
426  for (auto& p : ps) {
427  p.setGridColor(grid_color);
428  }
429  }
430  plot_testdata_window_.setGridColor(grid_color);
431  plot_testdata_overview_.setGridColor(grid_color);
432 
433  for (auto& p : plot_samples_) {
434  p.setGridColor(grid_color);
435  }
436  for (auto& p : plot_samples_snapshots_) {
437  p.setGridColor(grid_color);
438  }
439  for (auto& ps : plot_sample_features_) {
440  for (auto& p : ps) {
441  p.setGridColor(grid_color);
442  }
443  }
444  plot_class_likelihoods_.setGridColor(grid_color);
445  for (auto& p : plot_class_distances_) {
446  p.setGridColor(grid_color);
447  }
448  }
449 
450  void onLineWidthSliderEvent(ofxDatGuiSliderEvent e) {
451  ofSetLineWidth(e.value);
452  }
453 
454  //========================================================================
455  // visual: prediction
456  //
457  // live + likelihood + class_distances
458  //========================================================================
459  InteractiveTimeSeriesPlot plot_class_likelihoods_;
460  vector<InteractiveTimeSeriesPlot> plot_class_distances_;
461  void onClassLikelihoodsPlotValueHighlight(
463  void onClassDistancePlotValueHighlight(
465 
466  //==========================================================================
467  // Save and load functionalities
468  //==========================================================================
469  // Tuneable parameters
470  void saveTuneables(ofxDatGuiButtonEvent e);
471  void loadTuneables(ofxDatGuiButtonEvent e);
472  bool saveTuneablesWithPrompt();
473  bool saveTuneables(const string& filename);
474  bool loadTuneablesWithPrompt();
475  bool loadTuneables(const string& filename);
476  bool should_save_tuneables_;
477 
478  // Pipeline (including trained model)
479  bool savePipelineWithPrompt();
480  bool savePipeline(const string& filename);
481  bool loadPipelineWithPrompt();
482  bool loadPipeline(const string& filename);
483  bool should_save_pipeline_;
484 
485  // Calibration data
486  bool saveCalibrationDataWithPrompt();
487  bool saveCalibrationData(const string& filename);
488  bool loadCalibrationDataWithPrompt();
489  bool loadCalibrationData(const string& filename);
490  // Prompts to ask the user to save the calibration data if changed.
491  bool should_save_calibration_data_;
492 
493  bool saveTrainingDataWithPrompt();
494  bool saveTrainingData(const string& filename);
495  bool loadTrainingDataWithPrompt();
496  bool loadTrainingData(const string& filename);
497  // Prompts to ask the user to save the training data if changed.
498  bool should_save_training_data_;
499 
500  bool saveTestDataWithPrompt();
501  bool saveTestData(const string& filename);
502  bool loadTestDataWithPrompt();
503  bool loadTestData(const string& filename);
504  // Prompts to ask the user to save the test data if changed.
505  bool should_save_test_data_;
506 
507  // Convenient functions that save and load everything from a directory. This
508  // assumes the structure of the directory follows our naming convention (see
509  // the following few const string definitions). If the naming convention is
510  // not satisfied, the load will fail.
511  const string kPipelineFilename = "Pipeline.grt";
512  const string kCalibrationDataFilename = "CalibrationData.grt";
513  const string kTrainingDataFilename = "TrainingData.grt";
514  const string kTestDataFilename = "TestData.grt";
515  const string kTuneablesFilename = "TuneableParameters.grt";
516  string save_path_ = "";
517 
518  // Load all and save all
519  void loadAll();
520  void saveAll(bool saveAs = false);
521 
522  //========================================================================
523  // Training
524  //========================================================================
525  std::thread training_thread_;
526  bool is_training_scheduled_;
527  std::uint64_t schedule_time_;
528 
529  void beginTrainModel();
530  void trainModel();
531  void afterTrainModel();
532 
533  //========================================================================
534  // Scoring
535  //========================================================================
536  void scoreTrainingData(bool leaveOneOut);
537  void scoreImpactOfTrainingSample(int label, const MatrixDouble &sample);
538  bool use_leave_one_out_scoring_ = true;
539 
540  double true_positive_threshold_;
541  double false_negative_threshold_;
542 
543  //========================================================================
544  // Utils
545  //========================================================================
546  string getTrainingDataAdvice();
547  string training_data_advice_ = "";
548 
549  void updateEventReceived(ofEventArgs& arg); // For renaming
550  uint32_t update_counter_ = 0;
551  std::shared_ptr<ofConsoleFileLoggerChannel> logger_;
552 };
553 
555  public:
556  TrainingSampleGuiListener(ofApp *app, int num) : app(app), num(num) {}
557  void renameButtonPressed(ofxDatGuiButtonEvent e) {
558  app->renameTrainingSample(num);
559  }
560  void deleteButtonPressed(ofxDatGuiButtonEvent e) {
561  app->deleteTrainingSample(num);
562  }
563  void trimButtonPressed(ofxDatGuiButtonEvent e) {
564  app->trimTrainingSample(num);
565  }
566  void relabelButtonPressed(ofxDatGuiButtonEvent e) {
567  app->relabelTrainingSample(num);
568  }
569  void deleteAllButtonPressed(ofxDatGuiButtonEvent e) {
570  app->deleteAllTrainingSamples(num);
571  }
572  private:
573  ofApp *app;
574  int num;
575 };
Functions for specifying parameters that can be tuned by the user.
void setup() final
Definition: ofApp.cpp:159
double t
Definition: user_accelerometer_walk_detection.cpp:78
void useTrainingDataAdvice(string advice)
Provide the user with custom advice on collecting training data.
Definition: ofApp.cpp:2706
Definition: plotter.h:182
void gotMessage(ofMessage msg) final
Definition: ofApp.cpp:2611
void update() final
Definition: ofApp.cpp:1303
Definition: iostream.h:6
void trimButtonPressed(ofxDatGuiButtonEvent e)
Definition: ofApp.h:563
Calibrator calibrator
Definition: user_accelerometer_gestures.cpp:8
TrainingDataManager class that manages the training data and abstracts out common operations on the d...
TrainingSampleGuiListener(ofApp *app, int num)
Definition: ofApp.h:556
Definition: tuneable.h:21
void mouseDragged(int x, int y, int button) final
Definition: ofApp.cpp:2499
void mouseExited(int x, int y) final
Definition: ofApp.cpp:2602
Base class for output streams that forward ESP prediction results to other systems.
Definition: ostream.h:43
Specifies data samples and code used to calibrate incoming sensor data.
Definition: calibrator.h:121
void setBufferSize(uint32_t buffer_size)
Definition: ofApp.h:54
friend void setTruePositiveWarningThreshold(double threshold)
Only warn (highlight the confusion score) if the true positive rate is smaller than the threshold...
Definition: ofApp.cpp:2714
constexpr char kTrainingDataFilename[]
Definition: cli.cpp:13
Definition: ofApp.h:554
TrainingSampleCheckerResult(* TrainingSampleChecker)(const GRT::MatrixDouble &)
function that takes a constant reference to a GRT MatrixDouble and returns a TrainingSampleCheckerRes...
Definition: training.h:54
VectorDouble threshold(VectorDouble in)
Definition: user_accelerometer_walk_detection.cpp:79
void useTrainingSampleChecker(TrainingSampleChecker checker)
Register a function for checking training samples.
Definition: ofApp.cpp:2702
#define ESP_EVENT(s)
Definition: ofApp.h:20
TrainingDataManager class encloses GRT::TimeSeriesClassificationData and improves upon by adding util...
Definition: training-data-manager.h:38
ASCIISerialStream stream(115200, 3)
ofApp()
Definition: ofApp.cpp:141
void relabelButtonPressed(ofxDatGuiButtonEvent e)
Definition: ofApp.h:566
void exit() final
Definition: ofApp.cpp:2008
void dragEvent(ofDragInfo dragInfo) final
Definition: ofApp.cpp:2616
void windowResized(int w, int h) final
Definition: ofApp.cpp:2607
GestureRecognitionPipeline pipeline
Definition: user_accelerometer_gestures.cpp:7
Base class for output streams that forward ESP pipeline output to other systems.
Definition: ostream.h:60
void useLeaveOneOutScoring(bool enable=true)
Whether or not to do leave-one-out scoring of training data.
Definition: ofApp.cpp:2710
void setTextColor(ofColor color)
Definition: plotter.h:236
void useCalibrator(Calibrator &calibrator)
Definition: ofApp.cpp:2684
void keyReleased(int key) final
Definition: ofApp.cpp:2315
friend void useInputStream(InputStream &stream)
Definition: ofApp.cpp:2668
void deleteAllButtonPressed(ofxDatGuiButtonEvent e)
Definition: ofApp.h:569
Definition: iostream.h:7
constexpr char kPipelineFilename[]
Definition: cli.cpp:15
friend void setFalseNegativeWarningThreshold(double threshold)
Only warn (highlight the confusion score) if the false negative rate is larger than the threshold...
Definition: ofApp.cpp:2718
Definition: plotter.h:269
constexpr char kTestDataFilename[]
Definition: cli.cpp:14
Definition: ofApp.h:23
void usePipeline(GRT::GestureRecognitionPipeline &pipeline)
Definition: ofApp.cpp:2680
Base class for input streams that provide live sensor data to the ESP system. To use an InputStream i...
Definition: istream.h:31
friend void useOutputStream(OStream &stream)
Specify an OStream to which to stream predictions made by the active ESP pipeline. Multiple output streams are supported.
Definition: ofApp.cpp:2672
void mousePressed(int x, int y, int button) final
Definition: ofApp.cpp:2504
void mouseEntered(int x, int y) final
Definition: ofApp.cpp:2597
virtual void notify(const ErrorLogMessage &data) final
Definition: ofApp.h:50
void setGridColor(ofColor color)
Definition: plotter.h:240
void deleteButtonPressed(ofxDatGuiButtonEvent e)
Definition: ofApp.h:560
friend void useStream(IOStream &stream)
Definition: ofApp.cpp:2692
void mouseMoved(int x, int y) final
Definition: ofApp.cpp:2494
void registerTuneable(Tuneable *t)
Definition: ofApp.h:43
void setBackgroundColor(ofColor color)
Definition: plotter.h:232
void keyPressed(int key) final
Definition: ofApp.cpp:2204
void draw() final
Definition: ofApp.cpp:1553
void mouseReleased(int x, int y, int button) final
Definition: ofApp.cpp:2509
void renameButtonPressed(ofxDatGuiButtonEvent e)
Definition: ofApp.h:557
void reloadPipelineModules()
Definition: ofApp.cpp:2198