[Qt学习笔记]QT下获取Halcon图形窗口鼠标事件并执行相应操作

目录

  • 1、背景
  • 2、参考信息
  • 3、目标
  • 4、步骤
    • 4.1 Halcon库的配置
    • 4.2 读取图像,并实现图像自适应窗体控件大小
    • 4.3 主要的图形绘制和贴图操作见如下代码,其中重点为全局函数的创建来实现选择Select、拖拽Drag和尺寸Resize事件响应。
  • 5、总结

1、背景

在视觉项目开发过程中碰到了需要使用Halcon进行图像算法开发的需求,估计很多视觉工程师都用到过Halcon软件开发库,但是完成Halcon算法开发后就会遇到一个问题,就是图像的显示、读写、UI交互等问题,由于Halcon具有特殊的图像文件格式HObject和数据格式HTuple,所以说需要格式转换后才能实现相对应的操作,不过Halcon本身也有比较实用的显示、界面交互的功能,所以如何在C++或QT下使用这些功能成为了接下来需要去研究和实践的工作。

2、参考信息

Halcon针对不同的开发环境,给出了不同的开发例程,针对图形显示及界面操作这一块,Halcon只给出了C#的相关例程,其运行结果如下:
DrawingObject.png

Draw.png
其中可以实现在窗口界面创建矩形、圆、椭圆等形状的Region,并根据鼠标来选择、拖动和设置尺寸,并实现设置颜色,获取坐标,region区内二值化、轮廓化等一系列后续操作。

3、目标

实现在QT环境下,将Halcon窗口贴在QT的控件上,并实现上述创建和操作region的基本动作。

4、步骤

4.1 Halcon库的配置

本人使用的是Halcon12.0的破解版,目前调用Halcon的函数不会出错,但是项目中有调用新版本的Halcon库有出错状况,目前未查证是不是版本的问题,Halcon配置主要在PRO文件中添加Include和Lib的引用路径。其中HALCONROOT是环境变量中Halcon的安装路径。

  #includesINCLUDEPATH   += "$$(HALCONROOT)/include"INCLUDEPATH   += "$$(HALCONROOT)/include/halconcpp"#libsQMAKE_LIBDIR  += "$$(HALCONROOT)/lib/$$(HALCONARCH)"unix:LIBS     += -lhalconcpp -lhalcon -lXext -lX11 -ldl -lpthreadwin32:LIBS    += "$$(HALCONROOT)/lib/$$(HALCONARCH)/halconcpp.lib" \"$$(HALCONROOT)/lib/$$(HALCONARCH)/halcon.lib"

4.2 读取图像,并实现图像自适应窗体控件大小

这里我首先创建了一个QHalconWindow类,然后在qt的ui界面将widget提升为QHalconWindow类,这样就免去了Halcon窗口句柄和ui句柄的绑定,直接通过QHalconWindow类来调用就行。

qhalconwindow.h文件

#include <QObject>
#include <QWidget>
#include "HalconCpp.h"class QHalconWindow : public QWidget
{Q_OBJECT
public:explicit QHalconWindow(QWidget *parent = 0,long Width=0,long Height=0);virtual ~QHalconWindow(void);HalconCpp::HTuple WindowID(void) {return WinID;}   //f返回窗口句柄protected:void resizeEvent(QResizeEvent*);                 //窗口大小尺寸调整事件
private:HalconCpp::HTuple WinID;void OpenWindow(void);
}

Cpp文件主要是关于窗口基本操作的实现函数

#include "qhalconwindow.h"using namespace HalconCpp;QHalconWindow::QHalconWindow(QWidget *parent,long Width,long Height): QWidget(parent)
{resize(Width,Height);show();OpenWindow();}QHalconWindow::~QHalconWindow(void)
{CloseWindow(WindowID());
}void QHalconWindow::OpenWindow(void)
{SetWindowAttr("border_width",0);SetCheck("~father");HalconCpp::OpenWindow(0,0,100,100,(Hlong)winId(),"visible","",&WinID);SetCheck("father");
}//修改窗口尺寸
void QHalconWindow::resizeEvent(QResizeEvent *)
{SetWindowExtents(WindowID(),0,0,width(),height());
}

