文章目录
- 匹配类
- 构造函数初始化布局变量
- 初始化图片
- 匹配
- 匹配计时器事件
- 开启计时器
- 停止
- 析构函数
Qt 联合Halcon视觉框架(1)
匹配类
#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_OBJECTpublic:// 构造函数,初始化 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,用于周期性任务
};
构造函数初始化布局变量
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);// 设置布局// 最外层垂直布局 TopBoxQVBoxLayout *TopBox = new QVBoxLayout(this);// Mvtec 标签水平布局QHBoxLayout *Mvtec = new QHBoxLayout;Mvtec->addStretch(1); // 左侧伸缩空间Mvtec->addWidget(MvtecLabel); // 添加 Mvtec 标签Mvtec->addStretch(1); // 右侧伸缩空间// 内部垂直布局 TopVBoxQVBoxLayout *TopVBox = new QVBoxLayout;// 包含 HALCON 小部件和按钮的水平布局 HBoxDispAndButtonsQHBoxLayout *HBoxDispAndButtons = new QHBoxLayout;// 创建 HALCON 窗口小部件 Disp,并设置最小尺寸Disp = new QHalconWindow(this);Disp->setMinimumSize(50, 50);// 包含 HALCON 小部件和提示标签的垂直布局 DispVBoxQVBoxLayout *DispVBox = new QVBoxLayout;DispVBox->addWidget(Disp, 1); // 添加 HALCON 小部件DispVBox->addSpacing(8); // 添加间距DispVBox->addWidget(DispHintLabel); // 添加提示标签// 包含按钮的垂直布局 ButtonsQVBoxLayout *Buttons = new QVBoxLayout;Buttons->addWidget(CreateButton); // 添加创建按钮Buttons->addSpacing(8); // 添加间距Buttons->addWidget(StartButton); // 添加开始按钮Buttons->addSpacing(8); // 添加间距Buttons->addWidget(StopButton); // 添加停止按钮Buttons->addStretch(1); // 底部伸缩空间// 将 HALCON 小部件和按钮布局添加到 HBoxDispAndButtonsHBoxDispAndButtons->addSpacing(15); // 左侧间距HBoxDispAndButtons->addLayout(DispVBox, 1); // 添加 HALCON 和提示标签布局HBoxDispAndButtons->addSpacing(15); // 中间间距HBoxDispAndButtons->addLayout(Buttons); // 添加按钮布局HBoxDispAndButtons->addSpacing(15); // 右侧间距// 创建包含标签的水平布局 HBoxLabelsQHBoxLayout *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); // 第二行第六列// 将网格布局添加到 HBoxLabelsHBoxLabels->addSpacing(15); // 左侧间距HBoxLabels->addLayout(Labels); // 添加网格布局HBoxLabels->addSpacing(130); // 右侧间距// 将 HBoxDispAndButtons 和 HBoxLabels 添加到 TopVBoxTopVBox->addLayout(HBoxDispAndButtons);TopVBox->addSpacing(15); // 中间间距TopVBox->addLayout(HBoxLabels);// 将 TopVBox 和 Mvtec 布局添加到最外层布局 TopBoxTopBox->addSpacing(15); // 上方间距TopBox->addLayout(TopVBox);TopBox->addSpacing(15); // 中间间距TopBox->addLayout(Mvtec);TopBox->addSpacing(10); // 下方间距
}
初始化图片
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();
}
匹配
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();
}
匹配计时器事件
void Matching::timerEvent(QTimerEvent*)
{StartMatching();
}
开启计时器
void Matching::Start(void)
{StartButton->setEnabled(false);StopButton->setEnabled(true);// Start Timer -> ::timerEvent() is called continouslyTimer = startTimer(20);
}
停止
// Stop continuous matching
void Matching::Stop(void)
{StartButton->setEnabled(true);StopButton->setEnabled(false);// Kill Timerif (Timer != -1){killTimer(Timer);Timer = -1;}
}
析构函数
Matching::~Matching(void)
{using namespace HalconCpp;// Close all allocated HALCON resources.CloseFramegrabber(FGHandle);if (Timer != -1){killTimer(Timer);Timer = -1;}
}