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)是因為下載的.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項目设易,JobManager.Job(i)代表你項目中得第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ā)送項,這樣在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)系作者
  • 序言:七十年代末骏全,一起剝皮案震驚了整個濱河市苍柏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姜贡,老刑警劉巖试吁,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異楼咳,居然都是意外死亡熄捍,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門母怜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來余耽,“玉大人,你說我怎么就攤上這事苹熏〉郑” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵轨域,是天一觀的道長袱耽。 經(jīng)常有香客問我,道長干发,這世上最難降的妖魔是什么朱巨? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮枉长,結(jié)果婚禮上冀续,老公的妹妹穿的比我還像新娘。我一直安慰自己必峰,他們只是感情好洪唐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著自点,像睡著了一般桐罕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上桂敛,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機(jī)與錄音溅潜,去河邊找鬼术唬。 笑死,一個胖子當(dāng)著我的面吹牛滚澜,可吹牛的內(nèi)容都是我干的粗仓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼借浊!你這毒婦竟也來了塘淑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蚂斤,失蹤者是張志新(化名)和其女友劉穎存捺,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體曙蒸,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捌治,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了纽窟。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肖油。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖臂港,靈堂內(nèi)的尸體忽然破棺而出森枪,到底是詐尸還是另有隱情,我是刑警寧澤审孽,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布县袱,位于F島的核電站,受9級特大地震影響瓷胧,放射性物質(zhì)發(fā)生泄漏显拳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一搓萧、第九天 我趴在偏房一處隱蔽的房頂上張望杂数。 院中可真熱鬧,春花似錦瘸洛、人聲如沸揍移。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽那伐。三九已至,卻和暖如春石蔗,著一層夾襖步出監(jiān)牢的瞬間罕邀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工养距, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诉探,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓棍厌,卻偏偏與公主長得像肾胯,于是被迫代替她去往敵國和親竖席。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345