feat(PointCloudImageUtils): 添加通用点云画布类用于绘制点云底图和标记

This commit is contained in:
杰仔 2026-04-12 00:28:12 +08:00
parent 7e887aaeee
commit 598cd176f5
2 changed files with 194 additions and 4 deletions

View File

@ -111,6 +111,10 @@ public:
double rotateY_deg = 0.0, double rotateY_deg = 0.0,
bool useZGradient = false); bool useZGradient = false);
// 计算scan lines格式点云的范围
static void CalculateScanLinesRange(const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
double& xMin, double& xMax,
double& yMin, double& yMax);
private: private:
// 定义线特征颜色和大小获取函数 // 定义线特征颜色和大小获取函数
static void GetLineFeatureStyle(int vType, int hType, int objId, static void GetLineFeatureStyle(int vType, int hType, int objId,
@ -124,10 +128,6 @@ private:
double& xMin, double& xMax, double& xMin, double& xMax,
double& yMin, double& yMax); double& yMin, double& yMax);
// 计算scan lines格式点云的范围
static void CalculateScanLinesRange(const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
double& xMin, double& xMax,
double& yMin, double& yMax);
// 绘制LapWeld检测结果 // 绘制LapWeld检测结果
static void DrawLapWeldResults(QPainter& painter, static void DrawLapWeldResults(QPainter& painter,
@ -149,4 +149,53 @@ private:
int imgCols, int imgRows); int imgCols, int imgRows);
}; };
/**
* @brief
* + 3D2D投影 +
* 线
*/
class PointCloudCanvas
{
public:
/**
* @brief scan lines
* @param scanLines 线
* @param imageWidth
* @param imageHeight
* @param margin
*/
static PointCloudCanvas Create(const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
int imageWidth = 1056, int imageHeight = 992, int margin = 50);
bool isValid() const;
QImage& image();
const QImage& image() const;
/// 3D坐标→图像像素坐标
QPoint project(double x, double y) const;
/// 绘制实心圆点
void drawPoint(double x, double y, const QColor& color, int size = 4);
/// 绘制圆radius3D为3D空间半径自动投影为像素半径
void drawCircle(double x, double y, double radius3D, const QColor& color, int penWidth = 2, bool fill = false);
/// 绘制文字offsetX/offsetY 为像素偏移)
void drawText(double x, double y, const QString& text, const QColor& color, int fontSize = 14, int offsetX = 8, int offsetY = 6);
/// 绘制线段
void drawLine(double x1, double y1, double x2, double y2, const QColor& color, int penWidth = 2);
private:
QImage m_image;
double m_xMin = 0.0;
double m_yMin = 0.0;
double m_scale = 1.0;
int m_offsetX = 0;
int m_offsetY = 0;
int m_imgWidth = 0;
int m_imgHeight = 0;
bool m_valid = false;
};
#endif // POINTCLOUDIMAGEUTILS_H #endif // POINTCLOUDIMAGEUTILS_H

View File

@ -1695,3 +1695,144 @@ QImage PointCloudImageUtils::GenerateHoleDetectionImage(
return image; return image;
} }
// ==================== PointCloudCanvas 实现 ====================
PointCloudCanvas PointCloudCanvas::Create(
const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
int imageWidth, int imageHeight, int margin)
{
PointCloudCanvas canvas;
canvas.m_imgWidth = imageWidth;
canvas.m_imgHeight = imageHeight;
if (scanLines.empty()) {
return canvas;
}
// 计算点云范围
double xMin, xMax, yMin, yMax;
PointCloudImageUtils::CalculateScanLinesRange(scanLines, xMin, xMax, yMin, yMax);
if (xMax <= xMin || yMax <= yMin) {
return canvas;
}
// 计算投影参数
double drawableW = (double)(imageWidth - margin * 2);
double drawableH = (double)(imageHeight - margin * 2);
double xScale = (xMax - xMin) / drawableW;
double yScale = (yMax - yMin) / drawableH;
double scale = std::max(xScale, yScale);
canvas.m_xMin = xMin;
canvas.m_yMin = yMin;
canvas.m_scale = scale;
canvas.m_offsetX = margin;
canvas.m_offsetY = margin;
canvas.m_valid = true;
// 创建黑底图像
canvas.m_image = QImage(imageWidth, imageHeight, QImage::Format_RGB888);
canvas.m_image.fill(Qt::black);
// 绘制灰色点云底图
QPainter painter(&canvas.m_image);
QColor grayColor(150, 150, 150);
for (const auto& scanLine : scanLines) {
for (const auto& point : scanLine) {
if (point.pt3D.z < 1e-4) continue;
int px = (int)((point.pt3D.x - xMin) / scale + margin);
int py = (int)((point.pt3D.y - yMin) / scale + margin);
if (px >= 0 && px < imageWidth && py >= 0 && py < imageHeight) {
painter.setPen(QPen(grayColor, 1));
painter.drawPoint(px, py);
}
}
}
return canvas;
}
bool PointCloudCanvas::isValid() const
{
return m_valid;
}
QImage& PointCloudCanvas::image()
{
return m_image;
}
const QImage& PointCloudCanvas::image() const
{
return m_image;
}
QPoint PointCloudCanvas::project(double x, double y) const
{
int px = (int)((x - m_xMin) / m_scale + m_offsetX);
int py = (int)((y - m_yMin) / m_scale + m_offsetY);
return QPoint(px, py);
}
void PointCloudCanvas::drawPoint(double x, double y, const QColor& color, int size)
{
if (!m_valid) return;
QPoint pt = project(x, y);
if (pt.x() < 0 || pt.x() >= m_imgWidth || pt.y() < 0 || pt.y() >= m_imgHeight) return;
QPainter painter(&m_image);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(color, 1));
painter.setBrush(QBrush(color));
painter.drawEllipse(pt.x() - size / 2, pt.y() - size / 2, size, size);
}
void PointCloudCanvas::drawCircle(double x, double y, double radius3D,
const QColor& color, int penWidth, bool fill)
{
if (!m_valid) return;
QPoint pt = project(x, y);
if (pt.x() < 0 || pt.x() >= m_imgWidth || pt.y() < 0 || pt.y() >= m_imgHeight) return;
int pixelRadius = (int)(radius3D / m_scale);
if (pixelRadius < 3) pixelRadius = 3;
QPainter painter(&m_image);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(color, penWidth));
painter.setBrush(fill ? QBrush(color) : Qt::NoBrush);
painter.drawEllipse(pt.x() - pixelRadius, pt.y() - pixelRadius,
pixelRadius * 2, pixelRadius * 2);
}
void PointCloudCanvas::drawText(double x, double y, const QString& text,
const QColor& color, int fontSize,
int offsetX, int offsetY)
{
if (!m_valid) return;
QPoint pt = project(x, y);
if (pt.x() < 0 || pt.x() >= m_imgWidth || pt.y() < 0 || pt.y() >= m_imgHeight) return;
QPainter painter(&m_image);
painter.setPen(QPen(color, 1));
QFont font("Arial", fontSize, QFont::Bold);
painter.setFont(font);
painter.drawText(pt.x() + offsetX, pt.y() + offsetY, text);
}
void PointCloudCanvas::drawLine(double x1, double y1, double x2, double y2,
const QColor& color, int penWidth)
{
if (!m_valid) return;
QPoint pt1 = project(x1, y1);
QPoint pt2 = project(x2, y2);
QPainter painter(&m_image);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(QPen(color, penWidth));
painter.drawLine(pt1, pt2);
}