diff --git a/src/VizumCamera.cpp b/src/VizumCamera.cpp index d6f0244..1c77ba4 100755 --- a/src/VizumCamera.cpp +++ b/src/VizumCamera.cpp @@ -5,6 +5,10 @@ #include #include #include +#include +#include +#include +#include #ifdef ENABLE_VIZUM_CAMERA #include "VZNL_Common.h" @@ -106,46 +110,365 @@ struct VizumCamera::Impl { #ifdef ENABLE_VIZUM_CAMERA namespace { +std::string SdkErrorText(int errorCode) +{ + if (errorCode == 0) + return "none"; + + char errorMsg[256] = {0}; + const int errorInfoRet = VzNL_GetErrorInfo(errorCode, errorMsg); + LOG_INFO("[SDKCall] api=VzNL_GetErrorInfo input_error_code={} return_code={} " + "sdk_error_text=\"{}\"", + errorCode, errorInfoRet, errorInfoRet == 0 ? errorMsg : "unavailable"); + return errorInfoRet == 0 ? std::string(errorMsg) : "unavailable"; +} + +std::string LogSdkReturn(const char* stage, const char* api, int returnCode) +{ + const std::string errorText = SdkErrorText(returnCode); + LOG_INFO("[SDKCall] stage={} api={} return_code={} sdk_error_text=\"{}\"", + stage, api, returnCode, errorText); + return errorText; +} + +const char* SdkImageTypeName(EVzNLImageType imageType) +{ + switch (imageType) { + case keVzNLImageType_None: return "None"; + case keVzNLImageType_RGB888: return "RGB888"; + case keVzNLImageType_BGR888: return "BGR888"; + case keVzNLImageType_BAYERGR: return "BAYERGR"; + case keVzNLImageType_BAYERRG: return "BAYERRG"; + case keVzNLImageType_BAYERBG: return "BAYERBG"; + case keVzNLImageType_BAYERGB: return "BAYERGB"; + case keVzNLImageType_GRAY: return "GRAY"; + case keVzNLImageType_YUV420: return "YUV420"; + case keVzNLImageType_BGRA8888: return "BGRA8888"; + case keVzNLImageType_YUYV_YUV422: return "YUYV_YUV422"; + case keVzNLImageType_UNKNOWN: return "UNKNOWN"; + default: return "unrecognized"; + } +} + +struct BoundarySample +{ + uint64_t valid = 0; + uint64_t count = 0; + uint64_t brightnessSum = 0; + uint32_t maxBrightness = 0; +}; + +struct EffectivePixelStats +{ + bool layoutValid = false; + uint64_t totalPixels = 0; + uint64_t validPixels = 0; + int minX = -1; + int minY = -1; + int maxX = -1; + int maxY = -1; + BoundarySample top; + BoundarySample bottom; + BoundarySample left; + BoundarySample right; +}; + +uint32_t PixelBrightness(const unsigned char* pixel, unsigned int channels, + unsigned int bytesPerChannel) +{ + uint32_t brightness = 0; + for (unsigned int channel = 0; channel < channels; ++channel) { + uint32_t value = 0; + if (bytesPerChannel == 2) { + uint16_t value16 = 0; + std::memcpy(&value16, pixel + channel * bytesPerChannel, sizeof(value16)); + value = value16; + } else { + value = pixel[channel]; + } + brightness = std::max(brightness, value); + } + return brightness; +} + +void AddBoundarySample(BoundarySample& sample, uint32_t brightness, uint32_t threshold) +{ + ++sample.count; + sample.brightnessSum += brightness; + sample.maxBrightness = std::max(sample.maxBrightness, brightness); + if (brightness > threshold) + ++sample.valid; +} + +struct EffectivePixelStatsPair +{ + EffectivePixelStats nonZero; + EffectivePixelStats aboveEight; +}; + +void AccumulateEffectivePixel(EffectivePixelStats& stats, unsigned int x, + unsigned int y, unsigned int width, + unsigned int height, uint32_t brightness, + uint32_t threshold) +{ + if (y == 0) + AddBoundarySample(stats.top, brightness, threshold); + if (y + 1 == height) + AddBoundarySample(stats.bottom, brightness, threshold); + if (x == 0) + AddBoundarySample(stats.left, brightness, threshold); + if (x + 1 == width) + AddBoundarySample(stats.right, brightness, threshold); + if (brightness <= threshold) + return; + + const int pixelX = static_cast(x); + const int pixelY = static_cast(y); + if (stats.validPixels == 0) { + stats.minX = pixelX; + stats.minY = pixelY; + stats.maxX = pixelX; + stats.maxY = pixelY; + } else { + stats.minX = std::min(stats.minX, pixelX); + stats.minY = std::min(stats.minY, pixelY); + stats.maxX = std::max(stats.maxX, pixelX); + stats.maxY = std::max(stats.maxY, pixelY); + } + ++stats.validPixels; +} + +EffectivePixelStatsPair ComputeEffectivePixelStats(const SVzNLImageData* image) +{ + EffectivePixelStatsPair pair; + if (!image || !image->pBuffer || image->nWidth == 0 || image->nHeight == 0 + || image->nChannels == 0) { + return pair; + } + + const unsigned int bytesPerChannel = image->byBitDepth > 8 ? 2U : 1U; + const uint64_t packedRowBytes = static_cast(image->nWidth) + * image->nChannels * bytesPerChannel; + if (packedRowBytes == 0 || image->nBufferSize < packedRowBytes * image->nHeight) + return pair; + + const uint64_t sdkStride = image->nBufferSize % image->nHeight == 0 + ? image->nBufferSize / image->nHeight : packedRowBytes; + if (sdkStride < packedRowBytes) + return pair; + + const uint64_t totalPixels = static_cast(image->nWidth) * image->nHeight; + pair.nonZero.layoutValid = true; + pair.aboveEight.layoutValid = true; + pair.nonZero.totalPixels = totalPixels; + pair.aboveEight.totalPixels = totalPixels; + const uint64_t pixelBytes = static_cast(image->nChannels) * bytesPerChannel; + for (unsigned int y = 0; y < image->nHeight; ++y) { + const unsigned char* row = image->pBuffer + static_cast(y) * sdkStride; + for (unsigned int x = 0; x < image->nWidth; ++x) { + const uint32_t brightness = PixelBrightness(row + static_cast(x) * pixelBytes, + image->nChannels, bytesPerChannel); + AccumulateEffectivePixel(pair.nonZero, x, y, image->nWidth, + image->nHeight, brightness, 0U); + AccumulateEffectivePixel(pair.aboveEight, x, y, image->nWidth, + image->nHeight, brightness, 8U); + } + } + return pair; +} + +void LogBoundarySample(const char* eye, uint32_t threshold, const char* edge, + const BoundarySample& sample) +{ + const double validRatio = sample.count == 0 + ? 0.0 : static_cast(sample.valid) / sample.count; + const double meanBrightness = sample.count == 0 + ? 0.0 : static_cast(sample.brightnessSum) / sample.count; + LOG_INFO("[ImageBoundarySample] source=sdk eye={} threshold_native={} edge={} " + "valid={}/{} valid_ratio={:.8f} mean_brightness={:.3f} max_brightness={}", + eye, threshold, edge, sample.valid, sample.count, validRatio, + meanBrightness, sample.maxBrightness); +} + +void LogSdkImageDiagnostics(const char* eye, const SVzNLImageData* image) +{ + if (!image) { + LOG_WARN("[SDKImage] eye={} present=false", eye); + return; + } + + const unsigned int bytesPerChannel = image->byBitDepth > 8 ? 2U : 1U; + const uint64_t packedRowBytes = static_cast(image->nWidth) + * image->nChannels * bytesPerChannel; + const bool strideDerivable = image->nHeight != 0 + && image->nBufferSize % image->nHeight == 0; + const uint64_t derivedStride = strideDerivable + ? image->nBufferSize / image->nHeight : packedRowBytes; + LOG_INFO("[SDKImage] eye={} present=true width={} height={} sdk_stride={} " + "stride_source={} packed_row_bytes={} data_size={} origin=({}, {}) " + "format={} format_code={} channels={} bit_depth={} buffer_scope=metadata_only", + eye, image->nWidth, image->nHeight, derivedStride, + strideDerivable ? "buffer_size/height" : "packed_fallback", + packedRowBytes, image->nBufferSize, image->ptOriPos.x, image->ptOriPos.y, + SdkImageTypeName(image->eImageType), static_cast(image->eImageType), + static_cast(image->nChannels), + static_cast(image->byBitDepth)); + + const EffectivePixelStatsPair statsPair = ComputeEffectivePixelStats(image); + const auto logStats = [eye, image](uint32_t threshold, + const EffectivePixelStats& stats) { + const double validRatio = stats.totalPixels == 0 + ? 0.0 : static_cast(stats.validPixels) / stats.totalPixels; + const int bboxWidth = stats.validPixels > 0 ? stats.maxX - stats.minX + 1 : 0; + const int bboxHeight = stats.validPixels > 0 ? stats.maxY - stats.minY + 1 : 0; + const bool bboxCoversCanvas = stats.layoutValid && stats.minX == 0 && stats.minY == 0 + && stats.maxX + 1 == static_cast(image->nWidth) + && stats.maxY + 1 == static_cast(image->nHeight); + LOG_INFO("[ImageValidity] source=sdk eye={} threshold_native={} layout_valid={} " + "full_size_buffer={}x{} effective_bbox=[{}, {}, {}, {}] bbox_size={}x{} " + "effective_pixels={}/{} effective_ratio={:.8f} bbox_covers_canvas={} " + "interpretation=full_size_buffer_does_not_prove_full_frame_valid_pixels", + eye, threshold, stats.layoutValid, image->nWidth, image->nHeight, + stats.minX, stats.minY, stats.maxX, stats.maxY, bboxWidth, bboxHeight, + stats.validPixels, stats.totalPixels, validRatio, bboxCoversCanvas); + LogBoundarySample(eye, threshold, "top_row", stats.top); + LogBoundarySample(eye, threshold, "bottom_row", stats.bottom); + LogBoundarySample(eye, threshold, "left_column", stats.left); + LogBoundarySample(eye, threshold, "right_column", stats.right); + }; + logStats(0U, statsPair.nonZero); + logStats(8U, statsPair.aboveEight); +} + std::mutex& OutputRoiModeMutex() { static std::mutex mutex; return mutex; } -class OutputRoiModeRestoreGuard +bool SameSdkRoi(const SVzNLROIRect& lhs, const SVzNLROIRect& rhs); + +class FullFrameRoiRestoreGuard { public: - explicit OutputRoiModeRestoreGuard(VZNLHANDLE deviceHandle) - : m_guardDeviceHandle(deviceHandle) + FullFrameRoiRestoreGuard(VZNLHANDLE deviceHandle, + const SVzNLROIRect& initialLeftROI, + const SVzNLROIRect& initialRightROI) + : m_guardDeviceHandle(deviceHandle), + m_initialLeftROI(initialLeftROI), + m_initialRightROI(initialRightROI) { int queryError = 0; m_previousCalibRoi = VzNL_IsEnableCalibROI(m_guardDeviceHandle, &queryError); + LogSdkReturn("before_full_frame_roi", "VzNL_IsEnableCalibROI", queryError); + LOG_INFO("[CaptureState] stage=before_full_frame_roi calib_roi={} calib_roi_source=sdk_get " + "output_roi_expected=true output_roi_actual=unavailable " + "output_roi_getter=not_provided_by_sdk", + m_previousCalibRoi == VzTrue); if (queryError != 0) { - char errorMsg[256] = {0}; - VzNL_GetErrorInfo(queryError, errorMsg); LOG_ERROR("[VizumCamera] Cannot query CalibROI before full-frame capture: {} " - "(error code: {})", errorMsg, queryError); + "(error code: {})", SdkErrorText(queryError), queryError); 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 raw full-frame capture: {} " - "(error code: {})", errorMsg, ret); - return; - } - m_calibRoiChanged = true; + // SDK 官方 save_gray_depth_map 示例使用 ROI 输出,并在 CalibROI=false + // 坐标基准下保存/恢复检测 ROI,再切 CalibROI=true 配置全分辨率 ROI 取图。 + VzNL_SetOutputROIImage(VzTrue); + LOG_INFO("[SDKCall] stage=prepare_full_frame_roi api=VzNL_SetOutputROIImage(true) " + "return_code=unavailable sdk_error_text=\"unavailable: SDK API returns void\""); + + int ret = VzNL_EnableCalibROI(m_guardDeviceHandle, VzFalse); + LogSdkReturn("prepare_full_frame_roi", "VzNL_EnableCalibROI(false)", ret); + if (ret != 0) { + LOG_ERROR("[VizumCamera] Cannot enter ROI restore coordinate mode: {} " + "(error code: {})", SdkErrorText(ret), ret); + return; + } + m_restoreRequired = true; + + SVzNLROIRect currentLeftROI{}; + SVzNLROIRect currentRightROI{}; + ret = VzNL_GetConfigDetectROI(m_guardDeviceHandle, ¤tLeftROI, ¤tRightROI); + LogSdkReturn("prepare_full_frame_roi", "VzNL_GetConfigDetectROI", ret); + if (ret != 0) { + LOG_ERROR("[VizumCamera] Cannot snapshot DetectROI in the SDK restore coordinate " + "mode: {} (error code: {})", SdkErrorText(ret), ret); + RestoreNow(); + return; + } + m_restoreLeftROI = currentLeftROI; + m_restoreRightROI = currentRightROI; + m_restoreRoiAvailable = true; + const bool sameAcrossCalibModes = SameSdkRoi(currentLeftROI, m_initialLeftROI) + && SameSdkRoi(currentRightROI, m_initialRightROI); + LOG_INFO("[CaptureState] stage=restore_roi_snapshot calib_roi=false " + "left=[{}, {}, {}, {}] right=[{}, {}, {}, {}] " + "connection_mode_left=[{}, {}, {}, {}] " + "connection_mode_right=[{}, {}, {}, {}] same_across_calib_modes={}", + currentLeftROI.left, currentLeftROI.right, + currentLeftROI.top, currentLeftROI.bottom, + currentRightROI.left, currentRightROI.right, + currentRightROI.top, currentRightROI.bottom, + m_initialLeftROI.left, m_initialLeftROI.right, + m_initialLeftROI.top, m_initialLeftROI.bottom, + m_initialRightROI.left, m_initialRightROI.right, + m_initialRightROI.top, m_initialRightROI.bottom, + sameAcrossCalibModes); + + ret = VzNL_EnableCalibROI(m_guardDeviceHandle, VzTrue); + LogSdkReturn("apply_full_frame_roi", "VzNL_EnableCalibROI(true)", ret); + if (ret != 0) { + LOG_ERROR("[VizumCamera] Cannot enable calibrated full-frame acquisition: {} " + "(error code: {})", SdkErrorText(ret), ret); + RestoreNow(); + return; + } + + SVzVideoResolution resolution{}; + ret = VzNL_GetResolution(m_guardDeviceHandle, &resolution); + LogSdkReturn("apply_full_frame_roi", "VzNL_GetResolution", ret); + if (ret != 0 || resolution.nFrameWidth == 0 || resolution.nFrameHeight == 0) { + LOG_ERROR("[VizumCamera] Cannot read full-frame resolution: {} " + "(error code: {}), size={}x{}", + SdkErrorText(ret), ret, resolution.nFrameWidth, resolution.nFrameHeight); + RestoreNow(); + return; + } + m_frameWidth = resolution.nFrameWidth; + m_frameHeight = resolution.nFrameHeight; + + const SVzNLROIRect fullLeftROI{0, static_cast(m_frameWidth), + 0, static_cast(m_frameHeight)}; + const SVzNLROIRect fullRightROI = fullLeftROI; + ret = VzNL_ConfigDetectROI(m_guardDeviceHandle, &fullLeftROI, &fullRightROI); + LogSdkReturn("apply_full_frame_roi", "VzNL_ConfigDetectROI(full_frame)", ret); + if (ret != 0) { + LOG_ERROR("[VizumCamera] Cannot configure temporary full-frame ROI: {} " + "(error code: {}), requested=[0, {}, 0, {}]", + SdkErrorText(ret), ret, m_frameWidth, m_frameHeight); + RestoreNow(); + return; + } + + ret = VzNL_GetConfigDetectROI(m_guardDeviceHandle, ¤tLeftROI, ¤tRightROI); + LogSdkReturn("verify_full_frame_roi", "VzNL_GetConfigDetectROI", ret); + const bool fullRoiReadback = ret == 0 + && SameSdkRoi(currentLeftROI, fullLeftROI) + && SameSdkRoi(currentRightROI, fullRightROI); + LOG_INFO("[CaptureState] stage=verify_full_frame_roi left=[{}, {}, {}, {}] " + "right=[{}, {}, {}, {}] expected=[0, {}, 0, {}] readback_matches={} " + "calib_roi_expected=true output_roi_expected=true", + currentLeftROI.left, currentLeftROI.right, + currentLeftROI.top, currentLeftROI.bottom, + currentRightROI.left, currentRightROI.right, + currentRightROI.top, currentRightROI.bottom, + m_frameWidth, m_frameHeight, fullRoiReadback); + if (!fullRoiReadback) { + RestoreNow(); + return; } - // 官方接口语义:VzFalse 输出完整原始图,检测/点云 ROI 不参与也不得改写。 - VzNL_SetOutputROIImage(VzFalse); - m_outputModeChanged = true; m_ready = true; - LOG_INFO("[VizumCamera] Full-frame 2D mode applied: CalibROI=false, " - "OutputROI=false; configured detection/point-cloud ROI untouched"); } bool IsReady() const @@ -155,51 +478,108 @@ 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); + int ret = VzNL_EnableCalibROI(m_guardDeviceHandle, VzFalse); + LogSdkReturn("restore_point_cloud_roi", "VzNL_EnableCalibROI(false)", ret); + const bool restoreCoordinateModeReady = ret == 0; + if (ret != 0) { + LOG_ERROR("[VizumCamera] Failed to enter ROI restore coordinate mode: {} " + "(error code: {})", SdkErrorText(ret), ret); + m_restoreSucceeded = false; + } + + if (restoreCoordinateModeReady && m_restoreRoiAvailable) { + ret = VzNL_ConfigDetectROI(m_guardDeviceHandle, &m_restoreLeftROI, + &m_restoreRightROI); + LogSdkReturn("restore_point_cloud_roi", "VzNL_ConfigDetectROI(saved_restore_roi)", + ret); 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); + LOG_ERROR("[VizumCamera] Failed to restore saved point-cloud ROI: {} " + "(error code: {})", SdkErrorText(ret), ret); m_restoreSucceeded = false; } + } else if (!restoreCoordinateModeReady) { + LOG_INFO("[SDKCall] stage=restore_point_cloud_roi " + "api=VzNL_ConfigDetectROI(saved_restore_roi) called=false " + "reason=restore_coordinate_mode_unavailable return_code=not_applicable " + "sdk_error_text=\"not_applicable\""); + } else { + LOG_INFO("[SDKCall] stage=restore_point_cloud_roi " + "api=VzNL_ConfigDetectROI(saved_restore_roi) called=false " + "reason=roi_snapshot_unavailable return_code=not_applicable " + "sdk_error_text=\"not_applicable\""); } - if (m_restoreSucceeded) { - LOG_INFO("[VizumCamera] ROI image mode restored: CalibROI={}, OutputROI=true; " - "configured detection/point-cloud ROI untouched", - m_previousCalibRoi == VzTrue); + ret = VzNL_EnableCalibROI(m_guardDeviceHandle, m_previousCalibRoi); + LogSdkReturn("restore_image_mode", "VzNL_EnableCalibROI(previous)", ret); + if (ret != 0) { + LOG_ERROR("[VizumCamera] Failed to restore CalibROI after full-frame capture: {} " + "(error code: {})", SdkErrorText(ret), ret); + m_restoreSucceeded = false; } + + VzNL_SetOutputROIImage(VzTrue); + LOG_INFO("[SDKCall] stage=restore_image_mode api=VzNL_SetOutputROIImage(true) " + "return_code=unavailable sdk_error_text=\"unavailable: SDK API returns void\""); + + SVzNLROIRect restoredLeftROI{}; + SVzNLROIRect restoredRightROI{}; + ret = VzNL_GetConfigDetectROI(m_guardDeviceHandle, &restoredLeftROI, + &restoredRightROI); + LogSdkReturn("verify_restored_state", "VzNL_GetConfigDetectROI", ret); + const bool roiMatches = ret == 0 + && SameSdkRoi(restoredLeftROI, m_initialLeftROI) + && SameSdkRoi(restoredRightROI, m_initialRightROI); + int queryError = 0; + const VzBool restoredCalibRoi = VzNL_IsEnableCalibROI(m_guardDeviceHandle, + &queryError); + LogSdkReturn("verify_restored_state", "VzNL_IsEnableCalibROI", queryError); + const bool calibMatches = queryError == 0 && restoredCalibRoi == m_previousCalibRoi; + LOG_INFO("[CaptureState] stage=verify_restored_state left=[{}, {}, {}, {}] " + "right=[{}, {}, {}, {}] roi_matches={} calib_roi={} " + "calib_roi_expected={} calib_matches={} output_roi_expected=true " + "output_roi_actual=unavailable output_roi_getter=not_provided_by_sdk", + restoredLeftROI.left, restoredLeftROI.right, + restoredLeftROI.top, restoredLeftROI.bottom, + restoredRightROI.left, restoredRightROI.right, + restoredRightROI.top, restoredRightROI.bottom, + roiMatches, restoredCalibRoi == VzTrue, m_previousCalibRoi == VzTrue, + calibMatches); + m_restoreSucceeded = m_restoreSucceeded && roiMatches && calibMatches; return m_restoreSucceeded; } - ~OutputRoiModeRestoreGuard() + ~FullFrameRoiRestoreGuard() { RestoreNow(); } - OutputRoiModeRestoreGuard(const OutputRoiModeRestoreGuard&) = delete; - OutputRoiModeRestoreGuard& operator=(const OutputRoiModeRestoreGuard&) = delete; + unsigned int FrameWidth() const { return m_frameWidth; } + unsigned int FrameHeight() const { return m_frameHeight; } + + FullFrameRoiRestoreGuard(const FullFrameRoiRestoreGuard&) = delete; + FullFrameRoiRestoreGuard& operator=(const FullFrameRoiRestoreGuard&) = delete; private: VZNLHANDLE m_guardDeviceHandle = nullptr; + SVzNLROIRect m_initialLeftROI{}; + SVzNLROIRect m_initialRightROI{}; + SVzNLROIRect m_restoreLeftROI{}; + SVzNLROIRect m_restoreRightROI{}; VzBool m_previousCalibRoi = VzFalse; - bool m_calibRoiChanged = false; - bool m_outputModeChanged = false; + unsigned int m_frameWidth = 0; + unsigned int m_frameHeight = 0; + bool m_restoreRequired = false; + bool m_restoreRoiAvailable = false; bool m_ready = false; bool m_restoreAttempted = false; bool m_restoreSucceeded = false; @@ -221,16 +601,18 @@ public: m_attempted = true; if (!m_image) { m_succeeded = true; + LOG_INFO("[SDKCall] stage=release_sdk_image api=VzNL_ReleaseImage eye={} " + "called=false reason=null_image return_code=not_applicable " + "sdk_error_text=\"not_applicable\"", m_label); return true; } const int ret = VzNL_ReleaseImage(&m_image); + LogSdkReturn(m_label, "VzNL_ReleaseImage", ret); m_succeeded = ret == 0; if (!m_succeeded) { - char errorMsg[256] = {0}; - VzNL_GetErrorInfo(ret, errorMsg); LOG_ERROR("[VizumCamera] Failed to release {} SDK image: {} (error code: {})", - m_label, errorMsg, ret); + m_label, SdkErrorText(ret), ret); } return m_succeeded; } @@ -256,6 +638,28 @@ bool SameSdkRoi(const SVzNLROIRect& lhs, const SVzNLROIRect& rhs) && lhs.top == rhs.top && lhs.bottom == rhs.bottom; } +void LogCaptureStateSnapshot(VZNLHANDLE deviceHandle, const char* stage, + bool outputRoiExpected) +{ + SVzNLROIRect leftROI{}; + SVzNLROIRect rightROI{}; + const int roiRet = VzNL_GetConfigDetectROI(deviceHandle, &leftROI, &rightROI); + LogSdkReturn(stage, "VzNL_GetConfigDetectROI", roiRet); + + int calibQueryError = 0; + const VzBool calibRoi = VzNL_IsEnableCalibROI(deviceHandle, &calibQueryError); + LogSdkReturn(stage, "VzNL_IsEnableCalibROI", calibQueryError); + + LOG_INFO("[CaptureState] stage={} thread_id={} detect_roi_available={} " + "left=[{}, {}, {}, {}] right=[{}, {}, {}, {}] calib_roi_available={} " + "calib_roi={} output_roi_expected={} output_roi_actual=unavailable " + "output_roi_getter=not_provided_by_sdk", + stage, std::hash{}(std::this_thread::get_id()), roiRet == 0, + leftROI.left, leftROI.right, leftROI.top, leftROI.bottom, + rightROI.left, rightROI.right, rightROI.top, rightROI.bottom, + calibQueryError == 0, calibRoi == VzTrue, outputRoiExpected); +} + const char* DeviceStatusName(int status) { switch (static_cast(status)) { @@ -746,9 +1150,11 @@ bool VizumCamera::Connect(const std::string& ipAddress) { const std::lock_guard outputModeLock(OutputRoiModeMutex()); VzNL_SetOutputImageFormat(keVzNLImageType_BGR888); - LOG_INFO("[VizumCamera] Output image format set to BGR888"); + LOG_INFO("[SDKCall] stage=connect api=VzNL_SetOutputImageFormat(BGR888) " + "return_code=unavailable sdk_error_text=\"unavailable: SDK API returns void\""); VzNL_SetOutputROIImage(VzTrue); - LOG_INFO("[VizumCamera] SDK image output initialized to configured-ROI mode"); + LOG_INFO("[SDKCall] stage=connect api=VzNL_SetOutputROIImage(true) " + "return_code=unavailable sdk_error_text=\"unavailable: SDK API returns void\""); } // 更新设备信息 @@ -1042,6 +1448,14 @@ bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, #ifdef ENABLE_VIZUM_CAMERA const std::lock_guard outputModeLock(OutputRoiModeMutex()); const std::lock_guard deviceLock(m_deviceAccessMutex); + const auto transactionStart = std::chrono::steady_clock::now(); + const auto elapsedMs = [&transactionStart]() { + return std::chrono::duration_cast( + std::chrono::steady_clock::now() - transactionStart).count(); + }; + LOG_INFO("[CaptureTimeline] stage=2d_transaction_begin elapsed_ms={} thread_id={} " + "requested_frame_id=pending", elapsedMs(), + std::hash{}(std::this_thread::get_id())); if (!m_isConnected || !m_deviceHandle) { LOG_ERROR("[VizumCamera] Full-frame capture failed: device not connected"); return false; @@ -1054,11 +1468,10 @@ bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, SVzNLROIRect currentLeftROI{}; SVzNLROIRect currentRightROI{}; int ret = VzNL_GetConfigDetectROI(m_deviceHandle, ¤tLeftROI, ¤tRightROI); + LogSdkReturn("before_2d_transaction", "VzNL_GetConfigDetectROI", ret); if (ret != 0) { - char errorMsg[256] = {0}; - VzNL_GetErrorInfo(ret, errorMsg); LOG_ERROR("[VizumCamera] Full-frame capture cannot read detection ROI: {} " - "(error code: {})", errorMsg, ret); + "(error code: {})", SdkErrorText(ret), ret); return false; } @@ -1084,54 +1497,101 @@ bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, currentLeftROI.top, currentLeftROI.bottom, currentRightROI.left, currentRightROI.right, currentRightROI.top, currentRightROI.bottom); + LogCaptureStateSnapshot(m_deviceHandle, "before_full_frame_roi_transaction", true); - OutputRoiModeRestoreGuard outputModeGuard(m_deviceHandle); - if (!outputModeGuard.IsReady()) + FullFrameRoiRestoreGuard fullFrameGuard(m_deviceHandle, expectedLeftROI, + expectedRightROI); + if (!fullFrameGuard.IsReady()) { + cameraStateRestored = fullFrameGuard.RestoreNow(); return false; + } + LogCaptureStateSnapshot(m_deviceHandle, "before_get_eye_image", true); + LOG_INFO("[CaptureTimeline] stage=before_get_eye_image elapsed_ms={} thread_id={} " + "frame_id=pending", elapsedMs(), + std::hash{}(std::this_thread::get_id())); SVzNLImageData* leftImage = nullptr; SVzNLImageData* rightImage = nullptr; SdkImageReleaseGuard leftImageGuard(leftImage, "left"); SdkImageReleaseGuard rightImageGuard(rightImage, "right"); ret = VzNL_GetEyeImage(m_deviceHandle, &leftImage, &rightImage, 3000); + const int getEyeRet = ret; + LogSdkReturn("get_eye_image", "VzNL_GetEyeImage(timeout_ms=3000)", ret); + LOG_INFO("[GetEyeImage] frame_id=pending return_code={} sdk_error_text=\"{}\" " + "left_present={} right_present={} elapsed_ms={} thread_id={}", + ret, SdkErrorText(ret), leftImage != nullptr, rightImage != nullptr, + elapsedMs(), std::hash{}(std::this_thread::get_id())); + LogSdkImageDiagnostics("left", leftImage); + LogSdkImageDiagnostics("right", rightImage); + const auto sdkStride = [](const SVzNLImageData* sdkImage) -> uint64_t { + if (!sdkImage || sdkImage->nHeight == 0) + return 0; + const uint64_t packed = static_cast(sdkImage->nWidth) + * sdkImage->nChannels * (sdkImage->byBitDepth > 8 ? 2U : 1U); + return sdkImage->nBufferSize % sdkImage->nHeight == 0 + ? sdkImage->nBufferSize / sdkImage->nHeight : packed; + }; + const unsigned int leftWidth = leftImage ? leftImage->nWidth : 0; + const unsigned int leftHeight = leftImage ? leftImage->nHeight : 0; + const unsigned int leftDataSize = leftImage ? leftImage->nBufferSize : 0; + const int leftOriginX = leftImage ? leftImage->ptOriPos.x : 0; + const int leftOriginY = leftImage ? leftImage->ptOriPos.y : 0; + const int leftFormat = leftImage ? static_cast(leftImage->eImageType) : -1; + const unsigned int leftChannels = leftImage ? leftImage->nChannels : 0; + const unsigned int leftDepth = leftImage ? leftImage->byBitDepth : 0; + const uint64_t leftStride = sdkStride(leftImage); + const unsigned int rightWidth = rightImage ? rightImage->nWidth : 0; + const unsigned int rightHeight = rightImage ? rightImage->nHeight : 0; + const unsigned int rightDataSize = rightImage ? rightImage->nBufferSize : 0; + const int rightOriginX = rightImage ? rightImage->ptOriPos.x : 0; + const int rightOriginY = rightImage ? rightImage->ptOriPos.y : 0; + const int rightFormat = rightImage ? static_cast(rightImage->eImageType) : -1; + const unsigned int rightChannels = rightImage ? rightImage->nChannels : 0; + const unsigned int rightDepth = rightImage ? rightImage->byBitDepth : 0; + const uint64_t rightStride = sdkStride(rightImage); + LogCaptureStateSnapshot(m_deviceHandle, "after_get_eye_image_before_restore", true); bool converted = false; if (ret == 0 && leftImage) { converted = ConvertVzImageToSLImage(leftImage, image); - LOG_INFO("[VizumCamera] Full-frame SDK image received: size={}x{}, origin=({}, {})", + LOG_INFO("[VizumCamera] Full-size SDK buffer received: size={}x{}, origin=({}, {}), " + "valid_pixel_scope=see_ImageValidity_logs", leftImage->nWidth, leftImage->nHeight, leftImage->ptOriPos.x, leftImage->ptOriPos.y); } else { - char errorMsg[256] = {0}; - VzNL_GetErrorInfo(ret, errorMsg); LOG_ERROR("[VizumCamera] Full-frame image acquisition failed: {} (error code: {})", - errorMsg, ret); + SdkErrorText(ret), ret); } const bool leftReleased = leftImageGuard.ReleaseNow(); const bool rightReleased = rightImageGuard.ReleaseNow(); const bool imagesReleased = leftReleased && rightReleased; - // OutputROI=false 返回原始全画幅;它与校正画布分辨率属于不同坐标空间。 + // SDK 官方示例的有效全画幅条件:CalibROI=true 且 DetectROI=设备全分辨率。 const bool validFullFrame = converted && !image.empty() - && image.originX == 0 && image.originY == 0; + && image.originX == 0 && image.originY == 0 + && image.width == fullFrameGuard.FrameWidth() + && image.height == fullFrameGuard.FrameHeight(); if (converted && !validFullFrame) { - LOG_ERROR("[VizumCamera] Raw full-frame image has invalid payload/origin: " - "image={}x{} origin=({}, {})", - image.width, image.height, image.originX, image.originY); + LOG_ERROR("[VizumCamera] Full-frame SDK image contract failed: " + "image={}x{} origin=({}, {}), expected={}x{} origin=(0, 0)", + image.width, image.height, image.originX, image.originY, + fullFrameGuard.FrameWidth(), fullFrameGuard.FrameHeight()); } - const bool imageModesRestored = outputModeGuard.RestoreNow(); + const bool imageModesRestored = fullFrameGuard.RestoreNow(); + LOG_INFO("[CaptureTimeline] stage=image_modes_restore_finished elapsed_ms={} thread_id={} " + "restore_result={}", elapsedMs(), + std::hash{}(std::this_thread::get_id()), imageModesRestored); ret = VzNL_GetConfigDetectROI(m_deviceHandle, ¤tLeftROI, ¤tRightROI); + LogSdkReturn("after_2d_transaction", "VzNL_GetConfigDetectROI", ret); const bool roiUnchanged = ret == 0 && 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); + "(error code: {})", SdkErrorText(ret), 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 temporary full-frame capture; " "before left=[{}, {}, {}, {}], right=[{}, {}, {}, {}]; " "after left=[{}, {}, {}, {}], right=[{}, {}, {}, {}]", expectedLeftROI.left, expectedLeftROI.right, @@ -1150,6 +1610,7 @@ bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, currentRightROI.left, currentRightROI.right, currentRightROI.top, currentRightROI.bottom); } + LogCaptureStateSnapshot(m_deviceHandle, "after_2d_transaction", true); cameraStateRestored = imageModesRestored && roiUnchanged; @@ -1160,9 +1621,20 @@ bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, const uint64_t id = ++m_frameCounter; frameId = "VZ_FULL_" + std::to_string(id); - LOG_INFO("[VizumCamera] Full-frame 2D transaction completed without writing camera ROI: " - "frameId={}, output={}x{} origin=(0, 0), image modes restored", - frameId, image.width, image.height); + LOG_INFO("[GetEyeImage] frame_id={} return_code={} sdk_error_text=\"{}\" " + "left=(width={},height={},stride={},data_size={},origin=[{},{}],format={},channels={},depth={}) " + "right=(width={},height={},stride={},data_size={},origin=[{},{}],format={},channels={},depth={}) " + "buffer_scope=full_size_metadata pixel_scope=measured_separately", + frameId, getEyeRet, SdkErrorText(getEyeRet), + leftWidth, leftHeight, leftStride, leftDataSize, leftOriginX, leftOriginY, + leftFormat, leftChannels, leftDepth, + rightWidth, rightHeight, rightStride, rightDataSize, rightOriginX, rightOriginY, + rightFormat, rightChannels, rightDepth); + LOG_INFO("[CaptureTimeline] stage=2d_transaction_complete elapsed_ms={} thread_id={} " + "frame_id={} image_modes_restored={} detect_roi_unchanged={} " + "full_size_buffer={}x{} full_frame_valid_pixels=not_inferred_from_dimensions", + elapsedMs(), std::hash{}(std::this_thread::get_id()), + frameId, imageModesRestored, roiUnchanged, image.width, image.height); return true; #else return false; @@ -1189,26 +1661,28 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti LOG_INFO("[VizumCamera] ========================================"); int result = 0; - char errorMsg[256] = {0}; - // 0. 检查并配置摆镜扫描(关键步骤!) LOG_INFO("[VizumCamera] Step 0: Checking and configuring swing motor..."); // 检查是否支持摆镜 int errorCode = 0; VzBool supportSwing = VzNL_IsSupportSwingMotor(m_deviceHandle, &errorCode); + LogSdkReturn("point_cloud_prepare", "VzNL_IsSupportSwingMotor", errorCode); if (supportSwing == VzTrue) { LOG_INFO("[VizumCamera] Swing motor is supported"); // 检查摆镜是否已启用 VzBool swingEnabled = VzNL_IsEnableSwingMotor(m_deviceHandle, &errorCode); + LogSdkReturn("point_cloud_prepare", "VzNL_IsEnableSwingMotor", errorCode); if (swingEnabled != VzTrue) { // 启用摆镜 LOG_INFO("[VizumCamera] Enabling swing motor..."); result = VzNL_EnableSwingMotor(m_deviceHandle, VzTrue); + const std::string enableSwingError = LogSdkReturn( + "point_cloud_prepare", "VzNL_EnableSwingMotor(true)", result); if (result != 0) { - VzNL_GetErrorInfo(result, errorMsg); - LOG_WARN("[VizumCamera] Failed to enable swing motor: {} (error code: {})", errorMsg, result); + LOG_WARN("[VizumCamera] Failed to enable swing motor: {} (error code: {})", + enableSwingError, result); // 继续尝试,可能摆镜已经手动启用 } else { LOG_INFO("[VizumCamera] Swing motor enabled successfully"); @@ -1219,17 +1693,23 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti // 获取并记录摆镜配置信息 int startAngle = 0, endAngle = 0; - if (VzNL_GetSwingMotorAngle(m_deviceHandle, &startAngle, &endAngle) == 0) { + const int angleRangeResult = VzNL_GetSwingMotorAngle(m_deviceHandle, &startAngle, + &endAngle); + LogSdkReturn("point_cloud_prepare", "VzNL_GetSwingMotorAngle", angleRangeResult); + if (angleRangeResult == 0) { LOG_INFO("[VizumCamera] Swing motor angle range: {} to {}", startAngle, endAngle); } int angleSpeed = 0; - if (VzNL_GetSwingAngleSpeed(m_deviceHandle, &angleSpeed) == 0) { + const int angleSpeedResult = VzNL_GetSwingAngleSpeed(m_deviceHandle, &angleSpeed); + LogSdkReturn("point_cloud_prepare", "VzNL_GetSwingAngleSpeed", angleSpeedResult); + if (angleSpeedResult == 0) { LOG_INFO("[VizumCamera] Swing motor angle speed: {}", angleSpeed); } // 获取当前角度 float curAngle = VzNL_GetSwingCurAngle(m_deviceHandle, &errorCode); + LogSdkReturn("point_cloud_prepare", "VzNL_GetSwingCurAngle", errorCode); if (errorCode == 0) { LOG_INFO("[VizumCamera] Current swing angle: {:.2f}", curAngle); } @@ -1257,7 +1737,9 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti // 获取当前点云处理模式 EVzPointCloudProcMode procMode = kePointCloudProcMode_Invalid; - if (VzNL_GetPointCloudProcMode(m_deviceHandle, &procMode) == 0) { + const int procModeResult = VzNL_GetPointCloudProcMode(m_deviceHandle, &procMode); + LogSdkReturn("point_cloud_prepare", "VzNL_GetPointCloudProcMode", procModeResult); + if (procModeResult == 0) { const char* modeStr = "Unknown"; switch(procMode) { case kePointCloudProcMode_Speed: modeStr = "Speed"; break; @@ -1282,11 +1764,14 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti // 示例代码中 StopAutoDetect 会调用 EndDetectLaser,所以这里需要 BeginDetectLaser LOG_INFO("[VizumCamera] Step 1.5: Re-initializing laser detection..."); VzNL_EndDetectLaser(m_deviceHandle); // 确保之前的已结束 - + LOG_INFO("[SDKCall] stage=point_cloud_prepare api=VzNL_EndDetectLaser " + "return_code=unavailable sdk_error_text=\"unavailable: SDK API returns void\""); + result = VzNL_BeginDetectLaser(m_deviceHandle); + const std::string beginLaserError = LogSdkReturn( + "point_cloud_prepare", "VzNL_BeginDetectLaser", result); if (result != 0) { - VzNL_GetErrorInfo(result, errorMsg); - LOG_WARN("[VizumCamera] Failed to begin detect laser: {}", errorMsg); + LOG_WARN("[VizumCamera] Failed to begin detect laser: {}", beginLaserError); // 如果失败,可能是因为已经处于检测状态,尝试继续 } else { LOG_INFO("[VizumCamera] Laser detection initialized successfully"); @@ -1295,9 +1780,11 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti // 2.5 启用激光点填充:SDK 对每条激光线输出定长点序列,无测量处填充占位点, // 使扫描线构成真正列对齐的 W×H 栅格(供组织化点云保存/栅格聚类使用) result = VzNL_EnableFillLaserPoint(m_deviceHandle, VzTrue); + const std::string fillLaserError = LogSdkReturn( + "point_cloud_prepare", "VzNL_EnableFillLaserPoint(true)", result); if (result != 0) { - VzNL_GetErrorInfo(result, errorMsg); - LOG_WARN("[VizumCamera] VzNL_EnableFillLaserPoint failed: {} (error code: {})", errorMsg, result); + LOG_WARN("[VizumCamera] VzNL_EnableFillLaserPoint failed: {} (error code: {})", + fillLaserError, result); } else { LOG_INFO("[VizumCamera] Fill laser point mode enabled (rasterized scan lines)"); } @@ -1310,12 +1797,16 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti result = VzNL_StartAutoDetectEx(m_deviceHandle, keResultDataType_PointXYZRGBA, keFlipType_None, &AutoOutputLaserLineExCB, this); + const std::string startAutoDetectError = LogSdkReturn( + "point_cloud_scan_start", "VzNL_StartAutoDetectEx", result); if (result != 0) { m_autoDetectRunning = false; - VzNL_GetErrorInfo(result, errorMsg); - LOG_ERROR("[VizumCamera] Failed to start auto detect: {} (error code: {})", errorMsg, result); + LOG_ERROR("[VizumCamera] Failed to start auto detect: {} (error code: {})", + startAutoDetectError, result); // 尝试清理 VzNL_EndDetectLaser(m_deviceHandle); + LOG_INFO("[SDKCall] stage=point_cloud_scan_start_cleanup api=VzNL_EndDetectLaser " + "return_code=unavailable sdk_error_text=\"unavailable: SDK API returns void\""); return false; } LOG_INFO("[VizumCamera] AutoDetectEx started successfully"); @@ -1325,14 +1816,14 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti // 检查自动检测状态 VzBool isDetecting = VzNL_IsAutoDetecting(m_deviceHandle, &errorCode); + const std::string detectingErrorText = LogSdkReturn( + "point_cloud_scan_start", "VzNL_IsAutoDetecting", errorCode); if (errorCode == 0) { LOG_INFO("[VizumCamera] IsAutoDetecting after start: {}", isDetecting == VzTrue ? "Yes" : "No"); } else { - char detectingErrorMsg[256] = {0}; - VzNL_GetErrorInfo(errorCode, detectingErrorMsg); LOG_WARN("[VizumCamera] Failed to query IsAutoDetecting after start: {} " - "(error code: {})", detectingErrorMsg, errorCode); + "(error code: {})", detectingErrorText, errorCode); } // 3. 等待扫描完成 @@ -1430,6 +1921,7 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti // 检查摆镜状态 float curAngle = VzNL_GetSwingCurAngle(m_deviceHandle, &errorCode); + LogSdkReturn("point_cloud_scan_progress", "VzNL_GetSwingCurAngle", errorCode); if (errorCode == 0) { LOG_INFO("[VizumCamera] Current swing angle: {:.2f}", curAngle); } @@ -1453,10 +1945,8 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti } else { int detectingError = 0; const VzBool stillDetecting = VzNL_IsAutoDetecting(m_deviceHandle, &detectingError); - char detectingErrorMsg[256] = {0}; - if (detectingError != 0) { - VzNL_GetErrorInfo(detectingError, detectingErrorMsg); - } + const std::string timeoutDetectError = LogSdkReturn( + "point_cloud_timeout", "VzNL_IsAutoDetecting", detectingError); size_t timeoutScanLines = 0; size_t timeoutValidPoints = 0; { @@ -1467,7 +1957,7 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti LOG_WARN("[VizumCamera] Timeout diagnostics: duration={}ms, autoDetecting={}, " "detectError={} ({}), completion status={} ({}), scan lines={}, valid points={}", totalDuration, stillDetecting == VzTrue ? "Yes" : "No", detectingError, - detectingError == 0 ? "none" : detectingErrorMsg, + timeoutDetectError, DeviceStatusName(completionStatus), completionStatus, timeoutScanLines, timeoutValidPoints); } @@ -1481,15 +1971,17 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti // 4. 停止自动检测(与VznlCamera::StopAutoDetect一致) LOG_INFO("[VizumCamera] Step 4: Stopping AutoDetect..."); result = VzNL_StopAutoDetect(m_deviceHandle); + const std::string stopAutoDetectError = LogSdkReturn( + "point_cloud_cleanup", "VzNL_StopAutoDetect", result); if (result != 0) { - char errorMsg[256] = {0}; - VzNL_GetErrorInfo(result, errorMsg); - LOG_WARN("[VizumCamera] Failed to stop auto detect: {}", errorMsg); + LOG_WARN("[VizumCamera] Failed to stop auto detect: {}", stopAutoDetectError); } // 4.1 结束激光检测(关键:与示例代码一致,每次扫描后结束检测) LOG_INFO("[VizumCamera] Step 4.1: Ending laser detection..."); VzNL_EndDetectLaser(m_deviceHandle); + LOG_INFO("[SDKCall] stage=point_cloud_cleanup api=VzNL_EndDetectLaser " + "return_code=unavailable sdk_error_text=\"unavailable: SDK API returns void\""); // 5. 获取累积的点云数据 { @@ -1536,7 +2028,9 @@ bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int ti // 记录摆镜角速度(供保存元信息用,查询失败保持 0) int angleSpeed = 0; - if (VzNL_GetSwingAngleSpeed(m_deviceHandle, &angleSpeed) == 0) { + const int speedResult = VzNL_GetSwingAngleSpeed(m_deviceHandle, &angleSpeed); + LogSdkReturn("point_cloud_result", "VzNL_GetSwingAngleSpeed", speedResult); + if (speedResult == 0) { pointCloud.scanSpeed = static_cast(angleSpeed); } @@ -1816,6 +2310,7 @@ bool VizumCamera::GetFloatParam(const std::string& name, float& value) EVzNLExposeMode exposeMode = keVzNLExposeMode_Fix; uint32_t exposeUs = 0; const int result = VzNL_GetConfigEyeExpose(m_deviceHandle, &exposeMode, &exposeUs); + LogSdkReturn("camera_param_read", "VzNL_GetConfigEyeExpose", result); if (result != 0) { return false; } @@ -1826,8 +2321,10 @@ bool VizumCamera::GetFloatParam(const std::string& name, float& value) if (name == "Gain" || name == "gain") { unsigned short rawGain = 0; int result = VzNL_GetCameraGain(m_deviceHandle, keEyeSensorType_Left, &rawGain); + LogSdkReturn("camera_param_read_left", "VzNL_GetCameraGain", result); if (result != 0) { result = VzNL_GetCameraGain(m_deviceHandle, keEyeSensorType_Right, &rawGain); + LogSdkReturn("camera_param_read_right", "VzNL_GetCameraGain", result); } if (result != 0) { return false; @@ -1855,15 +2352,19 @@ bool VizumCamera::SetFloatParam(const std::string& name, float value) if (name == "ExposureTime" || name == "Exposure" || name == "exposure") { unsigned int minVal = 1; unsigned int maxVal = 65535; - VzNL_QueryParamRange(m_deviceHandle, keDeviceParamType_Expose, &minVal, &maxVal); + const int rangeResult = VzNL_QueryParamRange(m_deviceHandle, + keDeviceParamType_Expose, + &minVal, &maxVal); + LogSdkReturn("camera_param_write", "VzNL_QueryParamRange(exposure)", rangeResult); LOG_INFO("[VizumCamera] SetExposure: requested={:.1f}us, range=[{}, {}]", value, minVal, maxVal); const float bounded = std::clamp(value, static_cast(minVal), static_cast(maxVal)); const uint32_t exposeUs = static_cast(bounded + 0.5f); const int result = VzNL_ConfigEyeExpose(m_deviceHandle, keVzNLExposeMode_Fix, exposeUs); + const std::string exposureError = LogSdkReturn( + "camera_param_write", "VzNL_ConfigEyeExpose", result); if (result != 0) { - char errMsg[256] = {0}; - VzNL_GetErrorInfo(result, errMsg); - LOG_ERROR("[VizumCamera] VzNL_ConfigEyeExpose failed: code={} msg={}", result, errMsg); + LOG_ERROR("[VizumCamera] VzNL_ConfigEyeExpose failed: code={} msg={}", + result, exposureError); } else { LOG_INFO("[VizumCamera] VzNL_ConfigEyeExpose OK: {}us", exposeUs); } @@ -1873,18 +2374,22 @@ bool VizumCamera::SetFloatParam(const std::string& name, float value) if (name == "Gain" || name == "gain") { unsigned int minVal = 0; unsigned int maxVal = 255; - VzNL_QueryParamRange(m_deviceHandle, keDeviceParamType_Gain, &minVal, &maxVal); + const int rangeResult = VzNL_QueryParamRange(m_deviceHandle, + keDeviceParamType_Gain, + &minVal, &maxVal); + LogSdkReturn("camera_param_write", "VzNL_QueryParamRange(gain)", rangeResult); LOG_INFO("[VizumCamera] SetGain: requested={:.2f}, range=[{}, {}]", value, minVal, maxVal); const float bounded = std::clamp(value, static_cast(minVal), static_cast(maxVal)); const unsigned short rawGain = static_cast(bounded + 0.5f); const int leftResult = VzNL_SetCameraGain(m_deviceHandle, keEyeSensorType_Left, rawGain); const int rightResult = VzNL_SetCameraGain(m_deviceHandle, keEyeSensorType_Right, rawGain); + const std::string leftGainError = LogSdkReturn( + "camera_param_write_left", "VzNL_SetCameraGain", leftResult); + const std::string rightGainError = LogSdkReturn( + "camera_param_write_right", "VzNL_SetCameraGain", rightResult); if (leftResult != 0 && rightResult != 0) { - char errMsgL[256] = {0}, errMsgR[256] = {0}; - VzNL_GetErrorInfo(leftResult, errMsgL); - VzNL_GetErrorInfo(rightResult, errMsgR); LOG_ERROR("[VizumCamera] VzNL_SetCameraGain both failed: L={}({}) R={}({})", - leftResult, errMsgL, rightResult, errMsgR); + leftResult, leftGainError, rightResult, rightGainError); } else { LOG_INFO("[VizumCamera] VzNL_SetCameraGain OK: gain={} L={} R={}", rawGain, leftResult, rightResult); } @@ -1941,11 +2446,10 @@ bool VizumCamera::GetDetectROI(ROIRect& leftROI, ROIRect& rightROI) SVzNLROIRect sdkLeft{}; SVzNLROIRect sdkRight{}; const int ret = VzNL_GetConfigDetectROI(m_deviceHandle, &sdkLeft, &sdkRight); + LogSdkReturn("public_roi_read", "VzNL_GetConfigDetectROI", ret); if (ret != 0) { - char errorMsg[256] = {0}; - VzNL_GetErrorInfo(ret, errorMsg); LOG_ERROR("[VizumCamera] VzNL_GetConfigDetectROI failed: {} (error code: {})", - errorMsg, ret); + SdkErrorText(ret), ret); return false; } @@ -1972,8 +2476,11 @@ bool VizumCamera::SetCalibROIEnabled(bool enable) return false; } const int ret = VzNL_EnableCalibROI(m_deviceHandle, enable ? VzTrue : VzFalse); + LogSdkReturn("public_calib_roi_write", + enable ? "VzNL_EnableCalibROI(true)" : "VzNL_EnableCalibROI(false)", ret); if (ret != 0) { - LOG_ERROR("[VizumCamera] VzNL_EnableCalibROI({}) failed, error={}", enable, ret); + LOG_ERROR("[VizumCamera] VzNL_EnableCalibROI({}) failed: {} (error code: {})", + enable, SdkErrorText(ret), ret); return false; } LOG_INFO("[VizumCamera] CalibROI (rectified image output) {}", enable ? "enabled" : "disabled");