Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 5 additions & 11 deletions cpp/k4a/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,25 @@ if(MSVC)
# Windows build uses newer features
cmake_minimum_required(VERSION 3.21)
else()
cmake_minimum_required(VERSION 3.3)
cmake_minimum_required(VERSION 3.12)
endif()

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")

project(spectacularAI_k4a_tools)

if(MSVC)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
else()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
endif()

find_package(Threads REQUIRED)
find_package(spectacularAI_k4aPlugin REQUIRED)

if(MSVC) # Must be after project() is called
if(MSVC)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /Gy")
# ./cmake/Findk4a.cmake is only tested on Windows and ideally we would rely on system dependency
find_package(k4a MODULE REQUIRED)
else()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
find_package(k4a REQUIRED PATHS "${k4a_DIR}")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs=ALL")
Expand Down
34 changes: 29 additions & 5 deletions cpp/k4a/record.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@
#include <iostream>
#include <thread>
#include <vector>
#include <sstream>
#include <iomanip>
#include <chrono>
#include <filesystem>
#include <k4a/k4a.h>
#include <k4a/k4atypes.h>
#include <spectacularAI/k4a/plugin.hpp>

void showUsage() {
std::cout << "Supported arguments:" << std::endl
<< " -h, --help Help" << std::endl
<< " --output <recording_folder>, recorded output" << std::endl
<< " --output <recording_folder>, otherwise recording is saved to current working directory" << std::endl
<< " --auto_subfolders, create timestamp-named subfolders for each recording" << std::endl
<< " --recording_only, disables Vio" << std::endl
<< " --color_res <720p, 1080p, 1440p, 1536p, 2160p, 3070p>" << std::endl
<< " --depth_mode <1 (NVOF_2X2BINNED), 2 (NVOF_UNBINNED), 3 (WFOV_2X2BINNED), 4 (WFOV_UNBINNED)>" << std::endl
Expand All @@ -26,6 +31,18 @@ void showUsage() {
<< std::endl;
}

void setAutoSubfolder(std::string &recordingFolder) {
auto now = std::chrono::system_clock::now();
auto timePoint = std::chrono::system_clock::to_time_t(now);
std::tm localTime = *std::localtime(&timePoint);
std::ostringstream oss;
oss << std::put_time(&localTime, "%Y-%m-%d_%H-%M-%S");
std::filesystem::path basePath = recordingFolder;
std::filesystem::path filename = oss.str();
std::filesystem::path combinedPath = basePath / filename;
recordingFolder = combinedPath.string();
}

int main(int argc, char *argv[]) {
std::vector<std::string> arguments(argv, argv + argc);
std::string colorResolution = "720p";
Expand All @@ -37,11 +54,14 @@ int main(int argc, char *argv[]) {
int32_t brightness = -1;
spectacularAI::k4aPlugin::Configuration config;
bool print = false;
bool autoSubfolders = false;

for (size_t i = 1; i < arguments.size(); ++i) {
const std::string &argument = arguments.at(i);
if (argument == "--output")
config.recordingFolder = arguments.at(++i);
else if (argument == "--auto_subfolders")
autoSubfolders = true;
else if (argument == "--recording_only")
config.recordingOnly = true;
else if (argument == "--color_res")
Expand Down Expand Up @@ -78,12 +98,15 @@ int main(int argc, char *argv[]) {
}
}

// Require recording folder when using recording only mode.
if (config.recordingOnly && config.recordingFolder.empty()) {
std::cerr << "Record only but recording folder is not set!" << std::endl;
return EXIT_FAILURE;
// Set default recording folder if user didn't specify output
if (config.recordingFolder.empty()) {
autoSubfolders = true;
config.recordingFolder = "data";
}

// Create timestamp-named subfolders for each recording
if (autoSubfolders) setAutoSubfolder(config.recordingFolder);

// In monocular mode, disable depth camera.
if (!config.useStereo) depthMode = K4A_DEPTH_MODE_OFF;

Expand Down Expand Up @@ -171,6 +194,7 @@ int main(int argc, char *argv[]) {

std::atomic<bool> shouldQuit(false);
std::thread inputThread([&]() {
std::cout << "Recording to '" << config.recordingFolder << "'" << std::endl;
std::cout << "Press Enter to quit." << std::endl << std::endl;
getchar();
shouldQuit = true;
Expand Down
15 changes: 4 additions & 11 deletions cpp/orbbec/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ if(MSVC)
# Windows build uses newer features
cmake_minimum_required(VERSION 3.21)
else()
cmake_minimum_required(VERSION 3.3)
cmake_minimum_required(VERSION 3.12)
endif()

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
Expand All @@ -11,25 +11,18 @@ project(spectacularAI_orbbec_tools)

if(MSVC)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
else()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
endif()

find_package(Threads REQUIRED)
find_package(spectacularAI_orbbecPlugin REQUIRED)
find_package(OrbbecSDK REQUIRED PATHS "${OrbbecSDK_DIR}")

if(MSVC) # Must be after project() is called
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /Gy")
else()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--exclude-libs=ALL")
endif()

set(TOOL_LIBS
Threads::Threads
spectacularAI::orbbecPlugin
Expand Down
36 changes: 30 additions & 6 deletions cpp/orbbec/record.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
#include <atomic>
#include <iostream>
#include <sstream>
#include <memory>
#include <thread>
#include <vector>
#include <sstream>
#include <iomanip>
#include <chrono>
#include <filesystem>
#include <libobsensor/ObSensor.hpp>
#include <spectacularAI/orbbec/plugin.hpp>

void showUsage() {
std::cout << "Supported arguments:" << std::endl
<< " -h, --help Help" << std::endl
<< " --output <recording_folder>, recorded output" << std::endl
<< " --output <recording_folder>, otherwise recording is saved to current working directory" << std::endl
<< " --auto_subfolders, create timestamp-named subfolders for each recording" << std::endl
<< " --recording_only, disables Vio" << std::endl
<< " --color_res <width,height>" << std::endl
<< " --depth_res <width,height>" << std::endl
Expand Down Expand Up @@ -81,6 +85,18 @@ std::pair<int, int> tryParseResolution(const std::string &s) {
}
}

void setAutoSubfolder(std::string &recordingFolder) {
auto now = std::chrono::system_clock::now();
auto timePoint = std::chrono::system_clock::to_time_t(now);
std::tm localTime = *std::localtime(&timePoint);
std::ostringstream oss;
oss << std::put_time(&localTime, "%Y-%m-%d_%H-%M-%S");
std::filesystem::path basePath = recordingFolder;
std::filesystem::path filename = oss.str();
std::filesystem::path combinedPath = basePath / filename;
recordingFolder = combinedPath.string();
}

int main(int argc, char *argv[]) {
std::vector<std::string> arguments(argv, argv + argc);
ob::Context::setLoggerSeverity(OB_LOG_SEVERITY_OFF);
Expand All @@ -102,10 +118,14 @@ int main(int argc, char *argv[]) {
int gain = -1;
int brightness = -1;
bool print = false;
bool autoSubfolders = false;

for (size_t i = 1; i < arguments.size(); ++i) {
const std::string &argument = arguments.at(i);
if (argument == "--output")
config.recordingFolder = arguments.at(++i);
else if (argument == "--auto_subfolders")
autoSubfolders = true;
Comment on lines +127 to +128
Copy link
Member

@pekkaran pekkaran Jan 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the automatic creation of timestamped folders is the most commonly desired mode of operation, so it's a bit awkward that you need to set this parameter to get that behavior. Instead, the argument could be removed by making it work like this:

  • If recordingFolder is set, record to that directory without any subfolders (overwrites if run twice). This allows the user to save data exactly where he wants, as he can create the parent folder himself.
  • If recordingFolder is not set, save in data/%Y-%m-%d_%H-%M-%S. It probably does not matter much that the user can't set name of the parent folder, but you could also add an optional argument to set that path.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it works like this:
If --output is set, then recordings are saved to output
If --output is not set, then recordings are saved to data/timestamp (default)
If --output --auto_subfolders is set, then recordings are saved to output/timestamp

else if (argument == "--recording_only")
config.recordingOnly = true;
else if (argument == "--color_res")
Expand Down Expand Up @@ -136,12 +156,15 @@ int main(int argc, char *argv[]) {
}
}

// Require recording folder when using recording only mode.
if (config.recordingOnly && config.recordingFolder.empty()) {
std::cerr << "Record only but recording folder is not set!" << std::endl;
return EXIT_FAILURE;
// Set default recording folder if user didn't specify output
if (config.recordingFolder.empty()) {
autoSubfolders = true;
config.recordingFolder = "data";
}

// Create timestamp-named subfolders for each recording
if (autoSubfolders) setAutoSubfolder(config.recordingFolder);

// Create vio pipeline using the config & setup orbbec pipeline
spectacularAI::orbbecPlugin::Pipeline vioPipeline(*obPipeline, config);

Expand Down Expand Up @@ -170,6 +193,7 @@ int main(int argc, char *argv[]) {

std::atomic<bool> shouldQuit(false);
std::thread inputThread([&]() {
std::cout << "Recording to '" << config.recordingFolder << "'" << std::endl;
std::cout << "Press Enter to quit." << std::endl << std::endl;
getchar();
shouldQuit = true;
Expand Down
6 changes: 4 additions & 2 deletions cpp/realsense/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ if(MSVC)
# Windows build uses newer features
cmake_minimum_required(VERSION 3.21)
else()
cmake_minimum_required(VERSION 3.3)
cmake_minimum_required(VERSION 3.12)
endif()

project(spectacularAI_realsense_tools)

if(MSVC)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
else()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
endif()

Expand Down
31 changes: 28 additions & 3 deletions cpp/realsense/record.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
#include <thread>
#include <vector>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <chrono>
#include <filesystem>
#include <librealsense2/rs.hpp>
#include <spectacularAI/realsense/plugin.hpp>

void showUsage() {
std::cout << "Supported arguments:" << std::endl
<< " -h, --help Help" << std::endl
<< " --output <recording_folder>, recorded output" << std::endl
<< " --output <recording_folder>, otherwise recording is saved to current working directory" << std::endl
<< " --auto_subfolders, create timestamp-named subfolders for each recording" << std::endl
<< " --recording_only, disables Vio" << std::endl
<< " --resolution <value>, 400p or 800p" << std::endl
<< " --brightness <value>" << std::endl
Expand All @@ -24,6 +29,18 @@ void showUsage() {
<< std::endl;
}

void setAutoSubfolder(std::string &recordingFolder) {
auto now = std::chrono::system_clock::now();
auto timePoint = std::chrono::system_clock::to_time_t(now);
std::tm localTime = *std::localtime(&timePoint);
std::ostringstream oss;
oss << std::put_time(&localTime, "%Y-%m-%d_%H-%M-%S");
std::filesystem::path basePath = recordingFolder;
std::filesystem::path filename = oss.str();
std::filesystem::path combinedPath = basePath / filename;
recordingFolder = combinedPath.string();
}

struct ColorCameraConfig {
int brightness = -1;
int contrast = -1;
Expand All @@ -40,12 +57,15 @@ int main(int argc, char** argv) {
spectacularAI::rsPlugin::Configuration config;
ColorCameraConfig colorConfig;
bool print = false;
bool autoSubfolders = false;

std::vector<std::string> arguments(argv, argv + argc);
for (size_t i = 1; i < arguments.size(); ++i) {
const std::string &argument = arguments.at(i);
if (argument == "--output")
config.recordingFolder = arguments.at(++i);
else if (argument == "--auto_subfolders")
autoSubfolders = true;
else if (argument == "--recording_only")
config.recordingOnly = true;
else if (argument == "--resolution")
Expand Down Expand Up @@ -80,11 +100,15 @@ int main(int argc, char** argv) {
}
}

// Set default recording folder if user didn't specify output
if (config.recordingFolder.empty()) {
std::cerr << " You must provide output folder with --output <folder> argument." << std::endl;;
return EXIT_FAILURE;
autoSubfolders = true;
config.recordingFolder = "data";
}

// Create timestamp-named subfolders for each recording
if (autoSubfolders) setAutoSubfolder(config.recordingFolder);

spectacularAI::rsPlugin::Pipeline vioPipeline(config);

{
Expand Down Expand Up @@ -123,6 +147,7 @@ int main(int argc, char** argv) {

std::atomic<bool> shouldQuit(false);
std::thread inputThread([&]() {
std::cout << "Recording to '" << config.recordingFolder << "'" << std::endl;
std::cout << "Press Enter to quit." << std::endl << std::endl;
getchar();
shouldQuit = true;
Expand Down
24 changes: 15 additions & 9 deletions python/cli/record/oak.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@
# script and as a subcommand in sai-cli.

def define_args(p):
p.add_argument("--output", help="Recording output folder", default="data")
p.add_argument('--auto_subfolders', action='store_true',
help='Create timestamp-named subfolders for each recording')
p.add_argument("--output", help="Recording output folder, otherwise recording is saved to current working directory")
p.add_argument('--auto_subfolders', action='store_true', help='Create timestamp-named subfolders for each recording')
p.add_argument("--use_rgb", help="Use RGB data for tracking (OAK-D S2)", action="store_true")
p.add_argument("--mono", help="Use a single camera (not stereo)", action="store_true")
p.add_argument("--no_rgb", help="Disable recording RGB video feed", action="store_true")
Expand Down Expand Up @@ -73,6 +72,13 @@ def define_subparser(subparsers):
sub.set_defaults(func=record)
return define_args(sub)

def auto_subfolder(outputFolder):
import datetime
import os
autoFolderName = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
outputFolder = os.path.join(outputFolder, autoFolderName)
return outputFolder

def record(args):
import depthai
import spectacularAI
Expand All @@ -87,11 +93,11 @@ def record(args):

config.useSlam = True
config.inputResolution = args.resolution
outputFolder = args.output
if args.auto_subfolders:
import datetime
autoFolderName = datetime.datetime.now().strftime("%Y%m%dT%H%M%S")
outputFolder = os.path.join(outputFolder, autoFolderName)
if args.output:
outputFolder = args.output
if args.auto_subfolders: outputFolder = auto_subfolder(outputFolder)
else:
outputFolder = auto_subfolder("data")

internalParameters = {}

Expand Down Expand Up @@ -189,7 +195,7 @@ def open_gray_video(name):
videoFile = open(outputFolder + "/rgb_video.h265", "wb")
rgbQueue = device.getOutputQueue(name="h265-rgb", maxSize=30, blocking=False)

print("Recording!")
print("Recording to '{0}'".format(config.recordingFolder))
print("")
if plotter is not None:
print("Close the visualization window to stop recording")
Expand Down