参考Halcon中关于SetDrawingObjectCallback函数的描述,需要在c++下面调用时,调用C++格式的函数,即下图的Void的回调函数指针。
回调函数.PNG
但是这个回调函数在程序中需要定义为一个全局函数,主要依据是Halcon中介绍,如下:
回调函数要求.PNG
所以根据这些需求完成Halcon窗口中绘制矩形、圆形和直线的操作

4.3 主要的图形绘制和贴图操作见如下代码,其中重点为全局函数的创建来实现选择Select、拖拽Drag和尺寸Resize事件响应。

Widget.h文件

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QList>
#include <QStack>
#include <functional>
#include "HalconCpp.h"
//#include "qhalconwindow.h"using namespace HalconCpp;namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();void InitWin(void);static Widget* getInstance();protected:void resizeEvent (QResizeEvent*);void InitFg(void);private slots:void on_HalconWinD_customContextMenuRequested(const QPoint &pos);void onTaskBoxContextMenuEvent();void  onTaskDeleteObj();void on_btn_DrawRectangle_clicked();void on_btn_DrawCircle_clicked();void on_btn_DrawLine_clicked();void on_btn_ClearAllObj_clicked();void AttachDrawObj(HDrawingObject obj);void slot_ReceiveData(long);signals:void signal_data(long);
private:Ui::Widget *ui;//Halcon窗口的参数HTuple WindowIDBuf,FGHandle,Width,Height,Area;HTuple WindowWidth,WindowHeight;HObject Image;QStack<HObject> graphic_stack;QList<HDrawingObject> drawing_objects;HTuple Draw_Text;QList<HTuple>Drawing_Index;
};#endif // WIDGET_H

主要实现代码

