rb88会员入口rb88会员入口
>

应用设计

>

ZBasic结合Qt实现机器视觉图像采集

ZBasic结合Qt实现机器视觉图像采集

深圳市正运动技术有限企业
2022/1/13 13:55:08

1.webp.jpg

QT是目前众多App开发工程师使用的C++应用程序开发框架。QT具有完整的GUI图形库,界面控件的样式和布局可直接通过控件属性进行设置,简化了代码的使用。对于需要人机界面操作的机器视觉程序而言,QT强大的界面设计功能很大程度地减少了视觉App开发工程师设计操作界面的开发难度。正运动技术VPLC系列控制器可搭载Linux系统,且支撑QT调用正运动App的ZBasic指令。

本节课程大家将和大家一起分享ZBasic结合QT实现图像采集功能的方法。

一认识QT

Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器“Meta Object Compiler, moc”)以及一些宏,Qt很容易扩展,并且允许真正地组件编程。

image.png

二ZBasic and QT

正运动技术将ZDevelopApp主要使用的ZBasic语言封装成C++动态链接库,QT可以通过调用动态库的形式调用ZBasic指令。  

三App实现

(一)准备

image.png

(二)实例演示

1.打开QTCreatorApp,新建QT项目:点击“New Project”→项目选择“Application”→选择“QT Widgets Application”→点击“Choose...”按钮进入下一步→输入项目名称“ZVision_QT_1”,选择项目存储的路径(路径不能包含中文),点击“下一步”按钮→默认选择“下一步”,最后点击“完成”按钮,完成项目的建立。

2.添加库相关文件:将相关库文件拷贝到项目所在文件夹下→鼠标左键点击项目名称,再点击鼠标右键弹出快捷菜单,选择“添加现有文件”→依次将“zaux.h”文件、“zmotion.h”文件、“zaux.cpp”文件添加到项目→双击“.pro”文件,手动添加动态链接库代码“win32: LIBS += -L$$PWD/ -lzmotion”→在“mainwindow.cpp”文件中定义调用库相关头文件,即添加代码:#include “zmotion.h”和#include “zaux.h”。

image.png

3.在mainwindow.cpp文件中定义程序中使用到的全局变量。

ZMC_HANDLE g_handle;//控制器句柄

int Times=0;

uint8 zv0_pBuff[400*300*2]={0};//锁存0缓存大小

int ContinuousGetImgFlag=0;   //连续采集标志

4.设计UI界面。

image.png

5.添加界面初始化代码。

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui->setupUi(this);

    ui->ZV0->setText("");//清空字体

    ui->ZV0->setStyleSheet("QLabel{background-color:rgb(0, 0, 100);}");  //设置样式表

    ui->ExposureValue->setText("5000");

}

6.添加【扫描控制器IP】槽函数:选择【扫描控制器IP】按钮,右击弹出快捷菜单栏,选择“转到槽”选项→弹出“转到槽”窗口,选择对应的信号源“clicked()”,点击“OK”确认,即可完成槽函数的定义和声明→在槽函数的声明函数中添加函数实现的具体代码内容。

image.png

//扫描控制器IP

void MainWindow::on_Scan_Control_IP_clicked()

