Vision Pro 界面源码编写基础(C#配合vpp文件)

在康耐视实习,那就必须得掌握我们公司大大大厉害的产品Vision Pro啦。经过大半个月的学习训练,基本掌握了不少技能。在这里写个阶段性小结,记录一下子。
贴两个文档,一个中文的(版本较老,VB版),还有一个VP自带的英文文档。
传送门,提取码ny2r


下面进入正题

准备工具:

正版Vision Pro、Visual Studio 2012(笔者使用版本,也是公司默认版本)、
Cognex开发工具包

步骤0:添加引用如下
注意Cognex名下的包即可
(前4个是必须的基本引用)

步骤1:使用QuickBuild创建自己的操作程序(.vpp)

这里我就不多说了,默认大家都会一些PM、Blob这种基本操作,如果有需要详细说的,评论打出1让我看见哈(啧啧,这个人有点过分哈哈)

步骤2:配置VS

这里由于公司给我们配置了电脑,给的时候就有Cognex的工具包了。我想大家如果购买的正版Vision Pro也是会有的,这里提两个注意点:

(1).net框架是需要4.6版本的,2012默认4.5,记得升级。
VS 框架选择

大部分人下载下来的4.6安装时都会提示电脑已安装更高版本。这个问题困扰了我好一会儿,同事都纷纷转战2015或2017,但最后我发现是因为下载的.net 4.6的版本问题,导致的无法安装。应该安装开发包(给个官方链接),如果实在搞不懂,那就全下下来试一遍吧~

(2)Vision Pro工具箱的安装。
VisionPro 控件向导
傻瓜式点就完了,然后VS里面ToolBox应该就有了。
ToolBox安装完成

步骤3:根据pdf438页开始码

这里按照他说的来就行了,不过他给的是VB程序,我改成了C#,现在公司内部好像都用C#开发了。
过程比较多,我从我的难点一步步说,详细的大家自己看pdf。最后我会贴码。

(1)看的懂.net框架的构造
project框架
每个文件的作用是什么,得知道。
(2)JobManager在代码中就代表了你的整个vpp项目,JobManager.Job(i)代表你项目中得第i个Job。
// 加载vpp作为一个job manager
myJobManager = (CogJobManager)CogSerializer.LoadObjectFromFile("../../../Job722.vpp")
// 引用job manager中的第一个
myJob = myJobManager.Job(0);
(3)”委托“指A线程访问B线程的功能时使用的东西,其处理模式为:

首先为跨线程事务创建一个相同声明的委托

// 每个win窗体控件只能通过创建它的线程来访问
// 创建一个有预期签名的委托 用于指向下面的停止事
delegate void myJobManagerDelegate(Object ByVaklsender,CogJobManagerActionEventArgs _ByVale);

在该事务创建该委托实例,提供2中实例化方法如下

 // 创建委托实例 并指向停止事件的函数指
myJobManagerDelegate mydelegate = myJobManager_Stopped
myJobManagerDelegate mydelegate = new myJobManagerDelegate(myJobManager_Stopped);

创建一个该事务参数的数组

// 定义一个参数数
Object[] myobj = new Object[2] { ByValsender, _ByVale };

使用控件Invoke方法调用委托,完成操作

// 使用控件“魔术”调用Invoke,在GUI线程上调用我们的委托(当前我们在vpp线程,但是需要使用GUI线程来使按钮恢复可选,所以需要委托给GUI线程
this.Invoke(mydelegate, myobj);

最后,程序是怎么发现线程之间的不通融的呢?这就是为什么Invoke厉害的地方了,在事务中添加下列代码

if (InvokeRequired)
{
    # 创建一个指针指向该函数
    # 在正确的线程上调用同一个函数
}

InvokeRequired是每一个控件的”魔术“属性,如果程序处在错误的线程上,它就会返回”true“。这就是Microsoft的一个用于校正线程乱问题的标准方法。请牢记!

(4)Vision Pro 内部控件的调用,参数获取
运行状态在操作队列中

首先我们需要现实的代码状态,是一个ICogRecord类,所以我们需要实例化该对象,然后将JobManager.UserResult传递给他。这样我们就获取到我们Job的结果了。之后就是检索我们需要的result。

// 输出运行状
Cognex.VisionPro.ICogRecord myrecord = myJobManager.UserResult() as ICogRecord
RunStatusTextBox.Text = myrecord.SubRecords["UserResultTag"].Content.ToString() + ":" + myrecord.SubRecords["JobName"].Content.ToString() + "-->";
RunStatusTextBox.Text += myrecord.SubRecords["RunStatus"].Content.ToString();

如果是要显示Job工具里的运行结果或者运行参数等,需要先在QuickBuild里面将你想要的参数添加到发送项,这样在Code里面才能获取到,不然有的参数(如Item里面的参数)是没有权限获得的,而Count这样的public变量可以直接调用,见程序

// 输出参数
Cognex.VisionPro.ToolGroup.CogToolGroup myTG = myJob.VisionTool as Cognex.VisionPro.ToolGroup.CogToolGroup;
Cognex.VisionPro.ToolBlock.CogToolBlock myTB1 = myTG.Tools["Detect_Defects"] as Cognex.VisionPro.ToolBlock.CogToolBlock;
Cognex.VisionPro.PMAlign.CogPMAlignTool myPM = myTB1.Tools["CogPMAlignTool2"] as Cognex.VisionPro.PMAlign.CogPMAlignTool
try
{
    textBox1.Text = myPM.Results.Count.ToString();
}
catch (Exception e5)
{
    textBox1.Text = e5.ToString();
}

输出图像的话,Vision Pro提供四类图像显示控件,分别是:
1)CogToolDisplay
2)CogRecordsDisplay
3)CogRecordDisplay
4)CogDisplay
ToolD最复杂,它知道如何连接到Vision Pro工具以及如何调用工具所有的执行结果,它通过显示区上放一个下拉框允许用户选择浏览哪张图像(就像QB里面的显示结果控件一样)。
RecordsD看上去和TD一样,也允许下拉选择,但是他对Vision Pro工具一无所知,他不能从工具中获取Records树,必须用编程的方法自己来获取。
RecordD(注意上面一个是Recordsssssssssss)显示单个图像记录及其图形的子记录(也就是你在fixture生成的图上进行操作,那么这些操作都会显示在fixture图上,这就是子记录),不可以自己选择下拉咯,所以他也是一无所知的,而且不提供Record树。
Display是最低级的显示控件,由其他所有显示控件来使用,一无所知,只显示一个图像和一组图形,图形图像必须通过编程提供。
这里我们选择RecordD。

Cognex.VisionPro.ICogRecord graphic_record;
graphic_record = myrecord.SubRecords["ShowLastRunRecordForUserQueue"];
graphic_record = graphic_record.SubRecords["LastRun"];
graphic_record = graphic_record.SubRecords[1];
// graphic_record = graphic_record.SubRecords["CogFixtureTool1.OutputImage"]; 方法2
CogRecordDisplay1.Record = graphic_record;
CogRecordDisplay1.Fit(true);

差不多基本的功能就是这样了,这一套做完无Bug,大家基本上可以在此基础上进行二次开发了。下面贴一下

源码

控件外形

设置的各控件名称
控件定义

Form1.cs整体

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Cognex.VisionPro;
using Cognex.VisionPro.QuickBuild;

namespace mywind
{
    public partial class Form1 : Form
    {
        private CogJobManager myJobManager;
        private CogJob myJob;
        private CogJobIndependent myIndepenentJob;

        public Form1()
        {
            InitializeComponent();
            // 临时办法:线程间相互访问
            //Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            // 加载vpp作为一个job manager
            myJobManager = (CogJobManager)CogSerializer.LoadObjectFromFile("../../../Job722.vpp");
            // 引用job manager中的第一个job
            myJob = myJobManager.Job(0);
            // 初始化一个对象,其参数引用包含更多关于job manager的信息
            myIndepenentJob = myJob.OwnedIndependent;
            // 清空所有job manager队列,刷新陈旧的图像和结果
            myJobManager.UserQueueFlush();
            myJobManager.FailureQueueFlush();
            myJob.ImageQueueFlush();
            myIndepenentJob.RealTimeQueueFlush();

            // 为停止操作绑定事件
            // CJM没有在GUI创建按钮,但是它调用了一个按钮停止事件!这个事件需要访问GUI线程的按钮!故需要“委托”
            myJobManager.Stopped += new CogJobManager.CogJobManagerStoppedEventHandler(myJobManager_Stopped);
            //myJobManager.Stopped += myJobManager_Stopped;
            // 状态显示操作绑定事件
            myJobManager.UserResultAvailable += myJobManager_UserResultAvailable;

            // 连接bar状态栏
            CogDisplaystatusBar1.Display = CogRecordDisplay1;

        }



        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                // 避免死锁
                //ControlBox = false;

                ShowTrainCheckBox.Enabled = false;
                RunContCheckBox.Enabled = false;
                // 防止在单词任务完成前再次调用任务 让按钮不可点击就行了
                RunOnceButton.Enabled = false;
                myJobManager.Run();
               
            }
            catch (Exception e1)
            {
                MessageBox.Show(e1.Message);
            }

        }

        // 每个win窗体控件只能通过创建它的线程来访问
        // 创建一个有预期签名的委托 用于指向下面的停止事件
        delegate void myJobManagerDelegate(Object ByVaklsender,CogJobManagerActionEventArgs _ByVale);

        // 所有工作完成 CJM运行一个停止事件 重启按钮
        private void myJobManager_Stopped(Object ByValsender, CogJobManagerActionEventArgs _ByVale)
        {
            if (InvokeRequired)
            {
                // 创建委托实例 并指向停止事件的函数指针
                //myJobManagerDelegate mydelegate = myJobManager_Stopped;
                myJobManagerDelegate mydelegate = new myJobManagerDelegate(myJobManager_Stopped);
                // 定义一个参数数组
                Object[] myobj = new Object[2] { ByValsender, _ByVale };
                // 使用控件“魔术”调用Invoke,在GUI线程上调用我们的委托(当前我们在vpp线程,但是需要使用GUI线程来使按钮恢复可选,所以需要委托给GUI线程)
                this.Invoke(mydelegate, myobj);
            }
            //线程报错 暂时不管
            //ControlBox = true;
            RunOnceButton.Enabled = true;
            RunContCheckBox.Enabled = true;
            ShowTrainCheckBox.Enabled = true;
        }

        private void RunContCheckBox_CheckedChanged(object sender, EventArgs e)
        {

            if (RunContCheckBox.Checked)
            {
                try
                {
                    //ControlBox = false;
                    ShowTrainCheckBox.Enabled = false;
                    RunOnceButton.Enabled = false;
                    myJobManager.RunContinuous();
                }
                catch (Exception e2)
                {
                    MessageBox.Show(e2.Message);
                }
            }
            else
            {
                try
                {
                    
                    RunContCheckBox.Enabled = false;
                    myJobManager.Stop();
                }
                catch(Exception e3)
                {
                    MessageBox.Show(e3.Message);

                }
            }
        }

        private void myJobManager_UserResultAvailable(Object sender, CogJobManagerActionEventArgs e)
        {
            if (InvokeRequired)
            {
                myJobManagerDelegate mydel = new myJobManagerDelegate(myJobManager_UserResultAvailable);
                Object[] args = new Object[2] { sender, e };
                Invoke(mydel, args);
                return;
            }
            // 输出运行状态
            Cognex.VisionPro.ICogRecord myrecord = myJobManager.UserResult() as ICogRecord;
            RunStatusTextBox.Text = myrecord.SubRecords["UserResultTag"].Content.ToString() + ":" + myrecord.SubRecords["JobName"].Content.ToString() + "-->";
            RunStatusTextBox.Text += myrecord.SubRecords["RunStatus"].Content.ToString();

            // 输出参数
            Cognex.VisionPro.ToolGroup.CogToolGroup myTG = myJob.VisionTool as Cognex.VisionPro.ToolGroup.CogToolGroup;
            Cognex.VisionPro.ToolBlock.CogToolBlock myTB1 = myTG.Tools["Detect_Defects"] as Cognex.VisionPro.ToolBlock.CogToolBlock;
            Cognex.VisionPro.PMAlign.CogPMAlignTool myPM = myTB1.Tools["CogPMAlignTool2"] as Cognex.VisionPro.PMAlign.CogPMAlignTool;
            Cognex.VisionPro.ICogRecord tmpRecord;
            try
            {
                textBox1.Text = myPM.Results.Count.ToString();
            }
            catch (Exception e5)
            {
                textBox1.Text = e5.ToString();
            }
            // 输出图像
            Cognex.VisionPro.ICogRecord graphic_record;
            graphic_record = myrecord.SubRecords["ShowLastRunRecordForUserQueue"];
            graphic_record = graphic_record.SubRecords["LastRun"];
            graphic_record = graphic_record.SubRecords[1];
            //graphic_record = graphic_record.SubRecords["CogFixtureTool1.OutputImage"];
            CogRecordDisplay1.Record = graphic_record;
            CogRecordDisplay1.Fit(true);
            //RunStatusTextBox.Text = "";
        }

        private void RetrainButton_Click(object sender, EventArgs e)
        {
            // 调取工具
            Cognex.VisionPro.ToolGroup.CogToolGroup myTG = myJob.VisionTool as Cognex.VisionPro.ToolGroup.CogToolGroup;
            Cognex.VisionPro.ToolBlock.CogToolBlock myTB = myTG.Tools["Detect_Defects"] as Cognex.VisionPro.ToolBlock.CogToolBlock;
            Cognex.VisionPro.PMAlign.CogPMAlignTool myPM = myTB.Tools["CogPMAlignTool1"] as Cognex.VisionPro.PMAlign.CogPMAlignTool;
            // 重训练
            myPM.Pattern.Train();
            RunStatusTextBox.Text = myPM.RunStatus.ToString();
        }

        private void ShowTrainCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (ShowTrainCheckBox.Checked)
            {
                RunOnceButton.Enabled = false;
                RunContCheckBox.Enabled = false;
                RetrainButton.Enabled = true;
                Cognex.VisionPro .ToolGroup .CogToolGroup myTG = myJob.VisionTool as Cognex.VisionPro.ToolGroup.CogToolGroup;
                Cognex.VisionPro.ToolBlock.CogToolBlock myTB1 = myTG.Tools["Detect_Defects"] as Cognex.VisionPro.ToolBlock.CogToolBlock;
                Cognex.VisionPro.PMAlign.CogPMAlignTool myPM = myTB1.Tools["CogPMAlignTool1"] as Cognex.VisionPro.PMAlign.CogPMAlignTool;
                Cognex.VisionPro.ICogRecord tmpRecord;
                tmpRecord = myPM.CreateCurrentRecord();
                tmpRecord = tmpRecord.SubRecords["TrainImage"];
                CogRecordDisplay1.Record = tmpRecord;
                CogRecordDisplay1.Fit(true);

            }
            else
            {
                RunOnceButton.Enabled = true;
                RunContCheckBox.Enabled = true;
                RetrainButton.Enabled = false;
                CogRecordDisplay1.Record = null;
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }
    }
}

最后把我用的Job的框架给大家看一眼,不然不好理解我里面的一些名字是啥意思
Job
Detect_Defects的part1
Detect_Defects的part2

这四部分给出来,大家按照我给的名字命名你的控件,然后如果想先爽一下,直接把我给的Form1.cs覆盖掉你原本的就应该ok了哦。但是我建议大家,还是先按照pdf自己做,不懂了或者卡壳了,再来看,可以理解更深哦~


最后笔者想说,如果有不理解,或者读后有所感想,想说一说哪里写的不够清楚,或者思路或者语言构造,甚至一句感谢,都是我十分看重的财富。我写了也不少了,但真的没什么人有学术互动的。怎么说呢,有点悲伤。
还有一点,我写的所有东西,如果大家有需要,我可以放到Git里,哪怕有一个人,我也不嫌麻烦。所以,还是想大家跟我说的。。。

也不知道怎么结尾,就给大家拜个早年吧。

你可能感兴趣的:(Vision Pro 界面源码编写基础(C#配合vpp文件))