feat(PointCloudImageUtils): 添加通用点云画布类用于绘制点云底图和标记
This commit is contained in:
parent
7e887aaeee
commit
598cd176f5
@ -111,6 +111,10 @@ public:
|
||||
double rotateY_deg = 0.0,
|
||||
bool useZGradient = false);
|
||||
|
||||
// 计算scan lines格式点云的范围
|
||||
static void CalculateScanLinesRange(const std::vector<std::vector<SVzNL3DPosition>>& scanLines,
|
||||
double& xMin, double& xMax,
|
||||
double& yMin, double& yMax);
|
||||
private:
|
||||
// 定义线特征颜色和大小获取函数
|
||||
static void GetLineFeatureStyle(int vType, int hType, int objId,
|
||||
@ -124,10 +128,6 @@ private:
|
||||
double& xMin, double& xMax,
|
||||
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检测结果
|
||||
static void DrawLapWeldResults(QPainter& painter,
|
||||
@ -149,4 +149,53 @@ private:
|
||||
int imgCols, int imgRows);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 通用点云画布类
|
||||
* 封装点云底图生成 + 3D→2D投影 + 通用绘图原语
|
||||
* 调用方可自由组合绘制点、文字、线段、圆等标记
|
||||
*/
|
||||
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
|
||||
|
||||
@ -1695,3 +1695,144 @@ QImage PointCloudImageUtils::GenerateHoleDetectionImage(
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user