{

    char buffer[10240];

    int32 iresult;

    const char *ipaddress;

    iresult = ZMC_SearchEth(buffer, 10230, 100);//扫描控制器IP,返回错误码信息

    if(ERR_OK != iresult)

    {

        return ; //错误

    

    //将扫描到的所有IP地址进行分割,并按照IP地址格式显示在下拉列表中

    int ipos =0;

    const char * pstring;

    pstring = buffer;

    for(int j= 0; j< 100;j++) //最多100个IP列表

    {

        char buffer2[256];

        buffer2[0] = '\0';

        while(' ' == pstring[0])

        {

            pstring++;

        }

        ipos = sscanf(pstring , "%s", &buffer2);

        if(EOF  == ipos)

        {

            break;

        }

        //跳过字符

        while((' ' != pstring[0]) && ('\t' != pstring[0]) && ('\0' != pstring[0]))

        {

            pstring++;

        }

        if(0 == strcmp(buffer2, ipaddress))

        {

            return ;

        }

        ui->ComboBoxIP->addItem(buffer2);

    }

}

7.添加【连接】槽函数:选择【连接】按钮,右击弹出快捷菜单栏,选择“转到槽”选项→弹出“转到槽”窗口,选择对应的信号源“clicked()”,点击“OK”确认,即可完成槽函数的定义和声明→在槽函数的声明函数中添加函数实现的具体代码内容。

//连接控制器

void MainWindow::on_Link_Control_clicked()

{

    //get ip from current list

    int32 iresult;//错误码

    int nIndex = 0;

    char * tmp_buff = new char[16];

    char str1[64];

    QString str;

    str = ui->ComboBoxIP->currentText();//获取IP列表里的IP地址数据

    qDebug()<<"current ip"<<str;//打印当前选择的IP地址数据

    QByteArray ba = str.toLatin1();//将IP的字符串格式转到char * 格式

    tmp_buff = ba.data();

    if(0 != g_handle)//如果控制器句柄不为0

    {

        ZAux_Close(g_handle);//关闭控制器链接

    }

    iresult=ZAux_OpenEth(tmp_buff,&g_handle);//根据获取的IP地址与控制器建立链接,返回错误码

    if (iresult==0)

    {

        sprintf(str1, "控制器连接成功,当前IP:%s", tmp_buff);

        setWindowTitle(str1);

        qDebug()<<"Link Success! ip:"<<tmp_buff;

    }

    else

    {

        qDebug()<<"Link Fail!";

        setWindowTitle("控制器已断开");

    }

}

8.添加【断开】槽函数:选择【断开】按钮,右击弹出快捷菜单栏,选择“转到槽”选项→弹出“转到槽”窗口,选择对应的信号源“clicked()”,点击“OK”确认,即可完成槽函数的定义和声明→在槽函数的声明函数中添加函数实现的具体代码内容。

//断开连接控制器

void MainWindow::on_Disconnect_clicked()

{

    if(0 != g_handle)

    {

        ZAux_Close(g_handle);//关闭控制器链接

        g_handle = NULL;//清空句柄

        setWindowTitle("控制器已断开");

    }

}

9.添加【扫描相机】槽函数:选择【扫描相机】按钮,右击弹出快捷菜单栏,选择“转到槽”选项→弹出“转到槽”窗口,选择对应的信号源“clicked()”,点击“OK”确认,即可完成槽函数的定义和声明→在槽函数的声明函数中添加函数实现的具体代码内容。

//扫描相机

void MainWindow::on_Scan_Camera_clicked()

{

    float CamNum=0;

    int32 iresult;//错误码

    QString str;

    char buffer[2048];

    iresult=ZAux_RunTask(g_handle,0,"cam_scan_all()");//运行控制器里面指定的SUB

    if (iresult==0)

    {

         qDebug()<<"run cam_scan_all() success";

    }

    else

    {

         qDebug()<<"run cam_scan_all() fail !!"<<iresult;

    }

    ZAux_Direct_GetTable(g_handle,0,1,&CamNum);//读取控制器table变量

    str = QString("扫描到的相机个数:%1").arg(CamNum);

    ui->CamNum->setText(str);//显示扫描到的相机数量

}

10.添加【采集图像】槽函数:选择【采集图像】按钮,右击弹出快捷菜单栏,选择“转到槽”选项→弹出“转到槽”窗口,选择对应的信号源“clicked()”,点击“OK”确认,即可完成槽函数的定义和声明→在槽函数的声明函数中添加函数实现的具体代码内容(此前需要在头文件中定义使用到的QPixmap fPixmap 变量)。

//单次采集

void MainWindow::on_Camera_Grab_clicked()

{

    int32 iresult;//错误码

    iresult=ZAux_RunTask(g_handle,0,"btn_grab()");//运行控制器里面指定的SUB

    if (iresult==0)

    {

         qDebug()<<"run btn_grab() success";

    }

    else

    {

         qDebug()<<"run btn_grab() fail !!"<<iresult;

    }

    ZV0_Show();//将控制器获取到的图像转换成Qt可显示的图片格式,并显示图像

}

//将获取到的图像显示到ZV0控件中

void MainWindow::ZV0_Show()

{

    int latin=0,buffsize=400*300*2;

    int width, height,bite,WrTimes;

    int flag=1, count=0;

    //获取zvlatch的信息

    ZMC_ZVLatinImgGetInfo(g_handle, latin, &width, &height, &bite, &WrTimes);//获取图像信息

    if(WrTimes==0)

    {

        return;//时间没有改变退出函数

    }

    //获取到的锁存0的缓存数据

    buffsize = width*height*2;

    ZMC_ZVLatinImgGet(g_handle, latin, &width, &height, &bite, zv0_pBuff, buffsize);//获取图像数据

    //将获取到的锁存0的缓存数据在qt中显示出来

    QImage Image((uchar *)zv0_pBuff,width, height,QImage::Format_RGB555);

    Image = Image.mirrored(false,true);

    QPixmap Pixmap = QPixmap:: fromImage (Image);

    fPixmap = Pixmap.scaled(width, height);

    ui->ZV0->clear();

    ui->ZV0->setPixmap(fPixmap);

}

11.添加显示函数ZV0_Show()的定义和声明函数。

private slots:

    void on_Scan_Control_IP_clicked();

    void on_Link_Control_clicked();

    void on_Disconnect_clicked();

    void on_Scan_Camera_clicked();

    void on_Camera_Grab_clicked();

    void on_Contiue_Grab_clicked();

    void on_Stop_Grab_clicked();

    void on_Set_Exposure_clicked();

    void ZV0_Show();  //锁存0显示

//将获取到的图像显示到ZV0控件中

void MainWindow::ZV0_Show()

{

    int latin=0,buffsize=400*300*2;

    int width, height,bite,WrTimes;

    int count=0;

    int flag=0;

    ZMC_ZVLatinImgGetInfo(g_handle, latin, &width, &height, &bite, &WrTimes);

    qDebug()<<WrTimes;

    if(Times == WrTimes)

    {

        return;//时间没有改变退出函数

    }

    else

    {

        Times = WrTimes;

    }

    QThread::msleep(100);

    while(0 == flag)//等待

    {

       ZAux_Direct_GetVariableInt(g_handle,"CamGetPhotoFlag",&flag);

       QThread::msleep(10);

       count++;

       if(1000 < count)//等待时间大于10s

       {

           break;//退出循环

       }

    }

    flag=0;

    //获取zvlatch的信息

    ZAux_Direct_SetVariableInt(g_handle,"CamGetPhotoFlag",flag);

    //获取到的锁存0的缓存数据

    buffsize = width*height*2;

    ZMC_ZVLatinImgGet(g_handle, latin, &width, &height, &bite, zv0_pBuff, buffsize);//获取图像数据

    //将获取到的锁存0的缓存数据在qt中显示出来

    flag=1;

    //获取zvlatch的信息

    ZAux_Direct_SetVariableInt(g_handle,"CamGetPhotoFlag",flag);

    QImage Image((uchar *)zv0_pBuff,width, height,QImage::Format_RGB555);

    Image = Image.mirrored(false,true);

    QPixmap Pixmap = QPixmap:: fromImage (Image);

    fPixmap = Pixmap.scaled(width, height);

    ui->ZV0->clear();

    ui->ZV0->setPixmap(fPixmap);

}

12.添加【连续采集】槽函数:选择【连续采集】按钮,右击弹出快捷菜单栏,选择“转到槽”选项→弹出“转到槽”窗口,选择对应的信号源“clicked()”,点击“OK”确认,即可完成槽函数的定义和声明→在槽函数的声明函数中添加函数实现的具体代码内容。

//连续采集

void MainWindow::on_Contiue_Grab_clicked()

{

    int32 iresult;//错误码

    iresult=ZAux_RunTask(g_handle,0,"btn_cgrab()");//运行控制器里面指定的SUB

    if (iresult==0)

    {

         qDebug()<<"run btn_cgrab() success";

    }

    else

    {

         qDebug()<<"run btn_cgrab() fail !!"<<iresult;

    }

     ContinuousGetImgFlag=1;//连续采集标志置1

}

13.添加定时刷新函数:在“mainwindow.h”文件中添加包含QTimer定时器的类型库,并定义“QTimer UpZV_0”定时器变量→在界面初始化函数中添加定时器触发条件和信号与槽连接函数→添加定时采集图像的定义和声明函数,并在声明函数中添加具体的实现代码内容。

#include

#include

void ZV0_Show();  //锁存0显示

    void UpZV_0show();

private:

    Ui::MainWindow *ui;

    QPixmap fPixmap;

    QTimer UpZV_0;

MainWindow::MainWindow(QWidget *parent) :

    QMainWindow(parent),

    ui(new Ui::MainWindow)

{

    ui->setupUi(this);

    ui->ZV0->setText(""); //清空字体

    ui->ZV0->setStyleSheet("QLabel{background-color:rgb(0, 0, 100);}");  //设置样式表

    ui->ExposureValue->setText("5000");

    UpZV_0.start(20);//200ms定时判断采集并显示图像

    connect(&UpZV_0, SIGNAL(timeout()), this, SLOT(UpZV_0show()));

}

//定时器开启连续采集

void MainWindow::UpZV_0show()

{

   if(1 == ContinuousGetImgFlag)

   {

       ZV0_Show();

   }

}

14.添加【停止采集】槽函数:选择【停止采集】按钮,右击弹出快捷菜单栏,选择“转到槽”选项→弹出“转到槽”窗口,选择对应的信号源“clicked()”,点击“OK”确认,即可完成槽函数的定义和声明→在槽函数的声明函数中添加函数实现的具体代码内容。

//停止采集

void MainWindow::on_Stop_Grab_clicked()

{

    int32 iresult;//错误码

    iresult=ZAux_RunTask(g_handle,0,"btn_stopCgrab()");//运行控制器里面指定的SUB

    if (iresult==0)

    {

         qDebug()<<"run btn_stopCgrab() success";

    }

    else

    {

         qDebug()<<"run btn_stopCgrab() fail !!"<<iresult;

    }

    ContinuousGetImgFlag=0;//连续采集标志置0

}

15.添加【设置】槽函数:选择【设置】按钮,右击弹出快捷菜单栏,选择“转到槽”选项→弹出“转到槽”窗口,选择对应的信号源“clicked()”,点击“OK”确认,即可完成槽函数的定义和声明→在槽函数的声明函数中添加函数实现的具体代码内容。

//设置曝光时间

void MainWindow::on_Set_Exposure_clicked()

{

    int32 iresult;//错误码

    QString str_tmp;

    float ExposureValue;

    str_tmp = ui->ExposureValue->text();//获取QLineEdit控件显示的曝光值

    ExposureValue = str_tmp.toFloat();//字符串转成浮点数

    ZAux_Direct_SetTable(g_handle,1,1,&ExposureValue);//设置控制器的table变量

    iresult=ZAux_RunTask(g_handle,0,"Camera_Exposure()");//运行控制器里面指定的SUB

    if (iresult==0)

    {

         qDebug()<<"run Camera_Exposure() success";

    }

    else

    {

         qDebug()<<"run Camera_Exposure() fail !!"<<iresult;

    }

}

16.查看运行效果:将控制器接入电源,使用网线将控制器与PC连接,将相机通电并接入控制器→使用ZDevelopApp打开ZBasic指令编写包含采集函数的项目文件,将该项目下载到控制器→运行QT程序,并连接到控制器,进行对应采集操作。

完整代码获取地址

image.png

本次,正运动技术ZBasic结合Qt实现机器视觉图像采集,就分享到这里。

更多精彩内容请关注“正运动小助手”公众号,需要相关开发环境与例程代码,请咨询正运动技术销售工程师:400-089-8936。

本文由正运动技术原创,欢迎大家转载,共同学习,一起提高中国智能制造水平。文章版权归正运动技术所有,如有转载请注明文章来源。

审核编辑(
王静
)

评论

查看更多评论
深圳市正运动技术有限企业
其他资讯

查看更多

EtherCAT运动控制卡IO动作与运动控制的同步

8轴EtherCAT轴扩展模块EIO24088的使用

会PLC也能玩转机器视觉(三)

机器视觉运动控制一体机应用例程(四)提取目标轮廓

机器视觉运动控制一体机应用例程(三) 基于BLOB分析的多圆定位