Qt 联合Halcon视觉框架(2)

文章目录

Qt 联合Halcon视觉框架(1)

匹配类

cpp 复制代码
#if QT_VERSION >= 0x050000
    #include <QtWidgets/qlabel.h>
    #include <QtWidgets/qpushbutton.h>
#else
    #include <qlabel.h>
    #include <qpushbutton.h>
#endif

// 根据 Qt 版本选择合适的头文件。对于 Qt 5 及以上版本,使用 Qt Widgets 模块中的头文件。
// 对于较早版本的 Qt,则直接包含旧版的头文件。

#include <QScopedPointer>
#include "qhalconwindow.h"

class Matching: public QWidget
{
  Q_OBJECT

public:
    // 构造函数,初始化 Matching 小部件,并可选地指定父小部件。
    // parent 参数允许将这个小部件嵌入到另一个窗口或小部件中。
    Matching(QWidget *parent = nullptr);

    // 析构函数,确保正确清理资源。
    virtual ~Matching(void);

    // 初始化前景(Foreground)变量。
    void InitFg(void);

protected slots:
    // 创建模型的槽函数。
    void Create(void);

    // 开始匹配过程的槽函数。
    void Start(void);

    // 停止匹配过程的槽函数。
    void Stop(void);

protected:
    // 定时器事件处理函数,用于周期性任务(如更新显示或执行匹配)。
    void timerEvent(QTimerEvent*);

    // 开始匹配过程的辅助函数。
    void StartMatching(void);

private:
    // HALCON 相关变量
    Hlong ImageWidth, ImageHeight;           // 图像宽度和高度
    HalconCpp::HTuple FGHandle;              // 前景句柄
    HalconCpp::HImage Image;                 // 当前图像
    QScopedPointer<HalconCpp::HShapeModel> ShapeModel; // 形状模型智能指针
    HalconCpp::HTuple ModelRow, ModelColumn; // 模型参考点的行和列坐标
    HalconCpp::HTuple Rect1Row, Rect1Col, Rect2Row, Rect2Col; // 区域矩形的角点坐标
    HalconCpp::HTuple RectLength1, RectLength2; // 矩形的边长
    HalconCpp::HObject ShapeModelRegion;     // 形状模型区域对象

    // GUI 元素
    QLabel *MatchTimeLabel;                  // 显示匹配时间的标签
    QLabel *MatchScoreLabel;                 // 显示匹配得分的标签
    QLabel *MeasTimeLabel;                   // 显示测量时间的标签
    QLabel *NumLeadsLabel;                   // 显示导线数量的标签
    QLabel *MinLeadsDistLabel;               // 显示最小导线距离的标签
    QPushButton *CreateButton;               // 创建模型按钮
    QPushButton *StartButton;                // 开始匹配按钮
    QPushButton *StopButton;                 // 停止匹配按钮
    QHalconWindow *Disp;                     // 显示 HALCON 图像的窗口

    // 定时器
    long Timer;                              // 定时器 ID,用于周期性任务
};

构造函数初始化布局变量

