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

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的安装路径。

  #includes
  INCLUDEPATH   += "$$(HALCONROOT)/include"
  INCLUDEPATH   += "$$(HALCONROOT)/include/halconcpp"

  #libs
  QMAKE_LIBDIR  += "$$(HALCONROOT)/lib/$$(HALCONARCH)"
  unix:LIBS     += -lhalconcpp -lhalcon -lXext -lX11 -ldl -lpthread
  win32: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_OBJECT

public:
    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()就是发信号者 QAction
    
    int 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);
    //转换句柄为HDrawingObject
    HDrawingObject 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

  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值