// License: Apache 2.0. See LICENSE file in root directory. // Copyright(c) 2015 Intel Corporation. All Rights Reserved. #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tclap/CmdLine.h" #include "example-utils.hpp" using namespace std; using namespace chrono; using namespace TCLAP; using namespace rs2; #if (defined(_WIN32) || defined(_WIN64)) #include string get_cpu() { // Based on: https://weseetips.wordpress.com/tag/c-get-cpu-name/ // Get extended ids. int CPUInfo[4] = { -1 }; __cpuid(CPUInfo, 0x80000000); unsigned int nExIds = CPUInfo[0]; // Get the information associated with each extended ID. char CPUBrandString[0x40] = { 0 }; for (unsigned int i = 0x80000000; i <= nExIds; ++i) { __cpuid(CPUInfo, i); // Interpret CPU brand string and cache information. if (i == 0x80000002) { memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo)); } else if (i == 0x80000003) { memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo)); } else if (i == 0x80000004) { memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo)); } } char* ptr = CPUBrandString; while (*ptr == ' ') ptr++; return ptr; } #elif defined __linux__ || defined(__linux__) string get_cpu() { // Based on: http://forums.codeguru.com/showthread.php?472578-How-to-get-the-cpu-information-on-linux string line; ifstream finfo("/proc/cpuinfo"); while(getline(finfo,line)) { stringstream str(line); string itype; string info; if (getline(str, itype, ':') && getline(str, info) && itype.substr(0, 10) == "model name") { return info; } } return "unknown"; } #elif __APPLE__ string get_cpu() { return "unknown"; } #else string get_cpu() { return "unknown"; } #endif class test { public: virtual frame prepare(frame f) { return f; }; virtual frame process(frame f) = 0; virtual frame finish (frame f) { return f; }; virtual const std::string& name() const = 0; }; template class pb_test : public test { public: pb_test(std::string name) : _block(), _name(std::move(name)) {} frame process(frame f) override { return _block.process(f); } virtual const std::string& name() const override { return _name; } private: T _block; std::string _name; }; template class gl_test : public pb_test { public: gl_test(std::string name) : pb_test(std::move(name)) {} void flush() { glFlush(); glFinish(); } frame process(frame f) override { auto res = pb_test::process(f); flush(); return res; } frame prepare(frame f) override { auto res = _upload.process(f); flush(); return res; } frame finish(frame f) override { _ptr = (void*)f.get_data(); return f; } private: gl::uploader _upload; volatile void* _ptr; }; class suite { public: virtual void register_tests(stream_profile stream, vector>& tests) const = 0; }; #define REGISTER_TEST(x) tests.push_back(make_shared>(#x)) class processing_blocks : public suite { public: void register_tests(stream_profile stream, vector>& tests) const override { if (stream.stream_type() == RS2_STREAM_DEPTH) { REGISTER_TEST(colorizer); REGISTER_TEST(pointcloud); REGISTER_TEST(spatial_filter); REGISTER_TEST(temporal_filter); REGISTER_TEST(disparity_transform); REGISTER_TEST(threshold_filter); REGISTER_TEST(decimation_filter); } if (stream.format() == RS2_FORMAT_YUYV) { REGISTER_TEST(yuy_decoder); } } }; #define REGISTER_GL_TEST(x) tests.push_back(make_shared>(#x)) class gl_blocks : public suite { public: void register_tests(stream_profile stream, vector>& tests) const override { if (stream.stream_type() == RS2_STREAM_DEPTH) { REGISTER_GL_TEST(gl::colorizer); REGISTER_GL_TEST(gl::pointcloud); } if (stream.format() == RS2_FORMAT_YUYV) { REGISTER_GL_TEST(gl::yuy_decoder); } } }; int main(int argc, char** argv) try { std::string serial; rs2_stream second_stream; if (!device_with_streams({ RS2_STREAM_DEPTH }, serial)) return EXIT_SUCCESS; if (device_with_streams({ RS2_STREAM_COLOR }, serial)) second_stream = RS2_STREAM_COLOR; else if (device_with_streams({ RS2_STREAM_INFRARED }, serial)) second_stream = RS2_STREAM_INFRARED; else { std::cout<< " Connect a Depth Camera that supports either RGB or Infrared streams." <> suites; suites.push_back(make_shared()); #ifndef __APPLE__ gl::init_processing(win, true); suites.push_back(make_shared()); #endif pipeline p; config cfg; if (!serial.empty()) cfg.enable_device(serial); cfg.enable_stream(RS2_STREAM_DEPTH); if(second_stream == RS2_STREAM_COLOR) cfg.enable_stream(RS2_STREAM_COLOR, RS2_FORMAT_YUYV, 30); else cfg.enable_stream(RS2_STREAM_INFRARED); auto prof = p.start(cfg); auto dev = prof.get_device(); auto name = dev.get_info(RS2_CAMERA_INFO_NAME); cout << "|**Device Name** |" << name << " |" << endl << endl; cout.precision(3); for (auto stream : prof.get_streams()) { cout << "**Stream Type**: " << stream.stream_name(); if (auto vs = stream.as()) { cout << ", **Resolution**: " << vs.width() << " x " << vs.height() << endl; } auto fps = stream.fps(); vector> procs; for (auto&& suite : suites) suite->register_tests(stream, procs); vector frames; for (int i = 0; i < 5 * fps; i++) { auto fs = p.wait_for_frames(); for (auto&& f : fs) if (f.get_profile().unique_id() == stream.unique_id()) { f.keep(); frames.push_back(f); } } cout << endl; cout << "|Filter Name |Step |Median(m) |Mean(m) |STD(m) |Max(m) | Max FPS |" << endl; cout << "|------------|-----|------------|---------|--------|--------|---------|" << endl; string last_name = ""; for (auto&& test : procs) { map> steps; for (auto&& f : frames) { auto p1 = high_resolution_clock::now(); auto f1 = test->prepare(f); auto p2 = high_resolution_clock::now(); auto f2 = test->process(f1); auto p3 = high_resolution_clock::now(); test->finish(f2); auto p4 = high_resolution_clock::now(); auto prep = duration_cast(p2 - p1).count(); auto proc = duration_cast(p3 - p2).count(); auto down = duration_cast(p4 - p3).count(); auto total = duration_cast(p4 - p1).count(); steps[" Upload"].push_back(prep * 0.001); steps["Calculate"].push_back(proc * 0.001); steps["Download"].push_back(down * 0.001); steps["Total"].push_back(total * 0.001); } int printed_steps = 0; for (auto&& sm : steps) { if (sm.first == "Total" && printed_steps < 2) continue; auto& m = sm.second; double max = *max_element(m.begin(), m.end()); double sum = accumulate(m.begin(), m.end(), 0.0); double mean = sum / m.size(); double sq_sum = inner_product(m.begin(), m.end(), m.begin(), 0.0); double stdev = sqrt(sq_sum / m.size() - mean * mean); sort(m.begin(), m.end()); double median = m[m.size() / 2]; vector fps_values{ 6, 15, 30, 60, 90 }; auto expected_max = mean + 1.645 * stdev; // 95-percentile - camera spec allows up to 5% outliers int best_fps = 1; for (int fps : fps_values) { auto max_allowed = 1000.0 / fps; if (expected_max < max_allowed) best_fps = fps; } if (sm.first == "Calculate" || median > 0.001) { bool is_new = last_name != test->name(); bool is_total = sm.first == "Total"; cout << "|" << (is_new ? test->name() : "") << " |" << (is_total ? "**" : "") << sm.first << (is_total ? "**" : "") << " |" << fixed << median << " |" << mean << " |" << stdev << " |" << max << " |"; if (best_fps == 90) cout << "90 ![90](https://placehold.it/15/35ff4d/000000?text=+)"; else if (best_fps == 60) cout << "60 ![60](https://placehold.it/15/6fe837/000000?text=+)"; else if (best_fps == 30) cout << "30 ![30](https://placehold.it/15/82c13e/000000?text=+)"; else if (best_fps == 15) cout << "15 ![15](https://placehold.it/15/eff70c/000000?text=+)"; else if (best_fps == 6) cout << "6 ![6](https://placehold.it/15/d6a726/000000?text=+)"; else cout << "? ![unknown](https://placehold.it/15/d65d26/000000?text=+)"; cout << " |" << endl; printed_steps++; last_name = test->name(); } } } cout << endl; } return EXIT_SUCCESS; } catch (const error & e) { cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n " << e.what() << endl; return EXIT_FAILURE; } catch( const exception & e ) { cerr << e.what() << endl; return EXIT_FAILURE; } catch( ... ) { cerr << "some error" << endl; return EXIT_FAILURE; }