cpp 复制代码
Matching::Matching(QWidget *parent)
    : QWidget(parent), Timer(-1)
{
  // 创建按钮并设置信号槽连接
  // CreateButton:创建模型按钮,点击时调用 Create 槽函数。
  CreateButton = new QPushButton(tr("Create Model"), this);
  connect(CreateButton, SIGNAL(clicked()), SLOT(Create()));

  // StartButton:开始匹配按钮,初始状态下禁用,点击时调用 Start 槽函数。
  StartButton = new QPushButton(tr("Start"), this);
  StartButton->setEnabled(false);
  connect(StartButton, SIGNAL(clicked()), SLOT(Start()));

  // StopButton:停止匹配按钮,初始状态下禁用,点击时调用 Stop 槽函数。
  StopButton = new QPushButton(tr("Stop"), this);
  StopButton->setEnabled(false);
  connect(StopButton, SIGNAL(clicked()), SLOT(Stop()));

  // 创建标签用于显示信息
  QLabel *match_time = new QLabel(tr("Matching:"), this);
  QLabel *match_time2 = new QLabel(tr("Time:"), this);
  MatchTimeLabel = new QLabel("        ", this); // 显示匹配时间

  QLabel *match_score = new QLabel(tr("Score:  "), this);
  MatchScoreLabel = new QLabel("        ", this); // 显示匹配得分

  QLabel *meas_time = new QLabel(tr("Measure:"), this);
  QLabel *meas_time2 = new QLabel(tr("Time:"), this);
  MeasTimeLabel = new QLabel("        ", this); // 显示测量时间

  QLabel *num_leads = new QLabel(tr("Number of leads:  "), this);
  NumLeadsLabel = new QLabel("        ", this); // 显示导线数量

  QLabel *min_lead_dist = new QLabel(tr("Minimum Lead Distance:  "), this);
  MinLeadsDistLabel = new QLabel("        ", this); // 显示最小导线距离

  // 创建 Mvtec 标签并设置字体样式
  QLabel *MvtecLabel = new QLabel("\xa9 2004-2017 MVTec Software GmbH", this);
  MvtecLabel->setFont(QFont(nullptr, 10, QFont::Bold));

  // 创建 HALCON 小部件使用说明标签
  QLabel *DispHintLabel = new QLabel(
      "Zoom: mouse wheel; Move: left mouse button; Reset: double click", this);

  // 设置布局
  // 最外层垂直布局 TopBox
  QVBoxLayout *TopBox = new QVBoxLayout(this);

  // Mvtec 标签水平布局
  QHBoxLayout *Mvtec = new QHBoxLayout;
  Mvtec->addStretch(1); // 左侧伸缩空间
  Mvtec->addWidget(MvtecLabel); // 添加 Mvtec 标签
  Mvtec->addStretch(1); // 右侧伸缩空间

  // 内部垂直布局 TopVBox
  QVBoxLayout *TopVBox = new QVBoxLayout;

  // 包含 HALCON 小部件和按钮的水平布局 HBoxDispAndButtons
  QHBoxLayout *HBoxDispAndButtons = new QHBoxLayout;

  // 创建 HALCON 窗口小部件 Disp,并设置最小尺寸
  Disp = new QHalconWindow(this);
  Disp->setMinimumSize(50, 50);

  // 包含 HALCON 小部件和提示标签的垂直布局 DispVBox
  QVBoxLayout *DispVBox = new QVBoxLayout;
  DispVBox->addWidget(Disp, 1); // 添加 HALCON 小部件
  DispVBox->addSpacing(8); // 添加间距
  DispVBox->addWidget(DispHintLabel); // 添加提示标签

  // 包含按钮的垂直布局 Buttons
  QVBoxLayout *Buttons = new QVBoxLayout;
  Buttons->addWidget(CreateButton); // 添加创建按钮
  Buttons->addSpacing(8); // 添加间距
  Buttons->addWidget(StartButton); // 添加开始按钮
  Buttons->addSpacing(8); // 添加间距
  Buttons->addWidget(StopButton); // 添加停止按钮
  Buttons->addStretch(1); // 底部伸缩空间

  // 将 HALCON 小部件和按钮布局添加到 HBoxDispAndButtons
  HBoxDispAndButtons->addSpacing(15); // 左侧间距
  HBoxDispAndButtons->addLayout(DispVBox, 1); // 添加 HALCON 和提示标签布局
  HBoxDispAndButtons->addSpacing(15); // 中间间距
  HBoxDispAndButtons->addLayout(Buttons); // 添加按钮布局
  HBoxDispAndButtons->addSpacing(15); // 右侧间距

  // 创建包含标签的水平布局 HBoxLabels
  QHBoxLayout *HBoxLabels = new QHBoxLayout;

  // 创建网格布局 Labels 用于排列多个标签
  QGridLayout *Labels = new QGridLayout();
  Labels->addWidget(match_time, 0, 0); // 第一行第零列
  Labels->addWidget(match_time2, 0, 1); // 第一行第一列
  Labels->addWidget(MatchTimeLabel, 0, 2); // 第一行第二列
  Labels->addWidget(match_score, 0, 3); // 第一行第三列
  Labels->addWidget(MatchScoreLabel, 0, 4); // 第一行第四列
  Labels->addWidget(meas_time, 1, 0); // 第二行第零列
  Labels->addWidget(meas_time2, 1, 1); // 第二行第一列
  Labels->addWidget(MeasTimeLabel, 1, 2); // 第二行第二列
  Labels->addWidget(num_leads, 1, 3); // 第二行第三列
  Labels->addWidget(NumLeadsLabel, 1, 4); // 第二行第四列
  Labels->addWidget(min_lead_dist, 1, 5); // 第二行第五列
  Labels->addWidget(MinLeadsDistLabel, 1, 6); // 第二行第六列

  // 将网格布局添加到 HBoxLabels
  HBoxLabels->addSpacing(15); // 左侧间距
  HBoxLabels->addLayout(Labels); // 添加网格布局
  HBoxLabels->addSpacing(130); // 右侧间距

  // 将 HBoxDispAndButtons 和 HBoxLabels 添加到 TopVBox
  TopVBox->addLayout(HBoxDispAndButtons);
  TopVBox->addSpacing(15); // 中间间距
  TopVBox->addLayout(HBoxLabels);

  // 将 TopVBox 和 Mvtec 布局添加到最外层布局 TopBox
  TopBox->addSpacing(15); // 上方间距
  TopBox->addLayout(TopVBox);
  TopBox->addSpacing(15); // 中间间距
  TopBox->addLayout(Mvtec);
  TopBox->addSpacing(10); // 下方间距
}

