From 756bd1d64a911d019be01a91066d3d7f5230c579 Mon Sep 17 00:00:00 2001 From: Ben <987807597@qq.com> Date: Wed, 26 Aug 2026 11:54:17 +0800 Subject: [PATCH] fix: switch sdk roi for full-frame capture --- src/VizumCamera.cpp | 258 +++++++++++++++++++++++++++++++++----------- src/VizumCamera.h | 17 ++- 2 files changed, 208 insertions(+), 67 deletions(-) diff --git a/src/VizumCamera.cpp b/src/VizumCamera.cpp index b821186..1f9d9e9 100755 --- a/src/VizumCamera.cpp +++ b/src/VizumCamera.cpp @@ -116,11 +116,17 @@ std::mutex& OutputRoiModeMutex() return mutex; } -class OutputRoiModeRestoreGuard +class FullFrameRoiRestoreGuard { public: - explicit OutputRoiModeRestoreGuard(VZNLHANDLE deviceHandle) - : m_guardDeviceHandle(deviceHandle) + FullFrameRoiRestoreGuard(VZNLHANDLE deviceHandle, + const SVzNLROIRect& initialLeftROI, + const SVzNLROIRect& initialRightROI, + unsigned int frameWidth, + unsigned int frameHeight) + : m_guardDeviceHandle(deviceHandle), + m_initialLeftROI(initialLeftROI), + m_initialRightROI(initialRightROI) { int queryError = 0; m_previousCalibRoi = VzNL_IsEnableCalibROI(m_guardDeviceHandle, &queryError); @@ -132,23 +138,43 @@ public: return; } - if (m_previousCalibRoi == VzTrue) { - const int ret = VzNL_EnableCalibROI(m_guardDeviceHandle, VzFalse); - if (ret != 0) { - char errorMsg[256] = {0}; - VzNL_GetErrorInfo(ret, errorMsg); - LOG_ERROR("[VizumCamera] Cannot disable CalibROI for true full-frame pixels: {} " - "(error code: {})", errorMsg, ret); - return; - } - m_calibRoiChanged = true; + VzNL_SetOutputROIImage(VzTrue); + int ret = VzNL_EnableCalibROI(m_guardDeviceHandle, VzTrue); + if (ret != 0) { + char errorMsg[256] = {0}; + VzNL_GetErrorInfo(ret, errorMsg); + LOG_ERROR("[VizumCamera] Cannot enable CalibROI before configuring full-frame ROI: {} " + "(error code: {})", errorMsg, ret); + return; + } + m_restoreRequired = true; + + SVzNLROIRect fullLeftROI{}; + fullLeftROI.right = frameWidth; + fullLeftROI.bottom = frameHeight; + SVzNLROIRect fullRightROI{}; + fullRightROI.right = frameWidth; + fullRightROI.bottom = frameHeight; + ret = VzNL_ConfigDetectROI(m_guardDeviceHandle, &fullLeftROI, &fullRightROI); + if (ret != 0) { + char errorMsg[256] = {0}; + VzNL_GetErrorInfo(ret, errorMsg); + LOG_ERROR("[VizumCamera] Cannot configure full-frame detection ROI: {} " + "(error code: {}), requested=[0, {}, 0, {}]", + errorMsg, ret, frameWidth, frameHeight); + RestoreNow(); + return; } - VzNL_SetOutputROIImage(VzFalse); - m_outputModeChanged = true; m_ready = true; - LOG_INFO("[VizumCamera] Full-frame 2D mode applied: CalibROI=false, " - "OutputROI=false; configured detection ROI and point-cloud ROI unchanged"); + LOG_INFO("[VizumCamera] Temporary full-frame ROI configured through SDK: " + "left/right=[0, {}, 0, {}]; initial left=[{}, {}, {}, {}], " + "right=[{}, {}, {}, {}]", + frameWidth, frameHeight, + m_initialLeftROI.left, m_initialLeftROI.right, + m_initialLeftROI.top, m_initialLeftROI.bottom, + m_initialRightROI.left, m_initialRightROI.right, + m_initialRightROI.top, m_initialRightROI.bottom); } bool IsReady() const @@ -158,50 +184,75 @@ public: bool RestoreNow() { - if (m_restoreAttempted) + if (m_restoreAttempted && m_restoreSucceeded) return m_restoreSucceeded; m_restoreAttempted = true; - if (!m_outputModeChanged && !m_calibRoiChanged) { + if (!m_restoreRequired) { m_restoreSucceeded = true; return true; } - if (m_outputModeChanged) - VzNL_SetOutputROIImage(VzTrue); - m_restoreSucceeded = true; - if (m_calibRoiChanged) { - const int ret = VzNL_EnableCalibROI(m_guardDeviceHandle, m_previousCalibRoi); - if (ret != 0) { - char errorMsg[256] = {0}; - VzNL_GetErrorInfo(ret, errorMsg); - LOG_ERROR("[VizumCamera] Failed to restore CalibROI after full-frame capture: {} " - "(error code: {})", errorMsg, ret); - m_restoreSucceeded = false; - } + int ret = VzNL_EnableCalibROI(m_guardDeviceHandle, VzFalse); + if (ret != 0) { + char errorMsg[256] = {0}; + VzNL_GetErrorInfo(ret, errorMsg); + LOG_ERROR("[VizumCamera] Failed to disable CalibROI before restoring initial ROI: {} " + "(error code: {})", errorMsg, ret); + m_restoreSucceeded = false; } + ret = VzNL_ConfigDetectROI(m_guardDeviceHandle, &m_initialLeftROI, &m_initialRightROI); + if (ret != 0) { + char errorMsg[256] = {0}; + VzNL_GetErrorInfo(ret, errorMsg); + LOG_ERROR("[VizumCamera] Failed to restore initial detection ROI: {} " + "(error code: {}), left=[{}, {}, {}, {}], right=[{}, {}, {}, {}]", + errorMsg, ret, + m_initialLeftROI.left, m_initialLeftROI.right, + m_initialLeftROI.top, m_initialLeftROI.bottom, + m_initialRightROI.left, m_initialRightROI.right, + m_initialRightROI.top, m_initialRightROI.bottom); + m_restoreSucceeded = false; + } + + ret = VzNL_EnableCalibROI(m_guardDeviceHandle, m_previousCalibRoi); + if (ret != 0) { + char errorMsg[256] = {0}; + VzNL_GetErrorInfo(ret, errorMsg); + LOG_ERROR("[VizumCamera] Failed to restore CalibROI mode after full-frame capture: {} " + "(error code: {})", errorMsg, ret); + m_restoreSucceeded = false; + } + VzNL_SetOutputROIImage(VzTrue); + if (m_restoreSucceeded) { - LOG_INFO("[VizumCamera] ROI detection image mode restored: CalibROI={}, " - "OutputROI=true", m_previousCalibRoi == VzTrue); + LOG_INFO("[VizumCamera] Initial detection ROI restored after full-frame capture: " + "left=[{}, {}, {}, {}], right=[{}, {}, {}, {}], CalibROI={}", + m_initialLeftROI.left, m_initialLeftROI.right, + m_initialLeftROI.top, m_initialLeftROI.bottom, + m_initialRightROI.left, m_initialRightROI.right, + m_initialRightROI.top, m_initialRightROI.bottom, + m_previousCalibRoi == VzTrue); } return m_restoreSucceeded; } - ~OutputRoiModeRestoreGuard() + ~FullFrameRoiRestoreGuard() { RestoreNow(); } - OutputRoiModeRestoreGuard(const OutputRoiModeRestoreGuard&) = delete; - OutputRoiModeRestoreGuard& operator=(const OutputRoiModeRestoreGuard&) = delete; + FullFrameRoiRestoreGuard(const FullFrameRoiRestoreGuard&) = delete; + FullFrameRoiRestoreGuard& operator=(const FullFrameRoiRestoreGuard&) = delete; private: VZNLHANDLE m_guardDeviceHandle = nullptr; + SVzNLROIRect m_initialLeftROI{}; + SVzNLROIRect m_initialRightROI{}; VzBool m_previousCalibRoi = VzFalse; - bool m_calibRoiChanged = false; - bool m_outputModeChanged = false; + bool m_restoreRequired = false; bool m_ready = false; bool m_restoreAttempted = false; bool m_restoreSucceeded = false; @@ -1032,10 +1083,15 @@ bool VizumCamera::GetRightImage(SLImage& image) return !image.empty(); } -bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, std::string& frameId) +bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, + std::string& frameId, + const ROIRect& initialLeftROI, + const ROIRect& initialRightROI, + bool& cameraStateRestored) { image.clear(); frameId.clear(); + cameraStateRestored = false; #ifdef ENABLE_VIZUM_CAMERA const std::lock_guard outputModeLock(OutputRoiModeMutex()); const std::lock_guard deviceLock(m_deviceAccessMutex); @@ -1044,9 +1100,13 @@ bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, std::string& frameId return false; } - SVzNLROIRect oldLeftROI{}; - SVzNLROIRect oldRightROI{}; - int ret = VzNL_GetConfigDetectROI(m_deviceHandle, &oldLeftROI, &oldRightROI); + const SVzNLROIRect expectedLeftROI{initialLeftROI.left, initialLeftROI.right, + initialLeftROI.top, initialLeftROI.bottom}; + const SVzNLROIRect expectedRightROI{initialRightROI.left, initialRightROI.right, + initialRightROI.top, initialRightROI.bottom}; + SVzNLROIRect currentLeftROI{}; + SVzNLROIRect currentRightROI{}; + int ret = VzNL_GetConfigDetectROI(m_deviceHandle, ¤tLeftROI, ¤tRightROI); if (ret != 0) { char errorMsg[256] = {0}; VzNL_GetErrorInfo(ret, errorMsg); @@ -1055,9 +1115,81 @@ bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, std::string& frameId return false; } - OutputRoiModeRestoreGuard outputModeGuard(m_deviceHandle); - if (!outputModeGuard.IsReady()) + SVzVideoResolution resolution{}; + ret = VzNL_GetResolution(m_deviceHandle, &resolution); + if (ret != 0 || resolution.nFrameWidth == 0 || resolution.nFrameHeight == 0) { + char errorMsg[256] = {0}; + VzNL_GetErrorInfo(ret, errorMsg); + LOG_ERROR("[VizumCamera] Full-frame capture cannot read a valid resolution: {} " + "(error code: {}), size={}x{}", + errorMsg, ret, resolution.nFrameWidth, resolution.nFrameHeight); return false; + } + + if (!SameSdkRoi(currentLeftROI, expectedLeftROI) + || !SameSdkRoi(currentRightROI, expectedRightROI)) { + LOG_ERROR("[VizumCamera] Current ROI differs from the connection-time point-cloud ROI; " + "restoring expected state and rejecting this capture. current left=[{}, {}, {}, {}], " + "right=[{}, {}, {}, {}]; expected left=[{}, {}, {}, {}], right=[{}, {}, {}, {}]", + currentLeftROI.left, currentLeftROI.right, + currentLeftROI.top, currentLeftROI.bottom, + currentRightROI.left, currentRightROI.right, + currentRightROI.top, currentRightROI.bottom, + expectedLeftROI.left, expectedLeftROI.right, + expectedLeftROI.top, expectedLeftROI.bottom, + expectedRightROI.left, expectedRightROI.right, + expectedRightROI.top, expectedRightROI.bottom); + FullFrameRoiRestoreGuard recoveryGuard(m_deviceHandle, expectedLeftROI, expectedRightROI, + resolution.nFrameWidth, resolution.nFrameHeight); + const bool recoverySucceeded = recoveryGuard.RestoreNow(); + ret = VzNL_GetConfigDetectROI(m_deviceHandle, ¤tLeftROI, ¤tRightROI); + cameraStateRestored = recoverySucceeded && ret == 0 + && SameSdkRoi(currentLeftROI, expectedLeftROI) + && SameSdkRoi(currentRightROI, expectedRightROI); + return false; + } + + FullFrameRoiRestoreGuard roiGuard(m_deviceHandle, expectedLeftROI, expectedRightROI, + resolution.nFrameWidth, resolution.nFrameHeight); + if (!roiGuard.IsReady()) { + const bool restoreSucceeded = roiGuard.RestoreNow(); + ret = VzNL_GetConfigDetectROI(m_deviceHandle, ¤tLeftROI, ¤tRightROI); + cameraStateRestored = restoreSucceeded && ret == 0 + && SameSdkRoi(currentLeftROI, expectedLeftROI) + && SameSdkRoi(currentRightROI, expectedRightROI); + return false; + } + + SVzNLROIRect configuredLeftROI{}; + SVzNLROIRect configuredRightROI{}; + ret = VzNL_GetConfigDetectROI(m_deviceHandle, &configuredLeftROI, &configuredRightROI); + const auto isFullFrameRoi = [&resolution](const SVzNLROIRect& roi) { + return roi.left == 0 && roi.top == 0 + && roi.right == resolution.nFrameWidth + && roi.bottom == resolution.nFrameHeight; + }; + if (ret != 0 || !isFullFrameRoi(configuredLeftROI) || !isFullFrameRoi(configuredRightROI)) { + char errorMsg[256] = {0}; + VzNL_GetErrorInfo(ret, errorMsg); + LOG_ERROR("[VizumCamera] SDK full-frame ROI readback verification failed: {} " + "(error code: {}), left=[{}, {}, {}, {}], right=[{}, {}, {}, {}], " + "expected=[0, {}, 0, {}]", + errorMsg, ret, + configuredLeftROI.left, configuredLeftROI.right, + configuredLeftROI.top, configuredLeftROI.bottom, + configuredRightROI.left, configuredRightROI.right, + configuredRightROI.top, configuredRightROI.bottom, + resolution.nFrameWidth, resolution.nFrameHeight); + const bool restoreSucceeded = roiGuard.RestoreNow(); + ret = VzNL_GetConfigDetectROI(m_deviceHandle, ¤tLeftROI, ¤tRightROI); + cameraStateRestored = restoreSucceeded && ret == 0 + && SameSdkRoi(currentLeftROI, expectedLeftROI) + && SameSdkRoi(currentRightROI, expectedRightROI); + return false; + } + LOG_INFO("[VizumCamera] SDK full-frame ROI readback verified before 2D capture: " + "left/right=[0, {}, 0, {}]", + resolution.nFrameWidth, resolution.nFrameHeight); SVzNLImageData* leftImage = nullptr; SVzNLImageData* rightImage = nullptr; @@ -1080,36 +1212,36 @@ bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, std::string& frameId const bool rightReleased = rightImageGuard.ReleaseNow(); const bool imagesReleased = leftReleased && rightReleased; - // CalibROI=false returns the raw eye frame (for example 1216x1920), while - // VzNL_GetResolution may report the calibrated output canvas (for example - // 1336x2115). They are different coordinate spaces and must not be compared. const bool validFullFrame = converted && !image.empty() - && image.originX == 0 && image.originY == 0; + && image.originX == 0 && image.originY == 0 + && image.width == resolution.nFrameWidth + && image.height == resolution.nFrameHeight; if (converted && !validFullFrame) { - LOG_ERROR("[VizumCamera] Raw full-frame image has an invalid origin or empty payload: " - "image={}x{} origin=({}, {})", - image.width, image.height, image.originX, image.originY); + LOG_ERROR("[VizumCamera] Configured full-frame image contract failed: " + "image={}x{} origin=({}, {}), expected={}x{} origin=(0, 0)", + image.width, image.height, image.originX, image.originY, + resolution.nFrameWidth, resolution.nFrameHeight); } - const bool imageModesRestored = outputModeGuard.RestoreNow(); + const bool initialRoiRestored = roiGuard.RestoreNow(); - SVzNLROIRect currentLeftROI{}; - SVzNLROIRect currentRightROI{}; ret = VzNL_GetConfigDetectROI(m_deviceHandle, ¤tLeftROI, ¤tRightROI); const bool roiUnchanged = ret == 0 - && SameSdkRoi(currentLeftROI, oldLeftROI) - && SameSdkRoi(currentRightROI, oldRightROI); + && SameSdkRoi(currentLeftROI, expectedLeftROI) + && SameSdkRoi(currentRightROI, expectedRightROI); if (ret != 0) { char errorMsg[256] = {0}; VzNL_GetErrorInfo(ret, errorMsg); LOG_ERROR("[VizumCamera] Failed to query detection ROI after full-frame capture: {} " "(error code: {})", errorMsg, ret); } else if (!roiUnchanged) { - LOG_ERROR("[VizumCamera] Detection ROI changed during output-only full-frame capture; " + LOG_ERROR("[VizumCamera] Detection ROI was not restored after full-frame capture; " "before left=[{}, {}, {}, {}], right=[{}, {}, {}, {}]; " "after left=[{}, {}, {}, {}], right=[{}, {}, {}, {}]", - oldLeftROI.left, oldLeftROI.right, oldLeftROI.top, oldLeftROI.bottom, - oldRightROI.left, oldRightROI.right, oldRightROI.top, oldRightROI.bottom, + expectedLeftROI.left, expectedLeftROI.right, + expectedLeftROI.top, expectedLeftROI.bottom, + expectedRightROI.left, expectedRightROI.right, + expectedRightROI.top, expectedRightROI.bottom, currentLeftROI.left, currentLeftROI.right, currentLeftROI.top, currentLeftROI.bottom, currentRightROI.left, currentRightROI.right, @@ -1123,15 +1255,17 @@ bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, std::string& frameId currentRightROI.top, currentRightROI.bottom); } - if (!validFullFrame || !imagesReleased || !imageModesRestored || !roiUnchanged) { + cameraStateRestored = initialRoiRestored && roiUnchanged; + + if (!validFullFrame || !imagesReleased || !cameraStateRestored) { image.clear(); return false; } const uint64_t id = ++m_frameCounter; frameId = "VZ_FULL_" + std::to_string(id); - LOG_INFO("[VizumCamera] True full-frame 2D capture completed without writing detection ROI: " - "frameId={}, output={}x{} origin=(0, 0), CalibROI restored", + LOG_INFO("[VizumCamera] Full-frame 2D transaction completed: " + "frameId={}, output={}x{} origin=(0, 0), initial ROI restored", frameId, image.width, image.height); return true; #else diff --git a/src/VizumCamera.h b/src/VizumCamera.h index 4f40bfd..f9f1cbf 100755 --- a/src/VizumCamera.h +++ b/src/VizumCamera.h @@ -128,13 +128,20 @@ public: bool GetRightImage(SLImage& image); /** - * @brief 不修改检测 ROI,临时关闭 CalibROI/ROI输出并采集真实全幅左目图像 - * @param[out] image SDK 原始返回的全幅眼图(CalibROI=false 坐标系,原点必须为(0,0)) + * @brief 临时把左右检测 ROI 配置为全幅,采集左目全图后恢复初始 ROI + * @param[out] image SDK 返回的矫正全幅左目图(尺寸等于设备分辨率,原点必须为(0,0)) * @param[out] frameId 本次采集帧编号 - * @return 采集、SDK 图像释放、全幅原点校验、模式恢复及检测 ROI 未变化校验是否全部成功 - * @note 检测 ROI 始终只读;任何失败路径都会恢复原 CalibROI 和 ROI 图输出模式 + * @param[in] initialLeftROI 连接时缓存的左目点云 ROI,也是唯一恢复目标 + * @param[in] initialRightROI 连接时缓存的右目点云 ROI,也是唯一恢复目标 + * @param[out] cameraStateRestored 返回前是否确认初始 ROI、CalibROI 和输出模式均已恢复 + * @return 全幅 ROI 配置、采集、SDK 图像释放、初始 ROI 恢复及校验是否全部成功 + * @note 该事务按 SDK 官方示例调用 ConfigDetectROI;任何失败路径都会尝试恢复初始左右 ROI */ - bool CaptureFullFrameLeftImage(SLImage& image, std::string& frameId); + bool CaptureFullFrameLeftImage(SLImage& image, + std::string& frameId, + const ROIRect& initialLeftROI, + const ROIRect& initialRightROI, + bool& cameraStateRestored); /** * @brief 启用/禁用矫正 ROI 图像输出(VzNL_EnableCalibROI)