#include "DetectPresenter.h" #include "IHandEyeCalib.h" #include "SG_baseAlgo_Export.h" #include "SG_errCode.h" #include #include #include #include #include namespace { const int kSupportedWorkpieceClassCount = 3; const double kDuplicate2DIouThreshold = 0.5; const char* WorkpieceModelLogName() { return "WorkpiceTaperedModel"; } char WorkpieceClassName(int classId) { if (classId >= 0 && classId < 26) { return static_cast('a' + classId); } return '?'; } double RectArea(const WorkpiecePositionModelAdapter::Rect& rect) { const double width = rect.right - rect.left; const double height = rect.bottom - rect.top; if (width <= 0.0 || height <= 0.0) { return 0.0; } return width * height; } double RectIou(const WorkpiecePositionModelAdapter::Rect& lhs, const WorkpiecePositionModelAdapter::Rect& rhs) { const double interLeft = std::max(lhs.left, rhs.left); const double interTop = std::max(lhs.top, rhs.top); const double interRight = std::min(lhs.right, rhs.right); const double interBottom = std::min(lhs.bottom, rhs.bottom); WorkpiecePositionModelAdapter::Rect intersection; intersection.left = interLeft; intersection.top = interTop; intersection.right = interRight; intersection.bottom = interBottom; const double interArea = RectArea(intersection); if (interArea <= 0.0) { return 0.0; } const double unionArea = RectArea(lhs) + RectArea(rhs) - interArea; if (unionArea <= 0.0) { return 0.0; } return interArea / unionArea; } void FilterDuplicate2DDetections( std::vector& detections) { if (detections.size() < 2) { return; } std::stable_sort(detections.begin(), detections.end(), [](const WorkpiecePositionModelAdapter::Detection& lhs, const WorkpiecePositionModelAdapter::Detection& rhs) { return lhs.confidence > rhs.confidence; }); std::vector filtered; filtered.reserve(detections.size()); for (const auto& detection : detections) { bool duplicated = false; for (const auto& kept : filtered) { if (RectIou(detection.objectRoi, kept.objectRoi) >= kDuplicate2DIouThreshold) { duplicated = true; break; } } if (!duplicated) { filtered.push_back(detection); } } detections.swap(filtered); } HECEulerOrder ToHandEyeEulerOrder(int eulerOrder) { switch (eulerOrder) { case 10: return HECEulerOrder::XYZ; case 11: return HECEulerOrder::ZYX; case 12: return HECEulerOrder::ZXY; case 13: return HECEulerOrder::YXZ; case 14: return HECEulerOrder::YZX; case 15: return HECEulerOrder::XZY; default: LOG_WARNING("Unsupported tool euler order %d, fallback to 11 (ZYX)\n", eulerOrder); return HECEulerOrder::ZYX; } } void ApplyToolRotationToEyeAxes(IHandEyeCalib& handEyeCalib, HECEulerOrder eulerOrder, const VrToolParam& toolParam, std::vector& axes) { if (axes.size() != 3 || (std::fabs(toolParam.rotX) < 1e-9 && std::fabs(toolParam.rotY) < 1e-9 && std::fabs(toolParam.rotZ) < 1e-9)) { return; } HECRotationMatrix toolRotation; handEyeCalib.EulerToRotationMatrix( HECEulerAngles::fromDegrees(toolParam.rotX, toolParam.rotY, toolParam.rotZ), eulerOrder, toolRotation); const std::vector originalAxes = axes; for (int column = 0; column < 3; ++column) { axes[column] = (originalAxes[0] * toolRotation.at(0, column) + originalAxes[1] * toolRotation.at(1, column) + originalAxes[2] * toolRotation.at(2, column)).normalized(); } } void ApplyConfiguredAxisInversion(int dirVectorInvert, std::vector& axes) { if (axes.size() != 3) { return; } switch (dirVectorInvert) { case DIR_INVERT_XY: axes[0] = axes[0] * -1.0; axes[1] = axes[1] * -1.0; break; case DIR_INVERT_XZ: axes[0] = axes[0] * -1.0; axes[2] = axes[2] * -1.0; break; case DIR_INVERT_YZ: axes[1] = axes[1] * -1.0; axes[2] = axes[2] * -1.0; break; case DIR_INVERT_NONE: default: break; } } SSG_planeCalibPara ToGroundCalibParam(const VrCameraPlaneCalibParam* cameraCalibParam) { SSG_planeCalibPara groundCalibPara; const double identity[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; if (cameraCalibParam) { std::memcpy(groundCalibPara.planeCalib, cameraCalibParam->planeCalib, sizeof(groundCalibPara.planeCalib)); std::memcpy(groundCalibPara.invRMatrix, cameraCalibParam->invRMatrix, sizeof(groundCalibPara.invRMatrix)); groundCalibPara.planeHeight = cameraCalibParam->planeHeight; } else { std::memcpy(groundCalibPara.planeCalib, identity, sizeof(identity)); std::memcpy(groundCalibPara.invRMatrix, identity, sizeof(identity)); groundCalibPara.planeHeight = -1.0; } return groundCalibPara; } WorkpiecePoint3D ToResultPoint(const HECPoint3D& point) { return WorkpiecePoint3D(point.x, point.y, point.z); } HECPoint3D ToHandEyePoint(const SVzNL3DPoint& point) { return HECPoint3D(point.x, point.y, point.z); } SVzNL3DPoint ToVzPoint(const double values[3]) { SVzNL3DPoint point; point.x = values[0]; point.y = values[1]; point.z = values[2]; return point; } WD_HRM_BinInfo ToWdBinInfo(const VrBinParam& param) { WD_HRM_BinInfo binInfo; std::memset(&binInfo, 0, sizeof(binInfo)); binInfo.length = param.length; binInfo.width = param.width; binInfo.binTopZ = param.binTopZ; binInfo.center = ToVzPoint(param.center); binInfo.bottomNormal = ToVzPoint(param.bottomNormal); binInfo.x_dir = ToVzPoint(param.xDir); binInfo.y_dir = ToVzPoint(param.yDir); for (int i = 0; i < 4; ++i) { binInfo.minRectVertex[i] = ToVzPoint(param.minRectVertex[i]); } return binInfo; } void LogTaperedAlgorithmInput( const std::vector>& scanLines, const std::vector& objROIs, const SSG_planeCalibPara& groundCalibPara, const VrAlgorithmParams& algorithmParams, const double clibMatrix[16], int eulerOrder, int dirVectorInvert) { LOG_INFO("[Tapered Debug] input summary: lines=%zu\n", scanLines.size()); LOG_INFO("[Tapered Debug] params: eulerOrder=%d, dirVectorInvert=%d, " "toolEulerOrder=%d, toolRot=(%.6f,%.6f,%.6f), " "toolOffset=(%.6f,%.6f,%.6f) \n", eulerOrder, dirVectorInvert, algorithmParams.toolParam.eulerOrder, algorithmParams.toolParam.rotX, algorithmParams.toolParam.rotY, algorithmParams.toolParam.rotZ, algorithmParams.toolParam.offsetX, algorithmParams.toolParam.offsetY, algorithmParams.toolParam.offsetZ); LOG_INFO("[Tapered Debug] planeCalib: planeHeight=%.6f\n", groundCalibPara.planeHeight); LOG_INFO("[Tapered Debug] planeCalib=[%.9f %.9f %.9f; %.9f %.9f %.9f; %.9f %.9f %.9f]\n", groundCalibPara.planeCalib[0], groundCalibPara.planeCalib[1], groundCalibPara.planeCalib[2], groundCalibPara.planeCalib[3], groundCalibPara.planeCalib[4], groundCalibPara.planeCalib[5], groundCalibPara.planeCalib[6], groundCalibPara.planeCalib[7], groundCalibPara.planeCalib[8]); LOG_INFO("[Tapered Debug] invRMatrix=[%.9f %.9f %.9f; %.9f %.9f %.9f; %.9f %.9f %.9f]\n", groundCalibPara.invRMatrix[0], groundCalibPara.invRMatrix[1], groundCalibPara.invRMatrix[2], groundCalibPara.invRMatrix[3], groundCalibPara.invRMatrix[4], groundCalibPara.invRMatrix[5], groundCalibPara.invRMatrix[6], groundCalibPara.invRMatrix[7], groundCalibPara.invRMatrix[8]); LOG_INFO("[Tapered Debug] handEye=[%.9f %.9f %.9f %.9f; %.9f %.9f %.9f %.9f; " "%.9f %.9f %.9f %.9f; %.9f %.9f %.9f %.9f]\n", clibMatrix[0], clibMatrix[1], clibMatrix[2], clibMatrix[3], clibMatrix[4], clibMatrix[5], clibMatrix[6], clibMatrix[7], clibMatrix[8], clibMatrix[9], clibMatrix[10], clibMatrix[11], clibMatrix[12], clibMatrix[13], clibMatrix[14], clibMatrix[15]); LOG_INFO("[Tapered Debug] objROIs=%zu\n", objROIs.size()); for (size_t index = 0; index < objROIs.size(); ++index) { const WD_objArea2D& roi = objROIs[index]; LOG_INFO("[Tapered Debug] objROI[%zu]: type=%d, score=%.6f, LTRB=(%.3f,%.3f,%.3f,%.3f)\n", index, roi.workpieceType, roi.score2D, roi.roi.left, roi.roi.top, roi.roi.right, roi.roi.bottom); } } void LogRawTaperedOutputs(const std::vector& workpiecePositions) { for (size_t index = 0; index < workpiecePositions.size(); ++index) { const WD_workpieceInfo& workpiece = workpiecePositions[index]; LOG_INFO("[Tapered Debug] rawOutput[%zu]: id=%d, type=%d, value=%.9f, " "center=(%.9f,%.9f,%.9f), " "x_dir=(%.9f,%.9f,%.9f), y_dir=(%.9f,%.9f,%.9f), z_dir=(%.9f,%.9f,%.9f)\n", index, workpiece.id, workpiece.workpieceType, workpiece.value, workpiece.center.x, workpiece.center.y, workpiece.center.z, workpiece.x_dir.x, workpiece.x_dir.y, workpiece.x_dir.z, workpiece.y_dir.x, workpiece.y_dir.y, workpiece.y_dir.z, workpiece.z_dir.x, workpiece.z_dir.y, workpiece.z_dir.z); } } } // namespace DetectPresenter::DetectPresenter() { const char* version = wd_hybridPositioningVersion(); LOG_INFO("DetectPresenter Init hybrid positioning algorithm ver: %s\n", version ? version : "unknown"); } DetectPresenter::~DetectPresenter() { } QString DetectPresenter::GetAlgoVersion() { const char* version = wd_hybridPositioningVersion(); return version ? QString::fromLocal8Bit(version) : QStringLiteral("未知"); } int DetectPresenter::LocateWorkpiece2D( const SVzNLImageData& leftImage, const VrWorkpieceModelParam& modelParam, const VrDebugParam& debugParam, std::vector& detections) { CVrTimeUtils modelTimer; const WorkpiecePositionModelAdapter::Status modelStatus = m_workpieceModel.Locate(leftImage, modelParam.minimumScore, detections); LOG_INFO("%s: found %zu ROIs, status=%d runtime=%.3fms\n", WorkpieceModelLogName(), detections.size(), static_cast(modelStatus), modelTimer.GetElapsedTimeInMilliSec()); if (modelStatus != WorkpiecePositionModelAdapter::Status::Ok) { const QString errorMessage = m_workpieceModel.LastError(); LOG_ERROR("%s failed: %s\n", WorkpieceModelLogName(), errorMessage.toStdString().c_str()); switch (modelStatus) { case WorkpiecePositionModelAdapter::Status::RuntimeUnavailable: return ERR_CODE(FUN_UNSUPPORT); case WorkpiecePositionModelAdapter::Status::InferenceFailed: return ERR_CODE(APP_ERR_EXEC); case WorkpiecePositionModelAdapter::Status::OutOfMemory: return ERR_CODE(DATA_ERR_MEM); case WorkpiecePositionModelAdapter::Status::InvalidResult: return ERR_CODE(DATA_ERR_INVALID); case WorkpiecePositionModelAdapter::Status::InvalidArgument: case WorkpiecePositionModelAdapter::Status::UnsupportedImageFormat: default: return ERR_CODE(DEV_DATA_INVALID); } } if (detections.empty()) { LOG_WARNING("%s returned no workpiece ROI\n", WorkpieceModelLogName()); return ERR_CODE(SX_ERR_ZERO_2D_OBJECTS); } const size_t rawDetectionCount = detections.size(); FilterDuplicate2DDetections(detections); if (detections.size() != rawDetectionCount) { LOG_INFO("%s duplicate ROI filter: raw=%zu, filtered=%zu, iouThreshold=%.2f\n", WorkpieceModelLogName(), rawDetectionCount, detections.size(), kDuplicate2DIouThreshold); } LOG_INFO("%s 2D model output results:\n", WorkpieceModelLogName()); for (size_t index = 0; index < detections.size(); ++index) { const WorkpiecePositionModelAdapter::Detection& detection = detections[index]; const WorkpiecePositionModelAdapter::Rect& roi = detection.objectRoi; LOG_INFO("obj_%zu: C=%c, Rect={ %.3f, %.3f, %.3f, %.3f }, Score=%.4f\n", index + 1, WorkpieceClassName(detection.classId), roi.left, roi.top, roi.right - roi.left, roi.bottom - roi.top, detection.confidence); } if (debugParam.enableDebug && debugParam.printDetailLog) { for (size_t index = 0; index < detections.size(); ++index) { const WorkpiecePositionModelAdapter::Detection& detection = detections[index]; LOG_INFO("[2D ROI %zu] class=%d " "label=%s score=%.3f " "objectLTRB=(%.1f,%.1f,%.1f,%.1f) mask=%s\n", index, detection.classId, detection.label.toStdString().c_str(), detection.confidence, detection.objectRoi.left, detection.objectRoi.top, detection.objectRoi.right, detection.objectRoi.bottom, detection.HasMask() ? "yes" : "no"); } } return SUCCESS; } int DetectPresenter::DetectStatorWorkpiecePosition( int cameraIndex, std::vector>& laserLines, const std::vector& detections, const VrAlgorithmParams& algorithmParams, const VrDebugParam& debugParam, LaserDataLoader& dataLoader, const double clibMatrix[16], int eulerOrder, int dirVectorInvert, const WD_HRM_BinInfo* binInfo, StatorWorkpiecePositionDetectionResult& detectionResult) { detectionResult.cameraIndex = cameraIndex; detectionResult.errorCode = SUCCESS; detectionResult.positions.clear(); if (laserLines.empty()) { detectionResult.errorCode = ERR_CODE(DEV_DATA_INVALID); return detectionResult.errorCode; } if (detections.empty()) { detectionResult.errorCode = ERR_CODE(SX_ERR_ZERO_2D_OBJECTS); return detectionResult.errorCode; } std::vector> algorithmData; const int positionResult = dataLoader.ConvertToSVzNLPositionD( laserLines, algorithmData); if (positionResult != SUCCESS) { detectionResult.errorCode = positionResult; LOG_WARNING("Failed to convert VzNLSDK data to SVzNLPositionD, err=%d, detail=%s\n", positionResult, dataLoader.GetLastError().c_str()); return positionResult; } if (algorithmData.empty()) { detectionResult.errorCode = ERR_CODE(DEV_DATA_INVALID); LOG_WARNING("Tapered algorithm input has no valid scan lines\n"); return detectionResult.errorCode; } if (debugParam.enableDebug && debugParam.printDetailLog) { LOG_INFO("[Tapered Debug] SVzNLPositionD input lines: %zu\n", algorithmData.size()); } VrCameraPlaneCalibParam cameraCalibParamValue; const VrCameraPlaneCalibParam* cameraCalibParam = nullptr; if (algorithmParams.planeCalibParam.GetCameraCalibParam(cameraIndex, cameraCalibParamValue) && cameraCalibParamValue.isCalibrated) { cameraCalibParam = &cameraCalibParamValue; } const SSG_planeCalibPara groundCalibPara = ToGroundCalibParam(cameraCalibParam); std::vector objROIs; objROIs.reserve(detections.size()); std::vector sourceDetectionIndices; sourceDetectionIndices.reserve(detections.size()); for (size_t index = 0; index < detections.size(); ++index) { const WorkpiecePositionModelAdapter::Detection& detection = detections[index]; if (detection.classId < 0 || detection.classId >= kSupportedWorkpieceClassCount) { LOG_WARNING("Ignoring unsupported 2D class at ROI %zu: class=%d\n", index, detection.classId); continue; } const int workpieceType = algorithmParams.modelParam.WorkpieceTypeForClass(detection.classId); if (workpieceType <= 0) { LOG_INFO("Ignoring disabled 2D class at ROI %zu: class=%d, configured workpieceType=%d\n", index, detection.classId, workpieceType); continue; } const WorkpiecePositionModelAdapter::Rect& roi = detection.objectRoi; if (!std::isfinite(detection.confidence) || detection.confidence < 0.0 || detection.confidence > 1.0 || !std::isfinite(roi.left) || !std::isfinite(roi.top) || !std::isfinite(roi.right) || !std::isfinite(roi.bottom) || roi.right <= roi.left || roi.bottom <= roi.top) { detectionResult.errorCode = ERR_CODE(DATA_ERR_INVALID); LOG_ERROR("Invalid 2D ROI at index %zu: class=%d score=%.6f " "LTRB=(%.3f,%.3f,%.3f,%.3f)\n", index,detection.classId, detection.confidence, roi.left, roi.top, roi.right, roi.bottom); return detectionResult.errorCode; } WD_objArea2D objROI = {}; objROI.workpieceType = workpieceType; // class0/1/2 -> a/b/c -> 1/2/3 objROI.roi.left = roi.left; objROI.roi.top = roi.top; objROI.roi.right = roi.right; objROI.roi.bottom = roi.bottom; objROI.score2D = detection.confidence; objROIs.push_back(objROI); sourceDetectionIndices.push_back(static_cast(index)); } if (objROIs.empty()) { detectionResult.errorCode = ERR_CODE(SX_ERR_ZERO_2D_OBJECTS); LOG_WARNING("No enabled 2D ROI is available for tapered workpiece positioning\n"); return detectionResult.errorCode; } std::vector workpiecePositions; CVrTimeUtils timer; int algorithmResult = SUCCESS; if (debugParam.enableDebug && debugParam.printDetailLog) { LogTaperedAlgorithmInput(algorithmData, objROIs, groundCalibPara, algorithmParams, clibMatrix, eulerOrder, dirVectorInvert); } (void)binInfo; size_t totalPoints = 0; for (const auto& line : algorithmData) { totalPoints += line.size(); } LOG_INFO("[Tapered] entering wd_HRM_TaperedWorkpiecePositioning: lines=%zu points=%zu objROIs=%zu\n", algorithmData.size(), totalPoints, objROIs.size()); try { wd_HRM_TaperedWorkpiecePositioning(algorithmData, objROIs, groundCalibPara, workpiecePositions, &algorithmResult); LOG_INFO("wd_HRM_TaperedWorkpiecePositioning returned: found %zu workpieces, err=%d runtime=%.3fms\n", workpiecePositions.size(), algorithmResult, timer.GetElapsedTimeInMilliSec()); } catch (const std::exception& e) { LOG_ERROR("wd_HRM_TaperedWorkpiecePositioning threw exception: %s\n", e.what()); detectionResult.errorCode = ERR_CODE(APP_ERR_EXEC); return detectionResult.errorCode; } catch (...) { LOG_ERROR("wd_HRM_TaperedWorkpiecePositioning threw unknown exception\n"); detectionResult.errorCode = ERR_CODE(APP_ERR_EXEC); return detectionResult.errorCode; } if (debugParam.enableDebug && debugParam.printDetailLog) { LogRawTaperedOutputs(workpiecePositions); } if (algorithmResult != SUCCESS) { detectionResult.errorCode = algorithmResult; return algorithmResult; } if (workpiecePositions.empty()) { detectionResult.errorCode = ERR_CODE(SX_ERR_ZERO_OBJECTS); LOG_WARNING("Tapered workpiece algorithm returned success without a target\n"); return detectionResult.errorCode; } std::unique_ptr handEyeCalib( CreateHandEyeCalibInstance(), DestroyHandEyeCalibInstance); if (!handEyeCalib) { detectionResult.errorCode = ERR_CODE(DEV_NOT_FIND); return detectionResult.errorCode; } (void)eulerOrder; // The supplied 4x4 matrix already fixes the hand-eye rotation. const HECCalibResult calibResult = HECCalibResult::fromHomogeneousArray(clibMatrix); const VrToolParam& toolParam = algorithmParams.toolParam; const HECEulerOrder toolEulerOrder = ToHandEyeEulerOrder(toolParam.eulerOrder); for (size_t index = 0; index < workpiecePositions.size(); ++index) { const WD_workpieceInfo& workpiece = workpiecePositions[index]; WorkpiecePosition position; position.workpieceType = workpiece.workpieceType; if (workpiece.id > 0 && workpiece.id <= static_cast(sourceDetectionIndices.size())) { position.sourceDetectionIndex = sourceDetectionIndices[workpiece.id - 1]; } else if (index < sourceDetectionIndices.size()) { position.sourceDetectionIndex = sourceDetectionIndices[index]; LOG_WARNING("Invalid workpiece id=%d at algorithm output %zu, fallback sourceDetectionIndex=%d\n", workpiece.id, index, position.sourceDetectionIndex); } else { position.sourceDetectionIndex = static_cast(index); LOG_WARNING("Invalid workpiece id=%d at algorithm output %zu, fallback output index=%d\n", workpiece.id, index, position.sourceDetectionIndex); } position.value = workpiece.value; HECPoint3D robotCenter; handEyeCalib->TransformPoint(calibResult.R, calibResult.T, ToHandEyePoint(workpiece.center), robotCenter); position.center = ToResultPoint(robotCenter); position.x = robotCenter.x + toolParam.offsetX; position.y = robotCenter.y + toolParam.offsetY; position.z = robotCenter.z + toolParam.offsetZ; std::vector eyeAxes; eyeAxes.push_back(ToHandEyePoint(workpiece.x_dir).normalized()); eyeAxes.push_back(ToHandEyePoint(workpiece.y_dir).normalized()); eyeAxes.push_back(ToHandEyePoint(workpiece.z_dir).normalized()); ApplyConfiguredAxisInversion(dirVectorInvert, eyeAxes); ApplyToolRotationToEyeAxes(*handEyeCalib, toolEulerOrder, toolParam, eyeAxes); std::vector robotAxes(3); for (int axis = 0; axis < 3; ++axis) { handEyeCalib->RotatePoint(calibResult.R, eyeAxes[axis], robotAxes[axis]); robotAxes[axis] = robotAxes[axis].normalized(); } position.xDir = ToResultPoint(robotAxes[0]); position.yDir = ToResultPoint(robotAxes[1]); position.zDir = ToResultPoint(robotAxes[2]); double rotation[3][3] = { {robotAxes[0].x, robotAxes[1].x, robotAxes[2].x}, {robotAxes[0].y, robotAxes[1].y, robotAxes[2].y}, {robotAxes[0].z, robotAxes[1].z, robotAxes[2].z} }; const SSG_EulerAngles robotRpy = rotationMatrixToEulerZYX(rotation); position.roll = robotRpy.roll; position.pitch = robotRpy.pitch; position.yaw = robotRpy.yaw; if (debugParam.enableDebug && debugParam.printDetailLog) { LOG_INFO("[Tapered Debug] finalOutput[%zu]: id=%d, sourceDetectionIndex=%d, type=%d, value=%.9f, " "centerRobot=(%.9f,%.9f,%.9f), targetXYZ=(%.9f,%.9f,%.9f), " "RPY=(%.9f,%.9f,%.9f)\n", index, workpiece.id, position.sourceDetectionIndex, position.workpieceType, position.value, position.center.x, position.center.y, position.center.z, position.x, position.y, position.z, position.roll, position.pitch, position.yaw); } detectionResult.positions.push_back(position); } return SUCCESS; } int DetectPresenter::DetectBin( int cameraIndex, std::vector>& laserLines, const VrAlgorithmParams& algorithmParams, const VrDebugParam& debugParam, LaserDataLoader& dataLoader, WD_HRM_BinInfo& binInfo) { (void)debugParam; if (laserLines.empty()) { return ERR_CODE(DEV_DATA_INVALID); } std::vector> scanLines; const int convertResult = dataLoader.ConvertToSVzNL3DPosition(laserLines, scanLines); if (convertResult != SUCCESS) { LOG_WARNING("Failed to convert VzNLSDK data to SVzNL3DPosition for bin detection, err=%d, detail=%s\n", convertResult, dataLoader.GetLastError().c_str()); return convertResult; } if (scanLines.empty()) { return ERR_CODE(DEV_DATA_INVALID); } VrCameraPlaneCalibParam cameraCalibParamValue; const VrCameraPlaneCalibParam* cameraCalibParam = nullptr; if (algorithmParams.planeCalibParam.GetCameraCalibParam(cameraIndex, cameraCalibParamValue) && cameraCalibParamValue.isCalibrated) { cameraCalibParam = &cameraCalibParamValue; } const SSG_planeCalibPara groundCalibPara = ToGroundCalibParam(cameraCalibParam); CVrTimeUtils timer; int errCode = SUCCESS; size_t totalPoints = 0; for (const auto& line : scanLines) { totalPoints += line.size(); } LOG_INFO("[Tapered] entering wd_HRM_getBinSize: lines=%zu points=%zu binHeight=%.3f\n", scanLines.size(), totalPoints, algorithmParams.binParam.binHeight); try { binInfo = wd_HRM_getBinSize( scanLines, groundCalibPara, algorithmParams.binParam.binHeight, &errCode); LOG_INFO("wd_HRM_getBinSize returned: err=%d runtime=%.3fms, binHeight=%.3f, length=%.3f, width=%.3f, topZ=%.3f, center=(%.3f,%.3f,%.3f)\n", errCode, timer.GetElapsedTimeInMilliSec(), algorithmParams.binParam.binHeight, binInfo.length, binInfo.width, binInfo.binTopZ, binInfo.center.x, binInfo.center.y, binInfo.center.z); } catch (const std::exception& e) { LOG_ERROR("wd_HRM_getBinSize threw exception: %s\n", e.what()); return ERR_CODE(APP_ERR_EXEC); } catch (...) { LOG_ERROR("wd_HRM_getBinSize threw unknown exception\n"); return ERR_CODE(APP_ERR_EXEC); } return errCode; }