初始化图片

cpp 复制代码
void Matching::InitFg(void)
{
  using namespace HalconCpp;

  // 打开帧采集器并获取初始图像
  // 使用 OpenFramegrabber 函数打开一个帧采集器(这里使用文件作为源),并获取句柄 FGHandle。
  // 参数解释:
  // - "File":指定帧采集器类型为文件。
  // - 后续参数为默认值或特定配置,如宽度、高度等。
  // - "board/board.seq":指定要读取的图像序列文件路径。
  // - 最后两个参数 "-1, 1" 分别表示最小和最大图像编号,-1 表示无限制。
  OpenFramegrabber("File", 1, 1, 0, 0, 0, 0, "default", -1, "default", -1, "default",
                   "board/board.seq", "default", -1, 1, &FGHandle);

  // 使用 GrabImage 函数从帧采集器中抓取一幅图像,并存储到 Image 变量中。
  GrabImage(&Image, FGHandle);

  // 获取图像尺寸,并将宽度和高度存储到 ImageWidth 和 ImageHeight 成员变量中。
  Image.GetImageSize(&ImageWidth, &ImageHeight);

  // 设置 HALCON 窗口显示区域为整个图像大小。
  // SetPart 的参数 (0, 0, ImageHeight-1, ImageWidth-1) 表示将显示区域设置为图像的完整范围。
  Disp->GetHalconBuffer()->SetPart(0, 0, ImageHeight - 1, ImageWidth - 1);

  // 设置 HALCON 窗口中线条的宽度为 3。
  Disp->GetHalconBuffer()->SetLineWidth(3);

  // 在 HALCON 窗口中显示抓取到的图像。
  Disp->GetHalconBuffer()->DispObj(Image);

  // 刷新 HALCON 缓冲区以应用更改并更新显示。
  Disp->GetHalconBuffer()->FlushBuffer();
}

匹配

