Compare commits

..

No commits in common. "WheelMeasure_1.1.2" and "master" have entirely different histories.

16 changed files with 115 additions and 30 deletions

View File

@ -51,8 +51,15 @@ int DetectPresenter::DetectHoles(
return ERR_CODE(DEV_DATA_INVALID);
}
// debug保存点云已由 BasePresenter::DetectTask() 统一处理,此处不再重复保存
// 保存debug数据
// 调试模式下先保存原始激光线数据,便于后续离线复现问题。
std::string timeStamp = CVrDateUtils::GetNowTime();
if (debugParam.enableDebug && debugParam.savePointCloud) {
LOG_INFO("[Algo Thread] Debug mode is enabled, saving point cloud data\n");
std::string fileName = debugParam.debugOutputPath + "/Laserline_" + std::to_string(cameraIndex) + "_" + timeStamp + ".txt";
dataLoader.SaveLaserScanData(fileName, laserLines, laserLines.size(), 0.0, 0, 0);
}
int nRet = SUCCESS;

View File

@ -3,7 +3,11 @@
#include "AlgoParamConverter.h"
#include "IHandEyeCalib.h"
#include <fstream>
#define _USE_MATH_DEFINES
#include <cmath>
#include <memory>
#include <QPainter>
#include <QPen>
#include <QColor>
namespace
@ -64,8 +68,17 @@ int DetectPresenter::DetectRod(
cameraCalibParam = &cameraCalibParamValue;
}
// debug保存点云已由 BasePresenter::DetectTask() 统一处理,此处不再重复保存
// 保存debug数据
std::string timeStamp = CVrDateUtils::GetNowTime();
if(debugParam.enableDebug && debugParam.savePointCloud){
LOG_INFO("[Algo Thread] Debug mode is enabled, saving point cloud data\n");
// 获取当前时间戳格式为YYYYMMDDHHMMSS
std::string fileName = debugParam.debugOutputPath + "/Laserline_" + std::to_string(cameraIndex) + "_" + timeStamp + ".txt";
// 直接使用统一格式保存数据
dataLoader.SaveLaserScanData(fileName, laserLines, laserLines.size(), 0.0, 0, 0);
}
int nRet = SUCCESS;
@ -123,32 +136,96 @@ int DetectPresenter::DetectRod(
const HECCalibResult calibResult = HECCalibResult::fromHomogeneousArray(clibMatrix);
const HECEulerOrder hecEulerOrder = ToHandEyeEulerOrder(eulerOrder);
// 使用 PointCloudCanvas 生成点云图像(灰色底图 + 棒材中心/方向线标记)
{
PointCloudCanvas canvas = PointCloudCanvas::Create(xyzData);
// 构建检测结果:生成点云图像
// 1. 获取所有棒材的中心点用于可视化
std::vector<std::vector<SVzNL3DPoint>> objOps;
std::vector<SVzNL3DPoint> rodCenters;
for (size_t i = 0; i < rodInfo.size(); i++) {
const auto& rod = rodInfo[i];
for (const auto& rod : rodInfo) {
SVzNL3DPoint pt;
pt.x = rod.center.x;
pt.y = rod.center.y;
pt.z = rod.center.z;
rodCenters.push_back(pt);
}
if (!rodCenters.empty()) {
objOps.push_back(rodCenters);
}
// 绘制棒材中心点(红色)
canvas.drawPoint(rod.center.x, rod.center.y, QColor(255, 0, 0), 6);
// 从点云数据生成投影图像10cm边界同时获取点云原始范围
double margin = 100.0; // 10cm = 100mm
double xMin, xMax, yMin, yMax;
detectionResult.image = PointCloudImageUtils::GeneratePointCloudRetPointImage(xyzData, objOps, margin, &xMin, &xMax, &yMin, &yMax);
// 在图像上绘制棒材的轴向方向线
if (!detectionResult.image.isNull() && !rodInfo.empty()) {
QPainter painter(&detectionResult.image);
painter.setRenderHint(QPainter::Antialiasing);
// 扩展边界与GeneratePointCloudRetPointImage相同
xMin -= margin;
xMax += margin;
yMin -= margin;
yMax += margin;
// 使用与GeneratePointCloudRetPointImage相同的参数
int imgRows = detectionResult.image.height();
int imgCols = detectionResult.image.width();
int x_skip = 50;
int y_skip = 50;
// 计算投影比例与PointCloudImageUtils相同的方式
double y_rows = (double)(imgRows - y_skip * 2);
double x_cols = (double)(imgCols - x_skip * 2);
double x_scale = (xMax - xMin) / x_cols;
double y_scale = (yMax - yMin) / y_rows;
// 使用统一的比例尺
double scale = std::max(x_scale, y_scale);
x_scale = scale;
y_scale = scale;
// 计算点云在图像中居中的偏移量与PointCloudImageUtils一致
double cloudWidth = (xMax - xMin) / scale;
double cloudHeight = (yMax - yMin) / scale;
int x_offset = x_skip + (int)((x_cols - cloudWidth) / 2);
int y_offset = y_skip + (int)((y_rows - cloudHeight) / 2);
// 转换3D坐标到图像坐标的lambda函数使用居中偏移
auto toImageCoord = [&](const SVzNL3DPoint& pt) -> QPointF {
int px = (int)((pt.x - xMin) / x_scale + x_offset);
int py = (int)((pt.y - yMin) / y_scale + y_offset);
return QPointF(px, py);
};
// 绘制棒材的轴向方向线
for (const auto& rod : rodInfo) {
// 绘制轴向方向线(红色)
double len = 60;
double ax0 = rod.center.x - len * rod.axialDir.x;
double ay0 = rod.center.y - len * rod.axialDir.y;
double ax1 = rod.center.x + len * rod.axialDir.x;
double ay1 = rod.center.y + len * rod.axialDir.y;
canvas.drawLine(ax0, ay0, ax1, ay1, QColor(255, 0, 0), 2);
QPen axisPen(QColor(255, 0, 0), 2);
painter.setPen(axisPen);
SVzNL3DPoint pt0 = { rod.center.x - len * rod.axialDir.x,
rod.center.y - len * rod.axialDir.y,
rod.center.z - len * rod.axialDir.z };
SVzNL3DPoint pt1 = { rod.center.x + len * rod.axialDir.x,
rod.center.y + len * rod.axialDir.y,
rod.center.z + len * rod.axialDir.z };
QPointF imgPt0 = toImageCoord(pt0);
QPointF imgPt1 = toImageCoord(pt1);
painter.drawLine(imgPt0, imgPt1);
// 绘制起点到终点线段(绿色)
canvas.drawLine(rod.startPt.x, rod.startPt.y, rod.endPt.x, rod.endPt.y, QColor(0, 255, 0), 2);
QPen segPen(QColor(0, 255, 0), 2);
painter.setPen(segPen);
// 中心点白色编号
canvas.drawText(rod.center.x, rod.center.y, QString("%1").arg(i + 1), Qt::white, 14);
SVzNL3DPoint startPt = { rod.startPt.x, rod.startPt.y, rod.startPt.z };
SVzNL3DPoint endPt = { rod.endPt.x, rod.endPt.y, rod.endPt.z };
QPointF imgStart = toImageCoord(startPt);
QPointF imgEnd = toImageCoord(endPt);
painter.drawLine(imgStart, imgEnd);
}
detectionResult.image = canvas.image();
}
// 转换检测结果为UI显示格式使用机械臂坐标系数据

View File

@ -5,7 +5,7 @@
// 应用名称
#define RODANDBARPOSITION_APP_NAME "棒材定位"
#define RODANDBARPOSITION_VERSION_STRING "1.1.0"
#define RODANDBARPOSITION_VERSION_STRING "1.0.2"
#define RODANDBARPOSITION_BUILD_STRING "1"
#define RODANDBARPOSITION_FULL_VERSION_STRING "V" RODANDBARPOSITION_VERSION_STRING "_" RODANDBARPOSITION_BUILD_STRING

View File

@ -1,7 +1,3 @@
# 1.1.0 2026-04-13
## build_1
1. 更新内存泄露问题
# 1.0.1 2026-03-27
## build_1
1. 修复协议,增加读取下一个目标的

View File

@ -3,7 +3,7 @@
#define WHEELMEASURE_APP_NAME "轮眉高度测量"
#define WHEELMEASURE_VERSION_STRING "1.1.2"
#define WHEELMEASURE_VERSION_STRING "1.1.1"
#define WHEELMEASURE_BUILD_STRING "1"
#define WHEELMEASURE_FULL_VERSION_STRING "V" WHEELMEASURE_VERSION_STRING "_" WHEELMEASURE_BUILD_STRING

View File

@ -1,7 +1,3 @@
# 1.1.2
## build_1 2026-04-09
1. 更新算法1.3.4
# 1.1.1
## build_1 2026-04-09
1. 更新算法1.3.3

View File

@ -45,8 +45,17 @@ int DetectPresenter::DetectWorkpieceHole(
cameraCalibParam = &cameraCalibParamValue;
}
// debug保存点云已由 BasePresenter::DetectTask() 统一处理,此处不再重复保存
// 保存debug数据
std::string timeStamp = CVrDateUtils::GetNowTime();
if(debugParam.enableDebug && debugParam.savePointCloud){
LOG_INFO("[Algo Thread] Debug mode is enabled, saving point cloud data\n");
// 获取当前时间戳格式为YYYYMMDDHHMMSS
std::string fileName = debugParam.debugOutputPath + "/Laserline_" + std::to_string(cameraIndex) + "_" + timeStamp + ".txt";
// 直接使用统一格式保存数据
dataLoader.SaveLaserScanData(fileName, laserLines, laserLines.size(), 0.0, 0, 0);
}
int nRet = SUCCESS;