Vision Pro 界面源碼編寫基礎(chǔ)(C#配合vpp文件)

在康耐視實(shí)習(xí),那就必須得掌握我們公司大大大厲害的產(chǎn)品Vision Pro啦。經(jīng)過大半個月的學(xué)習(xí)訓(xùn)練,基本掌握了不少技能。在這里寫個階段性小結(jié),記錄一下子。
貼兩個文檔,一個中文的(版本較老,VB版),還有一個VP自帶的英文文檔。
傳送門,提取碼ny2r


下面進(jìn)入正題

準(zhǔn)備工具:

正版Vision Pro、Visual Studio 2012(筆者使用版本,也是公司默認(rèn)版本)、
Cognex開發(fā)工具包

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

步驟1:使用QuickBuild創(chuàng)建自己的操作程序(.vpp)

這里我就不多說了,默認(rèn)大家都會一些PM、Blob這種基本操作,如果有需要詳細(xì)說的,評論打出1讓我看見哈(嘖嘖,這個人有點(diǎn)過分哈哈)

步驟2:配置VS

這里由于公司給我們配置了電腦,給的時候就有Cognex的工具包了。我想大家如果購買的正版Vision Pro也是會有的,這里提兩個注意點(diǎn):

(1).net框架是需要4.6版本的,2012默認(rèn)4.5,記得升級。
VS 框架選擇

大部分人下載下來的4.6安裝時都會提示電腦已安裝更高版本。這個問題困擾了我好一會兒,同事都紛紛轉(zhuǎn)戰(zhàn)2015或2017,但最后我發(fā)現(xiàn)是因?yàn)橄螺d的.net 4.6的版本問題,導(dǎo)致的無法安裝。應(yīng)該安裝開發(fā)包(給個官方鏈接),如果實(shí)在搞不懂,那就全下下來試一遍吧~

(2)Vision Pro工具箱的安裝。
VisionPro 控件向?qū)?/div>
傻瓜式點(diǎn)就完了,然后VS里面ToolBox應(yīng)該就有了。
ToolBox安裝完成

步驟3:根據(jù)pdf438頁開始碼

這里按照他說的來就行了,不過他給的是VB程序,我改成了C#,現(xiàn)在公司內(nèi)部好像都用C#開發(fā)了。
過程比較多,我從我的難點(diǎn)一步步說,詳細(xì)的大家自己看pdf。最后我會貼碼。

(1)看的懂.net框架的構(gòu)造
project框架
每個文件的作用是什么,得知道。
(2)JobManager在代碼中就代表了你的整個vpp項(xiàng)目,JobManager.Job(i)代表你項(xiàng)目中得第i個Job。
// 加載vpp作為一個job manager
myJobManager = (CogJobManager)CogSerializer.LoadObjectFromFile("../../../Job722.vpp")
// 引用job manager中的第一個
myJob = myJobManager.Job(0);
(3)”委托“指A線程訪問B線程的功能時使用的東西,其處理模式為:

首先為跨線程事務(wù)創(chuàng)建一個相同聲明的委托

// 每個win窗體控件只能通過創(chuàng)建它的線程來訪問
// 創(chuàng)建一個有預(yù)期簽名的委托 用于指向下面的停止事
delegate void myJobManagerDelegate(Object ByVaklsender,CogJobManagerActionEventArgs _ByVale);

在該事務(wù)創(chuàng)建該委托實(shí)例,提供2中實(shí)例化方法如下

 // 創(chuàng)建委托實(shí)例 并指向停止事件的函數(shù)指
myJobManagerDelegate mydelegate = myJobManager_Stopped
myJobManagerDelegate mydelegate = new myJobManagerDelegate(myJobManager_Stopped);

創(chuàng)建一個該事務(wù)參數(shù)的數(shù)組

// 定義一個參數(shù)數(shù)
Object[] myobj = new Object[2] { ByValsender, _ByVale };

使用控件Invoke方法調(diào)用委托,完成操作

// 使用控件“魔術(shù)”調(diào)用Invoke,在GUI線程上調(diào)用我們的委托(當(dāng)前我們在vpp線程,但是需要使用GUI線程來使按鈕恢復(fù)可選,所以需要委托給GUI線程
this.Invoke(mydelegate, myobj);

最后,程序是怎么發(fā)現(xiàn)線程之間的不通融的呢?這就是為什么Invoke厲害的地方了,在事務(wù)中添加下列代碼

if (InvokeRequired)
{
    # 創(chuàng)建一個指針指向該函數(shù)
    # 在正確的線程上調(diào)用同一個函數(shù)
}

InvokeRequired是每一個控件的”魔術(shù)“屬性,如果程序處在錯誤的線程上,它就會返回”true“。這就是Microsoft的一個用于校正線程亂問題的標(biāo)準(zhǔn)方法。請牢記!

(4)Vision Pro 內(nèi)部控件的調(diào)用,參數(shù)獲取
運(yùn)行狀態(tài)在操作隊列中

首先我們需要現(xiàn)實(shí)的代碼狀態(tài),是一個ICogRecord類,所以我們需要實(shí)例化該對象,然后將JobManager.UserResult傳遞給他。這樣我們就獲取到我們Job的結(jié)果了。之后就是檢索我們需要的result。

// 輸出運(yùn)行狀
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工具里的運(yùn)行結(jié)果或者運(yùn)行參數(shù)等,需要先在QuickBuild里面將你想要的參數(shù)添加到發(fā)送項(xiàng),這樣在Code里面才能獲取到,不然有的參數(shù)(如Item里面的參數(shù))是沒有權(quán)限獲得的,而Count這樣的public變量可以直接調(diào)用,見程序

// 輸出參數(shù)
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最復(fù)雜,它知道如何連接到Vision Pro工具以及如何調(diào)用工具所有的執(zhí)行結(jié)果,它通過顯示區(qū)上放一個下拉框允許用戶選擇瀏覽哪張圖像(就像QB里面的顯示結(jié)果控件一樣)。
RecordsD看上去和TD一樣,也允許下拉選擇,但是他對Vision Pro工具一無所知,他不能從工具中獲取Records樹,必須用編程的方法自己來獲取。
RecordD(注意上面一個是Recordsssssssssss)顯示單個圖像記錄及其圖形的子記錄(也就是你在fixture生成的圖上進(jìn)行操作,那么這些操作都會顯示在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,大家基本上可以在此基礎(chǔ)上進(jìn)行二次開發(fā)了。下面貼一下

源碼

控件外形

設(shè)置的各控件名稱
控件定義

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);
            // 初始化一個對象,其參數(shù)引用包含更多關(guān)于job manager的信息
            myIndepenentJob = myJob.OwnedIndependent;
            // 清空所有job manager隊列,刷新陳舊的圖像和結(jié)果
            myJobManager.UserQueueFlush();
            myJobManager.FailureQueueFlush();
            myJob.ImageQueueFlush();
            myIndepenentJob.RealTimeQueueFlush();

            // 為停止操作綁定事件
            // CJM沒有在GUI創(chuàng)建按鈕,但是它調(diào)用了一個按鈕停止事件!這個事件需要訪問GUI線程的按鈕!故需要“委托”
            myJobManager.Stopped += new CogJobManager.CogJobManagerStoppedEventHandler(myJobManager_Stopped);
            //myJobManager.Stopped += myJobManager_Stopped;
            // 狀態(tài)顯示操作綁定事件
            myJobManager.UserResultAvailable += myJobManager_UserResultAvailable;

            // 連接bar狀態(tài)欄
            CogDisplaystatusBar1.Display = CogRecordDisplay1;

        }



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

                ShowTrainCheckBox.Enabled = false;
                RunContCheckBox.Enabled = false;
                // 防止在單詞任務(wù)完成前再次調(diào)用任務(wù) 讓按鈕不可點(diǎn)擊就行了
                RunOnceButton.Enabled = false;
                myJobManager.Run();
               
            }
            catch (Exception e1)
            {
                MessageBox.Show(e1.Message);
            }

        }

        // 每個win窗體控件只能通過創(chuàng)建它的線程來訪問
        // 創(chuàng)建一個有預(yù)期簽名的委托 用于指向下面的停止事件
        delegate void myJobManagerDelegate(Object ByVaklsender,CogJobManagerActionEventArgs _ByVale);

        // 所有工作完成 CJM運(yùn)行一個停止事件 重啟按鈕
        private void myJobManager_Stopped(Object ByValsender, CogJobManagerActionEventArgs _ByVale)
        {
            if (InvokeRequired)
            {
                // 創(chuàng)建委托實(shí)例 并指向停止事件的函數(shù)指針
                //myJobManagerDelegate mydelegate = myJobManager_Stopped;
                myJobManagerDelegate mydelegate = new myJobManagerDelegate(myJobManager_Stopped);
                // 定義一個參數(shù)數(shù)組
                Object[] myobj = new Object[2] { ByValsender, _ByVale };
                // 使用控件“魔術(shù)”調(diào)用Invoke,在GUI線程上調(diào)用我們的委托(當(dāng)前我們在vpp線程,但是需要使用GUI線程來使按鈕恢復(fù)可選,所以需要委托給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;
            }
            // 輸出運(yùn)行狀態(tài)
            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();

            // 輸出參數(shù)
            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)
        {
            // 調(diào)取工具
            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;
            // 重訓(xùn)練
            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覆蓋掉你原本的就應(yīng)該ok了哦。但是我建議大家,還是先按照pdf自己做,不懂了或者卡殼了,再來看,可以理解更深哦~


最后筆者想說,如果有不理解,或者讀后有所感想,想說一說哪里寫的不夠清楚,或者思路或者語言構(gòu)造,甚至一句感謝,都是我十分看重的財富。我寫了也不少了,但真的沒什么人有學(xué)術(shù)互動的。怎么說呢,有點(diǎn)悲傷。
還有一點(diǎn),我寫的所有東西,如果大家有需要,我可以放到Git里,哪怕有一個人,我也不嫌麻煩。所以,還是想大家跟我說的。。。

也不知道怎么結(jié)尾,就給大家拜個早年吧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容