694 lines
24 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "DiscHolePosePresenter.h"
#include "DetectPresenter.h"
#include "PathManager.h"
#include "DiscHolePoseTCPProtocol.h"
#include "Version.h"
#include "VrConvert.h"
#include "VrError.h"
#include "VrLog.h"
#include "VrTimeUtils.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDateTime>
#include <QtCore/QString>
#include <algorithm>
#include <cstdio>
#include <cstring>
DiscHolePosePresenter::DiscHolePosePresenter(QObject *parent)
: BasePresenter(parent)
{
}
DiscHolePosePresenter::~DiscHolePosePresenter()
{
if (m_pConfigManager) {
delete m_pConfigManager;
m_pConfigManager = nullptr;
}
if (m_pTCPServer) {
m_pTCPServer->StopServer();
delete m_pTCPServer;
m_pTCPServer = nullptr;
}
if (m_pDetectPresenter) {
delete m_pDetectPresenter;
m_pDetectPresenter = nullptr;
}
}
int DiscHolePosePresenter::InitApp()
{
LOG_DEBUG("Start APP Version: %s\n", DISCHOLEPOSE_VERSION_STRING);
SetWorkStatus(WorkStatus::InitIng);
m_pDetectPresenter = new DetectPresenter();
m_pConfigManager = new ConfigManager();
if (!m_pConfigManager) {
LOG_ERROR("Failed to create ConfigManager instance\n");
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate("配置管理器创建失败");
}
return ERR_CODE(DEV_CONFIG_ERR);
}
if (!m_pConfigManager->Initialize()) {
LOG_ERROR("Failed to initialize ConfigManager\n");
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate("配置管理器初始化失败");
}
return ERR_CODE(DEV_CONFIG_ERR);
}
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
SetDebugParam(configResult.debugParam);
m_modbusRegistersInitialized = false;
m_modbusWorkStatus = 0;
std::vector<DeviceInfo> cameraList = configResult.cameraList;
InitCamera(cameraList, false, true);
LOG_INFO("Camera initialization completed. Connected cameras: %zu, default camera index: %d\n",
m_vrEyeDeviceList.size(), m_currentCameraIndex);
int nRet = InitTCPServer();
if (nRet != SUCCESS) {
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate("TCP服务器初始化失败");
}
m_bTCPConnected = false;
} else {
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate("TCP服务器初始化成功");
}
}
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate("设备初始化完成");
}
CheckAndUpdateWorkStatus();
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate("配置初始化成功");
}
return SUCCESS;
}
int DiscHolePosePresenter::InitAlgoParams()
{
LOG_DEBUG("initializing algorithm parameters\n");
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
SetDebugParam(configResult.debugParam);
LOG_INFO("Loaded %zu detection config sets\n",
configResult.detectionConfigList.size());
for (const auto& item : configResult.detectionConfigList) {
const char* typeStr = (item.detectionType == DETECTION_TYPE_DISC_RACK) ? "discRack" : "discHole";
LOG_INFO(" - camera %d / %s : cornerTh=%.1f scale=%.1f\n",
item.cameraIndex, typeStr,
item.algorithmParams.cornerParam.cornerTh,
item.algorithmParams.cornerParam.scale);
}
LOG_INFO("Algorithm parameters initialized successfully\n");
return SUCCESS;
}
CalibMatrix DiscHolePosePresenter::GetClibMatrix(int cameraIndex, DetectionType type) const
{
CalibMatrix clibMatrix;
const double identity[16] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
};
std::memcpy(clibMatrix.clibMatrix, identity, sizeof(identity));
if (!m_pConfigManager) {
LOG_WARNING("ConfigManager not initialized while requesting clib matrix\n");
return clibMatrix;
}
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
if (const auto* item = configResult.FindDetectionConfig(cameraIndex, type)) {
std::memcpy(clibMatrix.clibMatrix, item->handEyeMatrix.matrix, sizeof(identity));
} else {
LOG_WARNING("No clib matrix configured for camera=%d type=%d, using identity\n",
cameraIndex, static_cast<int>(type));
}
return clibMatrix;
}
CalibMatrix DiscHolePosePresenter::GetClibMatrix(int index) const
{
return GetClibMatrix(index + 1, DETECTION_TYPE_DISC_HOLE);
}
void DiscHolePosePresenter::CheckAndUpdateWorkStatus()
{
SetWorkStatus(m_bCameraConnected ? WorkStatus::Ready : WorkStatus::Error);
}
int DiscHolePosePresenter::ProcessAlgoDetection(std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& detectionDataCache)
{
LOG_INFO("[Algo Thread] Start real detection task using algorithm\n");
const unsigned int lineNum = detectionDataCache.size();
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate(QString("扫描线数:%1正在算法检测...").arg(lineNum).toStdString());
}
if (!m_pDetectPresenter) {
LOG_ERROR("DetectPresenter is null, cannot proceed with detection\n");
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate("检测处理器未初始化");
}
return ERR_CODE(DEV_NOT_FIND);
}
CVrTimeUtils oTimeUtils;
const CalibMatrix currentClibMatrix = GetClibMatrix(m_currentCameraIndex, m_currentDetectionType);
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
const VrDebugParam debugParam = configResult.debugParam;
const int poseOutputOrder = configResult.poseOutputOrder;
// 选中 (camera, detectionType) 对应的 4 套之一;找不到时使用默认值(已在加载时补齐,
// 此处保留兜底是为了应对运行期相机数量变化的极端场景)。
VrAlgorithmParams algorithmParams;
HandEyeExtrinsic extrinsic;
if (const auto* item = configResult.FindDetectionConfig(m_currentCameraIndex, m_currentDetectionType)) {
algorithmParams = item->algorithmParams;
// planeCalibParam 是相机级共享配置,永远从顶层取
algorithmParams.planeCalibParam = configResult.algorithmParams.planeCalibParam;
extrinsic.eulerOrder = item->handEyeMatrix.eulerOrder;
extrinsic.rotX = item->handEyeMatrix.rotX;
extrinsic.rotY = item->handEyeMatrix.rotY;
extrinsic.rotZ = item->handEyeMatrix.rotZ;
extrinsic.offsetX = item->handEyeMatrix.offsetX;
extrinsic.offsetY = item->handEyeMatrix.offsetY;
extrinsic.offsetZ = item->handEyeMatrix.offsetZ;
extrinsic.outRotX = item->handEyeMatrix.outRotX;
extrinsic.outRotY = item->handEyeMatrix.outRotY;
extrinsic.outRotZ = item->handEyeMatrix.outRotZ;
} else {
LOG_WARNING("No detection config set found for camera=%d type=%d, using defaults\n",
m_currentCameraIndex, static_cast<int>(m_currentDetectionType));
algorithmParams.planeCalibParam = configResult.algorithmParams.planeCalibParam;
}
LOG_INFO("[Algo Thread] camera=%d type=%d eulerOrder=%d poseOutputOrder=%d rot=(%.3f, %.3f, %.3f) outRot=(%.3f, %.3f, %.3f) offset=(%.3f, %.3f, %.3f)\n",
m_currentCameraIndex, static_cast<int>(m_currentDetectionType),
extrinsic.eulerOrder, poseOutputOrder,
extrinsic.rotX, extrinsic.rotY, extrinsic.rotZ,
extrinsic.outRotX, extrinsic.outRotY, extrinsic.outRotZ,
extrinsic.offsetX, extrinsic.offsetY, extrinsic.offsetZ);
DetectionResult detectionResult;
detectionResult.cameraIndex = m_currentCameraIndex;
int nRet = SUCCESS;
if (m_currentDetectionType == DETECTION_TYPE_DISC_RACK) {
nRet = m_pDetectPresenter->DetectDiscRack(
m_currentCameraIndex,
detectionDataCache,
algorithmParams,
debugParam,
m_dataLoader,
currentClibMatrix.clibMatrix,
m_currentRobotPose,
extrinsic,
poseOutputOrder,
detectionResult);
} else {
nRet = m_pDetectPresenter->DetectDiscHole(
m_currentCameraIndex,
detectionDataCache,
algorithmParams,
debugParam,
m_dataLoader,
currentClibMatrix.clibMatrix,
m_currentRobotPose,
extrinsic,
poseOutputOrder,
detectionResult);
}
if (nRet != SUCCESS) {
detectionResult.success = false;
if (detectionResult.errorCode == 0) {
detectionResult.errorCode = nRet;
}
if (detectionResult.message.isEmpty() || detectionResult.message == QStringLiteral("检测成功")) {
detectionResult.message = QString("检测失败:%1").arg(nRet);
}
}
LOG_INFO("[Algo Thread] detection type=%d objects=%zu time : %.2f ms\n",
static_cast<int>(m_currentDetectionType),
detectionResult.positions.size(),
oTimeUtils.GetElapsedTimeInMilliSec());
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnDetectionResult(detectionResult);
}
QString statusMsg;
if (!detectionResult.success) {
statusMsg = detectionResult.message;
} else if (m_currentDetectionType == DETECTION_TYPE_DISC_RACK) {
statusMsg = QString("砂轮盘架子检测完成,定位点数:%1").arg(detectionResult.positions.size());
} else {
statusMsg = QString("砂轮盘孔检测完成,发现%1个孔").arg(detectionResult.positions.size());
}
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate(statusMsg.toStdString());
}
_SendDetectionResultToTCP(detectionResult, m_currentCameraIndex);
_PublishDetectionResultToModbus(detectionResult);
return nRet;
}
void DiscHolePosePresenter::OnConfigChanged(const ConfigResult& configResult)
{
LOG_INFO("Configuration changed notification received, reloading algorithm parameters\n");
SetDebugParam(configResult.debugParam);
int result = InitAlgoParams();
stopServer();
const int tcpResult = InitTCPServer();
if (result == SUCCESS) {
LOG_INFO("Algorithm parameters reloaded successfully after config change\n");
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate("配置已更新,算法参数重新加载成功");
}
} else {
LOG_ERROR("Failed to reload algorithm parameters after config change, error: %d\n", result);
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate("配置更新后算法参数重新加载失败");
}
}
if (tcpResult != SUCCESS) {
LOG_ERROR("Failed to restart TCP server after config change, error: %d\n", tcpResult);
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate("TCP server restart failed");
}
}
}
SSG_planeCalibPara DiscHolePosePresenter::_GetCameraCalibParam(int cameraIndex)
{
SSG_planeCalibPara calibParam;
const double identityMatrix[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
for (int i = 0; i < 9; ++i) {
calibParam.planeCalib[i] = identityMatrix[i];
calibParam.invRMatrix[i] = identityMatrix[i];
}
calibParam.planeHeight = -1.0;
const VrAlgorithmParams algorithmParams = m_pConfigManager->GetAlgorithmParams();
for (const auto& cameraParam : algorithmParams.planeCalibParam.cameraCalibParams) {
if (cameraParam.cameraIndex == cameraIndex && cameraParam.isCalibrated) {
for (int i = 0; i < 9; ++i) {
calibParam.planeCalib[i] = cameraParam.planeCalib[i];
calibParam.invRMatrix[i] = cameraParam.invRMatrix[i];
}
calibParam.planeHeight = cameraParam.planeHeight;
}
}
return calibParam;
}
void DiscHolePosePresenter::OnCameraStatusChanged(int cameraIndex, bool isConnected)
{
LOG_INFO("Camera %d status changed: %s\n", cameraIndex, isConnected ? "connected" : "disconnected");
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
if (cameraIndex == 1) {
pStatus->OnCamera1StatusChanged(isConnected);
} else if (cameraIndex == 2) {
pStatus->OnCamera2StatusChanged(isConnected);
}
QString cameraName;
const int arrayIndex = cameraIndex - 1;
if (arrayIndex >= 0 && arrayIndex < static_cast<int>(m_vrEyeDeviceList.size())) {
cameraName = QString::fromStdString(m_vrEyeDeviceList[arrayIndex].first);
} else {
cameraName = QString("相机%1").arg(cameraIndex);
}
const QString statusMsg = QString("%1%2").arg(cameraName).arg(isConnected ? "已连接" : "已断开");
pStatus->OnStatusUpdate(statusMsg.toStdString());
}
CheckAndUpdateWorkStatus();
}
void DiscHolePosePresenter::OnWorkStatusChanged(WorkStatus status)
{
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnWorkStatusChanged(status);
}
if (!m_modbusRegistersInitialized && status == WorkStatus::Ready) {
_InitializeModbusRegisters();
}
if (status == WorkStatus::Working) {
_UpdateModbusWorkStatus(1);
} else if (status == WorkStatus::Error) {
_UpdateModbusWorkStatus(3);
}
}
void DiscHolePosePresenter::OnCameraCountChanged(int count)
{
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnCameraCountChanged(count);
}
}
void DiscHolePosePresenter::OnStatusUpdate(const std::string& statusMessage)
{
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate(statusMessage);
}
}
void DiscHolePosePresenter::OnModbusServerStatusChanged(bool isConnected)
{
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnRobotConnectionChanged(isConnected);
}
}
void DiscHolePosePresenter::OnModbusWriteCallback(uint16_t startAddress, const uint16_t* data, uint16_t count)
{
if (!data || count == 0) {
return;
}
// Modbus 地址分配(与 TCPServerMethods.cpp 一致):
// 地址 0 : 触发寄存器
// 地址 2~13 : 机械臂位姿6 个 float32 = 12 个 uint16
constexpr uint16_t kTriggerAddress = 0;
constexpr uint16_t kRobotPoseAddress = 2;
constexpr uint16_t kRobotPoseRegCount = 12;
// 缓存机械臂位姿写入地址2~136个float32
for (uint16_t i = 0; i < count; ++i) {
uint16_t addr = startAddress + i;
if (addr >= kRobotPoseAddress && addr < kRobotPoseAddress + kRobotPoseRegCount) {
m_modbusRobotPoseRegs[addr - kRobotPoseAddress] = data[i];
}
}
// 检查触发
uint16_t triggerValue = 0;
bool hasTrigger = false;
for (uint16_t i = 0; i < count; ++i) {
if (startAddress + i == kTriggerAddress) {
triggerValue = data[i];
hasTrigger = true;
break;
}
}
if (!hasTrigger) {
return;
}
const uint16_t resetValue = 0;
WriteModbusRegisters(kTriggerAddress, &resetValue, 1);
if (triggerValue == static_cast<uint16_t>(DETECTION_TYPE_DISC_HOLE) ||
triggerValue == static_cast<uint16_t>(DETECTION_TYPE_DISC_RACK)) {
// 从缓存的寄存器中解析机械臂位姿
RobotPose6D robotPose;
auto regToFloat = [this](int offset) -> float {
uint32_t raw = (static_cast<uint32_t>(m_modbusRobotPoseRegs[offset]) << 16) | static_cast<uint32_t>(m_modbusRobotPoseRegs[offset + 1]);
float val = 0;
std::memcpy(&val, &raw, sizeof(val));
return val;
};
robotPose.x = regToFloat(0);
robotPose.y = regToFloat(2);
robotPose.z = regToFloat(4);
robotPose.a = regToFloat(6);
robotPose.b = regToFloat(8);
robotPose.c = regToFloat(10);
LOG_INFO("Modbus trigger: type=%u, robotPose=(%.3f, %.3f, %.3f, %.3f, %.3f, %.3f)\n",
triggerValue, robotPose.x, robotPose.y, robotPose.z, robotPose.a, robotPose.b, robotPose.c);
TriggerDetection(-1, static_cast<DetectionType>(triggerValue), robotPose);
return;
}
LOG_WARNING("Unsupported Modbus trigger value: %u\n", triggerValue);
_UpdateModbusWorkStatus(3);
if (auto pStatus = GetStatusCallback<IYDiscHolePoseStatus>()) {
pStatus->OnStatusUpdate(QString("Modbus触发值无效:%1").arg(triggerValue).toStdString());
}
}
bool DiscHolePosePresenter::CalculatePlaneCalibration(
const std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>& scanData,
double planeCalib[9],
double& planeHeight,
double invRMatrix[9])
{
try {
if (scanData.empty()) {
LOG_ERROR("No scan data available for plane calibration\n");
return false;
}
LaserDataLoader dataLoader;
std::vector<std::vector<SVzNL3DPosition>> xyzData;
int convertResult = dataLoader.ConvertToSVzNL3DPosition(scanData, xyzData);
if (convertResult != SUCCESS || xyzData.empty()) {
LOG_WARNING("Failed to convert data to XYZ format or no XYZ data available\n");
return false;
}
const double identity[9] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0};
std::memcpy(planeCalib, identity, sizeof(double) * 9);
std::memcpy(invRMatrix, identity, sizeof(double) * 9);
planeHeight = -1.0;
LOG_INFO("Plane calibration calculated successfully: height=%.3f\n", planeHeight);
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception in CalculatePlaneCalibration: %s\n", e.what());
return false;
} catch (...) {
LOG_ERROR("Unknown exception in CalculatePlaneCalibration\n");
return false;
}
}
bool DiscHolePosePresenter::SaveLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9],
int cameraIndex, const QString& cameraName)
{
try {
if (!m_pConfigManager) {
LOG_ERROR("ConfigManager is null, cannot save leveling results\n");
return false;
}
if (cameraIndex <= 0 || cameraName.isEmpty()) {
LOG_ERROR("Invalid camera info when saving leveling results\n");
return false;
}
const QString configPath = PathManager::GetInstance().GetConfigFilePath();
SystemConfig systemConfig = m_pConfigManager->GetConfig();
VrCameraPlaneCalibParam cameraParam;
cameraParam.cameraIndex = cameraIndex;
cameraParam.cameraName = cameraName.toStdString();
cameraParam.planeHeight = planeHeight;
cameraParam.isCalibrated = true;
for (int i = 0; i < 9; ++i) {
cameraParam.planeCalib[i] = planeCalib[i];
cameraParam.invRMatrix[i] = invRMatrix[i];
}
systemConfig.configResult.algorithmParams.planeCalibParam.SetCameraCalibParam(cameraParam);
if (!m_pConfigManager->UpdateFullConfig(systemConfig)) {
LOG_ERROR("Failed to update config with leveling results\n");
return false;
}
if (!m_pConfigManager->SaveConfigToFile(configPath.toStdString())) {
LOG_ERROR("Failed to save config file with leveling results\n");
return false;
}
LOG_INFO("Leveling results saved successfully for camera %d (%s)\n",
cameraIndex, cameraName.toUtf8().constData());
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception in SaveLevelingResults: %s\n", e.what());
return false;
}
}
bool DiscHolePosePresenter::LoadLevelingResults(int cameraIndex, const QString& cameraName,
double planeCalib[9], double& planeHeight, double invRMatrix[9])
{
try {
if (!m_pConfigManager) {
LOG_ERROR("ConfigManager is null, cannot load calibration data\n");
return false;
}
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
VrCameraPlaneCalibParam cameraParamValue;
if (!configResult.algorithmParams.planeCalibParam.GetCameraCalibParam(cameraIndex, cameraParamValue) ||
!cameraParamValue.isCalibrated) {
LOG_INFO("No calibration data found for camera %d (%s)\n",
cameraIndex, cameraName.toUtf8().constData());
return false;
}
for (int i = 0; i < 9; ++i) {
planeCalib[i] = cameraParamValue.planeCalib[i];
invRMatrix[i] = cameraParamValue.invRMatrix[i];
}
planeHeight = cameraParamValue.planeHeight;
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception in LoadLevelingResults: %s\n", e.what());
return false;
}
}
void DiscHolePosePresenter::DeinitApp()
{
LOG_DEBUG("Deinitializing DiscHolePosePresenter\n");
StopDetection();
if (m_pTCPServer) {
m_pTCPServer->StopServer();
delete m_pTCPServer;
m_pTCPServer = nullptr;
}
if (m_pConfigManager) {
delete m_pConfigManager;
m_pConfigManager = nullptr;
}
if (m_pDetectPresenter) {
delete m_pDetectPresenter;
m_pDetectPresenter = nullptr;
}
}
bool DiscHolePosePresenter::TriggerDetection(int cameraIndex, DetectionType detectionType, const RobotPose6D& robotPose)
{
if (cameraIndex > 0) {
SetDefaultCameraIndex(cameraIndex);
}
m_currentDetectionType = detectionType;
m_currentRobotPose = robotPose;
m_requestTimestamp = QDateTime::currentMSecsSinceEpoch();
if (!m_bCameraConnected) {
LOG_WARNING("Camera not connected, cannot trigger detection\n");
_UpdateModbusWorkStatus(3);
return false;
}
if (GetCurrentWorkStatus() == WorkStatus::Working) {
LOG_WARNING("Detection is already running, skip duplicated trigger\n");
_UpdateModbusWorkStatus(1);
return false;
}
_InitializeModbusRegisters();
_ResetModbusResultRegisters();
_UpdateModbusWorkStatus(1);
int ret = StartDetection(cameraIndex, false);
if (ret != SUCCESS) {
LOG_ERROR("Failed to trigger detection, error: %d\n", ret);
_UpdateModbusWorkStatus(3);
return false;
}
return true;
}
int DiscHolePosePresenter::LoadAndDetect(const QString& fileName, DetectionType detectionType)
{
LOG_INFO("Loading data from file: %s, detectionType: %d\n",
fileName.toStdString().c_str(), static_cast<int>(detectionType));
m_currentDetectionType = detectionType;
return LoadDebugDataAndDetect(fileName.toStdString());
}
void DiscHolePosePresenter::ReconnectCamera()
{
LOG_INFO("Attempting to reconnect cameras\n");
TryReconnectCameras();
}
VrCornerParam DiscHolePosePresenter::GetCornerParams() const
{
VrCornerParam params;
if (m_pConfigManager) {
// 以 (Camera 1, DiscHole) 作为「公共默认」展示值。
// 这条 set 在加载时已被 EnsureDetectionConfig 兜底填充,肯定存在。
const ConfigResult configResult = m_pConfigManager->GetConfigResult();
const VrDetectionConfigSet* defaultSet =
configResult.FindDetectionConfig(1, DETECTION_TYPE_DISC_HOLE);
if (defaultSet) {
params = defaultSet->algorithmParams.cornerParam;
return params;
}
}
// 默认值由 VrCornerParam 结构体默认初始化提供
return params;
}
QString DiscHolePosePresenter::GetAlgoVersion() const
{
return DetectPresenter::GetAlgoVersion();
}
void DiscHolePosePresenter::SetCornerParams(const VrCornerParam& params)
{
if (!m_pConfigManager) {
LOG_WARNING("ConfigManager not initialized, cannot set algorithm params\n");
return;
}
// DiscHolePose 仅使用 cornerParam将其写到全部 4 套 (camera, type) 上,
// 想要差异化的用户通过逐套单独覆盖。
SystemConfig systemConfig = m_pConfigManager->GetConfig();
for (auto& item : systemConfig.configResult.detectionConfigList) {
item.algorithmParams.cornerParam = params;
}
m_pConfigManager->UpdateFullConfig(systemConfig);
LOG_INFO("Corner parameters updated for all (camera, type) sets\n");
}