cpp 复制代码
void Matching::StartMatching(void)
{
  using namespace HalconCpp;

  double S1, S2;
  HTuple Rect1RowCheck, Rect1ColCheck, Rect2RowCheck, Rect2ColCheck;
  HTuple MeasureHandle1, MeasureHandle2, NumLeads;
  HTuple RowCheck, ColumnCheck, AngleCheck, Score, HomMat2D, MinDistance;
  HTuple RowEdgeFirst1, ColumnEdgeFirst1, AmplitudeFirst1;
  HTuple RowEdgeSecond1, ColumnEdgeSecond1, AmplitudeSecond1;
  HTuple IntraDistance1, InterDistance1;
  HTuple RowEdgeFirst2, ColumnEdgeFirst2, AmplitudeFirst2;
  HTuple RowEdgeSecond2, ColumnEdgeSecond2, AmplitudeSecond2;
  HTuple IntraDistance2, InterDistance2;
  HObject ShapeModelTrans;
  HObject Rectangle1, Rectangle2;
  HImage Image;
  char buf[MAX_STRING];
  QString string;

  // 抓取下一帧图像并显示
  GrabImage(&Image, FGHandle);
  Disp->GetHalconBuffer()->DispObj(Image);

  // 开始计时以测量匹配时间
  S1 = HSystem::CountSeconds();
  
  // 在当前图像中查找模型实例
  ShapeModel->FindShapeModel(Image, 0, 2 * PI, 0.7, 1, 0.5, "least_squares", 4, 0.7,
                             &RowCheck, &ColumnCheck, &AngleCheck, &Score);
  
  // 结束计时并更新匹配时间标签
  S2 = HSystem::CountSeconds();
  sprintf(buf, "%5.2f", (S2 - S1) * 1000);
  string = buf;
  MatchTimeLabel->setText(string);

  // 如果找到了一个匹配结果(即 Score 的长度为 1)
  if (Score.Length() == 1)
  {
    // 更新匹配得分标签
    sprintf(buf, "%7.5f", (double)Score[0]);
    string = buf;
    MatchScoreLabel->setText(string);

    // 根据匹配结果旋转模型用于可视化
    VectorAngleToRigid(ModelRow, ModelColumn, 0, RowCheck, ColumnCheck, AngleCheck, &HomMat2D);
    AffineTransRegion(ShapeModelRegion, &ShapeModelTrans, HomMat2D, "false");
    Disp->GetHalconBuffer()->SetColor("green");
    Disp->GetHalconBuffer()->DispObj(ShapeModelTrans);

    // 计算测量矩形的参数
    AffineTransPixel(HomMat2D, Rect1Row, Rect1Col, &Rect1RowCheck, &Rect1ColCheck);
    AffineTransPixel(HomMat2D, Rect2Row, Rect2Col, &Rect2RowCheck, &Rect2ColCheck);

    // 生成两个测量矩形作为区域并显示它们
    GenRectangle2(&Rectangle1, Rect1RowCheck, Rect1ColCheck, AngleCheck, RectLength1, RectLength2);
    GenRectangle2(&Rectangle2, Rect2RowCheck, Rect2ColCheck, AngleCheck, RectLength1, RectLength2);
    Disp->GetHalconBuffer()->SetColor("blue");
    Disp->GetHalconBuffer()->SetDraw("margin");
    Disp->GetHalconBuffer()->DispObj(Rectangle1);
    Disp->GetHalconBuffer()->DispObj(Rectangle2);
    Disp->GetHalconBuffer()->SetDraw("fill");

    // 执行实际测量
    S1 = HSystem::CountSeconds();

    // 创建测量句柄
    GenMeasureRectangle2(Rect1RowCheck, Rect1ColCheck, AngleCheck, RectLength1, RectLength2,
                         ImageWidth, ImageHeight, "bilinear", &MeasureHandle1);
    GenMeasureRectangle2(Rect2RowCheck, Rect2ColCheck, AngleCheck, RectLength1, RectLength2,
                         ImageWidth, ImageHeight, "bilinear", &MeasureHandle2);

    // 进行边缘检测和测量
    MeasurePairs(Image, MeasureHandle1, 2, 90, "positive", "all",
                 &RowEdgeFirst1, &ColumnEdgeFirst1, &AmplitudeFirst1,
                 &RowEdgeSecond1, &ColumnEdgeSecond1, &AmplitudeSecond1,
                 &IntraDistance1, &InterDistance1);
    MeasurePairs(Image, MeasureHandle2, 2, 90, "positive", "all",
                 &RowEdgeFirst2, &ColumnEdgeFirst2, &AmplitudeFirst2,
                 &RowEdgeSecond2, &ColumnEdgeSecond2, &AmplitudeSecond2,
                 &IntraDistance2, &InterDistance2);

    // 关闭测量句柄
    CloseMeasure(MeasureHandle1);
    CloseMeasure(MeasureHandle2);

    S2 = HSystem::CountSeconds();

    // 显示测量结果
    Disp->GetHalconBuffer()->SetColor("red");
    Disp->GetHalconBuffer()->DispLine(
      RowEdgeFirst1 - RectLength2 * AngleCheck.TupleCos(),
      ColumnEdgeFirst1 - RectLength2 * AngleCheck.TupleSin(),
      RowEdgeFirst1 + RectLength2 * AngleCheck.TupleCos(),
      ColumnEdgeFirst1 + RectLength2 * AngleCheck.TupleSin());
    Disp->GetHalconBuffer()->DispLine(
      RowEdgeSecond1 - RectLength2 * AngleCheck.TupleCos(),
      ColumnEdgeSecond1 - RectLength2 * AngleCheck.TupleSin(),
      RowEdgeSecond1 + RectLength2 * AngleCheck.TupleCos(),
      ColumnEdgeSecond1 + RectLength2 * AngleCheck.TupleSin());
    Disp->GetHalconBuffer()->DispLine(
      RowEdgeFirst2 - RectLength2 * AngleCheck.TupleCos(),
      ColumnEdgeFirst2 - RectLength2 * AngleCheck.TupleSin(),
      RowEdgeFirst2 + RectLength2 * AngleCheck.TupleCos(),
      ColumnEdgeFirst2 + RectLength2 * AngleCheck.TupleSin());
    Disp->GetHalconBuffer()->DispLine(
      RowEdgeSecond2 - RectLength2 * AngleCheck.TupleCos(),
      ColumnEdgeSecond2 - RectLength2 * AngleCheck.TupleSin(),
      RowEdgeSecond2 + RectLength2 * AngleCheck.TupleCos(),
      ColumnEdgeSecond2 + RectLength2 * AngleCheck.TupleSin());

    // 更新测量时间标签
    sprintf(buf, "%5.2f", (S2 - S1) * 1000);
    string = buf;
    MeasTimeLabel->setText(string);

    // 更新导线数量标签
    NumLeads = IntraDistance1.Length() + IntraDistance2.Length();
    sprintf(buf, "%2ld", (Hlong)NumLeads[0]);
    string = buf;
    NumLeadsLabel->setText(string);

    // 更新最小导线距离标签
    MinDistance = (InterDistance1.TupleConcat(InterDistance2)).TupleMin();
    sprintf(buf, "%6.3f", (double)MinDistance[0]);
    string = buf;
    MinLeadsDistLabel->setText(string);
  }

  // 刷新 HALCON 缓冲区以应用所有更改并更新显示
  Disp->GetHalconBuffer()->FlushBuffer();
}

