【使用实际相机检测出结果】优化相机初始化逻辑;增强调试信息记录,修复相机选择和检测功能的相关问题。

This commit is contained in:
杰仔 2025-06-25 01:37:57 +08:00
parent b355ac9763
commit 2afa5b1983
21 changed files with 338786 additions and 178 deletions

View File

@ -28,7 +28,7 @@ public:
void SetStatusCallback(IYGrabBagStatus* status);
// 开始检测
int StartDetection(int cameraIndex = -1); // cameraIndex: -1表示所有相机0/1/2...表示特定相机
int StartDetection(int cameraIndex = -1, bool isAuto = true); // cameraIndex: -1表示所有相机1/2...表示特定相机
// 停止检测
int StopDetection();
@ -113,6 +113,7 @@ private:
// 算法参数成员变量
SG_bagPositionParam m_algoParam; // 算法参数
SSG_planeCalibPara m_planeCalibParam; // 平面校准参数
VrDebugParam m_debugParam; // 调试参数
double m_clibMatrix[16]; // 手眼标定矩阵
// 调试数据加载器

View File

@ -13,7 +13,9 @@
#include <QThread>
#include "VrTimeUtils.h"
#include "VrDateUtils.h"
#include "SG_bagPositioning_Export.h"
#include "SG_baseDataType.h"
#include "VrConvert.h"
GrabBagPresenter::GrabBagPresenter()
@ -265,6 +267,9 @@ int GrabBagPresenter::InitAlgorithmParams()
ConfigResult configResult = m_vrConfig->LoadConfig(configPath.toStdString());
const VrAlgorithmParams& xmlParams = configResult.algorithmParams;
// 保存调试参数
m_debugParam = configResult.debugParam;
LOG_INFO("Loaded XML params - Bag: L=%.1f, W=%.1f, H=%.1f\n",
xmlParams.bagParam.bagL, xmlParams.bagParam.bagW, xmlParams.bagParam.bagH);
LOG_INFO("Loaded XML params - Pile: L=%.1f, W=%.1f, H=%.1f\n",
@ -369,12 +374,13 @@ void GrabBagPresenter::SetStatusCallback(IYGrabBagStatus* status)
}
// 模拟检测函数,用于演示
int GrabBagPresenter::StartDetection(int cameraIndex)
int GrabBagPresenter::StartDetection(int cameraIndex, bool isAuto)
{
LOG_INFO("***** Start detection with camera index: %d\n", cameraIndex);
LOG_INFO("--------------------------------\n");
LOG_INFO("Start detection with camera index: %d\n", cameraIndex);
// 检查设备状态是否准备就绪
if (m_currentWorkStatus != WorkStatus::Ready) {
if (isAuto && m_currentWorkStatus != WorkStatus::Ready) {
LOG_INFO("Device not ready, cannot start detection\n");
if (m_pStatus) {
m_pStatus->OnStatusUpdate("设备未准备就绪,无法开始检测");
@ -396,9 +402,11 @@ int GrabBagPresenter::StartDetection(int cameraIndex)
m_pRobotProtocol->SetWorkStatus(RobotProtocol::WORK_STATUS_BUSY);
}
if(m_vrEyeDeviceList.empty())
{
if(m_vrEyeDeviceList.empty()){
LOG_ERROR("No camera device found\n");
if (m_pStatus) {
m_pStatus->OnStatusUpdate("未找到相机设备");
}
return ERR_CODE(DEV_NOT_FIND);
}
@ -541,8 +549,7 @@ int GrabBagPresenter::GetCameraCount()
}
// 获取相机列表和名称
void GrabBagPresenter::GetCameraListWithNames(std::vector<IVrEyeDevice*>& cameraList,
std::vector<QString>& cameraNames)
void GrabBagPresenter::GetCameraListWithNames(std::vector<IVrEyeDevice*>& cameraList, std::vector<QString>& cameraNames)
{
cameraList.clear();
cameraNames.clear();
@ -581,12 +588,12 @@ void GrabBagPresenter::_StaticCameraNotify(EVzDeviceWorkStatus eStatus, void* pE
void GrabBagPresenter::_CameraNotify(EVzDeviceWorkStatus eStatus, void *pExtData, unsigned int nDataLength, void *pInfoParam)
{
LOG_DEBUG("----- Camera notify received: status=%d\n", (int)eStatus);
LOG_DEBUG("[Camera Notify] received: status=%d\n", (int)eStatus);
switch (eStatus) {
case EVzDeviceWorkStatus::keDeviceWorkStatus_Offline:
{
LOG_WARNING("Camera device offline/disconnected\n");
LOG_WARNING("[Camera Notify] Camera device offline/disconnected\n");
// 更新相机连接状态
m_bCameraConnected = false;
@ -606,7 +613,7 @@ void GrabBagPresenter::_CameraNotify(EVzDeviceWorkStatus eStatus, void *pExtData
case EVzDeviceWorkStatus::keDeviceWorkStatus_Eye_Reconnect:
{
LOG_INFO("Camera device online/connected\n");
LOG_INFO("[Camera Notify] Camera device online/connected\n");
// 更新相机连接状态
m_bCameraConnected = true;
@ -624,7 +631,7 @@ void GrabBagPresenter::_CameraNotify(EVzDeviceWorkStatus eStatus, void *pExtData
case EVzDeviceWorkStatus::keDeviceWorkStatus_Device_Swing_Finish:
{
LOG_INFO("Received scan finish signal from camera\n");
LOG_INFO("[Camera Notify] Received scan finish signal from camera\n");
// 发送页面提示信息
if (m_pStatus) {
@ -637,7 +644,6 @@ void GrabBagPresenter::_CameraNotify(EVzDeviceWorkStatus eStatus, void *pExtData
}
default:
LOG_DEBUG("Unhandled camera status: %d\n", (int)eStatus);
break;
}
}
@ -655,6 +661,17 @@ void GrabBagPresenter::_StaticDetectionCallback(EVzResultDataType eDataType, SVz
void GrabBagPresenter::_DetectionCallback(EVzResultDataType eDataType, SVzLaserLineData* pLaserLinePoint)
{
if (!pLaserLinePoint) {
LOG_WARNING("[Detection Callback] pLaserLinePoint is null\n");
return;
}
if (pLaserLinePoint->nPointCount <= 0) {
LOG_WARNING("[Detection Callback] Point count is zero or negative: %d\n", pLaserLinePoint->nPointCount);
return;
}
if (!pLaserLinePoint->p3DPoint) {
LOG_WARNING("[Detection Callback] p3DPoint is null\n");
return;
}
@ -696,7 +713,14 @@ void GrabBagPresenter::_AlgoDetectThread()
});
// 检查设备状态是否准备就绪
_DetectTask();
int nRet = _DetectTask();
if(nRet != SUCCESS){
m_currentWorkStatus = WorkStatus::Error;
if(m_pStatus){
m_pStatus->OnWorkStatusChanged(m_currentWorkStatus);
}
}
}
}
@ -715,7 +739,17 @@ int GrabBagPresenter::_DetectTask()
// 2. 准备算法输入数据
if(m_pStatus){
m_pStatus->OnStatusUpdate("正在进行算法检测...");
m_pStatus->OnStatusUpdate("扫描线数:" + std::to_string(m_detectionDataCache.size()) + ",正在进行算法检测...");
}
if(m_debugParam.savePointCloud){
LOG_INFO("[Algo Thread] Debug mode is enabled\n");
// 获取当前时间戳格式为YYYYMMDDHHMMSS
std::string timeStamp = CVrDateUtils::GetNowTime();
std::string fileName = m_debugParam.debugOutputPath + "/pointCloud_" + timeStamp + ".txt";
m_dataLoader.SaveLaserScanData(fileName, m_detectionDataCache, m_detectionDataCache.size(), 0.0, 0, 0);
}
// 3. 使用成员变量算法参数已在初始化时从XML读取
@ -886,8 +920,7 @@ void GrabBagPresenter::_SendDetectionResultToRobot(const DetectionResult& detect
}
// 点云转图像 - 简化版本
QImage GrabBagPresenter::_GeneratePointCloudImage(SVzNL3DLaserLine* scanData, int lineNum,
const std::vector<SSG_peakRgnInfo>& objOps)
QImage GrabBagPresenter::_GeneratePointCloudImage(SVzNL3DLaserLine* scanData, int lineNum, const std::vector<SSG_peakRgnInfo>& objOps)
{
if (!scanData || lineNum <= 0) {
return QImage(); // 返回空图像
@ -945,8 +978,76 @@ QImage GrabBagPresenter::_GeneratePointCloudImage(SVzNL3DLaserLine* scanData, in
SVzNL3DPosition* pt3D = &scanData[line].p3DPosition[i];
if (pt3D->pt3D.z < 1e-4) continue;
// 解析点索引信息
int vType = pt3D->nPointIdx & 0xff;
int hType = vType >> 4;
int objId = (pt3D->nPointIdx >> 16) & 0xff;
QColor pointColor = (objId > 0) ? objColors[objId % 8] : QColor(60, 60, 60);
vType = vType & 0x0f;
// 根据线特征类型确定颜色和大小
QColor pointColor;
int pointSize = 1;
// 优先根据垂直方向特征设置颜色
if (LINE_FEATURE_L_JUMP_H2L == vType) {
pointColor = QColor(255, 97, 0); // 橙色
pointSize = 2;
}
else if (LINE_FEATURE_L_JUMP_L2H == vType) {
pointColor = QColor(255, 255, 0); // 黄色
pointSize = 2;
}
else if (LINE_FEATURE_V_SLOPE == vType) {
pointColor = QColor(255, 0, 255); // 紫色
pointSize = 2;
}
else if (LINE_FEATURE_L_SLOPE_H2L == vType) {
pointColor = QColor(160, 82, 45); // 褐色
pointSize = 2;
}
else if ((LINE_FEATURE_LINE_ENDING_0 == vType) || (LINE_FEATURE_LINE_ENDING_1 == vType)) {
pointColor = QColor(255, 0, 0); // 红色
pointSize = 2;
}
else if (LINE_FEATURE_L_SLOPE_L2H == vType) {
pointColor = QColor(233, 150, 122); // 浅褐色
pointSize = 2;
}
// 检查水平方向特征
else if (LINE_FEATURE_L_JUMP_H2L == hType) {
pointColor = QColor(0, 0, 255); // 蓝色
pointSize = 2;
}
else if (LINE_FEATURE_L_JUMP_L2H == hType) {
pointColor = QColor(0, 255, 255); // 青色
pointSize = 2;
}
else if (LINE_FEATURE_V_SLOPE == hType) {
pointColor = QColor(0, 255, 0); // 绿色
pointSize = 2;
}
else if (LINE_FEATURE_L_SLOPE_H2L == hType) {
pointColor = QColor(85, 107, 47); // 橄榄绿
pointSize = 2;
}
else if (LINE_FEATURE_L_SLOPE_L2H == hType) {
pointColor = QColor(0, 255, 154); // 浅绿色
pointSize = 2;
}
else if ((LINE_FEATURE_LINE_ENDING_0 == hType) || (LINE_FEATURE_LINE_ENDING_1 == hType)) {
pointColor = QColor(255, 0, 0); // 红色
pointSize = 3;
}
// 检查是否为目标对象
else if (objId > 0) {
pointColor = objColors[objId % 8];
pointSize = 1;
}
// 默认颜色
else {
pointColor = QColor(60, 60, 60); // 深灰色
pointSize = 1;
}
int px = (int)((pt3D->pt3D.x - x_range.min) / x_scale + x_skip);
int py = (int)((pt3D->pt3D.y - y_range.min) / y_scale + y_skip);
@ -974,7 +1075,13 @@ QImage GrabBagPresenter::_GeneratePointCloudImage(SVzNL3DLaserLine* scanData, in
// 绘制方向线
const double deg2rad = PI / 180.0;
double R = 100;
// 使用检测目标实际2D尺寸的较大值的一半作为方向线长度
// 使用较大值的一半作为方向线长度最小值设为20以确保可见性
double maxSize = std::max(objOps[i].objSize.dHeight, objOps[i].objSize.dWidth);
double R = std::max(20.0, maxSize / 6.0);
const double yaw = objOps[i].centerPos.z_yaw * deg2rad;
double cy = cos(yaw);
double sy = sin(yaw);
@ -1005,6 +1112,9 @@ void GrabBagPresenter::OnConfigChanged(const ConfigResult& configResult)
{
LOG_INFO("Configuration changed notification received, reloading algorithm parameters\n");
// 更新调试参数
m_debugParam = configResult.debugParam;
// 重新初始化算法参数
int result = InitAlgorithmParams();
if (result == SUCCESS) {

View File

@ -130,19 +130,10 @@ int LaserDataLoader::SaveLaserScanData(const std::string& fileName,
for (int line = 0; line < lineNum && line < static_cast<int>(laserLines.size()); line++) {
const SVzNL3DLaserLine& scanLine = laserLines[line]; // 使用对象引用而不是指针
// 计算有效点数(移除零点)
int realNum = 0;
for (int i = 0; i < scanLine.nPositionCnt; i++) {
if (scanLine.p3DPosition[i].pt3D.z > 1e-4) {
realNum++;
}
}
sw << "Line_" << line << "_" << scanLine.nTimeStamp << "_" << realNum << std::endl;
sw << "Line_" << line << "_" << scanLine.nTimeStamp << "_" << scanLine.nPositionCnt << std::endl;
// 写入有效的3D点
for (int i = 0; i < scanLine.nPositionCnt; i++) {
if (scanLine.p3DPosition[i].pt3D.z > 1e-4) {
const SVzNL3DPosition* pt3D = &scanLine.p3DPosition[i];
float x = static_cast<float>(pt3D->pt3D.x);
float y = static_cast<float>(pt3D->pt3D.y);
@ -151,7 +142,6 @@ int LaserDataLoader::SaveLaserScanData(const std::string& fileName,
sw << "{0,0}-{0,0}" << std::endl;
}
}
}
sw.close();
LOG_INFO("Successfully saved laser scan data to file: %s\n", fileName.c_str());

View File

@ -3,8 +3,8 @@
#define GRABBAG_VERSION_STRING "1.0.0"
#define GRABBAG_BUILD_STRING "2"
#define GRABBAG_FULL_VERSION_STRING "V1.0.0_2"
#define GRABBAG_BUILD_STRING "4"
#define GRABBAG_FULL_VERSION_STRING "V1.0.0_4"
// 获取版本信息的便捷函数
inline const char* GetGrabBagVersion() {

View File

@ -103,7 +103,7 @@ void devstatus::setCameraCount(int cameraCount)
// 如果相机数量小于2隐藏相机二相关的UI元素
bool showCamera2 = (cameraCount >= 2);
LOG_DEBUG("setCameraCount: %d", cameraCount);
LOG_DEBUG("setCameraCount: %d \n", cameraCount);
ui->dev_camer_2_img->setVisible(showCamera2);
ui->dev_camera_2_txt->setVisible(showCamera2);

View File

@ -57,7 +57,7 @@ void DialogCamera::InitCameraComboBox()
}
// 设置ComboBox样式
ui->combo_camera->setStyleSheet("QComboBox { font-size: 18pt; }");
ui->combo_camera->setStyleSheet("QComboBox { font-size: 18pt; color: white; }");
}
void DialogCamera::on_camera_selection_changed(int index)

View File

@ -379,6 +379,7 @@ background-color: rgb(47, 48, 52);</string>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(221, 225, 233);
selection-color: rgb(255, 255, 255);
background-color: rgb(47, 48, 52);</string>
</property>
</widget>

View File

@ -130,12 +130,6 @@ void MainWindow::Init()
m_deviceStatusWidget = new devstatus(); //因为初始化回调的数据要存储所以要在init前创建好
// 初始化业务逻辑
int result = m_presenter->Init();
if (result != 0) {
updateStatusLog(tr("初始化失败,错误码:%1").arg(result));
}
// 初始化完成后在detect_result_list中增加设备状态widget
QListWidgetItem* deviceStatusItem = new QListWidgetItem();
deviceStatusItem->setBackground(QBrush(Qt::transparent));
@ -149,6 +143,24 @@ void MainWindow::Init()
ui->detect_result_list->setResizeMode(QListView::Adjust);
ui->detect_result_list->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
ui->detect_result_list->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// 初始化期间禁用所有功能按钮
setButtonsEnabled(false);
// 在线程中执行初始化业务逻辑
std::thread initThread([this]() {
updateStatusLog(tr("正在初始化系统..."));
int result = m_presenter->Init();
if (result != 0) {
updateStatusLog(tr("初始化失败,错误码:%1").arg(result));
} else {
updateStatusLog(tr("系统初始化完成"));
}
});
// 分离线程,让其在后台运行
initThread.detach();
}
void MainWindow::displayImage(const QImage& image)
@ -248,7 +260,6 @@ void MainWindow::OnStatusUpdate(const std::string& statusMessage)
void MainWindow::OnDetectionResult(const DetectionResult& result)
{
LOG_DEBUG("[UI Display] ======== Detection result update.\n");
// 通过信号槽机制更新UI确保在主线程中执行
emit detectionResultUpdateRequested(result);
}
@ -291,7 +302,6 @@ void MainWindow::OnCameraCountChanged(int cameraCount)
// 机械臂状态更新槽函数
void MainWindow::OnRobotConnectionChanged(bool isConnected)
{
// 直接更新设备状态widget
if (m_deviceStatusWidget) {
m_deviceStatusWidget->updateRobotStatus(isConnected);
@ -319,23 +329,31 @@ void MainWindow::updateWorkStatusLabel(WorkStatus status)
if (ui->label_work) {
ui->label_work->setText(statusText);
// 根据不同状态设置不同的样式
// 根据不同状态设置不同的样式和按钮启用状态
switch (status) {
case WorkStatus::Ready:
ui->label_work->setStyleSheet("color: green;");
setButtonsEnabled(true); // 就绪状态下启用所有按钮
break;
case WorkStatus::InitIng:
ui->label_work->setStyleSheet("color: blue;");
setButtonsEnabled(false); // 初始化期间禁用按钮
break;
case WorkStatus::Working:
ui->label_work->setStyleSheet("color: blue;");
setButtonsEnabled(false); // 工作期间禁用按钮
break;
case WorkStatus::Completed:
ui->label_work->setStyleSheet("color: green; font-weight: bold;");
setButtonsEnabled(true); // 完成后启用按钮
break;
case WorkStatus::Error:
ui->label_work->setStyleSheet("color: red; font-weight: bold;");
setButtonsEnabled(true); // 错误状态下仍可操作
break;
default:
ui->label_work->setStyleSheet("");
setButtonsEnabled(false); // 未知状态禁用按钮
break;
}
}
@ -383,27 +401,40 @@ void MainWindow::clearDetectionLogUI()
}
}
void MainWindow::on_btn_start_clicked()
{
// 检查Presenter是否已初始化
if (!m_presenter) {
updateStatusLog(tr("系统未初始化,请等待初始化完成"));
return;
}
// 清空检测日志,开始新的检测
clearDetectionLog();
// 使用Presenter启动检测
if (m_presenter) {
m_presenter->StartDetection();
}
m_presenter->StartDetection(1, false);
}
void MainWindow::on_btn_stop_clicked()
{
if (m_presenter) {
m_presenter->StopDetection();
// 检查Presenter是否已初始化
if (!m_presenter) {
updateStatusLog(tr("系统未初始化,请等待初始化完成"));
return;
}
m_presenter->StopDetection();
}
void MainWindow::on_btn_camera_clicked()
{
// 检查Presenter是否已初始化
if (!m_presenter) {
updateStatusLog(tr("系统未初始化,请等待初始化完成"));
return;
}
// 使用新的相机列表获取功能
std::vector<IVrEyeDevice*> availableCameras;
std::vector<QString> cameraNames;
@ -421,6 +452,12 @@ void MainWindow::on_btn_camera_clicked()
void MainWindow::on_btn_algo_config_clicked()
{
// 检查Presenter是否已初始化
if (!m_presenter) {
updateStatusLog(tr("系统未初始化,请等待初始化完成"));
return;
}
// 获取配置对象
IVrConfig* config = m_presenter->GetConfig();
if (!config) {
@ -500,3 +537,19 @@ void MainWindow::on_btn_test_clicked()
t.detach();
}
// 设置按钮启用/禁用状态
void MainWindow::setButtonsEnabled(bool enabled)
{
// 功能按钮
if (ui->btn_start) ui->btn_start->setEnabled(enabled);
if (ui->btn_stop) ui->btn_stop->setEnabled(enabled);
if (ui->btn_camera) ui->btn_camera->setEnabled(enabled);
if (ui->btn_algo_config) ui->btn_algo_config->setEnabled(enabled);
if (ui->btn_camera_levelling) ui->btn_camera_levelling->setEnabled(enabled);
if (ui->btn_test) ui->btn_test->setEnabled(enabled);
// 窗口控制按钮(最小化和关闭)始终可用
// if (ui->btn_hide) ui->btn_hide->setEnabled(true);
// if (ui->btn_close) ui->btn_close->setEnabled(true);
}

View File

@ -102,5 +102,8 @@ private:
// 扩展版本的检测结果添加函数
void addDetectionResult(const DetectionResult& result);
// 设置按钮启用/禁用状态
void setButtonsEnabled(bool enabled);
};
#endif // MAINWINDOW_H

View File

@ -24,9 +24,9 @@
<property name="geometry">
<rect>
<x>20</x>
<y>90</y>
<y>140</y>
<width>1312</width>
<height>940</height>
<height>890</height>
</rect>
</property>
<property name="styleSheet">
@ -58,30 +58,146 @@ color: rgb(239, 241, 245);</string>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>194</x>
<y>25</y>
<width>251</width>
<height>32</height>
<x>40</x>
<y>34</y>
<width>341</width>
<height>51</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>24</pointsize>
<pointsize>40</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">color: rgb(239, 241, 245);</string>
<string notr="true">color: rgb(239, 241, 245);
background-color: rgba(255, 255, 255, 0);</string>
</property>
<property name="text">
<string>自动拆包系统</string>
</property>
</widget>
<widget class="QListWidget" name="detect_result_list">
<property name="geometry">
<rect>
<x>1344</x>
<y>140</y>
<width>556</width>
<height>571</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(37, 38, 42);</string>
</property>
<property name="modelColumn">
<number>0</number>
</property>
</widget>
<widget class="QPushButton" name="btn_test">
<property name="geometry">
<rect>
<x>1218</x>
<y>21</y>
<width>220</width>
<height>80</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/config_data_test.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="btn_algo_config">
<property name="geometry">
<rect>
<x>728</x>
<y>21</y>
<width>220</width>
<height>80</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/config_algo.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="btn_camera_levelling">
<property name="geometry">
<rect>
<x>973</x>
<y>18</y>
<width>220</width>
<height>80</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/config_camera_level.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="btn_camera">
<property name="geometry">
<rect>
<x>483</x>
<y>21</y>
<width>220</width>
<height>80</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/config_camera.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1920</width>
<height>120</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(38, 40, 47);</string>
</property>
<property name="title">
<string/>
</property>
<widget class="QLabel" name="label_work">
<property name="geometry">
<rect>
<x>1540</x>
<y>0</y>
<width>221</width>
<x>1630</x>
<y>20</y>
<width>171</width>
<height>81</height>
</rect>
</property>
@ -100,27 +216,11 @@ color: rgb(239, 241, 245);</string>
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
<widget class="QListWidget" name="detect_result_list">
<property name="geometry">
<rect>
<x>1344</x>
<y>90</y>
<width>556</width>
<height>621</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(37, 38, 42);</string>
</property>
<property name="modelColumn">
<number>0</number>
</property>
</widget>
<widget class="QPushButton" name="btn_close">
<property name="geometry">
<rect>
<x>1860</x>
<y>20</y>
<x>1870</x>
<y>40</y>
<width>41</width>
<height>41</height>
</rect>
@ -135,8 +235,8 @@ color: rgb(239, 241, 245);</string>
<widget class="QPushButton" name="btn_hide">
<property name="geometry">
<rect>
<x>1790</x>
<y>20</y>
<x>1800</x>
<y>40</y>
<width>41</width>
<height>41</height>
</rect>
@ -148,13 +248,13 @@ color: rgb(239, 241, 245);</string>
<string/>
</property>
</widget>
<widget class="QPushButton" name="btn_test">
<widget class="QPushButton" name="btn_start">
<property name="geometry">
<rect>
<x>1190</x>
<y>18</y>
<width>135</width>
<height>50</height>
<x>1460</x>
<y>20</y>
<width>80</width>
<height>80</height>
</rect>
</property>
<property name="font">
@ -163,70 +263,7 @@ color: rgb(239, 241, 245);</string>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/config_data_test.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="btn_algo_config">
<property name="geometry">
<rect>
<x>890</x>
<y>18</y>
<width>135</width>
<height>50</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/config_algo.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="btn_camera_levelling">
<property name="geometry">
<rect>
<x>1040</x>
<y>18</y>
<width>135</width>
<height>50</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/config_camera_level.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="btn_camera">
<property name="geometry">
<rect>
<x>740</x>
<y>18</y>
<width>135</width>
<height>50</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/config_camera.png);</string>
<string notr="true">background-image: url(:/resource/start.png);</string>
</property>
<property name="text">
<string/>
@ -235,10 +272,10 @@ color: rgb(239, 241, 245);</string>
<widget class="QPushButton" name="btn_stop">
<property name="geometry">
<rect>
<x>1444</x>
<y>0</y>
<width>81</width>
<height>81</height>
<x>1562</x>
<y>20</y>
<width>80</width>
<height>80</height>
</rect>
</property>
<property name="font">
@ -247,33 +284,22 @@ color: rgb(239, 241, 245);</string>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/stop.png);</string>
<string notr="true">background-image: url(:/resource/stop.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<widget class="QPushButton" name="btn_start">
<property name="geometry">
<rect>
<x>1342</x>
<y>0</y>
<width>91</width>
<height>81</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>18</pointsize>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/resource/start.png);</string>
</property>
<property name="text">
<string/>
</property>
</widget>
<zorder>groupBox</zorder>
<zorder>detect_image</zorder>
<zorder>detect_log</zorder>
<zorder>label</zorder>
<zorder>detect_result_list</zorder>
<zorder>btn_test</zorder>
<zorder>btn_algo_config</zorder>
<zorder>btn_camera_levelling</zorder>
<zorder>btn_camera</zorder>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 984 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -157,10 +157,60 @@ else
systemctl start grabbag-port-mapping.service 2>/dev/null || true
fi
# 为所有用户设置桌面自启动复制到用户的autostart目录会在用户登录时自动处理
# 检查并创建当前用户的桌面快捷方式
echo "检查当前用户的桌面快捷方式..."
# 获取当前执行安装的用户信息
if [ -n "$SUDO_USER" ]; then
# 如果是通过sudo执行的获取真实用户
current_user="$SUDO_USER"
current_home=$(getent passwd "$current_user" | cut -d: -f6)
else
# 直接执行的情况
current_user=$(whoami)
current_home="$HOME"
fi
echo "当前用户: $current_user"
echo "用户主目录: $current_home"
# 检查多种可能的桌面目录名称
desktop_dirs=("Desktop" "桌面" "desktop")
desktop_dir=""
desktop_shortcut=""
for dir_name in "${desktop_dirs[@]}"; do
potential_dir="$current_home/$dir_name"
if [ -d "$potential_dir" ]; then
desktop_dir="$potential_dir"
desktop_shortcut="$desktop_dir/grabbag.desktop"
echo "找到桌面目录: $desktop_dir"
break
fi
done
# 检查是否找到桌面目录
if [ -n "$desktop_dir" ]; then
# 检查桌面上是否已有快捷方式
if [ ! -f "$desktop_shortcut" ]; then
echo "为当前用户创建桌面快捷方式..."
# 复制桌面文件到用户桌面
cp /usr/share/applications/grabbag.desktop "$desktop_shortcut"
# 设置正确的所有者和权限
chown $current_user:$current_user "$desktop_shortcut" 2>/dev/null || true
chmod 755 "$desktop_shortcut"
echo "已创建桌面快捷方式: $desktop_shortcut"
else
echo "桌面快捷方式已存在,跳过创建"
fi
else
echo "当前用户没有找到桌面目录(Desktop/桌面/desktop),跳过桌面快捷方式创建"
fi
echo "GrabBag 应用程序安装完成!"
echo "应用程序将在用户登录桌面后自动启动。"
echo "端口映射已配置502 -> 5020"
echo "桌面快捷方式已创建如果用户有Desktop目录"
echo "如需立即启动,请运行: /usr/local/bin/GrabBagApp"
echo "如需禁用自启动,请删除文件: ~/.config/autostart/grabbag.desktop"
EOF
@ -191,9 +241,41 @@ iptables -t nat -D PREROUTING -p tcp --dport 502 -j REDIRECT --to-port 5020 2>/d
# 重新加载systemd
systemctl daemon-reload
# 提醒用户手动清理自启动配置(如果需要)
# 清理当前用户的桌面快捷方式
echo "清理当前用户的桌面快捷方式..."
# 获取当前执行卸载的用户信息
if [ -n "$SUDO_USER" ]; then
# 如果是通过sudo执行的获取真实用户
current_user="$SUDO_USER"
current_home=$(getent passwd "$current_user" | cut -d: -f6)
else
# 直接执行的情况
current_user=$(whoami)
current_home="$HOME"
fi
# 检查多种可能的桌面目录名称并清理快捷方式
desktop_dirs=("Desktop" "桌面" "desktop")
shortcut_found=false
for dir_name in "${desktop_dirs[@]}"; do
desktop_shortcut="$current_home/$dir_name/grabbag.desktop"
if [ -f "$desktop_shortcut" ]; then
echo "删除当前用户的桌面快捷方式: $desktop_shortcut"
rm -f "$desktop_shortcut"
echo "已删除桌面快捷方式: $desktop_shortcut"
shortcut_found=true
fi
done
if [ "$shortcut_found" = false ]; then
echo "当前用户没有找到桌面快捷方式,跳过清理"
fi
echo "GrabBag 应用程序卸载完成!"
echo "端口映射配置已清理"
echo "桌面快捷方式已清理"
echo "如需彻底清理自启动配置,请手动删除: ~/.config/autostart/grabbag.desktop"
EOF

File diff suppressed because it is too large Load Diff

View File

@ -95,6 +95,18 @@ struct VrPlaneCalibParam
double invRMatrix[9]; // 逆旋转矩阵,回到原坐标系
};
/**
* @brief
*/
struct VrDebugParam
{
bool enableDebug = false; // 是否开启调试模式
bool savePointCloud = false; // 是否保存点云数据
bool saveDebugImage = false; // 是否保存调试图像
bool printDetailLog = false; // 是否打印详细日志
std::string debugOutputPath = ""; // 调试输出路径
};
/**
* @brief
*/
@ -118,6 +130,7 @@ struct ConfigResult
std::vector<DeviceInfo> cameraList;
std::vector<DeviceInfo> deviceList;
VrAlgorithmParams algorithmParams; // 算法参数
VrDebugParam debugParam; // 调试参数
};
/**

View File

@ -177,6 +177,23 @@ ConfigResult CVrConfig::LoadConfig(const std::string& filePath)
if (planeCalibParamElement->Attribute("planeHeight"))
result.algorithmParams.planeCalibParam.planeHeight = planeCalibParamElement->DoubleAttribute("planeHeight");
}
}
// 解析调试参数在AlgorithmParams外面
XMLElement* debugParamElement = root->FirstChildElement("DebugParam");
if (debugParamElement)
{
if (debugParamElement->Attribute("enableDebug"))
result.debugParam.enableDebug = debugParamElement->BoolAttribute("enableDebug");
if (debugParamElement->Attribute("savePointCloud"))
result.debugParam.savePointCloud = debugParamElement->BoolAttribute("savePointCloud");
if (debugParamElement->Attribute("saveDebugImage"))
result.debugParam.saveDebugImage = debugParamElement->BoolAttribute("saveDebugImage");
if (debugParamElement->Attribute("printDetailLog"))
result.debugParam.printDetailLog = debugParamElement->BoolAttribute("printDetailLog");
if (debugParamElement->Attribute("debugOutputPath"))
result.debugParam.debugOutputPath = debugParamElement->Attribute("debugOutputPath");
}
return result;
@ -281,6 +298,15 @@ bool CVrConfig::SaveConfig(const std::string& filePath, ConfigResult& configResu
planeCalibParamElement->SetAttribute("planeHeight", configResult.algorithmParams.planeCalibParam.planeHeight);
algoParamsElement->InsertEndChild(planeCalibParamElement);
// 添加调试参数在AlgorithmParams外面
XMLElement* debugParamElement = doc.NewElement("DebugParam");
debugParamElement->SetAttribute("enableDebug", configResult.debugParam.enableDebug);
debugParamElement->SetAttribute("savePointCloud", configResult.debugParam.savePointCloud);
debugParamElement->SetAttribute("saveDebugImage", configResult.debugParam.saveDebugImage);
debugParamElement->SetAttribute("printDetailLog", configResult.debugParam.printDetailLog);
debugParamElement->SetAttribute("debugOutputPath", configResult.debugParam.debugOutputPath.c_str());
root->InsertEndChild(debugParamElement);
// 保存到文件
XMLError err = doc.SaveFile(filePath.c_str());
if (err != XML_SUCCESS)

View File

@ -34,5 +34,8 @@
<!-- 平面校准参数 -->
<PlaneCalibParam planeHeight="-1.0" />
<!-- 调试参数 -->
</AlgorithmParams>
<DebugParam enableDebug="false" savePointCloud="false" saveDebugImage="false" printDetailLog="false" debugOutputPath="./debug" />
</VrConfig>

View File

@ -74,8 +74,8 @@ int CVrEyeDevice::OpenDevice(const char* sIP, VzNL_OnNotifyStatusCBEx fNotify, v
m_sEeyCBDeviceInfo.sEyeCBInfo.nSize = sizeof(SVzNLEyeDeviceInfoEx);
VzNL_GetDeviceInfo(m_pHandle, (SVzNLEyeCBInfo *)(&m_sEeyCBDeviceInfo));
LOG_DEBUG("video res : w-%u h-%u\n", m_sEeyCBDeviceInfo.sVideoRes.nFrameWidth, m_sEeyCBDeviceInfo.sVideoRes.nFrameHeight);
//启用RGBD
VzNL_EnableRGB(m_pHandle, VzTrue);
//配置RGBD参数
VzNL_BeginDetectLaser(m_pHandle);
VzNL_EnableSwingMotor(m_pHandle, VzTrue);
@ -105,15 +105,21 @@ int CVrEyeDevice::OpenDevice(const char* sIP, VzNL_OnNotifyStatusCBEx fNotify, v
LOG_DEBUG("EnableRGBAutoExpose [%d]\n", nnnRet);
}
#if 0
//启用RGBD
VzNL_EnableRGB(m_pHandle, VzTrue);
float exposeThres = VzNL_GetRGBAutoExposeThres(m_pHandle, &nnnRet);
LOG_DEBUG("RGBAutoExposeThres : %f [%d]\n", exposeThres, nnnRet);
#endif
//设置回调
VzNL_SetDeviceStatusNotifyEx(m_pHandle,fNotify, param);
//获取内部接口类
VzNL_QueryDeviceData(m_pHandle, (void **)(&m_pDeviceCore));
// 填充
VzNL_EnableFillLaserPoint(m_pHandle, VzTrue);
delete[] pCBInfo;
return SUCCESS;
@ -149,7 +155,7 @@ int CVrEyeDevice::StartDetect(VzNL_AutoOutputLaserLineExCB fCallFunc, void *para
{
int nErrCode = SUCCESS;
if(!m_pHandle) return ERRCODE(DEV_NO_OPEN);
nErrCode = VzNL_StartAutoDetectEx(m_pHandle,keResultDataType_PointXYZRGBA, keFlipType_None, fCallFunc, param);
nErrCode = VzNL_StartAutoDetectEx(m_pHandle, keResultDataType_Position, keFlipType_None, fCallFunc, param);
return nErrCode;
}

View File

@ -1,7 +1,7 @@
#include "VrDateUtils.h"
/**
*
*
*/
std::string CVrDateUtils::GetNowTime()
{

View File

@ -131,11 +131,16 @@ void VrLogUtils::InitLog()
if (nullptr == m_pLayout)
{
m_pLayout = new log4cpp::PatternLayout;
m_pLayout->setConversionPattern(std::string("[%d] [%p] %c %x: %m%n"));
// 设置布局格式,可以控制是否自动换行
// %d{%Y-%m-%d %H:%M:%S.%l} [%p] %c - %m%n
// 其中 %n 表示换行符,如果想要控制换行可以去掉或修改这个
m_pLayout->setConversionPattern("%d{%Y-%m-%d %H:%M:%S.%l} [%p] %m");
}
if (nullptr == m_prollfileAppender)
{
m_prollfileAppender = new log4cpp::RollingFileAppender(LOG_PATH, std::string(LOG_PATH).append(PATH_SEP).append(LOG_PRINT_FILE), 10 * 1024, 1);
m_prollfileAppender = new log4cpp::RollingFileAppender(LOG_PATH, std::string(LOG_PATH).append(PATH_SEP).append(LOG_PRINT_FILE),
1024 * 1024, // 单个文件大小1M
10); // 10个文件
m_prollfileAppender->setLayout(m_pLayout);

View File

@ -23,6 +23,7 @@ win32-msvc*:QMAKE_CXXFLAGS += /D_HAS_AUTO_PTR_ETC=1
HEADERS += \
Inc/IVrUtils.h \
Inc/VrDateUtils.h \
Inc/VrFileUtils.h \
Inc/VrLog.h \
Inc/VrNetUtils.h \
@ -92,6 +93,7 @@ HEADERS += \
tinyxml2/tinyxml2.h \
SOURCES += \
Src/VrDateUtils.cpp \
Src/VrFileUtils.cpp \
Src/VrLog.cpp \
Src/VrNetUtils.cpp \