#pragma execution_character_set("utf-8")
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDebug>
#include <QMenu>void CallBackFunc_Set(long DrawID,long WindowHandle, char* type);
void CallBackFunc_DrawObj(long DrawID,long WindowHandle, char* type);
HTuple selected_drawing_object;
Widget* instance;Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);WindowIDBuf = -1;Draw_Text=HTuple();InitWin();instance = this;connect(this,SIGNAL(signal_data(long)),this,SLOT(slot_ReceiveData(long)));
}Widget::~Widget()
{HalconCpp::CloseWindow(WindowIDBuf);delete ui;
}//建立自身调用
Widget *Widget::getInstance()
{return instance;
}void Widget::InitFg(void)
{Hlong disp_width, disp_height;//读取一张图像并获取图像大小ReadImage(&Image,"D:/Test_Image/kobe.jpg");GetImageSize(Image,&Width,&Height);//根据图像的大小修改界面的尺寸大小//    disp_width = ui->HalconWinD->width();//    disp_height = ui->HalconWinD->height();//    ui->HalconWinD->resize(Width[0].L(),Height[0].L());//    resize(width()+Width[0].L()-disp_width,height()+Height[0].L()-disp_height);
}void Widget::InitWin(void)
{InitFg();//    HTuple hv_WindowHandleCurrent;Hlong WinIDcurrent = (Hlong)ui->HalconWinD->winId();WindowWidth = ui->HalconWinD->width();WindowHeight = ui->HalconWinD->height();OpenWindow(0,0,WindowWidth,WindowHeight,WinIDcurrent,"","",&WindowIDBuf);    AttachBackgroundToWindow(Image,WindowIDBuf);//    DispObj(Image,ui->HalconWinD->WindowID());
}void Widget::resizeEvent(QResizeEvent *)
{if(WindowIDBuf>0 ){WindowWidth = ui->HalconWinD->width();WindowHeight = ui->HalconWinD->height();SetWindowExtents(WindowIDBuf,0,0,WindowWidth,WindowHeight);//       DispObj(Image,WindowIDBuf);}
}//右键选取后的Menu的对应操作函数
void Widget::onTaskBoxContextMenuEvent()
{QAction *pEven = qobject_cast<QAction *>(this->sender()); //this->sender()就是发信号者 QActionint iType = pEven->data().toInt();HTuple position;GetDrawingObjectParams(selected_drawing_object,(HTuple("row1").Append("column1")),&position);    switch (iType){case 1:{SetDrawingObjectParams(selected_drawing_object,"color","green");QMessageBox::about(this, "tip", pEven->text());break;}case 2:{SetDrawingObjectParams(selected_drawing_object,"color","blue");QMessageBox::about(this, "tip", pEven->text());break;}case 3:{SetDrawingObjectParams(selected_drawing_object,"color","yellow");QMessageBox::about(this, "tip", pEven->text());break;}case 4:{SetDrawingObjectParams(selected_drawing_object,"color","black");QMessageBox::about(this, "tip", pEven->text());break;}default:break;}int Select_DrawID;for(int i=0;i!=Drawing_Index.size();++i){if(Drawing_Index.at(i) == selected_drawing_object){Select_DrawID=i;qDebug()<<"select ID:"<<i<<endl;}}for(int i=0;i!=Drawing_Index.size();++i){if(Drawing_Index.at(i) == selected_drawing_object){Select_DrawID=i;}}QString Message_test = pEven->text();QByteArray ba = Message_test.toLocal8Bit();const char *str = ba.data();HTuple Draw_Message(str);HTuple Draw_MesObj;    CreateDrawingObjectText(position[0],position[1], Draw_Message,&Draw_MesObj);AttachDrawingObjectToWindow(WindowIDBuf,Draw_MesObj);Draw_Text[Select_DrawID]=Draw_MesObj;    
}//右键选取删除操作对应函数
void Widget::onTaskDeleteObj()
{int Select_DrawID;for(int i=0;i!=Drawing_Index.size();++i){if(Drawing_Index.at(i) == selected_drawing_object){Select_DrawID=i;qDebug()<<"select ID:"<<i<<endl;}}if(Draw_Text.Length() >Select_DrawID){DetachDrawingObjectFromWindow(WindowIDBuf,Draw_Text[Select_DrawID]);DetachDrawingObjectFromWindow(WindowIDBuf,selected_drawing_object);}else{DetachDrawingObjectFromWindow(WindowIDBuf,selected_drawing_object);}
}//右键响应事件
void Widget::on_HalconWinD_customContextMenuRequested(const QPoint &pos)
{    HTuple Row_Mouse,Column_Mouse,Button,position;GetMposition(WindowIDBuf,&Row_Mouse,&Column_Mouse,&Button);GetDrawingObjectParams(selected_drawing_object,(HTuple("column1").Append("column2").Append("row1").Append("row2")),&position);qDebug()<<Column_Mouse.D()<<Row_Mouse.D()<<position[0].D()<<position[1].D()<<position[2].D()<<position[3].D()<<endl;if(Column_Mouse>position[0] && Column_Mouse<position[1]){if(Row_Mouse>position[2] && Row_Mouse<position[3]){           //创建菜单对象QMenu *pMenu = new QMenu(this);QAction *pTask1 = new QAction(tr("得分王"), this);QAction *pTask2 = new QAction(tr("总冠军"), this);QAction *pTask3 = new QAction(tr("MVP"), this);QAction *pTask4 = new QAction(tr("单场81分"), this);QAction *action=new QAction(this);QAction *pDelete = new QAction(tr("追随黑曼巴!"), this);pTask1->setData(1);pTask2->setData(2);pTask3 ->setData(3);pTask4->setData(4);action->setSeparator(true);pDelete ->setData(5);//把QAction对象添加到菜单上pMenu->addAction(pTask1);pMenu->addAction(pTask2);pMenu->addAction(pTask3);pMenu->addAction(pTask4);pMenu->addAction(action);pMenu->addAction(pDelete);//连接鼠标右键点击信号connect(pTask1, SIGNAL(triggered()), this, SLOT(onTaskBoxContextMenuEvent()));connect(pTask2, SIGNAL(triggered()), this, SLOT(onTaskBoxContextMenuEvent()));connect(pTask3, SIGNAL(triggered()),this, SLOT(onTaskBoxContextMenuEvent()));connect(pTask4, SIGNAL(triggered()), this, SLOT(onTaskBoxContextMenuEvent()));connect(pDelete, SIGNAL(triggered()),this, SLOT(onTaskDeleteObj()));//在鼠标右键点击的地方显示菜单pMenu->exec(cursor().pos());qDebug()<<cursor().pos().x()<<cursor().pos().y()<<endl;//释放内存QList<QAction*> list = pMenu->actions();foreach (QAction* pAction, list) delete pAction;delete pMenu;}}
}
//画矩形框
void Widget::on_btn_DrawRectangle_clicked()
{   HTuple Rect_ID;CreateDrawingObjectRectangle1(100,100,200,200,&Rect_ID);SetDrawingObjectParams(Rect_ID,"color","red");qDebug()<<"Rect_ID"<<Rect_ID.D()<<endl;Drawing_Index.append(Rect_ID);//转换句柄为HDrawingObjectHDrawingObject draw=HDrawingObject(Rect_ID);AttachDrawingObjectToWindow(WindowIDBuf,Rect_ID);AttachDrawObj(draw);
}void Widget::AttachDrawObj(HDrawingObject obj)
{drawing_objects.append(obj);obj.SetDrawingObjectCallback("on_resize",(void*)CallBackFunc_DrawObj);obj.SetDrawingObjectCallback("on_drag",(void*)CallBackFunc_DrawObj);//    obj.SetDrawingObjectCallback("on_attach",CallBackFunc_Set);obj.SetDrawingObjectCallback("on_select",(void*)CallBackFunc_Set);//    AttachDrawingObjectToWindow(ui->HalconWinD->WindowID(),obj);
}//Drag和Resize对应的回调函数,这里用UI的一个自身指针将全局函数的变量传递给UI,从而调用UI下的函数
void CallBackFunc_DrawObj(long DrawID,long WindowHandle, char* type)
{Widget::getInstance()->signal_data(DrawID);
}//Drag和Resize对应的UI中的处理函数
void Widget::slot_ReceiveData(long DrawID)
{int Select_DrawID;for(int i=0;i!=Drawing_Index.size();++i){if(Drawing_Index.at(i) == (HTuple)DrawID){Select_DrawID=i;qDebug()<<"delete ID:"<<i<<endl;}}if(Draw_Text.Length() >Select_DrawID){DetachDrawingObjectFromWindow(WindowIDBuf,Draw_Text[Select_DrawID]);}
}//选取矩形框对应的回调函数
void CallBackFunc_Set(long DrawID,long WindowHandle, char* type)
{  selected_drawing_object=DrawID;SetDrawingObjectParams(DrawID,"color","blue");HObject Region;HTuple Area,row,column;GetDrawingObjectIconic(&Region,DrawID);AreaCenter(Region,&Area,&row,&column);
}//清除窗口所有图形
void Widget::on_btn_ClearAllObj_clicked()
{for(int i=0;i!=Drawing_Index.size();++i){ClearDrawingObject(Drawing_Index.at(i));       }for(int j=0;j<Draw_Text.Length();++j){ClearDrawingObject(Draw_Text[j]);}    Drawing_Index.clear();Draw_Text=HTuple();
}//画圆形
void Widget::on_btn_DrawCircle_clicked()
{HTuple Circle_ID;CreateDrawingObjectCircle(300,300,200,&Circle_ID);SetDrawingObjectParams(Circle_ID,"color","red");AttachDrawingObjectToWindow(WindowIDBuf,Circle_ID);
}//画直线
void Widget::on_btn_DrawLine_clicked()
{HTuple Line_ID;CreateDrawingObjectLine(300,300,600,600,&Line_ID);SetDrawingObjectParams(Line_ID,"color","yellow");AttachDrawingObjectToWindow(WindowIDBuf,Line_ID);
}

5、总结

这个知识点本身并不难,而且Halcon也带有c#的例程,主要当初碰到的难点是无法理解其回调函数的Draw_ID是如何传递的,最后查到Halcon的帮助资料才发现,按照全局回调函数的样子去定义,回调会自动返回你当前所选择的Draw_ID,从而可以使用该Draw_ID进行你所需要的操作。
最后放上最终的效果:
缅怀.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/279415.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SpringSecurity】十三、基于Session实现授权认证

文章目录 1、基于session的认证2、Demosession实现认证session实现授权 1、基于session的认证 流程&#xff1a; 用户认证成功后&#xff0c;服务端生成用户数据保存在session中服务端返回给客户端session id (sid&#xff09;&#xff0c;被客户端存到自己的cookie中客户端下…

k8s详细教程

Kubernetes详细教程 1. Kubernetes介绍 1.1 应用部署方式演变 在部署应用程序的方式上&#xff0c;主要经历了三个时代&#xff1a; 传统部署&#xff1a;互联网早期&#xff0c;会直接将应用程序部署在物理机上 优点&#xff1a;简单&#xff0c;不需要其它技术的参与 缺点…

4.线性数据结构——3.栈及例题

标准库的栈 定义&#xff1a;stack<typename> myStack;大小&#xff1a;size()压栈&#xff1a;push()弹栈&#xff1a;pop()栈顶&#xff1a;top()判空&#xff1a;empty() #include <cstdio> #include <string> #include <map> #include <algor…

HarmonyOS NEXT应用开发之搜索页一镜到底案例

介绍 本示例介绍使用bindContentCover、transition、animateTo实现一镜到底转场动画&#xff0c;常用于首页搜索框点击进入搜索页场景。 效果图预览 使用说明 点击首页搜索框跳转到搜索页面显式一镜到底转场动画 实现思路 通过点击首页搜索框改变bindContentCover全屏模态…

大数据面试题 —— HBase

目录 什么是HBase简述HBase 的数据模型HBase 的读写流程HBase 在写的过程中的region的split的时机HBase 和 HDFS 各自的使用场景HBase 的存储结构HBase 中的热现象&#xff08;数据倾斜&#xff09;是怎么产生的&#xff0c;以及解决办法有哪些HBase rowkey的设计原则HBase 的列…

[Qt学习笔记]QGraphicsView实现背景的绘制和前景图像的绘制

1、介绍 Qt中使用QGraphicsScene重写drawBackGround绘制背景&#xff0c;就是使用自定义的Scene类来重写drawBackGround的函数来重新绘制背景&#xff0c;这里需要注意的是自定义的Scene类要继承QGraphicsScene类&#xff0c;因为drawBackGround是一个虚函数&#xff0c;相当于…

【鸿蒙系统】 ---Harmony 鸿蒙编译构建指导(一)

&#x1f48c; 所属专栏&#xff1a;【鸿蒙系统】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢…

【python】爬取杭州市二手房销售数据做数据分析【附源码】

一、背景 在数据分析和市场调研中&#xff0c;获取房地产数据是至关重要的一环。本文介绍了如何利用 Python 中的 requests、lxml 库以及 pandas 库&#xff0c;结合 XPath 解析网页信息&#xff0c;实现对链家网二手房销售数据的爬取&#xff0c;并将数据导出为 Excel 文件的过…

服务器端(Debian 12)配置jupyter与R 语言的融合

融合前&#xff1a; 服务器端Debian 12,域名&#xff1a;www.leyuxy.online 1.安装r-base #apt install r-base 2.进入R并安装IRkernel #R >install.packages(“IRkernel”) 3.通过jupyter notebook的Terminal执行&#xff1a; R >IRkernel::installspec() 报错 解决办…

Qt笔记 信号和槽

在Qt中&#xff0c;如何将两个对象进行关联&#xff0c;让一个对象发出信号&#xff0c;然后另外一个对象接收到信号后&#xff0c;执行该对象的一个方法&#xff0c;要实现这种方式&#xff0c;则需要使用到信号和槽机制。 信号&#xff1a; 信号一定是一个没有返回值的函数…

【CSS练习】万年历 html+css+js

效果图 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</title><style>bod…

Linux之线程同步

目录 一、问题引入 二、实现线程同步的方案——条件变量 1、常用接口&#xff1a; 2、使用示例 一、问题引入 我们再次看看上次讲到的多线程抢票的代码&#xff1a;这次我们让一个线程抢完票之后不去做任何事。 #include <iostream> #include <unistd.h> #inc…

【NLP笔记】Transformer

文章目录 基本架构EmbeddingEncoderself-attentionMulti-Attention残差连接LayerNorm DecoderMask&Cross Attention线性层&softmax损失函数 论文链接&#xff1a; Attention Is All You Need 参考文章&#xff1a; 【NLP】《Attention Is All You Need》的阅读笔记 一…

【C语言】结构体类型名、变量名以及typedef

文章目录 分类判断结构体成员的使用typedef 分类判断 struct tag {char m;int i; }p;假设定义了上面这一个结构体&#xff0c;tag 就是类型名&#xff0c; p 就是变量名&#xff0c; m 和 i 就是结构体成员列表。 可以这么记&#xff0c;括号前面的是类型名&#xff0c;括号后…

内存条@电脑支持的最大内存@升级内存硬件

文章目录 电脑支持的最大内存规格cpu官网查看支持的规格命令行查看脚本化 DDR内存LPDDR内存内存升级扩展&#x1f47a;插槽检查板载内存SPD内存厂商其他 内存参数&#x1f47a;性能指标使用软件查看更多内存相关的软件工具 电脑支持的最大内存规格 确认电脑最大支持内存大小和频…

在Ubuntu20.04(原为cuda12.0, gcc9.几版本和g++9.几版本)下先安装cuda9.0后再配置gcc-5环境

因为自己对Linux相关操作不是很熟悉&#xff0c;所以因为之前的代码报错之后决定要安cuda9.0&#xff0c;于是先安装了cuda9.0。里面用到的一些链接&#xff0c;链接文件夹时直接去copy它的路径&#xff0c;就不那么容易错了。 今天运行程序之后发现gcc环境不太匹配cuda9.0&am…

图解CodeWhisperer的安装使用

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ 目录 &#x1f4d8; CodeWhisperer简介 &#…

原生html vue3使用element plus 的树tree上移下移案例源码

上效果 html源码 <!DOCTYPE html> <html lang"en"> <!-- * Name: mallSalesReports.html * Description: * Author Lani * date 2024-02-28 18:32:36 --> <head><meta charset"UTF-8"><meta name"viewport" …

[uni-app] uni.createAnimation动画在APP端无效问题记录

文章目录 uni.createAnimation动画描述动画代码templatejs部分 问题原因改进方案template js部分改动git 改进截图 uni.createAnimation 动画描述 实现一个以左上角为锚点,以Z轴做平面抬起及落下的动画效果 动画代码 template <image v-if"showHot(item.cname)&quo…

wayland(xdg_wm_base) + egl + opengles 使用 Assimp 加载带光照信息的材质文件Mtl 实现光照贴图的最简实例(十七)

文章目录 前言一、3d 立方体 model 属性相关文件1. cube1.obj2. cube1.Mtl3. 纹理图片 cordeBouee4.jpg二、实现光照贴图的效果1. 依赖库和头文件1.1 assimp1.2 stb_image.h2. egl_wayland_obj_cube1.cpp3. Matrix.h 和 Matrix.cpp4. xdg-shell-client-protocol.h 和 xdg-shell…