From 9f88e9ae315b5908c609eca8182bc9417a7f5f5f Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 5 Aug 2025 11:19:35 +0300 Subject: [PATCH] Added options to initialize Orbbec cameras with custom fps and resolution. --- modules/videoio/include/opencv2/videoio.hpp | 3 + modules/videoio/src/cap_interface.hpp | 2 +- modules/videoio/src/cap_obsensor_capture.cpp | 82 +++++++++++++------ modules/videoio/src/cap_obsensor_capture.hpp | 2 +- .../videoio/src/cap_obsensor_liborbbec.cpp | 59 +++++++++++-- .../videoio/src/cap_obsensor_liborbbec.hpp | 2 +- samples/cpp/videocapture_obsensor.cpp | 64 ++++++++++++++- 7 files changed, 177 insertions(+), 37 deletions(-) diff --git a/modules/videoio/include/opencv2/videoio.hpp b/modules/videoio/include/opencv2/videoio.hpp index b9a490bd0f..a3ce5dc6e9 100644 --- a/modules/videoio/include/opencv2/videoio.hpp +++ b/modules/videoio/include/opencv2/videoio.hpp @@ -716,6 +716,9 @@ enum VideoCaptureOBSensorProperties{ CAP_PROP_OBSENSOR_INTRINSIC_CY=26004, CAP_PROP_OBSENSOR_RGB_POS_MSEC=26005, CAP_PROP_OBSENSOR_DEPTH_POS_MSEC=26006, + CAP_PROP_OBSENSOR_DEPTH_WIDTH=26007, + CAP_PROP_OBSENSOR_DEPTH_HEIGHT=26008, + CAP_PROP_OBSENSOR_DEPTH_FPS=26009 }; //! @} OBSENSOR diff --git a/modules/videoio/src/cap_interface.hpp b/modules/videoio/src/cap_interface.hpp index 58cada06d3..bb1e0b4ec9 100644 --- a/modules/videoio/src/cap_interface.hpp +++ b/modules/videoio/src/cap_interface.hpp @@ -400,7 +400,7 @@ Ptr createAndroidVideoWriter(const std::string& filename, int four double fps, const Size& frameSize, const VideoWriterParameters& params); -Ptr create_obsensor_capture(int index); +Ptr create_obsensor_capture(int index, const cv::VideoCaptureParameters& params); bool VideoCapture_V4L_waitAny( const std::vector& streams, diff --git a/modules/videoio/src/cap_obsensor_capture.cpp b/modules/videoio/src/cap_obsensor_capture.cpp index 10e457f7fd..4b59ff26a8 100644 --- a/modules/videoio/src/cap_obsensor_capture.cpp +++ b/modules/videoio/src/cap_obsensor_capture.cpp @@ -23,15 +23,20 @@ #include "cap_obsensor_capture.hpp" #include "cap_obsensor/obsensor_stream_channel_interface.hpp" +#include + +#define OB_WIDTH_ANY 0 +#define OB_HEIGHT_ANY 0 +#define OB_FPS_ANY 0 #if defined(HAVE_OBSENSOR) && !defined(HAVE_OBSENSOR_ORBBEC_SDK) namespace cv { -Ptr create_obsensor_capture(int index) +Ptr create_obsensor_capture(int index, const cv::VideoCaptureParameters& params) { - return makePtr(index); + return makePtr(index, params); } -VideoCapture_obsensor::VideoCapture_obsensor(int index) : isOpened_(false) +VideoCapture_obsensor::VideoCapture_obsensor(int index, const cv::VideoCaptureParameters& params) : isOpened_(false) { static const obsensor::StreamProfile colorProfile = { 640, 480, 30, obsensor::FRAME_FORMAT_MJPG }; static const obsensor::StreamProfile depthProfile = { 640, 480, 30, obsensor::FRAME_FORMAT_Y16 }; @@ -55,15 +60,23 @@ VideoCapture_obsensor::VideoCapture_obsensor(int index) : isOpened_(false) { case obsensor::OBSENSOR_STREAM_COLOR: { - auto profile = colorProfile; - if(OBSENSOR_FEMTO_MEGA_PID == channel->getPid()){ - profile = megaColorProfile; - }else if(OBSENSOR_GEMINI2L_PID == channel->getPid()){ - profile = gemini2lColorProfile; - }else if(OBSENSOR_ASTRA2_PID == channel->getPid()){ - profile = astra2ColorProfile; - }else if(OBSENSOR_GEMINI2XL_PID == channel->getPid()){ - profile = gemini2XlColorProfile; + uint32_t color_width = params.get(CAP_PROP_FRAME_WIDTH, OB_WIDTH_ANY); + uint32_t color_height = params.get(CAP_PROP_FRAME_HEIGHT, OB_HEIGHT_ANY); + uint32_t color_fps = params.get(CAP_PROP_FPS, OB_FPS_ANY); + + obsensor::StreamProfile profile = colorProfile; + if (color_width != OB_WIDTH_ANY || color_height != OB_HEIGHT_ANY || color_fps != OB_FPS_ANY) { + profile = { color_width, color_height, color_fps, obsensor::FRAME_FORMAT_MJPG }; + } else { + if(OBSENSOR_FEMTO_MEGA_PID == channel->getPid()){ + profile = megaColorProfile; + }else if(OBSENSOR_GEMINI2L_PID == channel->getPid()){ + profile = gemini2lColorProfile; + }else if(OBSENSOR_ASTRA2_PID == channel->getPid()){ + profile = astra2ColorProfile; + }else if(OBSENSOR_GEMINI2XL_PID == channel->getPid()){ + profile = gemini2XlColorProfile; + } } channel->start(profile, [&](obsensor::Frame* frame) { std::unique_lock lk(frameMutex_); @@ -77,17 +90,25 @@ VideoCapture_obsensor::VideoCapture_obsensor(int index) : isOpened_(false) uint8_t data = 1; channel->setProperty(obsensor::DEPTH_TO_COLOR_ALIGN, &data, 1); + uint32_t depth_width = params.get(CAP_PROP_OBSENSOR_DEPTH_WIDTH, OB_WIDTH_ANY); + uint32_t depth_height = params.get(CAP_PROP_OBSENSOR_DEPTH_HEIGHT, OB_HEIGHT_ANY); + uint32_t depth_fps = params.get(CAP_PROP_OBSENSOR_DEPTH_FPS, OB_FPS_ANY); + obsensor::StreamProfile profile = depthProfile; - if(OBSENSOR_GEMINI2_PID == channel->getPid()){ - profile = gemini2DepthProfile; - }else if(OBSENSOR_ASTRA2_PID == channel->getPid()){ - profile = astra2DepthProfile; - }else if(OBSENSOR_FEMTO_MEGA_PID == channel->getPid()){ - profile = megaDepthProfile; - }else if(OBSENSOR_GEMINI2L_PID == channel->getPid()){ - profile = gemini2lDepthProfile; - }else if(OBSENSOR_GEMINI2XL_PID == channel->getPid()){ - profile = gemini2XlDepthProfile; + if (depth_width != OB_WIDTH_ANY || depth_height != OB_HEIGHT_ANY || depth_fps != OB_FPS_ANY) { + profile = { depth_width, depth_height, depth_fps, obsensor::FRAME_FORMAT_Y16 }; + } else { + if(OBSENSOR_GEMINI2_PID == channel->getPid()){ + profile = gemini2DepthProfile; + }else if(OBSENSOR_ASTRA2_PID == channel->getPid()){ + profile = astra2DepthProfile; + }else if(OBSENSOR_FEMTO_MEGA_PID == channel->getPid()){ + profile = megaDepthProfile; + }else if(OBSENSOR_GEMINI2L_PID == channel->getPid()){ + profile = gemini2lDepthProfile; + }else if(OBSENSOR_GEMINI2XL_PID == channel->getPid()){ + profile = gemini2XlDepthProfile; + } } channel->start(profile, [&](obsensor::Frame* frame) { std::unique_lock lk(frameMutex_); @@ -218,7 +239,22 @@ double VideoCapture_obsensor::getProperty(int propIdx) const { bool VideoCapture_obsensor::setProperty(int propIdx, double /*propVal*/) { - CV_LOG_WARNING(NULL, "Unsupported or read only property, id=" << propIdx); + switch(propIdx) + { + case CAP_PROP_OBSENSOR_DEPTH_WIDTH: + case CAP_PROP_OBSENSOR_DEPTH_HEIGHT: + case CAP_PROP_OBSENSOR_DEPTH_FPS: + CV_LOG_WARNING(NULL, "CAP_PROP_OBSENSOR_DEPTH_WIDTH, CAP_PROP_OBSENSOR_DEPTH_HEIGHT, CAP_PROP_OBSENSOR_DEPTH_FPS options are supported during camera initialization only"); + break; + case CAP_PROP_FRAME_WIDTH: + case CAP_PROP_FRAME_HEIGHT: + case CAP_PROP_FPS: + CV_LOG_WARNING(NULL, "CAP_PROP_FRAME_WIDTH, CAP_PROP_FRAME_HEIGHT, CAP_PROP_FPS options are supported during camera initialization only"); + break; + default: + CV_LOG_WARNING(NULL, "Unsupported or read only property, id=" << propIdx); + } + return false; } diff --git a/modules/videoio/src/cap_obsensor_capture.hpp b/modules/videoio/src/cap_obsensor_capture.hpp index 89ab403bb2..bd01050626 100644 --- a/modules/videoio/src/cap_obsensor_capture.hpp +++ b/modules/videoio/src/cap_obsensor_capture.hpp @@ -34,7 +34,7 @@ namespace cv { class VideoCapture_obsensor : public IVideoCapture { public: - VideoCapture_obsensor(int index); + VideoCapture_obsensor(int index, const cv::VideoCaptureParameters& params); virtual ~VideoCapture_obsensor(); virtual double getProperty(int propIdx) const CV_OVERRIDE; diff --git a/modules/videoio/src/cap_obsensor_liborbbec.cpp b/modules/videoio/src/cap_obsensor_liborbbec.cpp index 5bb4a925d3..40d8ba283f 100644 --- a/modules/videoio/src/cap_obsensor_liborbbec.cpp +++ b/modules/videoio/src/cap_obsensor_liborbbec.cpp @@ -28,23 +28,52 @@ namespace cv { -Ptr create_obsensor_capture(int index) +Ptr create_obsensor_capture(int index, const cv::VideoCaptureParameters& params) { - return makePtr(index); + return makePtr(index, params); } -VideoCapture_obsensor::VideoCapture_obsensor(int) +VideoCapture_obsensor::VideoCapture_obsensor(int, const cv::VideoCaptureParameters& params) { ob::Context::setLoggerToFile(OB_LOG_SEVERITY_OFF, ""); config = std::make_shared(); pipe = std::make_shared(); + + int color_width = params.get(CAP_PROP_FRAME_WIDTH, OB_WIDTH_ANY); + int color_height = params.get(CAP_PROP_FRAME_HEIGHT, OB_HEIGHT_ANY); + int color_fps = params.get(CAP_PROP_FPS, OB_FPS_ANY); + auto colorProfiles = pipe->getStreamProfileList(OB_SENSOR_COLOR); - auto colorProfile = colorProfiles->getProfile(OB_PROFILE_DEFAULT); - config->enableStream(colorProfile->as()); + if (color_width == OB_WIDTH_ANY && color_height == OB_HEIGHT_ANY && color_fps == OB_FPS_ANY) + { + CV_LOG_INFO(NULL, "Use default color stream profile"); + auto colorProfile = colorProfiles->getProfile(OB_PROFILE_DEFAULT); + config->enableStream(colorProfile->as()); + } + else + { + CV_LOG_INFO(NULL, "Looking for custom color profile " << color_width << "x" << color_height << "@" << color_fps << " fps"); + auto colorProfile = colorProfiles->getVideoStreamProfile(color_width, color_height, OB_FORMAT_MJPG, color_fps); + config->enableStream(colorProfile->as()); + } + + int depth_width = params.get(CAP_PROP_OBSENSOR_DEPTH_WIDTH, OB_WIDTH_ANY); + int depth_height = params.get(CAP_PROP_OBSENSOR_DEPTH_HEIGHT, OB_HEIGHT_ANY); + int depth_fps = params.get(CAP_PROP_OBSENSOR_DEPTH_FPS, OB_FPS_ANY); auto depthProfiles = pipe->getStreamProfileList(OB_SENSOR_DEPTH); - auto depthProfile = depthProfiles->getProfile(OB_PROFILE_DEFAULT); - config->enableStream(depthProfile->as()); + if (depth_width == OB_WIDTH_ANY && depth_height == OB_HEIGHT_ANY && depth_fps == OB_FPS_ANY) + { + CV_LOG_INFO(NULL, "Use default depth stream profile"); + auto depthProfile = depthProfiles->getProfile(OB_PROFILE_DEFAULT); + config->enableStream(depthProfile->as()); + } + else + { + CV_LOG_INFO(NULL, "Looking for custom color profile " << depth_width << "x" << depth_height << "@" << depth_fps << " fps"); + auto depthProfile = depthProfiles->getVideoStreamProfile(depth_width, depth_height, OB_FORMAT_Y14, depth_fps); + config->enableStream(depthProfile->as()); + } config->setAlignMode(ALIGN_D2C_SW_MODE); @@ -111,8 +140,22 @@ double VideoCapture_obsensor::getProperty(int propIdx) const return rst; } -bool VideoCapture_obsensor::setProperty(int, double) +bool VideoCapture_obsensor::setProperty(int prop, double) { + switch(prop) + { + case CAP_PROP_OBSENSOR_DEPTH_WIDTH: + case CAP_PROP_OBSENSOR_DEPTH_HEIGHT: + case CAP_PROP_OBSENSOR_DEPTH_FPS: + CV_LOG_WARNING(NULL, "CAP_PROP_OBSENSOR_DEPTH_WIDTH, CAP_PROP_OBSENSOR_DEPTH_HEIGHT, CAP_PROP_OBSENSOR_DEPTH_FPS options are supported during camera initialization only"); + break; + case CAP_PROP_FRAME_WIDTH: + case CAP_PROP_FRAME_HEIGHT: + case CAP_PROP_FPS: + CV_LOG_WARNING(NULL, "CAP_PROP_FRAME_WIDTH, CAP_PROP_FRAME_HEIGHT, CAP_PROP_FPS options are supported during camera initialization only"); + break; + } + return false; } diff --git a/modules/videoio/src/cap_obsensor_liborbbec.hpp b/modules/videoio/src/cap_obsensor_liborbbec.hpp index 13dbf413ca..44df040030 100644 --- a/modules/videoio/src/cap_obsensor_liborbbec.hpp +++ b/modules/videoio/src/cap_obsensor_liborbbec.hpp @@ -46,7 +46,7 @@ struct CameraParam class VideoCapture_obsensor : public IVideoCapture { public: - VideoCapture_obsensor(int index); + VideoCapture_obsensor(int index, const cv::VideoCaptureParameters& params); virtual ~VideoCapture_obsensor(); virtual double getProperty(int propIdx) const CV_OVERRIDE; diff --git a/samples/cpp/videocapture_obsensor.cpp b/samples/cpp/videocapture_obsensor.cpp index ce71a1808b..03f0c49381 100644 --- a/samples/cpp/videocapture_obsensor.cpp +++ b/samples/cpp/videocapture_obsensor.cpp @@ -8,10 +8,68 @@ #include using namespace cv; -int main() +int main(int argc, char** argv) { - VideoCapture obsensorCapture(0, CAP_OBSENSOR); - if(!obsensorCapture.isOpened()){ + cv::CommandLineParser parser(argc, argv, + "{help h ? | | help message}" + "{dw | | depth width }" + "{dh | | depth height }" + "{df | | depth fps }" + "{cw | | color width }" + "{ch | | color height }" + "{cf | | depth fps }" + + ); + if (parser.has("help")) + { + parser.printMessage(); + return 0; + } + + std::vector params; + if (parser.has("dw")) + { + params.push_back(CAP_PROP_OBSENSOR_DEPTH_WIDTH); + params.push_back(parser.get("dw")); + } + + if (parser.has("dh")) + { + params.push_back(CAP_PROP_OBSENSOR_DEPTH_HEIGHT); + params.push_back(parser.get("dh")); + } + + if (parser.has("df")) + { + params.push_back(CAP_PROP_OBSENSOR_DEPTH_FPS); + params.push_back(parser.get("df")); + } + + if (parser.has("cw")) + { + params.push_back(CAP_PROP_FRAME_WIDTH); + params.push_back(parser.get("cw")); + } + + if (parser.has("ch")) + { + params.push_back(CAP_PROP_FRAME_HEIGHT); + params.push_back(parser.get("ch")); + } + + if (parser.has("cf")) + { + params.push_back(CAP_PROP_FPS); + params.push_back(parser.get("cf")); + } + + VideoCapture obsensorCapture; + + if (params.empty()) + obsensorCapture.open(0, CAP_OBSENSOR); + else + obsensorCapture.open(0, CAP_OBSENSOR, params); + if(!obsensorCapture.isOpened()) { std::cerr << "Failed to open obsensor capture! Index out of range or no response from device"; return -1; }