Qt + OpenCV + Halcon + QScintilla 实现Halcon的脚本引擎功能 (源码)

前言

在工业领域中,缺陷检测、目标计数等功能的应用,其过程基本都是见招拆招,没有一个具体的标准,把输入输出接口标准化,过程用脚本引擎代替就可以实现功能的标准模块。

一、Qt + OpenCV + Halcon

输入输出接口采用Qt + OpenCV来实现,OpenCV需要将采集到的图片转为Halcon的图像接口用于脚本检测,脚本输出的接口需要转换为Qt和OpenCV,用于绘制缺陷或目标的轮廓和标记。

在这里插入图片描述

OpenCV的 Mat 转 Halcon 的 HObject:

HObject HMatToHObject(Mat image)
{
    HObject ho_obj=HObject();
    if(image.empty())
        return ho_obj;
    if(3==image.channels())
    {
        int w=image.cols;
        int h=image.rows;
        if(image.depth()==CV_8U)
        {
            vector<cv::Mat> ichannels;
            cv::Mat imagB;
            cv::Mat imagG;
            cv::Mat imagR;
            cv::split(image, ichannels);
            imagB=ichannels.at(0);
            imagG=ichannels.at(1);
            imagR=ichannels.at(2);
            uchar* dataRed=new uchar[w*h];
            uchar* dataGreen=new uchar[w*h];
            uchar* dataBlue=new uchar[w*h];
            for(int i=0;i<h;i++)
            {
                memcpy(dataRed + w*i, imagR.ptr() + imagR.step*i, w);
                memcpy(dataGreen + w*i, imagG.ptr() + imagG.step*i, w);
                memcpy(dataBlue + w*i, imagB.ptr() + imagB.step*i, w);
            }
            GenImage3(&ho_obj, "byte", w, h, (Hlong)(dataRed), (Hlong)(dataGreen), (Hlong)(dataBlue));
            delete[] dataRed;
            delete[] dataGreen;
            delete[] dataBlue;
        }
    }
    else if(1==image.channels())
    {
        int w=image.cols;
        int h=image.rows;
        if(image.depth()==CV_8U)
        {
            uchar* dataGray=new uchar[w*h];
            for(int i=0;i<h;i++)
                memcpy(dataGray + w*i, image.ptr() + image.step*i, w);
            GenImage1(&ho_obj, "byte", w, h, (Hlong)(dataGray));
            delete[] dataGray;
        }
    }
    return ho_obj;
}


输入-脚本-输出相关代码:

 try
    {
        HObject ho_ImageIn, ho_RegionIn, ho_RegionOn, ho_Chamber;
        HTuple hv_Objs, hv_Phi;
        HTuple hv_Rows, hv_Cols, hv_Area, hv_Row, hv_Column;
        //图像Mat转换
        ho_ImageIn=HMatToHObject(param->image);
        GenEmptyObj(&ho_RegionIn);
        GenEmptyObj(&ho_RegionOn);
        if(isOK)
        {
            //引擎
            m_HdevHpdc.SetInputIconicParamObject("ImageIn", ho_ImageIn);
            m_HdevHpdc.SetInputIconicParamObject("RegionIn", ho_RegionIn);
            //执行Haclon程序
            m_HdevHpdc.Execute();
            //输出结果
            ho_RegionOn=m_HdevHpdc.GetOutputIconicParamObject("RegionOn");
            try
            {
                CountObj(ho_RegionOn, &hv_Objs);
                hv_Objs = hv_Objs.Length()!=1 ? (int)0 : hv_Objs;
                for(int i=1;i<=hv_Objs.I();i++)
                {
                    //缺陷坐标、面积
                    SelectObj(ho_RegionOn, &ho_Chamber, i);
                    AreaCenter(ho_Chamber, &hv_Area, &hv_Row, &hv_Column);
                    OrientationRegion(ho_Chamber, &hv_Phi);
                    OutPatchResult result;
                    result.col=(float)hv_Column.D();
                    result.row=(float)hv_Row.D();
                    result.angle=(float)hv_Phi.D()*180/QM_PI;
                    result.area=(float)hv_Area.D();
                    GetRegionContour(ho_Chamber, &hv_Rows, &hv_Cols);
                    for(int i=0;i<hv_Cols.Length();i++)
                    {
                        result.contour.push_back((float)hv_Cols[i].D());
                        result.contour.push_back((float)hv_Rows[i].D());
                    }
                    importApi->results.push_back(result);
                    //记录总面积和数量
                    Area += hv_Area.D();
                    Count++;
                }
                //加载成功
                inter->hdevOk=true;
                inter->hdevError=QString("RegionNum: %1; Area: %2; Time: %3ms")
                                          .arg(Count)
                                          .arg(Area)
                                          .arg((double)clock()-Times);
            }
            catch(HOperatorException &hv_Except)
            {
                isOK=false;
                inter->hdevOk=false;
                inter->hdevError=QString("[error: EngineOperator=%1;]").arg(hv_Except.ErrorMessage().Text());
            }
        }
    }
    catch(HDevEngineException &hv_Except)
    {
        isOK=false;
        inter->hdevOk=false;
        inter->hdevError=QString("[error: EngineDetect=%1;]").arg(hv_Except.Message());
    }

Halcon加载脚本文件相关代码:

bool TB_HaclonEngin::loaded()
{
    bool isOK=true;
    HaclonEnginImport* importApi=&api.input;
    try
    {
        //初始化
        this->released();
        QFile file(importApi->inter.hdevPath);
        isOK = file.exists() ? isOK : false;
        if(isOK)
        {
            //加载
            m_HdevProgram.LoadProgram(importApi->inter.hdevPath.toLocal8Bit().data());
            //变量名
            m_HdevParamNames=m_HdevProgram.GetCtrlVarNames();
            //对象名
            m_HdevIconNames=m_HdevProgram.GetIconicVarNames();
            //函数名
            m_HdevFunNames=m_HdevProgram.GetLocalProcedureNames();
            //第一个子函数变量(runApi)
            HTuple funName=m_HdevFunNames.TupleSelect(HTuple(0));
            //进程
            m_HdevHpd=HDevProcedure(m_HdevProgram, funName.ToSArr()->Text());
            m_HdevHpdc=m_HdevHpd.CreateCall();
            importApi->inter.hdevOk=true;
            importApi->inter.hdevError=QString::fromLocal8Bit("Load: %1").arg(importApi->inter.hdevPath);
        }
    }
    catch(HDevEngineException &hv_Except)
    {
        isOK=false;
        importApi->inter.hdevOk=false;
        importApi->inter.hdevError=QString("[error: EngineLoad=%1;]").arg(hv_Except.Message());
    }
    return isOK;
}

二、QScintilla扩展包

QScintilla工具可实现Halcon脚本的颜色编译,包括关键字的提示,和语法错误信息提示等等。

关键字扩展文档:

在这里插入图片描述

关键字颜色、错误提示:

在这里插入图片描述
在这里插入图片描述


总结

软件的全套源码可参考

https://download.csdn.net/download/dede28/88530232
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刚出道的菜鸟@丢丢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值