匹配计时器事件

cpp 复制代码
void Matching::timerEvent(QTimerEvent*)
{
  StartMatching();
}

开启计时器

cpp 复制代码
void Matching::Start(void)
{
  StartButton->setEnabled(false);
  StopButton->setEnabled(true);
  // Start Timer -> ::timerEvent() is called continously
  Timer = startTimer(20);
}

停止

cpp 复制代码
// Stop continuous matching
void Matching::Stop(void)
{
  StartButton->setEnabled(true);
  StopButton->setEnabled(false);
  // Kill Timer
  if (Timer != -1)
  {
    killTimer(Timer);
    Timer = -1;
  }
}

析构函数

cpp 复制代码
Matching::~Matching(void)
{
  using namespace HalconCpp;

  // Close all allocated HALCON resources.
  CloseFramegrabber(FGHandle);
  if (Timer != -1)
  {
    killTimer(Timer);
    Timer = -1;
  }
}
相关推荐
恒辉信达12 分钟前
hhdb客户端介绍(15)
数据库·mysql·hhdb·数据库可视化界面客户端
安年CJ16 分钟前
计算机操作系统虚拟化与云计算教学指南
linux·运维·服务器·数据结构·数据库·云计算
编程修仙1 小时前
mysql日期类型的基本使用
数据库·mysql
2402_857589361 小时前
凭借 SSM 架构优势,塑造个性化商铺系统竞争力
系统架构
就爱学编程2 小时前
重生之我在异世界学智力题(6)
android·java·数据库
千千道2 小时前
Qt 实现 UDP 广播的详细教程
开发语言·qt·网络协议·udp
whn19773 小时前
向达梦告警日志说声hello
数据库
人生の三重奏3 小时前
django——admin后台管理1
数据库·python·django