1、背景

在视觉我的项目开发过程中碰到了须要应用Halcon进行图像算法开发的需要,预计很多视觉工程师都用到过Halcon软件开发库,然而实现Halcon算法开发后就会遇到一个问题,就是图像的显示、读写、UI交互等问题,因为Halcon具备非凡的图像文件格式HObject和数据格式HTuple,所以说须要格局转换后能力实现绝对应的操作,不过Halcon自身也有比拟实用的显示、界面交互的性能,所以如何在C++或QT下应用这些性能成为了接下来须要去钻研和实际的工作。

2、参考信息

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


其中能够实现在窗口界面创立矩形、圆、椭圆等形态的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_OBJECTpublic:    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的回调函数指针。

然而这个回调函数在程序中须要定义为一个全局函数,次要根据是Halcon中介绍,如下:

所以依据这些需要实现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()就是发信号者 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进行你所须要的操作。
最初放上最终的成果: