diff --git a/CMakeLists.txt b/CMakeLists.txt index 706bbd7de8..b725d77966 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -453,19 +453,15 @@ if(DEPTHAI_ENABLE_PROTOBUF) ) endif() -if(DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT) - list(APPEND TARGET_CORE_SOURCES - src/pipeline/node/DynamicCalibrationNode.cpp - src/pipeline/datatype/DynamicCalibrationResults.cpp - src/pipeline/datatype/DynamicCalibrationControl.cpp - src/pipeline/node/AutoCalibration.cpp - src/pipeline/datatype/AutoCalibrationResult.cpp - src/pipeline/datatype/AutoCalibrationConfig.cpp - ) -endif() - set(TARGET_OPENCV_SOURCES src/opencv/ImgFrame.cpp + src/opencv/ImgDetectionsT.cpp + src/opencv/SegmentationMask.cpp + src/opencv/DetectionNetwork.cpp + src/opencv/NeuralNetwork.cpp + src/opencv/EventsManager.cpp + src/opencv/Camera.cpp + src/opencv/matrixOps.cpp src/pipeline/node/host/Display.cpp src/pipeline/node/host/HostCamera.cpp src/pipeline/node/host/Record.cpp @@ -475,6 +471,17 @@ set(TARGET_OPENCV_SOURCES src/opencv/HolisticRecordReplay.cpp ) +if(DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT AND DEPTHAI_MERGED_TARGET) + list(APPEND TARGET_CORE_SOURCES + src/pipeline/node/DynamicCalibrationNode.cpp + src/pipeline/datatype/DynamicCalibrationResults.cpp + src/pipeline/datatype/DynamicCalibrationControl.cpp + src/pipeline/node/AutoCalibration.cpp + src/pipeline/datatype/AutoCalibrationResult.cpp + src/pipeline/datatype/AutoCalibrationConfig.cpp + ) +endif() + set(TARGET_PCL_SOURCES src/pcl/PointCloudData.cpp) set(TARGET_BASALT_SOURCES src/basalt/BasaltVIO.cpp) @@ -652,7 +659,7 @@ if(NOT BUILD_SHARED_LIBS) target_compile_definitions(${TARGET_CORE_NAME} PUBLIC MCAP_STATIC) endif() -if(DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT) +if(DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT AND DEPTHAI_MERGED_TARGET) # Link the dynamic calibration target target_link_libraries(${TARGET_CORE_NAME} PRIVATE dynamic_calibration_imported) target_compile_definitions(${TARGET_CORE_NAME} PUBLIC DEPTHAI_HAVE_DYNAMIC_CALIBRATION_SUPPORT) @@ -988,7 +995,7 @@ if(DEPTHAI_ENABLE_LIBUSB AND NOT XLINK_LIBUSB_SYSTEM) add_runtime_dependencies(${TARGET_CORE_NAME} usb-1.0) endif() # Add dynamic calibration dll in build time -if(DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT) +if(DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT AND DEPTHAI_MERGED_TARGET) add_runtime_dependencies(${TARGET_CORE_NAME} dynamic_calibration_imported) endif() @@ -1009,12 +1016,21 @@ if(DEPTHAI_HAVE_OPENCV_SUPPORT AND NOT DEPTHAI_MERGED_TARGET) # Link to OpenCV (publicly) target_link_libraries(${TARGET_OPENCV_NAME} PUBLIC ${REQUIRED_OPENCV_LIBRARIES} ${THIRDPARTY_OPENCV_LIBRARIES}) + target_link_libraries(${TARGET_OPENCV_NAME} PRIVATE spdlog::spdlog) # Specify that we are building target opencv target_compile_definitions(${TARGET_OPENCV_NAME} PUBLIC DEPTHAI_TARGET_OPENCV) target_compile_definitions(${TARGET_OPENCV_NAME} PUBLIC DEPTHAI_HAVE_OPENCV_SUPPORT) # Add public dependency to depthai::core library target_link_libraries(${TARGET_OPENCV_NAME} PUBLIC ${TARGET_CORE_NAME}) + target_include_directories(${TARGET_OPENCV_NAME} + PRIVATE + "$" + "$" + "$" + "$" + "$" + ) # Add to clangformat target if(COMMAND target_clangformat_setup) diff --git a/cmake/depthaiOptions.cmake b/cmake/depthaiOptions.cmake index 4d2991ee0f..240431b485 100644 --- a/cmake/depthaiOptions.cmake +++ b/cmake/depthaiOptions.cmake @@ -40,6 +40,11 @@ option(DEPTHAI_BUILD_ZOO_HELPER "Build the Zoo helper" OFF) option(DEPTHAI_NEW_FIND_PYTHON "Use new FindPython module" ON) option(DEPTHAI_INSTALL "Enable install target for depthai-core targets" ON) +if(DEPTHAI_BUILD_EXAMPLES AND NOT DEPTHAI_OPENCV_SUPPORT) + message(WARNING "DEPTHAI_BUILD_EXAMPLES requires DEPTHAI_OPENCV_SUPPORT to be ON. Turning DEPTHAI_BUILD_EXAMPLES OFF.") + set(DEPTHAI_BUILD_EXAMPLES OFF CACHE BOOL "Build examples - Requires OpenCV library to be installed" FORCE) +endif() + # ---------- Dependency Management ------------- option(DEPTHAI_BOOTSTRAP_VCPKG "Automatically bootstrap VCPKG" ON) option(DEPTHAI_VCPKG_INTERNAL_ONLY "Use VCPKG internally, but not for interface libraries" ON) @@ -55,12 +60,6 @@ option(DEPTHAI_XTENSOR_EXTERNAL "Use external xtensor library" ${USE_EXTERNAL_IN option(DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT "Enable Dynamic Calibration support" ${DEPTHAI_DEFAULT_DYNAMIC_CALIBRATION_SUPPORT}) -# ---------- Platform / Compiler Tweaks --------- -if(CMAKE_SIZEOF_VOID_P EQUAL 4 AND DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT) - # There is not 32b build of Dynamic Calibration Library - message(FATAL_ERROR "Dynamic calibration is not supported on 32b machines. Build with DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT=OFF") -endif() - # AprilTag node support set(DEPTHAI_HAS_APRIL_TAG ${DEPTHAI_ENABLE_APRIL_TAG}) if(WIN32) @@ -73,6 +72,18 @@ if(NOT DEPTHAI_OPENCV_SUPPORT) set(DEPTHAI_MERGED_TARGET OFF CACHE BOOL "Enable merged target build" FORCE) endif() +# Disable dynamic calibration support when merged target is disabled +if(DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT AND NOT DEPTHAI_MERGED_TARGET) + message(WARNING "DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT requires DEPTHAI_MERGED_TARGET to be ON. Turning DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT OFF.") + set(DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT OFF CACHE BOOL "Enable Dynamic Calibration support" FORCE) +endif() + +# ---------- Platform / Compiler Tweaks --------- +if(CMAKE_SIZEOF_VOID_P EQUAL 4 AND DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT) + # There is not 32b build of Dynamic Calibration Library + message(FATAL_ERROR "Dynamic calibration is not supported on 32b machines. Build with DEPTHAI_DYNAMIC_CALIBRATION_SUPPORT=OFF") +endif() + # Backward stacktrace printing if(ANDROID OR EMSCRIPTEN) # Backward not supported currently on Android diff --git a/examples/cpp/AutoCalibration/CMakeLists.txt b/examples/cpp/AutoCalibration/CMakeLists.txt index 4acc380315..e32548f7e5 100644 --- a/examples/cpp/AutoCalibration/CMakeLists.txt +++ b/examples/cpp/AutoCalibration/CMakeLists.txt @@ -1,4 +1,6 @@ project(auto_calibration_examples) cmake_minimum_required(VERSION 3.10) -dai_add_example(auto_calibration_example auto_calibration_example.cpp ON OFF) +if(DEPTHAI_MERGED_TARGET) + dai_add_example(auto_calibration_example auto_calibration_example.cpp ON OFF) +endif() diff --git a/examples/cpp/DynamicCalibration/CMakeLists.txt b/examples/cpp/DynamicCalibration/CMakeLists.txt index 9e6d4e5536..f42b26c618 100644 --- a/examples/cpp/DynamicCalibration/CMakeLists.txt +++ b/examples/cpp/DynamicCalibration/CMakeLists.txt @@ -4,7 +4,9 @@ cmake_minimum_required(VERSION 3.10) ## function: dai_add_example(example_name example_src enable_test use_pcl) ## function: dai_set_example_test_labels(example_name ...) -dai_add_example(calibration_quality_dynamic calibration_quality_dynamic.cpp ON OFF) -dai_add_example(calibration_dynamic calibration_dynamic.cpp ON OFF) -dai_add_example(calibration_dynamic_3_sensors calibration_dynamic_3_sensors.cpp ON OFF) -dai_add_example(calibration_integration calibration_integration.cpp ON OFF) +if(DEPTHAI_MERGED_TARGET) + dai_add_example(calibration_quality_dynamic calibration_quality_dynamic.cpp ON OFF) + dai_add_example(calibration_dynamic calibration_dynamic.cpp ON OFF) + dai_add_example(calibration_dynamic_3_sensors calibration_dynamic_3_sensors.cpp ON OFF) + dai_add_example(calibration_integration calibration_integration.cpp ON OFF) +endif() diff --git a/examples/cpp/RecordReplay/CMakeLists.txt b/examples/cpp/RecordReplay/CMakeLists.txt index 4d55097f15..9f10a04486 100644 --- a/examples/cpp/RecordReplay/CMakeLists.txt +++ b/examples/cpp/RecordReplay/CMakeLists.txt @@ -19,17 +19,19 @@ dai_add_example(replay_video replay_video.cpp OFF OFF) dai_add_example(replay_imu replay_imu.cpp OFF OFF) -if(DEPTHAI_FETCH_ARTIFACTS) - dai_add_example(holistic_replay holistic_replay.cpp ON OFF) - target_compile_definitions(holistic_replay PRIVATE RECORDING_PATH="${recording_path}") -endif() - dai_add_example(record_video record_video.cpp OFF OFF) -dai_add_example(holistic_record holistic_record.cpp OFF OFF) - dai_add_example(record_encoded record_encoded.cpp OFF OFF) dai_add_example(record_raw record_raw.cpp OFF OFF) dai_add_example(record_imu record_imu.cpp OFF OFF) + +if(DEPTHAI_MERGED_TARGET) + dai_add_example(holistic_record holistic_record.cpp OFF OFF) + + if(DEPTHAI_FETCH_ARTIFACTS) + dai_add_example(holistic_replay holistic_replay.cpp ON OFF) + target_compile_definitions(holistic_replay PRIVATE RECORDING_PATH="${recording_path}") + endif() +endif() diff --git a/examples/cpp/RecordReplay/holistic_record.cpp b/examples/cpp/RecordReplay/holistic_record.cpp index fdd910fe4a..8bcae53503 100644 --- a/examples/cpp/RecordReplay/holistic_record.cpp +++ b/examples/cpp/RecordReplay/holistic_record.cpp @@ -8,7 +8,7 @@ #include "depthai/utility/RecordReplay.hpp" #include "utility.hpp" #ifndef DEPTHAI_MERGED_TARGET - #error This example needs OpenCV support, which is not available on your system + #error This example needs DEPTHAI_MERGED_TARGET to be enabled #endif // Signal handling for clean shutdown diff --git a/examples/cpp/RecordReplay/holistic_replay.cpp b/examples/cpp/RecordReplay/holistic_replay.cpp index 3c2b5ee7b0..cf9cae4d5f 100644 --- a/examples/cpp/RecordReplay/holistic_replay.cpp +++ b/examples/cpp/RecordReplay/holistic_replay.cpp @@ -3,7 +3,7 @@ #include "depthai/depthai.hpp" #ifndef DEPTHAI_MERGED_TARGET - #error This example needs OpenCV support, which is not available on your system + #error This example needs DEPTHAI_MERGED_TARGET to be enabled #endif int main(int argc, char** argv) { diff --git a/include/depthai/pipeline/MessageQueue.hpp b/include/depthai/pipeline/MessageQueue.hpp index 0883ff66fb..1d1c85cfda 100644 --- a/include/depthai/pipeline/MessageQueue.hpp +++ b/include/depthai/pipeline/MessageQueue.hpp @@ -62,14 +62,14 @@ class MessageQueue : public std::enable_shared_from_this { name(c.name), callbacks(c.callbacks), uniqueCallbackId(c.uniqueCallbackId), - pipelineEventDispatcher(c.pipelineEventDispatcher){}; + pipelineEventDispatcher(c.pipelineEventDispatcher) {}; MessageQueue(MessageQueue&& m) noexcept : enable_shared_from_this(m), queue(std::move(m.queue)), name(std::move(m.name)), callbacks(std::move(m.callbacks)), uniqueCallbackId(m.uniqueCallbackId), - pipelineEventDispatcher(m.pipelineEventDispatcher){}; + pipelineEventDispatcher(m.pipelineEventDispatcher) {}; MessageQueue& operator=(const MessageQueue& c) { queue = c.queue; diff --git a/include/depthai/pipeline/Node.hpp b/include/depthai/pipeline/Node.hpp index 6d53c76a43..e37e6ddaa1 100644 --- a/include/depthai/pipeline/Node.hpp +++ b/include/depthai/pipeline/Node.hpp @@ -98,7 +98,9 @@ class Node : public std::enable_shared_from_this { static constexpr auto DEFAULT_NAME = ""; #define DEFAULT_TYPES \ { \ - { DatatypeEnum::Buffer, true } \ + { \ + DatatypeEnum::Buffer, true \ + } \ } static constexpr auto DEFAULT_BLOCKING = true; static constexpr auto DEFAULT_QUEUE_SIZE = 3; diff --git a/include/depthai/pipeline/datatype/AutoCalibrationResult.hpp b/include/depthai/pipeline/datatype/AutoCalibrationResult.hpp index 35ad4c23cb..9626d225d5 100644 --- a/include/depthai/pipeline/datatype/AutoCalibrationResult.hpp +++ b/include/depthai/pipeline/datatype/AutoCalibrationResult.hpp @@ -22,7 +22,7 @@ class AutoCalibrationResult : public Buffer { * @param calibration The actual calibration handler containing the new parameters. */ AutoCalibrationResult(double dataConfidence, double calibrationConfidence, bool passed, CalibrationHandler calibration) - : dataConfidence(dataConfidence), calibrationConfidence(calibrationConfidence), passed(passed), calibration(calibration){}; + : dataConfidence(dataConfidence), calibrationConfidence(calibrationConfidence), passed(passed), calibration(calibration) {}; virtual ~AutoCalibrationResult(); diff --git a/include/depthai/pipeline/datatype/GateControl.hpp b/include/depthai/pipeline/datatype/GateControl.hpp index 3c6a978be0..d947303969 100644 --- a/include/depthai/pipeline/datatype/GateControl.hpp +++ b/include/depthai/pipeline/datatype/GateControl.hpp @@ -26,7 +26,7 @@ class GateControl : public Buffer { GateControl() = default; - GateControl(bool open, int numMessages, int fps) : open(open), numMessages(numMessages), fps(fps){}; + GateControl(bool open, int numMessages, int fps) : open(open), numMessages(numMessages), fps(fps) {}; ~GateControl() override; diff --git a/include/depthai/pipeline/datatype/ImgDetectionsT.hpp b/include/depthai/pipeline/datatype/ImgDetectionsT.hpp index 270bc93f57..313fe7a8d6 100644 --- a/include/depthai/pipeline/datatype/ImgDetectionsT.hpp +++ b/include/depthai/pipeline/datatype/ImgDetectionsT.hpp @@ -100,6 +100,28 @@ class ImgDetectionsT : public Buffer { */ std::optional getCvSegmentationMaskByClass(uint8_t semanticClass, cv::MatAllocator* allocator = nullptr); +#else + + template + struct dependent_false { + static constexpr bool value = false; + }; + template + void setCvSegmentationMask(T...) { + static_assert(dependent_false::value, "Library not configured with OpenCV support"); + } + template + void getCvSegmentationMask(T...) { + static_assert(dependent_false::value, "Library not configured with OpenCV support"); + } + template + void getCvSegmentationMaskByIndex(T...) { + static_assert(dependent_false::value, "Library not configured with OpenCV support"); + } + template + void getCvSegmentationMaskByClass(T...) { + static_assert(dependent_false::value, "Library not configured with OpenCV support"); + } #endif }; diff --git a/include/depthai/pipeline/node/ToF.hpp b/include/depthai/pipeline/node/ToF.hpp index 96fda12af7..905ee143c6 100644 --- a/include/depthai/pipeline/node/ToF.hpp +++ b/include/depthai/pipeline/node/ToF.hpp @@ -177,12 +177,10 @@ class ToF : public DeviceNodeGroup { */ Input& tofBaseInputConfig{tofBase->inputConfig}; - #ifdef DEPTHAI_HAVE_OPENCV_SUPPORT /** * Input config for image filters */ Input* imageFiltersInputConfig = nullptr; - #endif #endif /** @@ -190,12 +188,10 @@ class ToF : public DeviceNodeGroup { */ ToFBase& tofBaseNode{*tofBase}; -#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT /** * Image filters node */ ImageFilters* imageFiltersNode = nullptr; -#endif }; } // namespace node diff --git a/include/depthai/utility/EventsManager.hpp b/include/depthai/utility/EventsManager.hpp index 25c6e86030..160e80cc8a 100644 --- a/include/depthai/utility/EventsManager.hpp +++ b/include/depthai/utility/EventsManager.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,8 @@ class FileData { bool toFile(const std::filesystem::path& inputPath); private: + static std::string calculateSHA256Checksum(const std::string& data); + std::string mimeType; std::string fileTag; std::string data; diff --git a/include/depthai/utility/LockingQueue.hpp b/include/depthai/utility/LockingQueue.hpp index c11a1f0c0c..c8aa0ade20 100644 --- a/include/depthai/utility/LockingQueue.hpp +++ b/include/depthai/utility/LockingQueue.hpp @@ -28,8 +28,8 @@ class LockingQueue { this->maxSize = maxSize; this->blocking = blocking; } - LockingQueue(const LockingQueue& obj) : maxSize(obj.maxSize), blocking(obj.blocking), queue(obj.queue), destructed(obj.destructed){}; - LockingQueue(LockingQueue&& obj) noexcept : maxSize(obj.maxSize), blocking(obj.blocking), queue(std::move(obj.queue)), destructed(obj.destructed){}; + LockingQueue(const LockingQueue& obj) : maxSize(obj.maxSize), blocking(obj.blocking), queue(obj.queue), destructed(obj.destructed) {}; + LockingQueue(LockingQueue&& obj) noexcept : maxSize(obj.maxSize), blocking(obj.blocking), queue(std::move(obj.queue)), destructed(obj.destructed) {}; LockingQueue& operator=(const LockingQueue& obj) { maxSize = obj.maxSize; blocking = obj.blocking; diff --git a/include/depthai/utility/MemoryWrappers.hpp b/include/depthai/utility/MemoryWrappers.hpp index cc0204904c..9a7ff64061 100644 --- a/include/depthai/utility/MemoryWrappers.hpp +++ b/include/depthai/utility/MemoryWrappers.hpp @@ -2,7 +2,7 @@ // memfd_create wrapper for glibc < 2.27 #if defined(__unix__) && !defined(__APPLE__) - #if(__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 27) + #if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 27) int memfd_create(const char* name, unsigned int flags); diff --git a/include/depthai/utility/NlohmannJsonCompat.hpp b/include/depthai/utility/NlohmannJsonCompat.hpp index c138bea8d4..1d86416f5d 100644 --- a/include/depthai/utility/NlohmannJsonCompat.hpp +++ b/include/depthai/utility/NlohmannJsonCompat.hpp @@ -3,8 +3,8 @@ #include // Check version of nlohmann json -#if(defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR)) - #if((NLOHMANN_JSON_VERSION_MAJOR < 3) || ((NLOHMANN_JSON_VERSION_MAJOR == 3) && (NLOHMANN_JSON_VERSION_MINOR < 6))) +#if (defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR)) + #if ((NLOHMANN_JSON_VERSION_MAJOR < 3) || ((NLOHMANN_JSON_VERSION_MAJOR == 3) && (NLOHMANN_JSON_VERSION_MINOR < 6))) static_assert(0, "DepthAI requires nlohmann library version 3.6.0 or higher"); #else // Set up compat macros for nlohmann json (independent of version) diff --git a/src/device/DeviceBase.cpp b/src/device/DeviceBase.cpp index 02fa2813d4..5db1532216 100644 --- a/src/device/DeviceBase.cpp +++ b/src/device/DeviceBase.cpp @@ -410,8 +410,8 @@ class DeviceBase::Impl { * RPC call with custom timeout. Set timeout to 0 to enable endless wait. */ template - auto rpcCall(std::chrono::milliseconds timeout, std::string name, Args&&... args) -> decltype(rpcClient->call(std::string(name), - std::forward(args)...)) { + auto rpcCall(std::chrono::milliseconds timeout, std::string name, Args&&... args) + -> decltype(rpcClient->call(std::string(name), std::forward(args)...)) { ScopedRpcTimeout guard(timeout); return rpcClient->call(name, std::forward(args)...); } diff --git a/src/opencv/Camera.cpp b/src/opencv/Camera.cpp new file mode 100644 index 0000000000..34a70e07fb --- /dev/null +++ b/src/opencv/Camera.cpp @@ -0,0 +1,45 @@ +#include "depthai/pipeline/node/Camera.hpp" + +#include + +#include "depthai/pipeline/Pipeline.hpp" +#include "utility/RecordReplayImpl.hpp" + +namespace dai::node { + +std::shared_ptr Camera::build(CameraBoardSocket boardSocket, ReplayVideo& replay) { + auto cam = build(boardSocket); + cam->setMockIsp(replay); + return cam; +} + +std::shared_ptr Camera::build(ReplayVideo& replay) { + auto cam = build(CameraBoardSocket::AUTO); + cam->setMockIsp(replay); + return cam; +} + +Camera& Camera::setMockIsp(ReplayVideo& replay) { + if(replay.getReplayVideoFile().empty()) { + throw std::runtime_error("ReplayVideo video path not set"); + } + + auto [width, height] = replay.getSize(); + double fps = replay.getFps(); + if(width <= 0 || height <= 0) { + const auto& [vidWidth, vidHeight, vidFps] = utility::getVideoSize(replay.getReplayVideoFile().string()); + width = vidWidth; + height = vidHeight; + fps = vidFps; + } + properties.mockIspWidth = width; + properties.mockIspHeight = height; + properties.mockIspFps = fps; + + auto device = getParentPipeline().getDefaultDevice(); + replay.setOutFrameType(device && device->getPlatform() == Platform::RVC2 ? ImgFrame::Type::YUV420p : ImgFrame::Type::NV12); + replay.out.link(mockIsp); + return *this; +} + +} // namespace dai::node diff --git a/src/opencv/DetectionNetwork.cpp b/src/opencv/DetectionNetwork.cpp new file mode 100644 index 0000000000..afff8d547b --- /dev/null +++ b/src/opencv/DetectionNetwork.cpp @@ -0,0 +1,15 @@ +#include "depthai/pipeline/node/DetectionNetwork.hpp" + +#include "utility/ErrorMacros.hpp" + +namespace dai::node { + +std::shared_ptr DetectionNetwork::build(const std::shared_ptr& input, const Model& model, std::optional fps) { + neuralNetwork->build(input, model, fps); + auto nnArchive = neuralNetwork->getNNArchive(); + DAI_CHECK(nnArchive.has_value(), "NeuralNetwork NNArchive is not set after build."); + detectionParser->setNNArchive(*nnArchive); + return std::static_pointer_cast(shared_from_this()); +} + +} // namespace dai::node diff --git a/src/opencv/EventsManager.cpp b/src/opencv/EventsManager.cpp new file mode 100644 index 0000000000..687d13fadf --- /dev/null +++ b/src/opencv/EventsManager.cpp @@ -0,0 +1,76 @@ +#include "depthai/utility/EventsManager.hpp" + +#include +#include + +#include "depthai/schemas/Event.pb.h" +#include "utility/Logging.hpp" + +namespace dai::utility { + +template +void addToFileData(std::vector>& container, Args&&... args) { + try { + container.emplace_back(std::make_shared(std::forward(args)...)); + } catch(const std::exception& e) { + logger::error("Failed to create FileData: {}", e.what()); + } +} + +FileData::FileData(const std::shared_ptr& imgFrame, std::string fileTag) + : mimeType("image/jpeg"), fileTag(std::move(fileTag)), classification(proto::event::PrepareFileUploadClass::IMAGE_COLOR) { + std::vector buffer; + try { + cv::Mat cvFrame = imgFrame->getCvFrame(); + if(!cv::imencode(".jpg", cvFrame, buffer)) { + throw std::runtime_error("ImgFrame encoding failed"); + } + } catch(const cv::Exception& e) { + throw std::runtime_error(std::string("ImgFrame encoding failed due to OpenCV error: ") + e.what()); + } + + data.assign(reinterpret_cast(buffer.data()), buffer.size()); + size = data.size(); + checksum = calculateSHA256Checksum(data); +} + +void FileGroup::addFile(const std::optional& fileTag, const std::shared_ptr& imgFrame) { + if(!imgFrame) { + throw std::invalid_argument("FileGroup::addFile called with null ImgFrame"); + } + addToFileData(fileData, imgFrame, fileTag.value_or("Image")); +} + +void FileGroup::addImageDetectionsPair(const std::optional& fileTag, + const std::shared_ptr& imgFrame, + const std::shared_ptr& imgDetections) { + if(!imgFrame) { + throw std::invalid_argument("FileGroup::addImageDetectionsPair called with null ImgFrame"); + } + if(!imgDetections) { + throw std::invalid_argument("FileGroup::addImageDetectionsPair called with null ImgDetections"); + } + std::string dataFileName = fileTag.value_or("ImageDetection"); + addToFileData(fileData, imgFrame, dataFileName); + addToFileData(fileData, imgDetections, std::move(dataFileName)); +} + +std::optional EventsManager::sendSnap(const std::string& name, + const std::optional& fileTag, + const std::shared_ptr imgFrame, + const std::optional>& imgDetections, + const std::vector& tags, + const std::unordered_map& extras, + const std::function successCallback, + const std::function failureCallback) { + auto fileGroup = std::make_shared(); + if(imgDetections.has_value()) { + fileGroup->addImageDetectionsPair(fileTag, imgFrame, imgDetections.value()); + } else { + fileGroup->addFile(fileTag, imgFrame); + } + + return sendSnap(name, fileGroup, tags, extras, successCallback, failureCallback); +} + +} // namespace dai::utility diff --git a/src/opencv/ImgDetectionsT.cpp b/src/opencv/ImgDetectionsT.cpp new file mode 100644 index 0000000000..a1541e8821 --- /dev/null +++ b/src/opencv/ImgDetectionsT.cpp @@ -0,0 +1,88 @@ +#include "depthai/pipeline/datatype/ImgDetectionsT.hpp" + +#include +#include + +#include "depthai/pipeline/datatype/ImgDetections.hpp" +#include "depthai/pipeline/datatype/SpatialImgDetections.hpp" + +namespace dai { + +template +void ImgDetectionsT::setCvSegmentationMask(cv::Mat mask) { + if(mask.type() != CV_8UC1) { + throw std::runtime_error("SetCvSegmentationMask: Mask must be of INT8 type, got opencv type " + cv::typeToString(mask.type()) + "."); + } + std::vector dataVec; + if(!mask.isContinuous()) { + for(int i = 0; i < mask.rows; i++) { + dataVec.insert(dataVec.end(), mask.ptr(i), mask.ptr(i) + mask.cols * mask.elemSize()); + } + } else { + dataVec.insert(dataVec.begin(), mask.datastart, mask.dataend); + } + setData(std::move(dataVec)); + this->segmentationMaskWidth = mask.cols; + this->segmentationMaskHeight = mask.rows; +} + +template +std::optional ImgDetectionsT::getCvSegmentationMask(cv::MatAllocator* allocator) { + if(data->getData().data() == nullptr) return std::nullopt; + + cv::Size size(getSegmentationMaskWidth(), getSegmentationMaskHeight()); + constexpr int type = CV_8UC1; + if(size.width <= 0 || size.height <= 0) { + throw std::runtime_error("Segmentation mask metadata not valid (width or height <= 0)."); + } + + const size_t requiredSize = CV_ELEM_SIZE(type) * static_cast(size.area()); + const size_t actualSize = data->getSize(); + if(actualSize != requiredSize) { + throw std::runtime_error("Segmentation mask data size does not match the expected size, required " + std::to_string(requiredSize) + ", actual " + + std::to_string(actualSize) + "."); + } + + cv::Mat mask(size, type, data->getData().data()); + cv::Mat output; + if(allocator != nullptr) output.allocator = allocator; + mask.copyTo(output); + return output; +} + +template +std::optional ImgDetectionsT::getCvSegmentationMaskByIndex(uint8_t index, cv::MatAllocator* allocator) { + auto mask = getCvSegmentationMask(allocator); + if(!mask) return std::nullopt; + + cv::Mat classMask; + cv::compare(*mask, index, classMask, cv::CmpTypes::CMP_EQ); + return classMask; +} + +template +std::optional ImgDetectionsT::getCvSegmentationMaskByClass(uint8_t semanticClass, cv::MatAllocator* allocator) { + auto mask = getCvSegmentationMask(allocator); + if(!mask) return std::nullopt; + + cv::Mat classMask = cv::Mat::zeros(mask->size(), CV_8UC1) + 255; + for(uint8_t idx = 0; idx < detections.size(); idx++) { + if(detections[idx].label == semanticClass) { + auto indexMask = getCvSegmentationMaskByIndex(idx, allocator); + if(!indexMask) return std::nullopt; + classMask.setTo(0, *indexMask); + } + } + return classMask; +} + +template void ImgDetectionsT::setCvSegmentationMask(cv::Mat); +template std::optional ImgDetectionsT::getCvSegmentationMask(cv::MatAllocator*); +template std::optional ImgDetectionsT::getCvSegmentationMaskByIndex(uint8_t, cv::MatAllocator*); +template std::optional ImgDetectionsT::getCvSegmentationMaskByClass(uint8_t, cv::MatAllocator*); +template void ImgDetectionsT::setCvSegmentationMask(cv::Mat); +template std::optional ImgDetectionsT::getCvSegmentationMask(cv::MatAllocator*); +template std::optional ImgDetectionsT::getCvSegmentationMaskByIndex(uint8_t, cv::MatAllocator*); +template std::optional ImgDetectionsT::getCvSegmentationMaskByClass(uint8_t, cv::MatAllocator*); + +} // namespace dai diff --git a/src/opencv/NeuralNetwork.cpp b/src/opencv/NeuralNetwork.cpp new file mode 100644 index 0000000000..dfdc5b5c23 --- /dev/null +++ b/src/opencv/NeuralNetwork.cpp @@ -0,0 +1,20 @@ +#include "depthai/pipeline/node/NeuralNetwork.hpp" + +#include "capabilities/ImgFrameCapability.hpp" + +namespace dai::node { + +std::shared_ptr NeuralNetwork::build(const std::shared_ptr& input, const Model& model, std::optional fps) { + decodeModel(model); + + ImgFrameCapability cap; + if(fps.has_value()) cap.fps.value = *fps; + cap = getFrameCapability(*nnArchive, cap); + input->setOutFrameType(cap.type.value()); + if(fps.has_value()) input->setFps(*fps); + input->setSize(std::get>(cap.size.value.value())); + input->out.link(this->input); + return std::static_pointer_cast(shared_from_this()); +} + +} // namespace dai::node diff --git a/src/opencv/SegmentationMask.cpp b/src/opencv/SegmentationMask.cpp new file mode 100644 index 0000000000..23dfca28d5 --- /dev/null +++ b/src/opencv/SegmentationMask.cpp @@ -0,0 +1,121 @@ +#include "depthai/pipeline/datatype/SegmentationMask.hpp" + +#include +#include +#include +#include + +#include "utility/ErrorMacros.hpp" + +namespace dai { + +void SegmentationMask::setCvMask(cv::Mat mask) { + if(mask.type() != CV_8UC1) { + throw std::runtime_error("SetCvSegmentationMask: Mask must be of INT8 type, got opencv type " + cv::typeToString(mask.type()) + "."); + } + std::vector dataVec; + if(!mask.isContinuous()) { + for(int i = 0; i < mask.rows; i++) { + dataVec.insert(dataVec.end(), mask.ptr(i), mask.ptr(i) + mask.cols * mask.elemSize()); + } + } else { + dataVec.insert(dataVec.begin(), mask.datastart, mask.dataend); + } + setData(std::move(dataVec)); + width = mask.cols; + height = mask.rows; +} + +cv::Mat SegmentationMask::getCvMask(cv::MatAllocator* allocator) { + cv::Mat mask; + if(data->getData().data() == nullptr || data->getSize() == 0) { + return mask; + } + cv::Size size(static_cast(getWidth()), static_cast(getHeight())); + constexpr int type = CV_8UC1; + + const size_t requiredSize = CV_ELEM_SIZE(type) * static_cast(size.area()); + const size_t actualSize = data->getSize(); + DAI_CHECK_V(actualSize == requiredSize, "Segmentation mask data size does not match the expected size, required {}, actual {}.", requiredSize, actualSize); + + mask = cv::Mat(size, type, data->getData().data()); + cv::Mat output; + if(allocator != nullptr) { + output.allocator = allocator; + } + mask.copyTo(output); + return output; +} + +cv::Mat SegmentationMask::getCvMaskByIndex(uint8_t index, cv::MatAllocator* allocator) { + cv::Mat mask = getCvMask(allocator); + if(mask.empty()) { + return {}; + } + + cv::Mat indexedMask; + cv::compare(mask, index, indexedMask, cv::CmpTypes::CMP_EQ); + return indexedMask; +} + +std::vector> SegmentationMask::getContour(uint8_t index) { + std::vector> result; + cv::Mat mask = getCvMaskByIndex(index); + if(mask.empty()) { + return result; + } + cv::Mat maskCopy = mask.clone(); + std::vector> contours; + + cv::findContours(maskCopy, contours, cv::RetrievalModes::RETR_EXTERNAL, cv::ContourApproximationModes::CHAIN_APPROX_SIMPLE); + for(const auto& contour : contours) { + std::vector daiContour; + for(const auto& point : contour) { + daiContour.emplace_back(static_cast(point.x), static_cast(point.y), false); + } + result.emplace_back(std::move(daiContour)); + } + + return result; +} + +std::vector SegmentationMask::getBoundingBoxes(uint8_t index, bool calculateRotation) { + std::vector boxes; + cv::Mat mask = getCvMaskByIndex(index); + if(mask.empty()) { + return {}; + } + + cv::Mat maskCopy = mask.clone(); + std::vector> contours; + cv::findContours(maskCopy, contours, cv::RetrievalModes::RETR_EXTERNAL, cv::ContourApproximationModes::CHAIN_APPROX_SIMPLE); + if(contours.empty()) { + return {}; + } + const float widthF = static_cast(width); + const float heightF = static_cast(height); + + for(const auto& contour : contours) { + dai::RotatedRect box; + if(calculateRotation) { + cv::RotatedRect cvBox = cv::minAreaRect(contour); + box = {dai::Point2f(cvBox.center.x / widthF, cvBox.center.y / heightF, true), + dai::Size2f(cvBox.size.width / widthF, cvBox.size.height / heightF, true), + cvBox.angle}; + } else { + cv::Rect boundingRect = cv::boundingRect(contour); + if(boundingRect.width == 0 || boundingRect.height == 0) { + continue; + } + box = {dai::Point2f((boundingRect.x + boundingRect.width / 2.0f) / widthF, (boundingRect.y + boundingRect.height / 2.0f) / heightF, true), + dai::Size2f(boundingRect.width / widthF, boundingRect.height / heightF, true), + 0.0f}; + } + + boxes.push_back(box); + } + + return boxes; +} + +} // namespace dai diff --git a/src/opencv/matrixOps.cpp b/src/opencv/matrixOps.cpp new file mode 100644 index 0000000000..28313ebef7 --- /dev/null +++ b/src/opencv/matrixOps.cpp @@ -0,0 +1,53 @@ +#include "depthai/utility/matrixOps.hpp" + +#include + +namespace dai::matrix { + +std::array, 3> cvMatToMatrix3x3(const cv::Mat& cvMat) { + if(cvMat.rows != 3 || cvMat.cols != 3) { + throw std::invalid_argument("Expected a 3x3 cv::Mat to convert to 3x3 matrix."); + } + std::array, 3> matrix; + for(size_t i = 0; i < 3; ++i) { + for(size_t j = 0; j < 3; ++j) { + matrix[i][j] = cvMat.at(i, j); + } + } + return matrix; +} + +std::array, 4> cvMatToMatrix4x4(const cv::Mat& cvMat) { + if(cvMat.rows != 4 || cvMat.cols != 4) { + throw std::invalid_argument("Expected a 4x4 cv::Mat to convert to 4x4 matrix."); + } + std::array, 4> matrix; + for(size_t i = 0; i < 4; ++i) { + for(size_t j = 0; j < 4; ++j) { + matrix[i][j] = cvMat.at(i, j); + } + } + return matrix; +} + +cv::Mat matrix3x3ToCvMat(const std::array, 3>& matrix) { + cv::Mat cvMat(3, 3, CV_32F); + for(size_t i = 0; i < 3; ++i) { + for(size_t j = 0; j < 3; ++j) { + cvMat.at(i, j) = matrix[i][j]; + } + } + return cvMat; +} + +cv::Mat matrix4x4ToCvMat(const std::array, 4>& matrix) { + cv::Mat cvMat(4, 4, CV_32F); + for(size_t i = 0; i < 4; ++i) { + for(size_t j = 0; j < 4; ++j) { + cvMat.at(i, j) = matrix[i][j]; + } + } + return cvMat; +} + +} // namespace dai::matrix diff --git a/src/pipeline/Node.cpp b/src/pipeline/Node.cpp index 47e5981318..1f628da244 100644 --- a/src/pipeline/Node.cpp +++ b/src/pipeline/Node.cpp @@ -333,7 +333,7 @@ Node::OutputMap::OutputMap(Node& parent, std::string name, const Node::OutputDes } } -Node::OutputMap::OutputMap(Node& parent, Node::OutputDescription defaultOutput, bool ref) : OutputMap(parent, "", std::move(defaultOutput), ref){}; +Node::OutputMap::OutputMap(Node& parent, Node::OutputDescription defaultOutput, bool ref) : OutputMap(parent, "", std::move(defaultOutput), ref) {}; Node::Output& Node::OutputMap::operator[](const std::string& key) { if(count({name, key}) == 0) { @@ -366,7 +366,7 @@ Node::InputMap::InputMap(Node& parent, std::string name, Node::InputDescription parent.setInputMapRefs(this); } -Node::InputMap::InputMap(Node& parent, Node::InputDescription description) : InputMap(parent, "", std::move(description)){}; +Node::InputMap::InputMap(Node& parent, Node::InputDescription description) : InputMap(parent, "", std::move(description)) {}; Node::Input& Node::InputMap::operator[](const std::string& key) { if(count({name, key}) == 0) { diff --git a/src/pipeline/datatype/ImgDetectionsT.cpp b/src/pipeline/datatype/ImgDetectionsT.cpp index 64bc4bf5c8..41ab1d0e8e 100644 --- a/src/pipeline/datatype/ImgDetectionsT.cpp +++ b/src/pipeline/datatype/ImgDetectionsT.cpp @@ -72,92 +72,6 @@ std::optional ImgDetectionsT::getSegmentationMask() c return img; } -#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT - -template -void ImgDetectionsT::setCvSegmentationMask(cv::Mat mask) { - if(mask.type() != CV_8UC1) { - throw std::runtime_error("SetCvSegmentationMask: Mask must be of INT8 type, got opencv type " + cv::typeToString(mask.type()) + "."); - } - std::vector dataVec; - if(!mask.isContinuous()) { - for(int i = 0; i < mask.rows; i++) { - dataVec.insert(dataVec.end(), mask.ptr(i), mask.ptr(i) + mask.cols * mask.elemSize()); - } - } else { - dataVec.insert(dataVec.begin(), mask.datastart, mask.dataend); - } - setData(std::move(dataVec)); // Call the rvalue overload to allocate a new memory holder - this->segmentationMaskWidth = mask.cols; - this->segmentationMaskHeight = mask.rows; -} - -template -std::optional ImgDetectionsT::getCvSegmentationMask(cv::MatAllocator* allocator) { - if(data->getData().data() == nullptr) { - return std::nullopt; - } - cv::Size size(getSegmentationMaskWidth(), getSegmentationMaskHeight()); - int type = CV_8UC1; - if(size.width <= 0 || size.height <= 0) { - throw std::runtime_error("Segmentation mask metadata not valid (width or height <= 0)."); - } - - const size_t requiredSize = CV_ELEM_SIZE(type) * static_cast(size.area()); - const size_t actualSize = data->getSize(); - - if(actualSize != requiredSize) { - throw std::runtime_error("Segmentation mask data size does not match the expected size, required " + std::to_string(requiredSize) + ", actual " - + std::to_string(actualSize) + "."); - } - - cv::Mat mask; - mask = cv::Mat(size, type, data->getData().data()); - CV_Assert(mask.type() == CV_8UC1); - - cv::Mat output; - if(allocator != nullptr) { - output.allocator = allocator; - } - (mask).copyTo(output); - return output; -} - -template -std::optional ImgDetectionsT::getCvSegmentationMaskByIndex(uint8_t index, cv::MatAllocator* allocator) { - std::optional mask = getCvSegmentationMask(allocator); - if(!mask.has_value()) { - return std::nullopt; - } - cv::Mat classMask; - cv::compare(*mask, index, classMask, cv::CmpTypes::CMP_EQ); - - return classMask; -} - -template -std::optional ImgDetectionsT::getCvSegmentationMaskByClass(uint8_t semanticClass, cv::MatAllocator* allocator) { - std::optional mask = getCvSegmentationMask(allocator); - if(!mask.has_value()) { - return std::nullopt; - } - cv::Mat classMask = cv::Mat::zeros((*mask).size(), CV_8UC1) + 255; - - for(uint8_t idx = 0; idx < detections.size(); idx++) { - if(detections[idx].label == semanticClass) { - std::optional indexMask = getCvSegmentationMaskByIndex(idx, allocator); - if(!indexMask.has_value()) { - return std::nullopt; - } - classMask.setTo(0, *indexMask); - } - } - - return classMask; -} - -#endif - template class ImgDetectionsT; template class ImgDetectionsT; diff --git a/src/pipeline/datatype/SegmentationMask.cpp b/src/pipeline/datatype/SegmentationMask.cpp index 26a81545ff..755127584e 100644 --- a/src/pipeline/datatype/SegmentationMask.cpp +++ b/src/pipeline/datatype/SegmentationMask.cpp @@ -12,10 +12,6 @@ #include "depthai/common/RotatedRect.hpp" #include "depthai/pipeline/datatype/ImgFrame.hpp" -#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT - #include "utility/ErrorMacros.hpp" -#endif - #ifdef DEPTHAI_ENABLE_PROTOBUF #include "utility/ProtoSerialize.hpp" #endif @@ -234,120 +230,6 @@ bool SegmentationMask::hasValidMask() const { return data->getSize() == width * height; } -#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT -void SegmentationMask::setCvMask(cv::Mat mask) { - if(mask.type() != CV_8UC1) { - throw std::runtime_error("SetCvSegmentationMask: Mask must be of INT8 type, got opencv type " + cv::typeToString(mask.type()) + "."); - } - std::vector dataVec; - if(!mask.isContinuous()) { - for(int i = 0; i < mask.rows; i++) { - dataVec.insert(dataVec.end(), mask.ptr(i), mask.ptr(i) + mask.cols * mask.elemSize()); - } - } else { - dataVec.insert(dataVec.begin(), mask.datastart, mask.dataend); - } - setData(std::move(dataVec)); // Call the rvalue overload to allocate a new memory holder - this->width = mask.cols; - this->height = mask.rows; -} - -cv::Mat SegmentationMask::getCvMask(cv::MatAllocator* allocator) { - cv::Mat mask; - if(data->getData().data() == nullptr || data->getSize() == 0) { - return mask; - } - cv::Size size(static_cast(getWidth()), static_cast(getHeight())); - int type = CV_8UC1; - - const size_t requiredSize = CV_ELEM_SIZE(type) * static_cast(size.area()); - const size_t actualSize = data->getSize(); - - DAI_CHECK_V(actualSize == requiredSize, "Segmentation mask data size does not match the expected size, required {}, actual {}.", requiredSize, actualSize); - - mask = cv::Mat(size, type, data->getData().data()); - - cv::Mat output; - if(allocator != nullptr) { - output.allocator = allocator; - } - (mask).copyTo(output); - return output; -} - -cv::Mat SegmentationMask::getCvMaskByIndex(uint8_t index, cv::MatAllocator* allocator) { - cv::Mat mask = getCvMask(allocator); - if(mask.empty()) { - return cv::Mat(); - } - - cv::Mat indexedMask; - cv::compare(mask, index, indexedMask, cv::CmpTypes::CMP_EQ); - return indexedMask; -} - -std::vector> SegmentationMask::getContour(uint8_t index) { - std::vector> result; - cv::Mat mask = getCvMaskByIndex(index); - if(mask.empty()) { - return result; - } - cv::Mat maskCopy = mask.clone(); - std::vector> contours; - - cv::findContours(maskCopy, contours, cv::RetrievalModes::RETR_EXTERNAL, cv::ContourApproximationModes::CHAIN_APPROX_SIMPLE); - for(const auto& contour : contours) { - std::vector daiContour; - for(const auto& point : contour) { - daiContour.emplace_back(static_cast(point.x), static_cast(point.y), false); - } - result.emplace_back(std::move(daiContour)); - } - - return result; -} - -std::vector SegmentationMask::getBoundingBoxes(uint8_t index, bool calculateRotation) { - std::vector boxes; - cv::Mat mask = getCvMaskByIndex(index); - if(mask.empty()) { - return {}; - } - - cv::Mat maskCopy = mask.clone(); - std::vector> contours; - cv::findContours(maskCopy, contours, cv::RetrievalModes::RETR_EXTERNAL, cv::ContourApproximationModes::CHAIN_APPROX_SIMPLE); - if(contours.empty()) { - return {}; - } - const float widthF = static_cast(width); - const float heightF = static_cast(height); - - for(const auto& contour : contours) { - dai::RotatedRect box; - if(calculateRotation) { - cv::RotatedRect cvBox = cv::minAreaRect(contour); - box = {dai::Point2f(cvBox.center.x / widthF, cvBox.center.y / heightF, true), - dai::Size2f(cvBox.size.width / widthF, cvBox.size.height / heightF, true), - cvBox.angle}; - } else { - cv::Rect boundingRect = cv::boundingRect(contour); - if(boundingRect.width == 0 || boundingRect.height == 0) { - continue; - } - box = {dai::Point2f((boundingRect.x + boundingRect.width / 2.0f) / widthF, (boundingRect.y + boundingRect.height / 2.0f) / heightF, true), - dai::Size2f(boundingRect.width / widthF, boundingRect.height / heightF, true), - 0.0f}; - } - - boxes.push_back(box); - } - - return boxes; -} - -#endif - void SegmentationMask::serialize(std::vector& metadata, DatatypeEnum& datatype) const { metadata = utility::serialize(*this); datatype = this->getDatatype(); diff --git a/src/pipeline/node/Camera.cpp b/src/pipeline/node/Camera.cpp index 5ab2455509..805d8c6a4e 100644 --- a/src/pipeline/node/Camera.cpp +++ b/src/pipeline/node/Camera.cpp @@ -146,20 +146,6 @@ std::shared_ptr Camera::build(CameraBoardSocket boardSocket, isBuilt = true; return std::static_pointer_cast(shared_from_this()); } -#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT -std::shared_ptr Camera::build(CameraBoardSocket boardSocket, ReplayVideo& replay) { - auto cam = build(boardSocket); - cam->setMockIsp(replay); - return cam; -} - -std::shared_ptr Camera::build(ReplayVideo& replay) { - auto cam = build(CameraBoardSocket::AUTO); - cam->setMockIsp(replay); - return cam; -} -#endif - Camera::Properties& Camera::getProperties() { properties.initialControl = initialControl; return properties; @@ -263,38 +249,6 @@ Node::Output* Camera::requestOutput(const Capability& capability, bool onHost) { return pimpl->requestOutput(*this, capability, onHost); } -#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT -Camera& Camera::setMockIsp(ReplayVideo& replay) { - if(!replay.getReplayVideoFile().empty()) { - auto [width, height] = replay.getSize(); - double fps = (double)replay.getFps(); - if(width <= 0 || height <= 0) { - const auto& [vidWidth, vidHeight, vidFps] = utility::getVideoSize(replay.getReplayVideoFile().string()); - width = vidWidth; - height = vidHeight; - fps = vidFps; - } - properties.mockIspWidth = width; - properties.mockIspHeight = height; - properties.mockIspFps = fps; - - auto device = getParentPipeline().getDefaultDevice(); - if(device) { - if(device->getPlatform() == Platform::RVC2) { - replay.setOutFrameType(ImgFrame::Type::YUV420p); - } else { - replay.setOutFrameType(ImgFrame::Type::NV12); - } - } - - replay.out.link(mockIsp); - } else { - throw std::runtime_error("ReplayVideo video path not set"); - } - return *this; -} -#endif - void Camera::buildStage1() { return pimpl->buildStage1(*this); } diff --git a/src/pipeline/node/DetectionNetwork.cpp b/src/pipeline/node/DetectionNetwork.cpp index b6339e134f..35494d18ac 100644 --- a/src/pipeline/node/DetectionNetwork.cpp +++ b/src/pipeline/node/DetectionNetwork.cpp @@ -28,11 +28,8 @@ namespace node { //-------------------------------------------------------------------- DetectionNetwork::DetectionNetwork(const std::shared_ptr& device) - : DeviceNodeGroup(device), - out{detectionParser->out}, - outNetwork{neuralNetwork->out}, - input{neuralNetwork->input}, - passthrough{neuralNetwork->passthrough} {}; + : DeviceNodeGroup(device), out{detectionParser->out}, outNetwork{neuralNetwork->out}, input{neuralNetwork->input}, passthrough{neuralNetwork->passthrough} { + }; // ------------------------------------------------------------------- // Neural Network API // ------------------------------------------------------------------- @@ -71,16 +68,6 @@ std::shared_ptr DetectionNetwork::build(const std::shared_ptr< return std::static_pointer_cast(shared_from_this()); } -#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT -std::shared_ptr DetectionNetwork::build(const std::shared_ptr& input, const Model& model, std::optional fps) { - neuralNetwork->build(input, model, fps); - auto nnArchive = neuralNetwork->getNNArchive(); - DAI_CHECK(nnArchive.has_value(), "NeuralNetwork NNArchive is not set after build."); - detectionParser->setNNArchive(*nnArchive); - return std::static_pointer_cast(shared_from_this()); -} -#endif - NNArchive DetectionNetwork::createNNArchive(NNModelDescription& modelDesc) { // Download model from zoo if(modelDesc.platform.empty()) { diff --git a/src/pipeline/node/NeuralNetwork.cpp b/src/pipeline/node/NeuralNetwork.cpp index 4403979fcb..769be1630a 100644 --- a/src/pipeline/node/NeuralNetwork.cpp +++ b/src/pipeline/node/NeuralNetwork.cpp @@ -46,23 +46,6 @@ std::shared_ptr NeuralNetwork::build(const std::shared_ptr(shared_from_this()); } -#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT -std::shared_ptr NeuralNetwork::build(const std::shared_ptr& input, const Model& model, std::optional fps) { - decodeModel(model); - - ImgFrameCapability cap; - if(fps.has_value()) cap.fps.value = *fps; - cap = getFrameCapability(*nnArchive, cap); - input->setOutFrameType(cap.type.value()); - if(fps.has_value()) { - input->setFps(*fps); - } - input->setSize(std::get>(cap.size.value.value())); - input->out.link(this->input); - return std::static_pointer_cast(shared_from_this()); -} -#endif - void NeuralNetwork::decodeModel(const Model& model) { std::optional nnArchive; diff --git a/src/pipeline/node/ToF.cpp b/src/pipeline/node/ToF.cpp index d94519132d..70700f75b2 100644 --- a/src/pipeline/node/ToF.cpp +++ b/src/pipeline/node/ToF.cpp @@ -15,19 +15,17 @@ namespace node { namespace { -bool usesImageFilters(const std::shared_ptr& device) { #ifdef DEPTHAI_HAVE_OPENCV_SUPPORT +bool usesImageFilters(const std::shared_ptr& device) { return device && device->getPlatform() == Platform::RVC2; -#else - (void)device; - return false; -#endif } +#endif bool usesAutoCamera(const std::shared_ptr& device) { return device && device->getPlatform() == Platform::RVC4; } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT ImageFiltersPresetMode profileToPresetMode(ToFConfig::Profile profile) { switch(profile) { case ToFConfig::Profile::LOW_RANGE: @@ -40,6 +38,7 @@ ImageFiltersPresetMode profileToPresetMode(ToFConfig::Profile profile) { throw std::runtime_error("Unknown ToF profile"); } +#endif ToFConfig::Profile presetModeToProfile(ImageFiltersPresetMode presetMode) { switch(presetMode) { @@ -193,8 +192,8 @@ std::shared_ptr ToF::build(dai::CameraBoardSocket boardSocket, dai::ToFConf tofBase->build(boardSocket, profile, fps); buildAutoCamera(); - const auto presetMode = profileToPresetMode(profile); #ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + const auto presetMode = profileToPresetMode(profile); if(usesImageFilters(getDevice()) && imageFilters) { (*imageFilters)->build(presetMode); } diff --git a/src/utility/EventsManager.cpp b/src/utility/EventsManager.cpp index ea875bc621..b3357d55a3 100644 --- a/src/utility/EventsManager.cpp +++ b/src/utility/EventsManager.cpp @@ -80,14 +80,6 @@ void FileGroup::addFile(std::string fileTag, std::filesystem::path filePath) { addToFileData(fileData, std::move(filePath), std::move(fileTag)); } -void FileGroup::addFile(const std::optional& fileTag, const std::shared_ptr& imgFrame) { - if(!imgFrame) { - throw std::invalid_argument("FileGroup::addFile called with null ImgFrame"); - } - std::string dataFileName = fileTag.value_or("Image"); - addToFileData(fileData, imgFrame, std::move(dataFileName)); -} - void FileGroup::addFile(const std::optional& fileTag, const std::shared_ptr& encodedFrame) { if(!encodedFrame) { throw std::invalid_argument("FileGroup::addFile called with null EncodedFrame"); @@ -108,20 +100,6 @@ void FileGroup::addFile(const std::optional& fileTag, const std::sh addToFileData(fileData, imgDetections, std::move(dataFileName)); } -void FileGroup::addImageDetectionsPair(const std::optional& fileTag, - const std::shared_ptr& imgFrame, - const std::shared_ptr& imgDetections) { - if(!imgFrame) { - throw std::invalid_argument("FileGroup::addImageDetectionsPair called with null ImgFrame"); - } - if(!imgDetections) { - throw std::invalid_argument("FileGroup::addImageDetectionsPair called with null ImgDetections"); - } - std::string dataFileName = fileTag.value_or("ImageDetection"); - addToFileData(fileData, imgFrame, dataFileName); - addToFileData(fileData, imgDetections, std::move(dataFileName)); -} - void FileGroup::addImageDetectionsPair(const std::optional& fileTag, const std::shared_ptr& encodedFrame, const std::shared_ptr& imgDetections) { @@ -146,7 +124,7 @@ void FileGroup::addImageDetectionsPair(const std::optional& fileTag // addToFileData(fileData, nnData, std::move(fileTag)); // } -std::string calculateSHA256Checksum(const std::string& data) { +std::string FileData::calculateSHA256Checksum(const std::string& data) { unsigned char digest[SHA256_DIGEST_LENGTH]; SHA256(reinterpret_cast(data.data()), data.size(), digest); @@ -194,26 +172,6 @@ FileData::FileData(std::filesystem::path filePath, std::string fileTag) : fileTa } } -FileData::FileData(const std::shared_ptr& imgFrame, std::string fileTag) - : mimeType("image/jpeg"), fileTag(std::move(fileTag)), classification(proto::event::PrepareFileUploadClass::IMAGE_COLOR) { - // Convert ImgFrame to bytes - std::vector buffer; - try { - cv::Mat cvFrame = imgFrame->getCvFrame(); - if(!cv::imencode(".jpg", cvFrame, buffer)) { - throw std::runtime_error("ImgFrame encoding failed"); - } - } catch(const cv::Exception& e) { - throw std::runtime_error(std::string("ImgFrame encoding failed due to OpenCV error: ") + e.what()); - } - - std::stringstream ss; - ss.write((const char*)buffer.data(), buffer.size()); - data = ss.str(); - size = data.size(); - checksum = calculateSHA256Checksum(data); -} - FileData::FileData(const std::shared_ptr& encodedFrame, std::string fileTag) : mimeType("image/jpeg"), fileTag(std::move(fileTag)), classification(proto::event::PrepareFileUploadClass::IMAGE_COLOR) { // Convert EncodedFrame to bytes @@ -887,25 +845,6 @@ std::optional EventsManager::sendSnap(const std::string& name, return localID; } -std::optional EventsManager::sendSnap(const std::string& name, - const std::optional& fileTag, - const std::shared_ptr imgFrame, - const std::optional>& imgDetections, - const std::vector& tags, - const std::unordered_map& extras, - const std::function successCallback, - const std::function failureCallback) { - // Create a FileGroup and send a snap containing it - auto fileGroup = std::make_shared(); - if(imgDetections.has_value()) { - fileGroup->addImageDetectionsPair(fileTag, imgFrame, imgDetections.value()); - } else { - fileGroup->addFile(fileTag, imgFrame); - } - - return sendSnap(name, fileGroup, tags, extras, successCallback, failureCallback); -} - bool EventsManager::validateEvent(const proto::event::Event& inputEvent) { // Name const auto& name = inputEvent.name(); diff --git a/src/utility/MemoryWrappers.cpp b/src/utility/MemoryWrappers.cpp index d7228b1549..9aa1bfdf5c 100644 --- a/src/utility/MemoryWrappers.cpp +++ b/src/utility/MemoryWrappers.cpp @@ -2,7 +2,7 @@ // memfd_create wrapper for glibc < 2.27 #if defined(__unix__) && !defined(__APPLE__) - #if(__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 27) + #if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 27) #include #ifndef SYS_memfd_create diff --git a/src/utility/ObjectTrackerImpl.cpp b/src/utility/ObjectTrackerImpl.cpp index 55dfd102b1..9d255e0d38 100644 --- a/src/utility/ObjectTrackerImpl.cpp +++ b/src/utility/ObjectTrackerImpl.cpp @@ -209,7 +209,7 @@ class OCSTracker::State { }; class KalmanBoxTracker { public: - KalmanBoxTracker(){}; + KalmanBoxTracker() {}; KalmanBoxTracker(Eigen::VectorXf bbox_, int cls_, const Point3f& spatialPoint_, int delta_t_ = 3); void update(Eigen::Matrix* bbox_, int cls_, const Point3f* spatialPoint_); void update_spatial_model_dt(float dtSeconds); diff --git a/src/utility/Platform.cpp b/src/utility/Platform.cpp index 23c7dfe9ad..146d102565 100644 --- a/src/utility/Platform.cpp +++ b/src/utility/Platform.cpp @@ -82,7 +82,7 @@ uint32_t getIPv4AddressAsBinary(const std::string& address) { } #if defined(_WIN32) || defined(__USE_W32_SOCKETS) - #if(_WIN32_WINNT <= 0x0501) + #if (_WIN32_WINNT <= 0x0501) binary = inet_addr(address.c_str()); // for XP #else inet_pton(AF_INET, address.c_str(), &binary); // for Vista or higher @@ -414,7 +414,7 @@ void FSLock::lock() { throw std::runtime_error("Failed to open file: " + lockPath.string()); } - struct flock fl {}; + struct flock fl{}; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; @@ -439,7 +439,7 @@ void FSLock::unlock() { CloseHandle(handle); handle = INVALID_HANDLE_VALUE; #else - struct flock fl {}; + struct flock fl{}; fl.l_type = F_UNLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; diff --git a/src/utility/RecordReplay.cpp b/src/utility/RecordReplay.cpp index bac8a249ea..4c7f3e9906 100644 --- a/src/utility/RecordReplay.cpp +++ b/src/utility/RecordReplay.cpp @@ -234,12 +234,5 @@ std::string matchTo(const std::vector& deviceIds, const std::vector return deviceId; } -#ifndef DEPTHAI_HAVE_OPENCV_SUPPORT -std::tuple getVideoSize(const std::string& filePath) { - (void)filePath; - throw std::runtime_error("OpenCV is required to get video size"); -} -#endif - } // namespace utility } // namespace dai diff --git a/src/utility/RecordReplayImpl.hpp b/src/utility/RecordReplayImpl.hpp index 801550fa1f..eb765e8131 100644 --- a/src/utility/RecordReplayImpl.hpp +++ b/src/utility/RecordReplayImpl.hpp @@ -164,7 +164,9 @@ bool allMatch(const std::vector& v1, const std::vector std::string matchTo(const std::vector& deviceIds, const std::vector& filenames, const std::vector& nodenames); +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT std::tuple getVideoSize(const std::string& filePath); +#endif } // namespace utility } // namespace dai diff --git a/src/utility/matrixOps.cpp b/src/utility/matrixOps.cpp index 08cfdbba1e..d6e4018e57 100644 --- a/src/utility/matrixOps.cpp +++ b/src/utility/matrixOps.cpp @@ -662,52 +662,6 @@ std::array, 4> invertSe3Matrix4x4(const std::array, 3> cvMatToMatrix3x3(const cv::Mat& cvMat) { - if(cvMat.rows != 3 || cvMat.cols != 3) { - throw std::invalid_argument("Expected a 3x3 cv::Mat to convert to 3x3 matrix."); - } - std::array, 3> matrix; - for(size_t i = 0; i < 3; ++i) { - for(size_t j = 0; j < 3; ++j) { - matrix[i][j] = cvMat.at(i, j); - } - } - return matrix; -} -std::array, 4> cvMatToMatrix4x4(const cv::Mat& cvMat) { - if(cvMat.rows != 4 || cvMat.cols != 4) { - throw std::invalid_argument("Expected a 4x4 cv::Mat to convert to 4x4 matrix."); - } - std::array, 4> matrix; - for(size_t i = 0; i < 4; ++i) { - for(size_t j = 0; j < 4; ++j) { - matrix[i][j] = cvMat.at(i, j); - } - } - return matrix; -} -cv::Mat matrix3x3ToCvMat(const std::array, 3>& matrix) { - cv::Mat cvMat(3, 3, CV_32F); - for(size_t i = 0; i < 3; ++i) { - for(size_t j = 0; j < 3; ++j) { - cvMat.at(i, j) = matrix[i][j]; - } - } - return cvMat; -} -cv::Mat matrix4x4ToCvMat(const std::array, 4>& matrix) { - cv::Mat cvMat(4, 4, CV_32F); - for(size_t i = 0; i < 4; ++i) { - for(size_t j = 0; j < 4; ++j) { - cvMat.at(i, j) = matrix[i][j]; - } - } - return cvMat; -} - -#endif - std::vector> toVecMatrix4x4(const std::array, 4>& m) { std::vector> result(4, std::vector(4)); for(int i = 0; i < 4; ++i) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9b00f0c190..57a1d17c1a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -318,7 +318,7 @@ function(dai_add_test test_name test_src) # Link to core and Catch2 testing framework set(DEPTHAI_TARGET depthai::core) - if(NOT DEPTHAI_MERGED_TARGET) + if(NOT DEPTHAI_MERGED_TARGET AND DEPTHAI_HAVE_OPENCV_SUPPORT) set(DEPTHAI_TARGET depthai::opencv) endif() target_link_libraries(${test_name} PRIVATE ${DEPTHAI_TARGET} ${OpenCV_LIBS} Catch2::Catch2WithMain Threads::Threads spdlog::spdlog trompeloeil) @@ -580,22 +580,30 @@ if(DEPTHAI_FETCH_ARTIFACTS) endif() # Vpp node tests -dai_add_test(vpp_test src/ondevice_tests/vpp_test.cpp) -dai_set_test_labels(vpp_test ondevice rvc4 ci) +if(DEPTHAI_HAVE_OPENCV_SUPPORT) + dai_add_test(vpp_test src/ondevice_tests/vpp_test.cpp) + dai_set_test_labels(vpp_test ondevice rvc4 ci) +endif() # GPUStereo node (device execution) test dai_add_test(gpu_stereo_device_test src/ondevice_tests/gpu_stereo_node_test.cpp) dai_set_test_labels(gpu_stereo_device_test ondevice rvc4 ci) -# Dynamic calibration tests -if(DEPTHAI_FETCH_ARTIFACTS) - dai_add_test(dynamic_calibration_test src/ondevice_tests/dynamic_calibration_test.cpp) - dai_set_test_labels(dynamic_calibration_test ondevice rvc2_all rvc4 ci) - target_compile_definitions(dynamic_calibration_test PRIVATE RECORDING_PATH="${dynamic_calibration_test_data}") -endif() +# Dynamic calibration and AutoCalibration tests +if(DEPTHAI_MERGED_TARGET) + if(DEPTHAI_FETCH_ARTIFACTS) + dai_add_test(dynamic_calibration_test src/ondevice_tests/dynamic_calibration_test.cpp) + dai_set_test_labels(dynamic_calibration_test ondevice rvc2_all rvc4 ci) + target_compile_definitions(dynamic_calibration_test PRIVATE RECORDING_PATH="${dynamic_calibration_test_data}") + endif() + + dai_add_test(dynamic_calibration_onhost_test src/onhost_tests/dynamic_calibration_test.cpp) + dai_set_test_labels(dynamic_calibration_onhost_test onhost) -dai_add_test(dynamic_calibration_onhost_test src/onhost_tests/dynamic_calibration_test.cpp) -dai_set_test_labels(dynamic_calibration_onhost_test onhost) + # AutoCalibration test + dai_add_test(auto_calibration_test src/ondevice_tests/pipeline/node/auto_calibration_test.cpp) + dai_set_test_labels(auto_calibration_test ondevice rvc4 rvc2_all ci) +endif() dai_add_test(flash_eeprom_fields_test src/ondevice_tests/flash_eeprom_fields_test.cpp) dai_set_test_labels(flash_eeprom_fields_test ondevice rvc2_all rvc4) @@ -675,9 +683,11 @@ dai_set_test_labels(rgbd_test ondevice rvc2_all rvc4 ci) dai_add_test(input_output_naming_test src/ondevice_tests/input_output_naming_test.cpp) dai_set_test_labels(input_output_naming_test ondevice rvc2_all rvc4 rvc4rgb ci) -# Resolutions test -dai_add_test(resolutions_test src/ondevice_tests/resolutions_test.cpp) -dai_set_test_labels(resolutions_test ondevice) # TODO(jakob) Make the test runnable in CI +if(DEPTHAI_HAVE_OPENCV_SUPPORT) + # Resolutions test + dai_add_test(resolutions_test src/ondevice_tests/resolutions_test.cpp) + dai_set_test_labels(resolutions_test ondevice) # TODO(jakob) Make the test runnable in CI +endif() # Serialization test dai_add_test(serialization_test src/onhost_tests/serialization_test.cpp) @@ -807,7 +817,7 @@ dai_add_test(stereo_depth_node_test src/ondevice_tests/stereo_depth_node_test.cp dai_set_test_labels(stereo_depth_node_test ondevice rvc2_all rvc4 ci) # ImageManip test -if(DEPTHAI_FETCH_ARTIFACTS) +if(DEPTHAI_FETCH_ARTIFACTS AND DEPTHAI_HAVE_OPENCV_SUPPORT) dai_add_test(image_manip_node_test src/ondevice_tests/pipeline/node/image_manip_test.cpp) target_compile_definitions(image_manip_node_test PRIVATE LENNA_PATH="${lenna_png}") dai_set_test_labels(image_manip_node_test ondevice rvc2_all rvc4 rvc4rgb ci) @@ -841,7 +851,7 @@ if(DEPTHAI_FETCH_ARTIFACTS) endif() # Record & Replay tests -if(DEPTHAI_FETCH_ARTIFACTS) +if(DEPTHAI_FETCH_ARTIFACTS AND DEPTHAI_MERGED_TARGET) dai_add_test(record_replay_test src/ondevice_tests/pipeline/node/record_replay_test.cpp) dai_set_test_labels(record_replay_test ondevice rvc2_all rvc4) # TODO(Morato) add to CI once the test is stable target_compile_definitions(record_replay_test PRIVATE RECORDING_PATH="${recording_path}") @@ -863,7 +873,7 @@ dai_set_test_labels(camera_fps_config_part_2_test ondevice rvc2_all rvc4 ci nore set_property(TEST camera_fps_config_part_2_test APPEND PROPERTY ENVIRONMENT "DEPTHAI_AUTOCALIBRATION=OFF") # VideoEncoder test -if(DEPTHAI_FETCH_ARTIFACTS) +if(DEPTHAI_FETCH_ARTIFACTS AND DEPTHAI_MERGED_TARGET) dai_add_test(video_encoder_test src/ondevice_tests/video_encoder_test.cpp) dai_set_test_labels(video_encoder_test ondevice rvc2 usb rvc4 rvc4rgb ci) target_compile_definitions(video_encoder_test PRIVATE VIDEO_PATH="${construction_vest}") @@ -897,10 +907,6 @@ dai_set_test_labels(neural_assisted_stereo_node_test ondevice rvc4 ci) dai_add_test(gate_node_test src/ondevice_tests/pipeline/node/gate_node_tests.cpp) dai_set_test_labels(gate_node_test ondevice rvc4 rvc2_all ci noreplayci) -# AutoCalibration test -dai_add_test(auto_calibration_test src/ondevice_tests/pipeline/node/auto_calibration_test.cpp) -dai_set_test_labels(auto_calibration_test ondevice rvc4 rvc2_all ci) - # Crashdump test dai_add_test(crashdump_test src/ondevice_tests/crashdump_test.cpp) dai_set_test_labels(crashdump_test ondevice rvc2_all rvc4 ci noreplayci) diff --git a/tests/src/ondevice_tests/encoded_frame_test.cpp b/tests/src/ondevice_tests/encoded_frame_test.cpp index f2a7c001a6..3df232c7fa 100644 --- a/tests/src/ondevice_tests/encoded_frame_test.cpp +++ b/tests/src/ondevice_tests/encoded_frame_test.cpp @@ -2,7 +2,10 @@ #include #include #include -#include + +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + #include +#endif #include "depthai/pipeline/Pipeline.hpp" #include "depthai/pipeline/datatype/EncodedFrame.hpp" @@ -27,6 +30,8 @@ TEST_CASE("OLD_OUTPUT") { } } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + TEST_CASE("JPEG_ENCODING_LOSSLESS") { dai::Pipeline pipeline; if(pipeline.getDefaultDevice()->getPlatform() == dai::Platform::RVC4) { @@ -84,6 +89,8 @@ TEST_CASE("JPEG_ENCODING_LOSSLESS") { std::filesystem::remove("encoded"); } +#endif + TEST_CASE("JPEG_ENCODING_LOSSY") { dai::Pipeline pipeline; auto camNode = pipeline.create()->build(); diff --git a/tests/src/ondevice_tests/filesystem_test.cpp b/tests/src/ondevice_tests/filesystem_test.cpp index 28b96ac35a..5df77f1932 100644 --- a/tests/src/ondevice_tests/filesystem_test.cpp +++ b/tests/src/ondevice_tests/filesystem_test.cpp @@ -5,7 +5,7 @@ using namespace Catch::Matchers; // Include depthai library #include -#if(__cplusplus >= 201703L) || (_MSVC_LANG >= 201703L) +#if (__cplusplus >= 201703L) || (_MSVC_LANG >= 201703L) #include #endif #include diff --git a/tests/src/ondevice_tests/img_transformation_test.cpp b/tests/src/ondevice_tests/img_transformation_test.cpp index e00aef4416..980fb0e370 100644 --- a/tests/src/ondevice_tests/img_transformation_test.cpp +++ b/tests/src/ondevice_tests/img_transformation_test.cpp @@ -16,15 +16,18 @@ #include #include #include -#include -#include -#include #include #include #include #include #include +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + #include + #include + #include +#endif + #include "depthai/common/CameraBoardSocket.hpp" #include "depthai/common/Extrinsics.hpp" #include "depthai/common/ImgTransformations.hpp" @@ -241,6 +244,8 @@ float calculateStdDev(const std::vector& errors, float mean) { return std::sqrt(variance); } +#ifdef DEPTHAI_MERGED_TARGET + std::tuple parseTransformations(const std::filesystem::path& refMetadataPath, const std::filesystem::path& targetMetadataPath) { dai::Pipeline pipeline{false}; @@ -334,6 +339,66 @@ nlohmann::json processVideo(const std::filesystem::path& videoPath) { }); } +TEST_CASE("projectPoints test") { + const std::filesystem::path& baseFolder = getTransformationTestDataFolder(); + + if(!std::filesystem::exists(baseFolder)) { + WARN("Capture folder not found, skipping projectPoints test: " << baseFolder.string()); + return; + } + + nlohmann::json currentResults; + int testIterator = 0; + for(const auto& directory : std::filesystem::directory_iterator(baseFolder)) { + if(!directory.is_directory()) continue; + const auto capturePath = directory.path(); + const std::filesystem::path folder = std::filesystem::path(capturePath); + const auto result = processVideo(folder); + INFO(result.dump(2)); + const int errorCount = result.value("projection_error_count", 0); + const double meanProjectionErrorPx = result.value("mean_projection_error_px", std::numeric_limits::quiet_NaN()); + const double medianProjectionErrorPx = result.value("median_projection_error_px", std::numeric_limits::quiet_NaN()); + const double stdProjectionErrorPx = result.value("std_projection_error_px", std::numeric_limits::quiet_NaN()); + + REQUIRE(errorCount > 0); + REQUIRE(std::isfinite(meanProjectionErrorPx)); + REQUIRE(std::isfinite(medianProjectionErrorPx)); + REQUIRE(std::isfinite(stdProjectionErrorPx)); + + currentResults[folder.stem().string()] = result; + testIterator++; + } + + REQUIRE(testIterator > 0); + + const std::filesystem::path outputPath = baseFolder / "aggregated_results.json"; + std::ifstream inputFile(outputPath); + REQUIRE(inputFile.is_open()); + + const auto aggregatedResults = nlohmann::json::parse(inputFile); + REQUIRE(aggregatedResults.is_object()); + + for(const auto& [captureName, currentResult] : currentResults.items()) { + INFO("Comparing results for capture: " << captureName); + REQUIRE(aggregatedResults.contains(captureName)); + + const auto& aggregatedResult = aggregatedResults.at(captureName); + const double currentMeanProjectionErrorPx = currentResult.value("mean_projection_error_px", std::numeric_limits::infinity()); + const double aggregatedMeanProjectionErrorPx = aggregatedResult.value("mean_projection_error_px", std::numeric_limits::quiet_NaN()); + constexpr double meanProjectionErrorTolerancePx = 1e-4; + + REQUIRE(std::isfinite(currentMeanProjectionErrorPx)); + REQUIRE(std::isfinite(aggregatedMeanProjectionErrorPx)); + + INFO("capture=" << captureName << ", current=" << currentMeanProjectionErrorPx << ", baseline=" << aggregatedMeanProjectionErrorPx + << ", tolerance=" << meanProjectionErrorTolerancePx); + + REQUIRE(currentMeanProjectionErrorPx <= aggregatedMeanProjectionErrorPx + meanProjectionErrorTolerancePx); + } +} + +#endif + std::filesystem::path extractTransformationTestDataFolder() { const std::filesystem::path archivePath{TRANSFORMATION_TEST_DATA}; if(!std::filesystem::exists(archivePath)) { @@ -648,6 +713,8 @@ TEST_CASE("ImgTransformation isAlignedTo distortion coefficients handling") { REQUIRE_FALSE(base.isAlignedTo(nonZero)); } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + TEST_CASE("AlignmentUtilities distort point") { dai::Point3f point3D{40, 75, 150.0f}; cv::Point3f point3Dcv(point3D.x, point3D.y, point3D.z); @@ -834,60 +901,4 @@ TEST_CASE("AlignmentUtilities undistort point") { } } -TEST_CASE("projectPoints test") { - const std::filesystem::path& baseFolder = getTransformationTestDataFolder(); - - if(!std::filesystem::exists(baseFolder)) { - WARN("Capture folder not found, skipping projectPoints test: " << baseFolder.string()); - return; - } - - nlohmann::json currentResults; - int testIterator = 0; - for(const auto& directory : std::filesystem::directory_iterator(baseFolder)) { - if(!directory.is_directory()) continue; - const auto capturePath = directory.path(); - const std::filesystem::path folder = std::filesystem::path(capturePath); - const auto result = processVideo(folder); - INFO(result.dump(2)); - const int errorCount = result.value("projection_error_count", 0); - const double meanProjectionErrorPx = result.value("mean_projection_error_px", std::numeric_limits::quiet_NaN()); - const double medianProjectionErrorPx = result.value("median_projection_error_px", std::numeric_limits::quiet_NaN()); - const double stdProjectionErrorPx = result.value("std_projection_error_px", std::numeric_limits::quiet_NaN()); - - REQUIRE(errorCount > 0); - REQUIRE(std::isfinite(meanProjectionErrorPx)); - REQUIRE(std::isfinite(medianProjectionErrorPx)); - REQUIRE(std::isfinite(stdProjectionErrorPx)); - - currentResults[folder.stem().string()] = result; - testIterator++; - } - - REQUIRE(testIterator > 0); - - const std::filesystem::path outputPath = baseFolder / "aggregated_results.json"; - std::ifstream inputFile(outputPath); - REQUIRE(inputFile.is_open()); - - const auto aggregatedResults = nlohmann::json::parse(inputFile); - REQUIRE(aggregatedResults.is_object()); - - for(const auto& [captureName, currentResult] : currentResults.items()) { - INFO("Comparing results for capture: " << captureName); - REQUIRE(aggregatedResults.contains(captureName)); - - const auto& aggregatedResult = aggregatedResults.at(captureName); - const double currentMeanProjectionErrorPx = currentResult.value("mean_projection_error_px", std::numeric_limits::infinity()); - const double aggregatedMeanProjectionErrorPx = aggregatedResult.value("mean_projection_error_px", std::numeric_limits::quiet_NaN()); - constexpr double meanProjectionErrorTolerancePx = 1e-4; - - REQUIRE(std::isfinite(currentMeanProjectionErrorPx)); - REQUIRE(std::isfinite(aggregatedMeanProjectionErrorPx)); - - INFO("capture=" << captureName << ", current=" << currentMeanProjectionErrorPx << ", baseline=" << aggregatedMeanProjectionErrorPx - << ", tolerance=" << meanProjectionErrorTolerancePx); - - REQUIRE(currentMeanProjectionErrorPx <= aggregatedMeanProjectionErrorPx + meanProjectionErrorTolerancePx); - } -} +#endif diff --git a/tests/src/ondevice_tests/neural_depth_node_test.cpp b/tests/src/ondevice_tests/neural_depth_node_test.cpp index c430618b78..ca26d71ce5 100644 --- a/tests/src/ondevice_tests/neural_depth_node_test.cpp +++ b/tests/src/ondevice_tests/neural_depth_node_test.cpp @@ -101,6 +101,8 @@ void testNeuralDepthModelBasic(dai::DeviceModelZoo model, float minFps) { } } // namespace +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + constexpr size_t FRAMES_TO_SAMPLE = 12; struct DepthStats { @@ -238,6 +240,8 @@ TEST_CASE("NeuralDepth replay aligns with StereoDepth medians") { } } +#endif + TEST_CASE("Test NeuralDepth node live-camera models") { const auto& testCase = GENERATE_REF(from_range(kLiveCameraTestCases)); INFO("Model: " << magic_enum::enum_name(testCase.model)); diff --git a/tests/src/ondevice_tests/pipeline/node/detection_parser_test.cpp b/tests/src/ondevice_tests/pipeline/node/detection_parser_test.cpp index b6964ac41b..2e3ac717a0 100644 --- a/tests/src/ondevice_tests/pipeline/node/detection_parser_test.cpp +++ b/tests/src/ondevice_tests/pipeline/node/detection_parser_test.cpp @@ -224,6 +224,8 @@ void validateSmokeKeypoints(const std::vector& keypoints, std::si } } +#ifdef DEPTHAI_MERGED_TARGET + void runDetectionParserReplayTest(const std::string& modelName, const std::filesystem::path& groundTruthPath, const std::filesystem::path& testVideoPath) { dai::Pipeline p; auto device = p.getDefaultDevice(); @@ -353,6 +355,8 @@ void runDetectionParserReplaySmokeTest(const std::string& modelName, REQUIRE(foundExpectedExtraOutput); } +#endif + TEST_CASE("DetectionParser can set properties") { dai::node::DetectionParser parser; SECTION("Yolo v6 base") { @@ -490,6 +494,8 @@ TEST_CASE("DetectionParser can be build using a specific head") { REQUIRE(parser->properties.parser.classes == 1); } +#ifdef DEPTHAI_MERGED_TARGET + TEST_CASE("DetectionParser replay test") { const std::filesystem::path yoloV6R2Coco512x288GroundTruth{YOLO_V6_R2_COCO_512x288_GROUND_TRUTH}; const std::filesystem::path yoloV6R2Coco512x384GroundTruth{YOLO_V6_R2_COCO_512x384_GROUND_TRUTH}; @@ -538,6 +544,8 @@ TEST_CASE("DetectionParser YOLO26 smoke test") { } } +#endif + #ifdef DEPTHAI_HAVE_OPENCV_SUPPORT TEST_CASE("DetectionParser segmentation mask test") { const std::string modelName = "yolov8-instance-segmentation-large:coco-640x352:701031f"; diff --git a/tests/src/ondevice_tests/pipeline/node/gate_node_tests.cpp b/tests/src/ondevice_tests/pipeline/node/gate_node_tests.cpp index 039251b2b1..2d26251f8c 100644 --- a/tests/src/ondevice_tests/pipeline/node/gate_node_tests.cpp +++ b/tests/src/ondevice_tests/pipeline/node/gate_node_tests.cpp @@ -1,6 +1,5 @@ #include #include -#include #include "depthai/depthai.hpp" #include "depthai/pipeline/node/Gate.hpp" diff --git a/tests/src/ondevice_tests/pipeline/node/neural_assisted_stereo_node_test.cpp b/tests/src/ondevice_tests/pipeline/node/neural_assisted_stereo_node_test.cpp index 8d4bb50ca3..b6bc099b16 100644 --- a/tests/src/ondevice_tests/pipeline/node/neural_assisted_stereo_node_test.cpp +++ b/tests/src/ondevice_tests/pipeline/node/neural_assisted_stereo_node_test.cpp @@ -7,6 +7,8 @@ #include "depthai/pipeline/node/Camera.hpp" #include "depthai/pipeline/node/NeuralAssistedStereo.hpp" +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + TEST_CASE("[NeuralAssistedStereo] Check that I am getting output from the subnodes") { // Create pipeline dai::Pipeline p; @@ -67,6 +69,8 @@ TEST_CASE("[NeuralAssistedStereo] Check that I am getting output from the subnod REQUIRE(disparityGotCv.cols == disparityGotCv.cols); } +#endif + TEST_CASE("[NeuralAssistedStereo] Case without rectification") { // Create pipeline dai::Pipeline p; diff --git a/tests/src/ondevice_tests/pipeline/node/neural_network_node_test.cpp b/tests/src/ondevice_tests/pipeline/node/neural_network_node_test.cpp index c723f408fe..03a1d58f89 100644 --- a/tests/src/ondevice_tests/pipeline/node/neural_network_node_test.cpp +++ b/tests/src/ondevice_tests/pipeline/node/neural_network_node_test.cpp @@ -1,7 +1,10 @@ #include #include #include -#include + +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + #include +#endif #include "depthai/common/CameraBoardSocket.hpp" #include "depthai/depthai.hpp" @@ -50,65 +53,6 @@ TEST_CASE("NNArchive API") { } } -TEST_CASE("Multi-Input NeuralNetwork API") { - dai::Pipeline p; - auto camera = p.create()->build(dai::CameraBoardSocket::CAM_A); - auto platformStr = p.getDefaultDevice()->getPlatformAsString(); - auto platform = p.getDefaultDevice()->getPlatform(); - auto inputType = dai::ImgFrame::Type::RGB888p; - if(platform == dai::Platform::RVC2 || platform == dai::Platform::RVC3) { - inputType = dai::ImgFrame::Type::BGR888p; - } else if(platform == dai::Platform::RVC4) { - inputType = dai::ImgFrame::Type::BGR888i; - } else { - FAIL("Unknown platform"); - } - auto description = dai::NNModelDescription{"depthai-test-models/simple-concatenate-model", platformStr}; - auto nn = p.create(); - nn->setModelPath(dai::getModelFromZoo(description)); - - auto* cameraInput = camera->requestOutput(std::make_pair(256, 256), inputType); - cameraInput->link(nn->inputs["image1"]); - auto lennaInputQueue = nn->inputs["image2"].createInputQueue(); - - // Load and prepare Lenna image (assuming path provided in a macro IMAGE_PATH) - cv::Mat lenaImage = cv::imread(LENNA_PATH, cv::IMREAD_COLOR); - REQUIRE(!lenaImage.empty()); // Ensure the image is loaded correctly - cv::resize(lenaImage, lenaImage, cv::Size(256, 256)); - - // Convert the image to dai::ImgFrame - auto daiLenaImage = std::make_shared(); - daiLenaImage->setCvFrame(lenaImage, inputType); - - // Create output queue - auto outputQueue = nn->out.createOutputQueue(); - - // Reuse the second input image to avoid sending every time - nn->inputs["image2"].setReusePreviousMessage(true); - auto passThroughQueue = nn->passthroughs["image2"].createOutputQueue(); - - // Start the pipeline - p.start(); - - // Send the Lenna image to the second input queue - lennaInputQueue->send(daiLenaImage); - - // Process output for 10 tensors and verify results - for(int i = 0; i < 10; i++) { - auto tensor = outputQueue->get(); - auto passThroughTensor = passThroughQueue->get(); - - REQUIRE(tensor != nullptr); - REQUIRE(tensor->getAllLayerNames().size() == 1); - auto firstTensor = tensor->getFirstTensor(); - REQUIRE(firstTensor.shape().size() == 4); - REQUIRE(firstTensor.shape()[0] == 1); - - // Verify the pass-through tensor came through - REQUIRE(passThroughTensor != nullptr); - } -} - TEST_CASE("Combined Input NeuralNetwork API") { dai::Pipeline p; @@ -193,6 +137,67 @@ TEST_CASE("Combined Input NeuralNetwork API") { REQUIRE(rightSideOK); } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + +TEST_CASE("Multi-Input NeuralNetwork API") { + dai::Pipeline p; + auto camera = p.create()->build(dai::CameraBoardSocket::CAM_A); + auto platformStr = p.getDefaultDevice()->getPlatformAsString(); + auto platform = p.getDefaultDevice()->getPlatform(); + auto inputType = dai::ImgFrame::Type::RGB888p; + if(platform == dai::Platform::RVC2 || platform == dai::Platform::RVC3) { + inputType = dai::ImgFrame::Type::BGR888p; + } else if(platform == dai::Platform::RVC4) { + inputType = dai::ImgFrame::Type::BGR888i; + } else { + FAIL("Unknown platform"); + } + auto description = dai::NNModelDescription{"depthai-test-models/simple-concatenate-model", platformStr}; + auto nn = p.create(); + nn->setModelPath(dai::getModelFromZoo(description)); + + auto* cameraInput = camera->requestOutput(std::make_pair(256, 256), inputType); + cameraInput->link(nn->inputs["image1"]); + auto lennaInputQueue = nn->inputs["image2"].createInputQueue(); + + // Load and prepare Lenna image (assuming path provided in a macro IMAGE_PATH) + cv::Mat lenaImage = cv::imread(LENNA_PATH, cv::IMREAD_COLOR); + REQUIRE(!lenaImage.empty()); // Ensure the image is loaded correctly + cv::resize(lenaImage, lenaImage, cv::Size(256, 256)); + + // Convert the image to dai::ImgFrame + auto daiLenaImage = std::make_shared(); + daiLenaImage->setCvFrame(lenaImage, inputType); + + // Create output queue + auto outputQueue = nn->out.createOutputQueue(); + + // Reuse the second input image to avoid sending every time + nn->inputs["image2"].setReusePreviousMessage(true); + auto passThroughQueue = nn->passthroughs["image2"].createOutputQueue(); + + // Start the pipeline + p.start(); + + // Send the Lenna image to the second input queue + lennaInputQueue->send(daiLenaImage); + + // Process output for 10 tensors and verify results + for(int i = 0; i < 10; i++) { + auto tensor = outputQueue->get(); + auto passThroughTensor = passThroughQueue->get(); + + REQUIRE(tensor != nullptr); + REQUIRE(tensor->getAllLayerNames().size() == 1); + auto firstTensor = tensor->getFirstTensor(); + REQUIRE(firstTensor.shape().size() == 4); + REQUIRE(firstTensor.shape()[0] == 1); + + // Verify the pass-through tensor came through + REQUIRE(passThroughTensor != nullptr); + } +} + TEST_CASE("Multi threaded test") { // Create pipeline dai::Pipeline p; @@ -253,3 +258,5 @@ TEST_CASE("Multi threaded test") { REQUIRE(report != nullptr); } } + +#endif diff --git a/tests/src/ondevice_tests/pipeline/node/object_tracker_test.cpp b/tests/src/ondevice_tests/pipeline/node/object_tracker_test.cpp index 51657f9eff..cfa453f9bb 100644 --- a/tests/src/ondevice_tests/pipeline/node/object_tracker_test.cpp +++ b/tests/src/ondevice_tests/pipeline/node/object_tracker_test.cpp @@ -18,6 +18,8 @@ bool has_duplicates(const Container& items, KeyFunc key_func) { return false; // no duplicates } +#ifdef DEPTHAI_MERGED_TARGET + TEST_CASE("Object Tracker smallest ID assignment policy") { // Create pipeline dai::Pipeline pipeline; @@ -106,6 +108,8 @@ TEST_CASE("Object Tracker unique ID assignment policy") { REQUIRE(counter > 0); // Ensure that at least some tracklets were processed } +#endif + TEST_CASE("Object Tracker transformation") { // Create pipeline dai::Pipeline pipeline; diff --git a/tests/src/ondevice_tests/pipeline/node/spatial_location_calculator_test.cpp b/tests/src/ondevice_tests/pipeline/node/spatial_location_calculator_test.cpp index 767d86b302..b0cf444ed1 100644 --- a/tests/src/ondevice_tests/pipeline/node/spatial_location_calculator_test.cpp +++ b/tests/src/ondevice_tests/pipeline/node/spatial_location_calculator_test.cpp @@ -26,6 +26,8 @@ using Catch::Approx; namespace { +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + void setDepthValue(cv::Mat& depth, int xStart, int yStart, int xEnd, int yEnd, std::uint16_t value) { for(int y = yStart; y < yEnd; ++y) { for(int x = xStart; x < xEnd; ++x) { @@ -51,6 +53,8 @@ std::shared_ptr createDepthFrame(const cv::Mat& depthMat, const s return depthFrame; } +#endif + std::shared_ptr createDetectionFrameWithManipulation(const std::shared_ptr& depthFrame, unsigned width, unsigned height, @@ -206,6 +210,8 @@ TEST_CASE("SpatialLocationCalculatorConfig tracks ROI updates") { CHECK(rois[1].roi.height == Approx(overrideB.roi.height)); } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + TEST_CASE("SpatialLocationCalculator synthetic depth data test") { constexpr unsigned width = 640; constexpr unsigned height = 480; @@ -998,3 +1004,5 @@ TEST_CASE("Spatial detections handle segmentation and keypoints together") { const auto& kp = keypoints.at(0); REQUIRE(kp.spatialCoordinates.z == Approx(0).margin(1.0F)); } + +#endif diff --git a/tests/src/ondevice_tests/pipeline_debugging_rvc2_test.cpp b/tests/src/ondevice_tests/pipeline_debugging_rvc2_test.cpp index b7cf7c41e5..a2ef78d95e 100644 --- a/tests/src/ondevice_tests/pipeline_debugging_rvc2_test.cpp +++ b/tests/src/ondevice_tests/pipeline_debugging_rvc2_test.cpp @@ -10,6 +10,8 @@ #define VIDEO_DURATION_SECONDS 5 +#ifdef DEPTHAI_MERGED_TARGET + TEST_CASE("Object Tracker Pipeline Debugging") { // Create pipeline dai::Pipeline pipeline; @@ -76,6 +78,8 @@ TEST_CASE("Object Tracker Pipeline Debugging") { } } +#endif + TEST_CASE("FPS check") { // Create pipeline dai::Pipeline pipeline; diff --git a/tests/src/ondevice_tests/pipeline_debugging_rvc4_test.cpp b/tests/src/ondevice_tests/pipeline_debugging_rvc4_test.cpp index 8bdc939983..f3cc483237 100644 --- a/tests/src/ondevice_tests/pipeline_debugging_rvc4_test.cpp +++ b/tests/src/ondevice_tests/pipeline_debugging_rvc4_test.cpp @@ -10,6 +10,8 @@ #define VIDEO_DURATION_SECONDS 5 +#ifdef DEPTHAI_MERGED_TARGET + TEST_CASE("Object Tracker Pipeline Debugging") { // Create pipeline dai::Pipeline pipeline; @@ -78,6 +80,8 @@ TEST_CASE("Object Tracker Pipeline Debugging") { } } +#endif + TEST_CASE("FPS check") { // Create pipeline dai::Pipeline pipeline; diff --git a/tests/src/ondevice_tests/resolutions_test.cpp b/tests/src/ondevice_tests/resolutions_test.cpp index d7643401d9..0e35782d66 100644 --- a/tests/src/ondevice_tests/resolutions_test.cpp +++ b/tests/src/ondevice_tests/resolutions_test.cpp @@ -2,13 +2,13 @@ #include #include #include -#include #include // Libraries #include #include #include +#include #include // Includes common necessary includes for development using depthai library @@ -20,7 +20,13 @@ #include "image_comparator.hpp" static const std::vector> bestResolutions = { - {320, 240}, {640, 480}, {960, 720}, {1280, 960}, {1440, 1080}, {1920, 1440}, {4000, 3000}, + {320, 240}, + {640, 480}, + {960, 720}, + {1280, 960}, + {1440, 1080}, + {1920, 1440}, + {4000, 3000}, // TODO(jakgra) this is probably sensor dependent. // add the max resolution with nice FOV // When we add support for getConnectedCameraFeatures() on rvc4 revisit this diff --git a/tests/src/ondevice_tests/video_encoder_test.cpp b/tests/src/ondevice_tests/video_encoder_test.cpp index 82813ee6b0..7edd5832de 100644 --- a/tests/src/ondevice_tests/video_encoder_test.cpp +++ b/tests/src/ondevice_tests/video_encoder_test.cpp @@ -1,12 +1,14 @@ #include #include -#include #include -#include "depthai/depthai.hpp" +#include + #include "depthai/pipeline/node/host/Record.hpp" #include "depthai/pipeline/node/host/Replay.hpp" +#include "depthai/depthai.hpp" + static constexpr unsigned int NUM_FRAMES = 350; static constexpr double PSNR_TOLERANCE_DB = 0.2; diff --git a/tests/src/ondevice_tests/xlink_test.cpp b/tests/src/ondevice_tests/xlink_test.cpp index 81a35688c0..938c762e54 100644 --- a/tests/src/ondevice_tests/xlink_test.cpp +++ b/tests/src/ondevice_tests/xlink_test.cpp @@ -71,6 +71,8 @@ TEST_CASE("XLinkBridge fps limit test") { } } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + TEST_CASE("Sync node packet transfer timing and data integrity with varying delays", "[sync][xlink][timing][generate]") { // Use GENERATE to run the entire test case once for each value const int sendingDistanceMs = GENERATE(1, 10, 50, 100); @@ -209,3 +211,5 @@ TEST_CASE("Sync node packet transfer data integrity with more frames in MessageG REQUIRE(same1); REQUIRE(same2); } + +#endif diff --git a/tests/src/onhost_tests/image_transformations_test.cpp b/tests/src/onhost_tests/image_transformations_test.cpp index 4bd54c6116..3dea7c84de 100644 --- a/tests/src/onhost_tests/image_transformations_test.cpp +++ b/tests/src/onhost_tests/image_transformations_test.cpp @@ -487,6 +487,8 @@ TEST_CASE("flipRotateFlip") { REQUIRE_THAT(p2.y, Catch::Matchers::WithinAbs(p.y, 0.01)); } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + // ----------------------------------------------------------------------------- // Purpose: // Compares the custom getOuterRotatedRect implementation against OpenCV's @@ -520,3 +522,5 @@ TEST_CASE("Get outer rect opencv comparison") { REQUIRE_THAT(rrImpl.angle, Catch::Matchers::WithinAbs(rrCv.angle, 0.01)); } } + +#endif diff --git a/tests/src/onhost_tests/multi_device_fsync_test.cpp b/tests/src/onhost_tests/multi_device_fsync_test.cpp index f0129baf6e..e27eb07177 100644 --- a/tests/src/onhost_tests/multi_device_fsync_test.cpp +++ b/tests/src/onhost_tests/multi_device_fsync_test.cpp @@ -8,7 +8,7 @@ TEST_CASE("Test Multi-device external frame sync with different FPS values", "[f // 60 FPS has a issue. STM looses sync on 60 FPS auto fps = GENERATE(10.0f, 13.0f, 18.5f, 30.0f, 45.0f); CAPTURE(fps); - struct FsyncTestParameters parameters {}; + struct FsyncTestParameters parameters{}; parameters.syncThresholdSec = 1 / (2 * fps); // lower this limit when we have better accuracy for timestamps parameters.testDurationSec = 180; parameters.recvAllTimeoutSec = 10; diff --git a/tests/src/onhost_tests/multi_device_ptp_test.cpp b/tests/src/onhost_tests/multi_device_ptp_test.cpp index 9a70f58db8..4b112b7c14 100644 --- a/tests/src/onhost_tests/multi_device_ptp_test.cpp +++ b/tests/src/onhost_tests/multi_device_ptp_test.cpp @@ -8,7 +8,7 @@ TEST_CASE("Test Multi-device PTP frame sync with different FPS values", "[ptp]") // 60 FPS does not work as of 1.30.1 auto fps = GENERATE(10.0f, 13.0f, 18.5f, 30.0f, 45.0f); CAPTURE(fps); - struct FsyncTestParameters parameters {}; + struct FsyncTestParameters parameters{}; parameters.syncThresholdSec = 1 / (2 * fps); // lower this limit when we have better accuracy for timestamps parameters.testDurationSec = 180; parameters.recvAllTimeoutSec = 15; diff --git a/tests/src/onhost_tests/pipeline/datatype/imgframe_test.cpp b/tests/src/onhost_tests/pipeline/datatype/imgframe_test.cpp index f90bed890b..67cd7182e2 100644 --- a/tests/src/onhost_tests/pipeline/datatype/imgframe_test.cpp +++ b/tests/src/onhost_tests/pipeline/datatype/imgframe_test.cpp @@ -1,5 +1,3 @@ -#include - #include #include #include @@ -12,6 +10,8 @@ #include #ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + #include + #include #include #endif diff --git a/tests/src/onhost_tests/pipeline/node/internal/XLinkInHostTest.cpp b/tests/src/onhost_tests/pipeline/node/internal/XLinkInHostTest.cpp index f0f7d6ddf4..c90ed6b583 100644 --- a/tests/src/onhost_tests/pipeline/node/internal/XLinkInHostTest.cpp +++ b/tests/src/onhost_tests/pipeline/node/internal/XLinkInHostTest.cpp @@ -97,6 +97,8 @@ std::vector getPackets(std::shared_ptr fra return result; } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT + TEST_CASE("XLinkInHost - readData") { using namespace dai::node::internal; @@ -234,3 +236,5 @@ TEST_CASE("XLinkInHost - readData") { REQUIRE_THROWS_AS(xlinkIn.readData(), std::runtime_error); } } + +#endif diff --git a/tests/src/onhost_tests/utility/events_manager_test.cpp b/tests/src/onhost_tests/utility/events_manager_test.cpp index fa465d4402..d4d8f63852 100644 --- a/tests/src/onhost_tests/utility/events_manager_test.cpp +++ b/tests/src/onhost_tests/utility/events_manager_test.cpp @@ -1,4 +1,8 @@ +#include #include +#include +#include +#include #include #include @@ -10,13 +14,41 @@ using namespace dai; using namespace dai::utility; +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT +TEST_CASE("FileData encodes ImgFrame as JPEG", "[FileData][EventsManager]") { + auto frame = std::make_shared(); + frame->setType(ImgFrame::Type::BGR888i).setSize(4, 4); + frame->setData(std::vector(4 * 4 * 3, 128)); + + const auto outputDirectory = + std::filesystem::temp_directory_path() / ("depthai_events_manager_" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count())); + std::filesystem::create_directory(outputDirectory); + + FileData fileData(frame, "frame"); + std::array signature{}; + const bool fileWritten = fileData.toFile(outputDirectory); + if(fileWritten) { + std::ifstream output(outputDirectory / "frame.jpg", std::ios::binary); + output.read(reinterpret_cast(signature.data()), signature.size()); + } + + std::filesystem::remove_all(outputDirectory); + + REQUIRE(fileWritten); + const std::array jpegSignature{0xFF, 0xD8}; + REQUIRE(signature == jpegSignature); +} +#endif + TEST_CASE("FileGroup throws on null pointer inputs", "[FileGroup][EventsManager]") { FileGroup fileGroup; +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT SECTION("addFile with null ImgFrame throws") { std::shared_ptr nullFrame = nullptr; REQUIRE_THROWS_AS(fileGroup.addFile("test.jpg", nullFrame), std::invalid_argument); } +#endif SECTION("addFile with null EncodedFrame throws") { std::shared_ptr nullFrame = nullptr; @@ -28,11 +60,13 @@ TEST_CASE("FileGroup throws on null pointer inputs", "[FileGroup][EventsManager] REQUIRE_THROWS_AS(fileGroup.addFile("test.json", nullDetections), std::invalid_argument); } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT SECTION("addImageDetectionsPair with null ImgFrame throws") { std::shared_ptr nullFrame = nullptr; auto detections = std::make_shared(); REQUIRE_THROWS_AS(fileGroup.addImageDetectionsPair("test", nullFrame, detections), std::invalid_argument); } +#endif SECTION("addImageDetectionsPair with null EncodedFrame throws") { std::shared_ptr nullFrame = nullptr; @@ -40,6 +74,7 @@ TEST_CASE("FileGroup throws on null pointer inputs", "[FileGroup][EventsManager] REQUIRE_THROWS_AS(fileGroup.addImageDetectionsPair("test", nullFrame, detections), std::invalid_argument); } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT SECTION("addImageDetectionsPair with null ImgDetections throws") { auto frame = std::make_shared(); frame->setType(ImgFrame::Type::BGR888i).setSize(4, 4); @@ -48,11 +83,13 @@ TEST_CASE("FileGroup throws on null pointer inputs", "[FileGroup][EventsManager] std::shared_ptr nullDetections = nullptr; REQUIRE_THROWS_AS(fileGroup.addImageDetectionsPair("test", frame, nullDetections), std::invalid_argument); } +#endif } TEST_CASE("FileGroup accepts valid inputs", "[FileGroup][EventsManager]") { FileGroup fileGroup; +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT SECTION("addFile with valid ImgFrame works") { auto frame = std::make_shared(); frame->setType(ImgFrame::Type::BGR888i).setSize(4, 4); @@ -60,12 +97,14 @@ TEST_CASE("FileGroup accepts valid inputs", "[FileGroup][EventsManager]") { frame->setData(data); REQUIRE_NOTHROW(fileGroup.addFile("test.jpg", frame)); } +#endif SECTION("addFile with valid ImgDetections works") { auto detections = std::make_shared(); REQUIRE_NOTHROW(fileGroup.addFile("test.json", detections)); } +#ifdef DEPTHAI_HAVE_OPENCV_SUPPORT SECTION("addImageDetectionsPair with valid inputs works") { auto frame = std::make_shared(); frame->setType(ImgFrame::Type::BGR888i).setSize(4, 4); @@ -74,6 +113,7 @@ TEST_CASE("FileGroup accepts valid inputs", "[FileGroup][EventsManager]") { auto detections = std::make_shared(); REQUIRE_NOTHROW(fileGroup.addImageDetectionsPair("test", frame, detections)); } +#endif SECTION("addFile with string data works") { REQUIRE_NOTHROW(fileGroup.addFile("test.txt", "hello world", "text/plain"));