test_profile.cpp
Go to the documentation of this file.
1 /*
2  * OpenVINS: An Open Platform for Visual-Inertial Research
3  * Copyright (C) 2018-2023 Patrick Geneva
4  * Copyright (C) 2018-2023 Guoquan Huang
5  * Copyright (C) 2018-2023 OpenVINS Contributors
6  * Copyright (C) 2018-2019 Kevin Eckenhoff
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include <cmath>
23 #include <sstream>
24 #include <unistd.h>
25 #include <vector>
26 
27 #include <Eigen/Dense>
28 
29 #include <opencv2/core/core.hpp>
30 #include <opencv2/opencv.hpp>
31 
32 #include <boost/date_time/posix_time/posix_time.hpp>
33 
34 #include "utils/print.h"
35 
36 // Define the function to be called when ctrl-c (SIGINT) is sent to process
37 void signal_callback_handler(int signum) { std::exit(signum); }
38 
39 void print_stats(std::string title, std::vector<double> times, std::string title2 = "", std::vector<int> stats = {}) {
40 
41  // Compute mean and rmse
42  double mean = 0.0;
43  double rmse = 0.0;
44  for (size_t i = 0; i < times.size(); i++) {
45  assert(!std::isnan(times.at(i)));
46  mean += times.at(i);
47  rmse += times.at(i) * times.at(i);
48  }
49  mean /= times.size();
50  rmse = std::sqrt(rmse / times.size());
51 
52  // Using mean, compute standard deviation
53  double std = 0;
54  for (size_t i = 0; i < times.size(); i++) {
55  std += std::pow(times.at(i) - mean, 2);
56  }
57  std = std::sqrt(std / (times.size() - 1));
58 
59  // Print!
60  if (stats.empty()) {
61  PRINT_INFO("%s: %.3f +- %.3fms\n", title.c_str(), mean, std);
62  } else {
63  double mean2 = 0.0;
64  for (size_t i = 0; i < stats.size(); i++) {
65  assert(!std::isnan(stats.at(i)));
66  mean2 += stats.at(i);
67  }
68  mean2 /= stats.size();
69  PRINT_INFO("%s: %.3f +- %.3f ms (%.2f avg %s)\n", title.c_str(), mean, std, mean2, title2.c_str());
70  }
71 }
72 
73 // Main function
74 int main(int argc, char **argv) {
75 
76  // Verbosity
77  std::string verbosity = "INFO";
79 
80  // Parameters used in all algorithms
81  int num_trials = 100;
82  int big_matrix = 1000;
83  int big_matrix_eigen1 = 300;
84  int big_matrix_eigen2 = 900;
85  int pyr_levels = 5;
86  int fast_threshold = 30;
87  int max_features = 500;
88  cv::Size win_size = cv::Size(15, 15);
89  cv::TermCriteria term_crit = cv::TermCriteria(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 30, 0.01);
90 
91  // Helper data structures
92  cv::Mat img1(big_matrix, big_matrix, CV_8UC1);
93  cv::Mat img3(big_matrix, big_matrix, CV_8UC3);
94  std::vector<double> times_ms;
95  std::vector<int> extra_stats;
96 
97  // OPENCV: RANDOM BIG IMAGE
98  times_ms.clear();
99  for (int i = 0; i < num_trials; i++) {
100  auto rT1 = boost::posix_time::microsec_clock::local_time();
101  cv::randu(img3, cv::Scalar(0, 0, 0), cv::Scalar(255, 255, 255));
102  auto rT2 = boost::posix_time::microsec_clock::local_time();
103  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
104  }
105  print_stats("OPENCV: RANDOM BIG IMAGE", times_ms);
106 
107  // OPENCV: HISTOGRAM EQUALIZATION
108  times_ms.clear();
109  for (int i = 0; i < num_trials; i++) {
110  cv::randu(img1, cv::Scalar(0), cv::Scalar(255));
111  auto rT1 = boost::posix_time::microsec_clock::local_time();
112  cv::equalizeHist(img1, img1);
113  auto rT2 = boost::posix_time::microsec_clock::local_time();
114  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
115  }
116  print_stats("OPENCV: HISTOGRAM EQUALIZATION", times_ms);
117 
118  // OPENCV: BUILD OPTICAL FLOW PYRAMID
119  times_ms.clear();
120  for (int i = 0; i < num_trials; i++) {
121  cv::randu(img1, cv::Scalar(0), cv::Scalar(255));
122  auto rT1 = boost::posix_time::microsec_clock::local_time();
123  std::vector<cv::Mat> imgpyr;
124  cv::buildOpticalFlowPyramid(img1, imgpyr, win_size, pyr_levels);
125  auto rT2 = boost::posix_time::microsec_clock::local_time();
126  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
127  }
128  print_stats("OPENCV: BUILD OPTICAL FLOW PYRAMID", times_ms);
129 
130  // OPENCV: FAST FEATURE EXTRACTION
131  times_ms.clear();
132  extra_stats.clear();
133  for (int i = 0; i < num_trials; i++) {
134  cv::randu(img1, cv::Scalar(0), cv::Scalar(255));
135  auto rT1 = boost::posix_time::microsec_clock::local_time();
136  std::vector<cv::KeyPoint> pts_new;
137  cv::FAST(img1, pts_new, fast_threshold, true);
138  auto rT2 = boost::posix_time::microsec_clock::local_time();
139  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
140  extra_stats.push_back((int)pts_new.size());
141  }
142  print_stats("OPENCV: FAST FEATURE EXTRACTION", times_ms, "feats", extra_stats);
143 
144  // OPENCV: KLT OPTICAL FLOW
145  times_ms.clear();
146  extra_stats.clear();
147  for (int i = 0; i < num_trials; i++) {
148  std::vector<cv::Mat> imgpyr1, imgpyr2;
149  cv::buildOpticalFlowPyramid(img1, imgpyr1, win_size, pyr_levels);
150  std::vector<cv::KeyPoint> pts0_tmp;
151  cv::FAST(img1, pts0_tmp, fast_threshold, true);
152  std::sort(pts0_tmp.begin(), pts0_tmp.end(), [](cv::KeyPoint first, cv::KeyPoint second) { return first.response > second.response; });
153  std::vector<cv::Point2f> pts0;
154  for (size_t j = 0; j < pts0_tmp.size() && (int)j < max_features; j++)
155  pts0.push_back(pts0_tmp.at(j).pt);
156  cv::randu(img1, cv::Scalar(0), cv::Scalar(255)); // second image
157  cv::buildOpticalFlowPyramid(img1, imgpyr2, win_size, pyr_levels);
158  auto rT1 = boost::posix_time::microsec_clock::local_time();
159  std::vector<uchar> mask_klt;
160  std::vector<float> error;
161  std::vector<cv::Point2f> pts1, pts1_good;
162  cv::calcOpticalFlowPyrLK(imgpyr1, imgpyr2, pts0, pts1, mask_klt, error, win_size, pyr_levels, term_crit);
163  for (size_t j = 0; j < mask_klt.size(); j++) {
164  if (mask_klt.at(j))
165  pts1_good.push_back(pts1.at(j));
166  }
167  auto rT2 = boost::posix_time::microsec_clock::local_time();
168  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
169  extra_stats.push_back((int)pts1_good.size());
170  }
171  print_stats("OPENCV: KLT OPTICAL FLOW", times_ms, "feats", extra_stats);
172 
173  //=====================================================================================
174  //=====================================================================================
175  //=====================================================================================
176 
177  // EIGEN3(double): RANDOM BIG MATRIX
178  times_ms.clear();
179  for (int i = 0; i < num_trials; i++) {
180  auto rT1 = boost::posix_time::microsec_clock::local_time();
181  Eigen::MatrixXd mat1 = Eigen::MatrixXd::Random(big_matrix_eigen1, big_matrix_eigen1);
182  Eigen::MatrixXd mat2 = Eigen::MatrixXd::Random(big_matrix_eigen1, big_matrix_eigen1);
183  auto rT2 = boost::posix_time::microsec_clock::local_time();
184  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
185  }
186  print_stats("EIGEN3(double): RANDOM BIG MATRIX", times_ms);
187 
188  // EIGEN3(double): MATRIX MULTIPLY
189  times_ms.clear();
190  for (int i = 0; i < num_trials; i++) {
191  Eigen::MatrixXd mat1 = Eigen::MatrixXd::Random(big_matrix_eigen1, big_matrix_eigen1);
192  Eigen::MatrixXd mat2 = Eigen::MatrixXd::Random(big_matrix_eigen1, big_matrix_eigen1);
193  auto rT1 = boost::posix_time::microsec_clock::local_time();
194  Eigen::MatrixXd mat3 = mat1 * mat2;
195  auto rT2 = boost::posix_time::microsec_clock::local_time();
196  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
197  }
198  print_stats("EIGEN3(double): MATRIX MULTIPLY", times_ms);
199 
200  // EIGEN3(double): MATRIX INVERSION
201  times_ms.clear();
202  for (int i = 0; i < num_trials; i++) {
203  Eigen::MatrixXd mat1 = Eigen::MatrixXd::Random(big_matrix_eigen1, big_matrix_eigen1);
204  auto rT1 = boost::posix_time::microsec_clock::local_time();
205  mat1 = mat1.inverse();
206  auto rT2 = boost::posix_time::microsec_clock::local_time();
207  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
208  }
209  print_stats("EIGEN3(double): MATRIX INVERSION", times_ms);
210 
211  // EIGEN3(double): HOUSEHOLDER QR FULL
212  times_ms.clear();
213  for (int i = 0; i < num_trials; i++) {
214  Eigen::MatrixXd mat1 = Eigen::MatrixXd::Random(big_matrix_eigen2, big_matrix_eigen1);
215  auto rT1 = boost::posix_time::microsec_clock::local_time();
216  Eigen::MatrixXd QR = mat1.householderQr().matrixQR();
217  auto rT2 = boost::posix_time::microsec_clock::local_time();
218  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
219  }
220  print_stats("EIGEN3(double): HOUSEHOLDER QR FULL", times_ms);
221 
222  // EIGEN3(double): HOUSEHOLDER QR PIV
223  times_ms.clear();
224  for (int i = 0; i < num_trials; i++) {
225  Eigen::MatrixXd mat1 = Eigen::MatrixXd::Random(big_matrix_eigen2, big_matrix_eigen1);
226  auto rT1 = boost::posix_time::microsec_clock::local_time();
227  Eigen::MatrixXd R = mat1.colPivHouseholderQr().matrixR();
228  auto rT2 = boost::posix_time::microsec_clock::local_time();
229  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
230  }
231  print_stats("EIGEN3(double): HOUSEHOLDER QR PIV", times_ms);
232 
233  // EIGEN3(double): HOUSEHOLDER QR CUSTOM
234  times_ms.clear();
235  for (int i = 0; i < num_trials; i++) {
236  Eigen::MatrixXd mat1 = Eigen::MatrixXd::Random(big_matrix_eigen2, big_matrix_eigen1);
237  Eigen::VectorXd tempV1 = Eigen::VectorXd::Zero(big_matrix_eigen2 * big_matrix_eigen1, 1);
238  Eigen::VectorXd tempV2;
239  auto rT1 = boost::posix_time::microsec_clock::local_time();
240  for (int k = 0; k < mat1.cols(); k++) {
241  int rows_left = mat1.rows() - k;
242  double beta, tau;
243  mat1.col(k).segment(k, rows_left).makeHouseholder(tempV2, tau, beta);
244  mat1.block(k, k, rows_left, mat1.cols() - k).applyHouseholderOnTheLeft(tempV2, tau, tempV1.data());
245  }
246  auto rT2 = boost::posix_time::microsec_clock::local_time();
247  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
248  }
249  print_stats("EIGEN3(double): HOUSEHOLDER QR CUSTOM", times_ms);
250 
251  //=====================================================================================
252  //=====================================================================================
253  //=====================================================================================
254 
255  // EIGEN3(float): RANDOM BIG MATRIX
256  times_ms.clear();
257  for (int i = 0; i < num_trials; i++) {
258  auto rT1 = boost::posix_time::microsec_clock::local_time();
259  Eigen::MatrixXf mat1 = Eigen::MatrixXf::Random(big_matrix_eigen1, big_matrix_eigen1);
260  Eigen::MatrixXf mat2 = Eigen::MatrixXf::Random(big_matrix_eigen1, big_matrix_eigen1);
261  auto rT2 = boost::posix_time::microsec_clock::local_time();
262  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
263  }
264  print_stats("EIGEN3(float): RANDOM BIG MATRIX", times_ms);
265 
266  // EIGEN3(float): MATRIX MULTIPLY
267  times_ms.clear();
268  for (int i = 0; i < num_trials; i++) {
269  Eigen::MatrixXf mat1 = Eigen::MatrixXf::Random(big_matrix_eigen1, big_matrix_eigen1);
270  Eigen::MatrixXf mat2 = Eigen::MatrixXf::Random(big_matrix_eigen1, big_matrix_eigen1);
271  auto rT1 = boost::posix_time::microsec_clock::local_time();
272  Eigen::MatrixXf mat3 = mat1 * mat2;
273  auto rT2 = boost::posix_time::microsec_clock::local_time();
274  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
275  }
276  print_stats("EIGEN3(float): MATRIX MULTIPLY", times_ms);
277 
278  // EIGEN3(float): MATRIX INVERSION
279  times_ms.clear();
280  for (int i = 0; i < num_trials; i++) {
281  Eigen::MatrixXf mat1 = Eigen::MatrixXf::Random(big_matrix_eigen1, big_matrix_eigen1);
282  auto rT1 = boost::posix_time::microsec_clock::local_time();
283  mat1 = mat1.inverse();
284  auto rT2 = boost::posix_time::microsec_clock::local_time();
285  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
286  }
287  print_stats("EIGEN3(float): MATRIX INVERSION", times_ms);
288 
289  // EIGEN3(float): HOUSEHOLDER QR FULL
290  times_ms.clear();
291  Eigen::MatrixXf mat1 = Eigen::MatrixXf::Random(big_matrix_eigen2, big_matrix_eigen1);
292  for (int i = 0; i < num_trials; i++) {
293  auto rT1 = boost::posix_time::microsec_clock::local_time();
294  Eigen::MatrixXf Q = mat1.householderQr().householderQ();
295  Eigen::MatrixXf R = Q.transpose() * mat1;
296  auto rT2 = boost::posix_time::microsec_clock::local_time();
297  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
298  }
299  print_stats("EIGEN3(float): HOUSEHOLDER QR FULL", times_ms);
300 
301  // EIGEN3(float): HOUSEHOLDER QR PIV
302  times_ms.clear();
303  for (int i = 0; i < num_trials; i++) {
304  Eigen::MatrixXf mat1 = Eigen::MatrixXf::Random(big_matrix_eigen2, big_matrix_eigen1);
305  auto rT1 = boost::posix_time::microsec_clock::local_time();
306  Eigen::MatrixXf R = mat1.colPivHouseholderQr().matrixR().triangularView<Eigen::Upper>();
307  auto rT2 = boost::posix_time::microsec_clock::local_time();
308  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
309  }
310  print_stats("EIGEN3(float): HOUSEHOLDER QR PIV", times_ms);
311 
312  // EIGEN3(float): HOUSEHOLDER QR CUSTOM
313  times_ms.clear();
314  for (int i = 0; i < num_trials; i++) {
315  Eigen::MatrixXf mat1 = Eigen::MatrixXf::Random(big_matrix_eigen2, big_matrix_eigen1);
316  Eigen::VectorXf tempV1 = Eigen::VectorXf::Zero(big_matrix_eigen2 * big_matrix_eigen1, 1);
317  Eigen::VectorXf tempV2;
318  auto rT1 = boost::posix_time::microsec_clock::local_time();
319  for (int k = 0; k < mat1.cols(); k++) {
320  int rows_left = mat1.rows() - k;
321  float beta, tau;
322  mat1.col(k).segment(k, rows_left).makeHouseholder(tempV2, tau, beta);
323  mat1.block(k, k, rows_left, mat1.cols() - k).applyHouseholderOnTheLeft(tempV2, tau, tempV1.data());
324  }
325  auto rT2 = boost::posix_time::microsec_clock::local_time();
326  times_ms.push_back((rT2 - rT1).total_microseconds() * 1e-3);
327  }
328  print_stats("EIGEN3(float): HOUSEHOLDER QR CUSTOM", times_ms);
329 
330  // Done!
331  return EXIT_SUCCESS;
332 }
signal_callback_handler
void signal_callback_handler(int signum)
Definition: test_profile.cpp:37
ov_core::Printer::setPrintLevel
static void setPrintLevel(const std::string &level)
Set the print level to use for all future printing to stdout.
Definition: print.cpp:29
print.h
print_stats
void print_stats(std::string title, std::vector< double > times, std::string title2="", std::vector< int > stats={})
Definition: test_profile.cpp:39
std
PRINT_INFO
#define PRINT_INFO(x...)
Definition: print.h:98
matplotlibcpp::title
void title(const std::string &titlestr, const std::map< std::string, std::string > &keywords={})
Definition: matplotlibcpp.h:1413
main
int main(int argc, char **argv)
Definition: test_profile.cpp:74


ov_core
Author(s): Patrick Geneva , Kevin Eckenhoff , Guoquan Huang
autogenerated on Mon Jan 22 2024 03:08:17