|
| 1 | +#include <atomic> |
| 2 | +#include <iostream> |
| 3 | +#include <thread> |
| 4 | +#include <vector> |
| 5 | +#include <k4a/k4a.h> |
| 6 | +#include <k4a/k4atypes.h> |
| 7 | +#include <spectacularAI/k4a/plugin.hpp> |
| 8 | + |
| 9 | +void showUsage() { |
| 10 | + std::cout << "Supported arguments:" << std::endl |
| 11 | + << " -h, --help Help" << std::endl |
| 12 | + << " --output <recording_folder>, recorded output" << std::endl |
| 13 | + << " --recording_only, disables Vio" << std::endl |
| 14 | + << " --color_res <720p, 1080p, 1440p, 1536p, 2160p, 3070p>" << std::endl |
| 15 | + << " --depth_mode <1 (NVOF_2X2BINNED), 2 (NVOF_UNBINNED), 3 (WFOV_2X2BINNED), 4 (WFOV_UNBINNED)>" << std::endl |
| 16 | + << " --frame_rate <5, 15, 30> " << std::endl |
| 17 | + << " --align, use k4a sdk to align depth images to color images (note depth image fov!)" << std::endl |
| 18 | + << " --mono (no depth images)" << std::endl |
| 19 | + << " --fast" << std::endl |
| 20 | + << " --vio_only (-useSlam=false)" << std::endl |
| 21 | + << " --exposure <microseconds>" << std::endl |
| 22 | + << " --whitebalance <kelvins>" << std::endl |
| 23 | + << " --gain [0-255]" << std::endl |
| 24 | + << " --brightness [0-255]" << std::endl |
| 25 | + << " --print" << std::endl |
| 26 | + << std::endl; |
| 27 | +} |
| 28 | + |
| 29 | +int main(int argc, char *argv[]) { |
| 30 | + std::vector<std::string> arguments(argv, argv + argc); |
| 31 | + std::string colorResolution = "720p"; |
| 32 | + int depthMode = K4A_DEPTH_MODE_WFOV_2X2BINNED; |
| 33 | + int frameRate = 30; |
| 34 | + int32_t exposureTimeMicroseconds = -1; |
| 35 | + int32_t whiteBalanceKelvins = -1; |
| 36 | + int32_t gain = -1; |
| 37 | + int32_t brightness = -1; |
| 38 | + spectacularAI::k4aPlugin::Configuration config; |
| 39 | + bool print = false; |
| 40 | + |
| 41 | + for (size_t i = 1; i < arguments.size(); ++i) { |
| 42 | + const std::string &argument = arguments.at(i); |
| 43 | + if (argument == "--output") |
| 44 | + config.recordingFolder = arguments.at(++i); |
| 45 | + else if (argument == "--recording_only") |
| 46 | + config.recordingOnly = true; |
| 47 | + else if (argument == "--color_res") |
| 48 | + colorResolution = arguments.at(++i); |
| 49 | + else if (argument == "--depth_mode") |
| 50 | + depthMode = std::stoi(arguments.at(++i)); |
| 51 | + else if (argument == "--frame_rate") |
| 52 | + frameRate = std::stoi(arguments.at(++i)); |
| 53 | + else if (argument == "--align") |
| 54 | + config.alignedDepth = true; |
| 55 | + else if (argument == "--mono") |
| 56 | + config.useStereo = false; |
| 57 | + else if (argument == "--fast") |
| 58 | + config.fastVio = true; |
| 59 | + else if (argument == "--vio_only") |
| 60 | + config.useSlam = false; |
| 61 | + else if (argument == "--print") |
| 62 | + print = true; |
| 63 | + else if (argument == "--exposure") |
| 64 | + exposureTimeMicroseconds = std::stoi(arguments.at(++i)); |
| 65 | + else if (argument == "--whitebalance") |
| 66 | + whiteBalanceKelvins = std::stoi(arguments.at(++i)); |
| 67 | + else if (argument == "--gain") |
| 68 | + gain = std::stoi(arguments.at(++i)); |
| 69 | + else if (argument == "--brightness") |
| 70 | + brightness = std::stoi(arguments.at(++i)); |
| 71 | + else if (argument == "--help" || argument == "-h") { |
| 72 | + showUsage(); |
| 73 | + return EXIT_SUCCESS; |
| 74 | + } else { |
| 75 | + showUsage(); |
| 76 | + std::cerr << "Unknown argument: " + argument << std::endl; |
| 77 | + return EXIT_FAILURE; |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + // Require recording folder when using recording only mode. |
| 82 | + if (config.recordingOnly && config.recordingFolder.empty()) |
| 83 | + fatal_error("Record only but recording folder is not set!"); |
| 84 | + |
| 85 | + // In monocular mode, disable depth camera. |
| 86 | + if (!config.useStereo) depthMode = K4A_DEPTH_MODE_OFF; |
| 87 | + |
| 88 | + // Get configuration for k4a device. |
| 89 | + config.k4aConfig = spectacularAI::k4aPlugin::getK4AConfiguration(colorResolution, depthMode, frameRate, config.useStereo); |
| 90 | + |
| 91 | + // Create vio pipeline using the config |
| 92 | + spectacularAI::k4aPlugin::Pipeline vioPipeline(config); |
| 93 | + |
| 94 | + k4a_device_t deviceHandle = vioPipeline.getDeviceHandle(); |
| 95 | + if (exposureTimeMicroseconds > 0) { |
| 96 | + /* |
| 97 | + Very limited number of options are actually supported; |
| 98 | + And the options depend on K4A_COLOR_CONTROL_POWERLINE_FREQUENCY. |
| 99 | + Mode: 50Hz, 60Hz |
| 100 | + { 500, 500}, |
| 101 | + { 1250, 1250}, |
| 102 | + { 2500, 2500}, |
| 103 | + { 10000, 8330}, |
| 104 | + { 20000, 16670}, |
| 105 | + { 30000, 33330}, |
| 106 | + { 40000, 41670}, |
| 107 | + { 50000, 50000}, |
| 108 | + { 60000, 66670}, |
| 109 | + { 80000, 83330}, |
| 110 | + { 100000, 100000}, |
| 111 | + { 120000, 116670}, |
| 112 | + { 130000, 133330} |
| 113 | + The exposure time is also limited by camera FPS and some of the options did not seem to work on Ubuntu 20.04. |
| 114 | + */ |
| 115 | + |
| 116 | + // https://github.com/microsoft/Azure-Kinect-Sensor-SDK/blob/develop/src/color/color_priv.h |
| 117 | + k4a_result_t res = k4a_device_set_color_control(deviceHandle, |
| 118 | + k4a_color_control_command_t::K4A_COLOR_CONTROL_EXPOSURE_TIME_ABSOLUTE, |
| 119 | + k4a_color_control_mode_t::K4A_COLOR_CONTROL_MODE_MANUAL, |
| 120 | + exposureTimeMicroseconds |
| 121 | + ); |
| 122 | + if (res != K4A_RESULT_SUCCEEDED) { |
| 123 | + std::cerr << "Failed to set exposure time to " + std::to_string(exposureTimeMicroseconds) << std::endl; |
| 124 | + return EXIT_FAILURE; |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + if (whiteBalanceKelvins > 0) { |
| 129 | + // The unit is degrees Kelvin. The setting must be set to a value evenly divisible by 10 degrees. |
| 130 | + int32_t kelvins = whiteBalanceKelvins; |
| 131 | + kelvins = kelvins - kelvins % 10; // floor to nearest 10 |
| 132 | + k4a_result_t res = k4a_device_set_color_control(deviceHandle, |
| 133 | + k4a_color_control_command_t::K4A_COLOR_CONTROL_WHITEBALANCE, |
| 134 | + k4a_color_control_mode_t::K4A_COLOR_CONTROL_MODE_MANUAL, |
| 135 | + kelvins |
| 136 | + ); |
| 137 | + if (res != K4A_RESULT_SUCCEEDED) { |
| 138 | + std::cerr << "Failed to set white balance to " << std::to_string(kelvins) << " (might be out of valid range, try 2500)" << std::endl; |
| 139 | + return EXIT_FAILURE; |
| 140 | + } |
| 141 | + } |
| 142 | + |
| 143 | + if (brightness >= 0) { |
| 144 | + k4a_result_t res = k4a_device_set_color_control(deviceHandle, |
| 145 | + k4a_color_control_command_t::K4A_COLOR_CONTROL_BRIGHTNESS, |
| 146 | + k4a_color_control_mode_t::K4A_COLOR_CONTROL_MODE_MANUAL, |
| 147 | + brightness |
| 148 | + ); |
| 149 | + if (res != K4A_RESULT_SUCCEEDED) { |
| 150 | + std::cerr << "Failed to set brightness to " << std::to_string(brightness) << " (try 255)" << std::endl; |
| 151 | + return EXIT_FAILURE; |
| 152 | + } |
| 153 | + } |
| 154 | + |
| 155 | + if (gain >= 0) { |
| 156 | + k4a_result_t res = k4a_device_set_color_control(deviceHandle, |
| 157 | + k4a_color_control_command_t::K4A_COLOR_CONTROL_GAIN, |
| 158 | + k4a_color_control_mode_t::K4A_COLOR_CONTROL_MODE_MANUAL, |
| 159 | + gain |
| 160 | + ); |
| 161 | + if (res != K4A_RESULT_SUCCEEDED) { |
| 162 | + std::cerr << "Failed to set gain to " << std::to_string(gain) << " (try 255)" << std::endl; |
| 163 | + return EXIT_FAILURE; |
| 164 | + } |
| 165 | + } |
| 166 | + |
| 167 | + // Start k4a device and vio |
| 168 | + auto session = vioPipeline.startSession(); |
| 169 | + |
| 170 | + std::atomic<bool> shouldQuit(false); |
| 171 | + std::thread inputThread([&]() { |
| 172 | + std::cout << "Press Enter to quit." << std::endl << std::endl; |
| 173 | + getchar(); |
| 174 | + shouldQuit = true; |
| 175 | + }); |
| 176 | + |
| 177 | + while (!shouldQuit) { |
| 178 | + if (session->hasOutput()) { |
| 179 | + auto out = session->getOutput(); |
| 180 | + if (print) { |
| 181 | + std::cout << "Vio API pose: " << out->pose.time << ", " << out->pose.position.x |
| 182 | + << ", " << out->pose.position.y << ", " << out->pose.position.z << ", " |
| 183 | + << out->pose.orientation.x << ", " << out->pose.orientation.y << ", " |
| 184 | + << out->pose.orientation.z << ", " << out->pose.orientation.w |
| 185 | + << std::endl; |
| 186 | + } |
| 187 | + } |
| 188 | + std::this_thread::sleep_for(std::chrono::milliseconds(1)); |
| 189 | + } |
| 190 | + |
| 191 | + std::cout << "Exiting." << std::endl; |
| 192 | + if (shouldQuit) inputThread.join(); |
| 193 | + |
| 194 | + return EXIT_SUCCESS; |
| 195 | +} |
0 commit comments