GrabBag/App/WheelMeasure/WheelMeasureApp/dialogcameralevel.cpp
2026-03-14 10:00:15 +08:00

834 lines
30 KiB
C++
Raw 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 "dialogcameralevel.h"
#include "ui_dialogcameralevel.h"
#include "WheelMeasurePresenter.h"
#include "PathManager.h"
#include "VrLog.h"
#include "wheelArchHeigthMeasure_Export.h"
#include <QThread>
#include <QApplication>
#include <QListView>
#include <cmath>
#include <mutex>
#include <vector>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
DialogCameraLevel::DialogCameraLevel(QWidget *parent)
: QDialog(parent)
, ui(new Ui::DialogCameraLevel)
, m_pConfig(nullptr)
, m_pConfigResult(nullptr)
, m_currentCameraIndex(-1)
{
ui->setupUi(this);
// 初始化结果显示区域
ui->label_level_result->setText("请选择相机,然后点击调平按钮\n开始相机调平操作");
ui->label_level_result->setAlignment(Qt::AlignCenter);
}
DialogCameraLevel::~DialogCameraLevel()
{
// 清理扫描数据缓存
clearScanDataCache();
// 确保恢复Presenter的状态回调
restorePresenterStatusCallback();
delete ui;
}
void DialogCameraLevel::setCameraList(const std::vector<std::pair<std::string, IVrEyeDevice*>>& cameraList,
WheelMeasurePresenter* presenter)
{
m_cameraList = cameraList;
m_presenter = presenter;
LOG_INFO("setCameraList called with %zu cameras\n", cameraList.size());
// 详细记录每个相机的信息
for (size_t i = 0; i < cameraList.size(); ++i) {
const auto& camera = cameraList[i];
LOG_INFO(" Camera %zu: name='%s', device=%s\n",
i + 1,
camera.first.c_str(),
(camera.second != nullptr ? "connected" : "not connected"));
}
// 初始化/重新初始化相机选择框
initializeCameraCombo();
}
void DialogCameraLevel::setConfig(IVrWheelMeasureConfig* config, WheelMeasureConfigResult* configResult)
{
m_pConfig = config;
m_pConfigResult = configResult;
// 如果相机已经选择,重新加载当前相机的标定状态
// 修复:打开页面时配置可能在相机列表之后设置,导致初始加载失败
if (m_currentCameraIndex >= 0 && m_currentCameraIndex < static_cast<int>(m_cameraList.size())) {
checkAndDisplayCalibrationStatus(m_currentCameraIndex);
loadCameraRoiRange(m_currentCameraIndex);
}
}
void DialogCameraLevel::initializeCameraCombo()
{
LOG_INFO("initializeCameraCombo called, camera list size: %zu\n", m_cameraList.size());
ui->combo_camera->clear();
if (m_cameraList.empty()) {
ui->combo_camera->setEnabled(false);
if (!m_presenter) {
ui->label_level_result->setText("Presenter未初始化\n无法获取相机列表");
LOG_ERROR("Presenter is null in initializeCameraCombo\n");
} else {
ui->label_level_result->setText("相机列表为空\n\n可能原因:\n1. 配置文件中未配置相机\n2. 系统正在初始化中\n3. 所有相机连接失败");
LOG_WARNING("Camera list is empty in initializeCameraCombo\n");
}
ui->label_level_result->setAlignment(Qt::AlignCenter);
} else {
LOG_INFO("Adding %zu cameras to combo box\n", m_cameraList.size());
// 添加所有相机到下拉列表
for (size_t i = 0; i < m_cameraList.size(); ++i) {
const auto& camera = m_cameraList[i];
QString cameraName = QString::fromStdString(camera.first);
// 如果相机没有连接,在名称后添加标记
if (camera.second == nullptr) {
cameraName += " [未连接]";
}
ui->combo_camera->addItem(cameraName);
LOG_INFO(" Added camera %zu: %s (device=%s)\n",
i + 1,
camera.first.c_str(),
(camera.second != nullptr ? "OK" : "NULL"));
}
ui->combo_camera->setEnabled(true);
// 获取默认相机索引
int defaultCameraIndex = 0;
if (m_presenter) {
int presenterDefaultIndex = m_presenter->GetDefaultCameraIndex();
LOG_INFO("Presenter default camera index (1-based): %d\n", presenterDefaultIndex);
if (presenterDefaultIndex > 0 && presenterDefaultIndex <= static_cast<int>(m_cameraList.size())) {
defaultCameraIndex = presenterDefaultIndex - 1;
}
}
// 设置默认选中的相机
if (defaultCameraIndex >= 0 && defaultCameraIndex < static_cast<int>(m_cameraList.size())) {
ui->combo_camera->setCurrentIndex(defaultCameraIndex);
m_currentCameraIndex = defaultCameraIndex;
}
// 检查并显示当前选中相机的标定状态
if (m_currentCameraIndex >= 0) {
checkAndDisplayCalibrationStatus(m_currentCameraIndex);
}
}
}
void DialogCameraLevel::on_btn_apply_clicked()
{
ui->label_level_result->setAlignment(Qt::AlignLeft);
// 检查是否有可用的相机
if (m_cameraList.empty()) {
QMessageBox::warning(this, "错误", "无可用相机设备!");
return;
}
// 获取选中的相机
int selectedIndex = ui->combo_camera->currentIndex();
if (selectedIndex < 0 || selectedIndex >= static_cast<int>(m_cameraList.size())) {
QMessageBox::warning(this, "错误", "请选择有效的相机!");
return;
}
// 清空之前的结果显示
ui->label_level_result->setText("调平计算中,请稍候...");
// 显示进度提示
ui->btn_apply->setEnabled(false);
QApplication::processEvents();
try {
// 执行相机调平
if (performCameraLeveling()) {
// 调平成功
} else {
ui->label_level_result->setText("调平失败!\n\n请检查:\n1. 相机连接是否正常\n2. 地面扫描数据是否充足\n3. 扫描区域是否有足够的地面");
}
} catch (const std::exception& e) {
LOG_ERROR("Camera leveling failed with exception: %s\n", e.what());
QMessageBox::critical(this, "错误", QString("调平过程发生异常:%1").arg(e.what()));
}
// 恢复按钮状态
ui->btn_apply->setEnabled(true);
}
void DialogCameraLevel::on_btn_cancel_clicked()
{
reject();
}
bool DialogCameraLevel::performCameraLeveling()
{
try {
// 获取选中的相机索引
int selectedIndex = ui->combo_camera->currentIndex();
// 先检查索引有效性,再设置回调
if (selectedIndex < 0 || selectedIndex >= static_cast<int>(m_cameraList.size())) {
LOG_ERROR("Invalid camera index: %d\n", selectedIndex);
return false;
}
LOG_INFO("Performing camera leveling with camera %d (index %d)\n", selectedIndex + 1, selectedIndex);
// 1. 设置调平状态回调(在索引检查之后)
setLevelingStatusCallback();
// 2. 清空之前的扫描数据
clearScanDataCache();
// 3. 启动相机扫描地面数据
if (!startCameraScan(selectedIndex)) {
LOG_ERROR("Failed to start camera scan for leveling\n");
restorePresenterStatusCallback(); // 恢复回调
return false;
}
// 4. 等待扫描完成
LOG_INFO("Collecting ground scan data, waiting for swing finish signal...\n");
int waitTime = 0;
const int maxWaitTime = 10000; // 最大等待10秒
const int checkInterval = 100;
while (!m_swingFinished && waitTime < maxWaitTime) {
QThread::msleep(checkInterval);
QApplication::processEvents();
waitTime += checkInterval;
}
// 5. 停止扫描
stopCameraScan(selectedIndex);
if (m_swingFinished) {
LOG_INFO("Camera swing finished signal received, scan completed\n");
} else if (waitTime >= maxWaitTime) {
LOG_WARNING("Timeout waiting for camera swing finish signal\n");
}
// 6. 调用调平算法计算
double planeCalib[9];
double planeHeight;
double invRMatrix[9];
if (!calculatePlaneCalibration(planeCalib, planeHeight, invRMatrix)) {
LOG_ERROR("Failed to calculate plane calibration\n");
restorePresenterStatusCallback(); // 恢复回调
return false;
}
LOG_INFO("Camera leveling calculation completed\n");
// 7. 更新界面显示
updateLevelingResults(planeCalib, planeHeight, invRMatrix);
// 8. 保存结果到配置
int cameraIndex = m_currentCameraIndex + 1; // 转换为1-based索引
QString cameraName;
if (m_currentCameraIndex >= 0 && m_currentCameraIndex < static_cast<int>(m_cameraList.size())) {
cameraName = QString::fromStdString(m_cameraList[m_currentCameraIndex].first);
} else {
cameraName = QString("Camera_%1").arg(cameraIndex);
}
if (!saveLevelingResults(planeCalib, planeHeight, invRMatrix, cameraIndex, cameraName)) {
LOG_ERROR("Failed to save leveling results\n");
restorePresenterStatusCallback(); // 恢复回调
return false;
}
clearScanDataCache();
// 9. 调平完成后恢复回调
restorePresenterStatusCallback();
LOG_INFO("Camera leveling completed successfully\n");
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception in performCameraLeveling: %s\n", e.what());
restorePresenterStatusCallback(); // 异常时也恢复回调
return false;
}
}
void DialogCameraLevel::updateLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9])
{
// 构建显示文本
QString resultText;
resultText += QString("地面高度: %1 mm\n").arg(QString::number(planeHeight, 'f', 2));
// 调平矩阵
resultText += QString("调平矩阵:\n");
for (int i = 0; i < 3; i++) {
resultText += QString("[%1, %2, %3]\n")
.arg(QString::number(planeCalib[i*3], 'f', 4))
.arg(QString::number(planeCalib[i*3+1], 'f', 4))
.arg(QString::number(planeCalib[i*3+2], 'f', 4));
}
resultText += QString("逆旋转矩阵:\n");
for (int i = 0; i < 3; i++) {
resultText += QString("[%1, %2, %3]\n")
.arg(QString::number(invRMatrix[i*3], 'f', 4))
.arg(QString::number(invRMatrix[i*3+1], 'f', 4))
.arg(QString::number(invRMatrix[i*3+2], 'f', 4));
}
ui->label_level_result->setText(resultText);
ui->label_level_result->setAlignment(Qt::AlignLeft | Qt::AlignTop);
}
bool DialogCameraLevel::startCameraScan(int cameraIndex)
{
if (cameraIndex < 0 || cameraIndex >= static_cast<int>(m_cameraList.size())) {
LOG_ERROR("Invalid camera index for scan: %d\n", cameraIndex);
return false;
}
IVrEyeDevice* camera = m_cameraList[cameraIndex].second;
if (!camera) {
LOG_ERROR("Camera device is null at index: %d\n", cameraIndex);
return false;
}
// 启动相机检测
int result = camera->StartDetect(&DialogCameraLevel::StaticDetectionCallback, keResultDataType_Position, this);
if (result != 0) {
LOG_ERROR("Failed to start camera detection: %d\n", result);
return false;
}
LOG_INFO("Camera scan started successfully for camera index: %d\n", cameraIndex);
return true;
}
bool DialogCameraLevel::stopCameraScan(int cameraIndex)
{
if (cameraIndex < 0 || cameraIndex >= static_cast<int>(m_cameraList.size())) {
LOG_ERROR("Invalid camera index for stop scan: %d\n", cameraIndex);
return false;
}
IVrEyeDevice* camera = m_cameraList[cameraIndex].second;
if (!camera) {
LOG_ERROR("Camera device is null at index: %d\n", cameraIndex);
return false;
}
int result = camera->StopDetect();
if (result != 0) {
LOG_WARNING("Failed to stop camera detection, error: %d\n", result);
return false;
}
LOG_INFO("Camera scan stopped successfully for camera index: %d\n", cameraIndex);
return true;
}
void DialogCameraLevel::StaticDetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint, void* pUserData)
{
DialogCameraLevel* pThis = reinterpret_cast<DialogCameraLevel*>(pUserData);
if (pThis && pLaserLinePoint) {
pThis->DetectionCallback(eDataType, pLaserLinePoint);
}
}
void DialogCameraLevel::StaticStatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
{
DialogCameraLevel* pThis = reinterpret_cast<DialogCameraLevel*>(pInfoParam);
if (pThis) {
pThis->StatusCallback(eStatus, pExtData, nDataLength, pInfoParam);
}
}
void DialogCameraLevel::StatusCallback(EVzDeviceWorkStatus eStatus, void* pExtData, unsigned int nDataLength, void* pInfoParam)
{
LOG_DEBUG("[Leveling Status Callback] received: status=%d\n", (int)eStatus);
switch (eStatus) {
case EVzDeviceWorkStatus::keDeviceWorkStatus_Device_Swing_Finish:
{
LOG_INFO("[Leveling Status Callback] Camera swing finished, scan completed\n");
m_swingFinished = true;
break;
}
default:
LOG_DEBUG("[Leveling Status Callback] Other status: %d\n", (int)eStatus);
break;
}
}
void DialogCameraLevel::DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint)
{
if (!pLaserLinePoint) {
LOG_WARNING("[Leveling Callback] pLaserLinePoint is null\n");
return;
}
if (pLaserLinePoint->nPointCount <= 0) {
LOG_WARNING("[Leveling Callback] Point count is zero or negative: %d\n", pLaserLinePoint->nPointCount);
return;
}
if (!pLaserLinePoint->p3DPoint) {
LOG_WARNING("[Leveling Callback] p3DPoint is null\n");
return;
}
// 将数据添加到缓存
std::vector<SVzNL3DPosition> lineData;
lineData.reserve(pLaserLinePoint->nPointCount);
// p3DPoint 是 void*,需要转换为 SVzNL3DPosition*
SVzNL3DPosition* p3DPoints = reinterpret_cast<SVzNL3DPosition*>(pLaserLinePoint->p3DPoint);
for (int i = 0; i < pLaserLinePoint->nPointCount; ++i) {
lineData.push_back(p3DPoints[i]);
}
std::lock_guard<std::mutex> lock(m_scanDataMutex);
m_scanDataCache.push_back(std::move(lineData));
}
bool DialogCameraLevel::calculatePlaneCalibration(double planeCalib[9], double& planeHeight, double invRMatrix[9])
{
std::lock_guard<std::mutex> lock(m_scanDataMutex);
if (m_scanDataCache.empty()) {
LOG_ERROR("No scan data available for plane calibration\n");
return false;
}
LOG_INFO("Calculating plane calibration from %zu scan lines\n", m_scanDataCache.size());
try {
// 调用 wheelArchHeigthMeasure SDK 的调平算法
SSG_planeCalibPara calibResult = wd_horizonCamera_getGroundCalibPara(m_scanDataCache);
// 复制调平矩阵
for (int i = 0; i < 9; i++) {
planeCalib[i] = calibResult.planeCalib[i];
invRMatrix[i] = calibResult.invRMatrix[i];
}
planeHeight = calibResult.planeHeight;
LOG_INFO("Plane calibration calculated successfully\n");
LOG_INFO(" planeHeight: %.3f\n", planeHeight);
LOG_INFO(" planeCalib: [%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f]\n",
planeCalib[0], planeCalib[1], planeCalib[2],
planeCalib[3], planeCalib[4], planeCalib[5],
planeCalib[6], planeCalib[7], planeCalib[8]);
LOG_INFO(" invRMatrix: [%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f]\n",
invRMatrix[0], invRMatrix[1], invRMatrix[2],
invRMatrix[3], invRMatrix[4], invRMatrix[5],
invRMatrix[6], invRMatrix[7], invRMatrix[8]);
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception in calculatePlaneCalibration: %s\n", e.what());
return false;
}
}
void DialogCameraLevel::clearScanDataCache()
{
std::lock_guard<std::mutex> lock(m_scanDataMutex);
LOG_DEBUG("Clearing scan data cache, current size: %zu\n", m_scanDataCache.size());
m_scanDataCache.clear();
LOG_DEBUG("Scan data cache cleared successfully\n");
}
bool DialogCameraLevel::saveLevelingResults(double planeCalib[9], double planeHeight, double invRMatrix[9],
int cameraIndex, const QString& cameraName)
{
try {
if (!m_pConfig || !m_pConfigResult) {
LOG_ERROR("Config is null, cannot save leveling results\n");
return false;
}
if (cameraIndex <= 0) {
LOG_ERROR("Invalid camera index: %d\n", cameraIndex);
return false;
}
if (cameraName.isEmpty()) {
LOG_ERROR("Camera name is empty\n");
return false;
}
// 获取UI中的误差补偿值
double errorCompensation = ui->edit_error_compensation->text().toDouble();
// 创建或更新相机调平参数
WheelCameraPlaneCalibParam cameraParam;
cameraParam.cameraIndex = cameraIndex;
cameraParam.cameraName = cameraName.toStdString();
cameraParam.planeHeight = planeHeight;
cameraParam.isCalibrated = true;
cameraParam.errorCompensation = errorCompensation;
// 复制校准矩阵
for (int i = 0; i < 9; i++) {
cameraParam.planeCalib[i] = planeCalib[i];
cameraParam.invRMatrix[i] = invRMatrix[i];
}
// 查找是否已有该相机的调平参数
bool found = false;
for (auto& param : m_pConfigResult->planeCalibParams) {
if (param.cameraIndex == cameraIndex) {
param = cameraParam;
found = true;
break;
}
}
if (!found) {
m_pConfigResult->planeCalibParams.push_back(cameraParam);
}
// 保存配置
QString configPath = PathManager::GetInstance().GetConfigFilePath();
bool saveResult = m_pConfig->SaveConfig(configPath.toStdString(), *m_pConfigResult);
if (!saveResult) {
LOG_ERROR("Failed to save config with leveling results\n");
return false;
}
LOG_INFO("Leveling results saved successfully for camera %d (%s)\n",
cameraIndex, cameraName.toUtf8().constData());
LOG_INFO("Plane height: %.3f, Error compensation: %.2f\n", planeHeight, errorCompensation);
return true;
} catch (const std::exception& e) {
LOG_ERROR("Exception in saveLevelingResults: %s\n", e.what());
return false;
}
}
bool DialogCameraLevel::loadCameraCalibrationData(int cameraIndex, const QString& cameraName,
double planeCalib[9], double& planeHeight, double invRMatrix[9])
{
try {
if (!m_pConfigResult) {
LOG_ERROR("Config result is null, cannot load calibration data\n");
return false;
}
// 查找对应相机的调平参数
for (const auto& param : m_pConfigResult->planeCalibParams) {
if (param.cameraIndex == cameraIndex && param.isCalibrated) {
for (int i = 0; i < 9; i++) {
planeCalib[i] = param.planeCalib[i];
invRMatrix[i] = param.invRMatrix[i];
}
planeHeight = param.planeHeight;
// 加载该相机的误差补偿值到UI
ui->edit_error_compensation->setText(QString::number(param.errorCompensation, 'f', 1));
LOG_INFO("Calibration data loaded successfully for camera %d (%s)\n",
cameraIndex, cameraName.toUtf8().constData());
return true;
}
}
// 没有找到标定数据时,设置默认误差补偿值
ui->edit_error_compensation->setText(QString::number(-5.0, 'f', 1));
LOG_INFO("No calibration data found for camera %d (%s)\n",
cameraIndex, cameraName.toUtf8().constData());
return false;
} catch (const std::exception& e) {
LOG_ERROR("Exception in loadCameraCalibrationData: %s\n", e.what());
return false;
}
}
void DialogCameraLevel::checkAndDisplayCalibrationStatus(int cameraIndex)
{
if (cameraIndex < 0 || cameraIndex >= static_cast<int>(m_cameraList.size())) {
LOG_WARNING("Invalid camera index for status check: %d\n", cameraIndex);
ui->label_level_result->setText("无效的相机索引");
ui->label_level_result->setAlignment(Qt::AlignCenter);
return;
}
QString cameraName = QString::fromStdString(m_cameraList[cameraIndex].first);
int configCameraIndex = cameraIndex + 1;
double planeCalib[9];
double planeHeight;
double invRMatrix[9];
if (loadCameraCalibrationData(configCameraIndex, cameraName, planeCalib, planeHeight, invRMatrix)) {
// 有标定数据,显示
LOG_INFO("Displaying existing calibration data for camera %s\n", cameraName.toUtf8().constData());
updateLevelingResults(planeCalib, planeHeight, invRMatrix);
} else {
// 没有标定数据
LOG_INFO("No calibration data found for camera %s\n", cameraName.toUtf8().constData());
ui->label_level_result->setText(QString("相机: %1\n\n请点击调平按钮开始调平操作").arg(cameraName));
ui->label_level_result->setAlignment(Qt::AlignCenter);
}
}
void DialogCameraLevel::on_combo_camera_currentIndexChanged(int index)
{
m_currentCameraIndex = index;
if (index >= 0 && index < static_cast<int>(m_cameraList.size())) {
LOG_INFO("Camera selection changed to index: %d (%s)\n", index,
QString::fromStdString(m_cameraList[index].first).toUtf8().constData());
checkAndDisplayCalibrationStatus(m_currentCameraIndex);
loadCameraRoiRange(m_currentCameraIndex);
} else {
LOG_WARNING("Invalid camera index selected: %d\n", index);
ui->label_level_result->setText("无效的相机选择");
ui->label_level_result->setAlignment(Qt::AlignCenter);
}
}
void DialogCameraLevel::setLevelingStatusCallback()
{
if (!m_presenter) {
LOG_ERROR("Presenter is null, cannot set leveling status callback\n");
return;
}
m_presenter->SetCameraStatusCallback(&DialogCameraLevel::StaticStatusCallback, this);
m_swingFinished = false;
m_callbackRestored = false;
LOG_INFO("Leveling status callback set for all cameras\n");
}
void DialogCameraLevel::restorePresenterStatusCallback()
{
if (m_callbackRestored.exchange(true)) {
LOG_DEBUG("Presenter status callback already restored, skipping\n");
return;
}
if (!m_presenter) {
LOG_ERROR("Presenter is null, cannot restore status callback\n");
return;
}
m_presenter->SetCameraStatusCallback(&WheelMeasurePresenter::_StaticCameraNotify, m_presenter);
LOG_INFO("Presenter status callback restored for all cameras\n");
}
void DialogCameraLevel::on_btn_save_compensation_clicked()
{
// 保存误差补偿值到当前相机的调平参数
if (!m_pConfig || !m_pConfigResult) {
LOG_ERROR("Config is null, cannot save error compensation\n");
return;
}
if (m_currentCameraIndex < 0 || m_currentCameraIndex >= static_cast<int>(m_cameraList.size())) {
LOG_WARNING("Invalid camera index: %d\n", m_currentCameraIndex);
return;
}
// 获取UI中的误差补偿值
double errorCompensation = ui->edit_error_compensation->text().toDouble();
int cameraIndex = m_currentCameraIndex + 1; // 转换为1-based索引
QString cameraName = QString::fromStdString(m_cameraList[m_currentCameraIndex].first);
LOG_INFO("Saving error compensation for camera %d (%s): %.2f\n",
cameraIndex, cameraName.toUtf8().constData(), errorCompensation);
// 查找或创建相机调平参数
bool found = false;
for (auto& param : m_pConfigResult->planeCalibParams) {
if (param.cameraIndex == cameraIndex) {
param.errorCompensation = errorCompensation;
found = true;
break;
}
}
// 如果没有找到现有记录,创建一个新的(仅包含误差补偿,其他值为默认)
if (!found) {
WheelCameraPlaneCalibParam newParam;
newParam.cameraIndex = cameraIndex;
newParam.cameraName = cameraName.toStdString();
newParam.errorCompensation = errorCompensation;
newParam.isCalibrated = false; // 尚未标定
m_pConfigResult->planeCalibParams.push_back(newParam);
}
// 保存配置到文件
QString configPath = PathManager::GetInstance().GetConfigFilePath();
bool saveResult = m_pConfig->SaveConfig(configPath.toStdString(), *m_pConfigResult);
if (saveResult) {
LOG_INFO("Error compensation saved successfully for camera %d: %.2f\n", cameraIndex, errorCompensation);
} else {
LOG_ERROR("Failed to save error compensation\n");
}
}
void DialogCameraLevel::loadCameraRoiRange(int cameraIndex)
{
if (!m_pConfig || !m_pConfigResult) {
LOG_WARNING("Config is null, cannot load ROI range\n");
return;
}
if (cameraIndex < 0 || cameraIndex >= static_cast<int>(m_cameraList.size())) {
LOG_WARNING("Invalid camera index: %d\n", cameraIndex);
return;
}
int configCameraIndex = cameraIndex + 1; // 转换为1-based索引
// 查找相机的调平参数
for (const auto& param : m_pConfigResult->planeCalibParams) {
if (param.cameraIndex == configCameraIndex) {
// 加载ROI范围到UI
ui->edit_roi_x_min->setText(QString::number(param.wheelRoi3d_xMin, 'f', 1));
ui->edit_roi_x_max->setText(QString::number(param.wheelRoi3d_xMax, 'f', 1));
ui->edit_roi_y_min->setText(QString::number(param.wheelRoi3d_yMin, 'f', 1));
ui->edit_roi_y_max->setText(QString::number(param.wheelRoi3d_yMax, 'f', 1));
ui->edit_roi_z_min->setText(QString::number(param.wheelRoi3d_zMin, 'f', 1));
ui->edit_roi_z_max->setText(QString::number(param.wheelRoi3d_zMax, 'f', 1));
LOG_INFO("Loaded ROI range for camera %d: X[%.1f, %.1f], Y[%.1f, %.1f], Z[%.1f, %.1f]\n",
configCameraIndex,
param.wheelRoi3d_xMin, param.wheelRoi3d_xMax,
param.wheelRoi3d_yMin, param.wheelRoi3d_yMax,
param.wheelRoi3d_zMin, param.wheelRoi3d_zMax);
return;
}
}
// 如果没有找到,使用默认值
ui->edit_roi_x_min->setText("-1000.0");
ui->edit_roi_x_max->setText("1000.0");
ui->edit_roi_y_min->setText("-1000.0");
ui->edit_roi_y_max->setText("1000.0");
ui->edit_roi_z_min->setText("-1000.0");
ui->edit_roi_z_max->setText("1000.0");
LOG_INFO("No ROI range found for camera %d, using default values\n", configCameraIndex);
}
void DialogCameraLevel::saveCameraRoiRange()
{
if (!m_pConfig || !m_pConfigResult) {
LOG_ERROR("Config is null, cannot save ROI range\n");
QMessageBox::warning(this, "错误", "配置对象为空无法保存ROI范围");
return;
}
if (m_currentCameraIndex < 0 || m_currentCameraIndex >= static_cast<int>(m_cameraList.size())) {
LOG_WARNING("Invalid camera index: %d\n", m_currentCameraIndex);
QMessageBox::warning(this, "错误", "请先选择相机");
return;
}
// 获取UI中的ROI范围值
double xMin = ui->edit_roi_x_min->text().toDouble();
double xMax = ui->edit_roi_x_max->text().toDouble();
double yMin = ui->edit_roi_y_min->text().toDouble();
double yMax = ui->edit_roi_y_max->text().toDouble();
double zMin = ui->edit_roi_z_min->text().toDouble();
double zMax = ui->edit_roi_z_max->text().toDouble();
// 验证范围有效性
if (xMin >= xMax || yMin >= yMax || zMin >= zMax) {
QMessageBox::warning(this, "错误", "ROI范围无效最小值必须小于最大值");
return;
}
int cameraIndex = m_currentCameraIndex + 1; // 转换为1-based索引
QString cameraName = QString::fromStdString(m_cameraList[m_currentCameraIndex].first);
LOG_INFO("Saving ROI range for camera %d (%s): X[%.1f, %.1f], Y[%.1f, %.1f], Z[%.1f, %.1f]\n",
cameraIndex, cameraName.toUtf8().constData(),
xMin, xMax, yMin, yMax, zMin, zMax);
// 查找或创建相机调平参数
bool found = false;
for (auto& param : m_pConfigResult->planeCalibParams) {
if (param.cameraIndex == cameraIndex) {
param.wheelRoi3d_xMin = xMin;
param.wheelRoi3d_xMax = xMax;
param.wheelRoi3d_yMin = yMin;
param.wheelRoi3d_yMax = yMax;
param.wheelRoi3d_zMin = zMin;
param.wheelRoi3d_zMax = zMax;
found = true;
break;
}
}
// 如果没有找到现有记录,创建一个新的
if (!found) {
WheelCameraPlaneCalibParam newParam;
newParam.cameraIndex = cameraIndex;
newParam.cameraName = cameraName.toStdString();
newParam.wheelRoi3d_xMin = xMin;
newParam.wheelRoi3d_xMax = xMax;
newParam.wheelRoi3d_yMin = yMin;
newParam.wheelRoi3d_yMax = yMax;
newParam.wheelRoi3d_zMin = zMin;
newParam.wheelRoi3d_zMax = zMax;
newParam.isCalibrated = false; // 尚未标定
m_pConfigResult->planeCalibParams.push_back(newParam);
}
// 保存配置到文件
QString configPath = PathManager::GetInstance().GetConfigFilePath();
bool saveResult = m_pConfig->SaveConfig(configPath.toStdString(), *m_pConfigResult);
if (saveResult) {
LOG_INFO("ROI range saved successfully for camera %d\n", cameraIndex);
QMessageBox::information(this, "成功", "ROI范围已保存");
} else {
LOG_ERROR("Failed to save ROI range\n");
QMessageBox::critical(this, "错误", "保存ROI范围失败");
}
}
void DialogCameraLevel::on_btn_save_roi_clicked()
{
saveCameraRoiRange();
}