2023年11月27日发(作者:)
VisionPro脚本(⼀⽂读懂VisionPro脚本原理与使⽤⽅法)
⼀、脚本简介
1.1 VisionPro项⽬组成简介
在介绍脚本之前先简单介绍⼀下VisionPro开发环境(QuickBuild)的项⽬结构,Job是QuickBuild⼯程的基本组成单位,⼀个QucikBuild⼯程⾄少含有⼀个Job,
⼯程中所有的Job是并⾏结构,各个Job之间不会相互影响。每个Job中默认包含⼀个toolGroup,⽤户可以在默认的toolGroup中添加项⽬所需的⼯具和⼯具块。
⼯具块(toolBlock)与⼯具组(toolGroup)都是⼯具的**“容器”**,通过使⽤⼯具块与⼯具组可以将完成某⼀功能的⼯具进⾏封装,实现项⽬模块化,同时亦
可将某⼀特定功能的⼯具块或⼯具组导出实现重复使⽤,类似于编程语⾔中“函数”功能。⼯具块中亦可以包含⼯具块与⼯具组,两者之间的包含关系没有明确
层次关系。
1.2 VisionPro脚本简介
VisionPro⼯具封装了视觉算法与⽤户交互界⾯,toolGroup与toolBlock提供了组合⼯具的容器,但是并⾮所有的功能都能通过既定交互界⾯实现。为了让⽤户
实现客制化功能更加“随⼼所欲”,实现VisionPro本⾝⽆法实现的逻辑功能,VisionPro预留了脚本功能。脚本的类型、作⽤与⽀持语⾔如下图所⽰:
⼆、脚本类与⽅法
VisionPro通过”多态”技术实现脚本功能,VisionPro 的每⼀Job、toolGroup、toolBlock对象都含有⼀个接⼝对象,⽤户通过重写接⼝⽅法实现⾃定义拓展功
能。以toolGroup为例, ICogToolGroupScript接⼝中定义了⼦类中必须实现的函数,当toolGruoup执⾏到某⼀节点(⼯具准备运⾏、⼯具运⾏完成等)时会
调⽤相应的接⼝函数实现⽤户指定的功能。
如果你对接⼝、多态理解不够深⼊,你只需要明⽩脚本就是**“填空题”**,VisionPro在适当的位置给你留下空⽩,在这个空⽩区域你可以在满⾜条件的情况
下“⾃由发挥”,实现你想要实现的功能。
2.1 toolGroup脚本类
以ToolGroup脚本为例展开,toolGroup 脚本是继承于CogToolGroupBaseScript,实现了ICogToolGroupScript接⼝,该接⼝有四个⽅法,详细介绍如下:
1 public class CogToolGroupBaseScript : ICogToolGroupScript
2 {
3 //
4 public virtual bool GroupRun(ref string message,ref lResultConstants result)
5 {
6 return true;
7 }
8
9 public virtual void ModifyCurrentRunRecord(ICogRecord currentRecord)
10 {}
11 public virtual void ModifyLastRunRecord(ICogRecord lastRecord)
12 {}
13 public virtual void Initialize(lGroup host)
14 {
15 toolGroup = host;
16 }
17 protected lGroup toolGroup=null;
18 }
Initialize() 顾名思义,该⽅法⽤于对toolGroup⼯具进⾏初始化,当退出脚本编辑⼯具时脚本会进⾏编译并进⾏初始化,此时该⽅法会被调⽤。此外,在对
该group通过*.vpp⽂件进⾏加载时也会被⽴即调⽤。所以,所有的“⼀次性”的初始化⼯作都应该写在该⽅法中。
GroupRun()⽅法运⾏该Group中的⼯具,如果该⽅法返回值为true,所有的属于当前Group的视觉⼯具都将运⾏,如果返回值为false,⽤户可以⾃定义⼯
具的执⾏顺序,返回值为false为常见情况。
ModifyCurrentRunRecord() ⽅法⽤于修改CurrentRecord,在toolGroup的CurrentRecord被创建后调⽤。
ModifyLastRunRecord() ⽅法⽤于修改LastRunRecord,在toolGroup的LastRunRecord被创建后调⽤,例如:在最终⽣成图像中添加标签、该表颜⾊、
⽤不同⼏何图像标记⽬标区域。
成员变量toolGroup为CogToolGroup类型,该类的runTool⽅法⽤于运⾏指定视觉⼯具;Tools 属性为当前Group的⼯具集合,⼀般⽤于获取当前⼯具组
中某⼀⼯具的引⽤;DefineScriptTerminal、GetScriptTerminalData、SetScriptTerminalData ⽅法⽤于定义、获取、设置输⼊输出终端。
1 //对于当前Group存在的视觉⼯具的程序集与命名空间会⾃动添加,如果⽤户想要使⽤当前Group不存在的⼯具或者添加⾃定义程序集可以⼿动添加
2 //详细的操作步骤会在后续实例中进⾏介绍
3 using System;
4 using Pro;
5 using Pro3D;
6 using oup;
7
8 public class UserScript : CogToolGroupBaseScript
9 {
10 //默认情况下遍历group中所有的⼯具并运⾏,⽤户可以根据实际情况⾃定义运⾏逻辑与顺序
11 public override bool GroupRun(ref string message, ref CogToolResultConstants result)
12 for (Int32 toolIdx = 0; toolIdx < ; toolIdx++)
13 l([toolIdx], ref message, ref result);
14 return false;//默认情况下为false表⽰⽤户可以控制⼯具的运⾏顺序,返回值为true则运⾏当前Group中所有⼯具。
15 }
16 public override void ModifyCurrentRunRecord(cord currentRecord)
17 {
18 //在此处添加⽤户代码实现⾃定义修改CurrentRunRecord的功能
19 }
20 public override void ModifyLastRunRecord(cord lastRecord)
21 {
22 //在此处添加⽤户代码⽤于所有⼯具运⾏完成后根据⽤户需求创建Record或者在既有Record中添加标记等
23 }
24 public override void Initialize(CogToolGroup host)
25 {
26 //调⽤⽗类初始化函数,初始化toolGroup对象
27 base.Initialize(host);
28 }
29 }
2.2 toolBlcok脚本类
与toolGroup脚本类似,toolBlock的脚本⽗类CogToolBlockAdvancedScriptBase,该类实现的接⼝与toolGroup相同,都是ICogToolGroupScript,不同之处在
于toolBlock与两个脚本基类,CogToolBlockSimpleScript 与 CogToolBlockAdvancedScript 分别⽤于“简单脚”与“复杂”脚本,两者之间的区别在于复杂脚本能
够实现:①动态定义toolBlock的输⼊输出终端,② 能够访问当前⼯具块所包含⼯具的所有属性与⽅法 ,为保证与toolGroup脚本使⽤的统⼀性,推荐直接使⽤
复杂脚本。
存在即合理,简单脚本具有使⽤的便利性,在访问⼯具块的输⼊输出终端时,两者的具体访问⽅式如下:
1 //使⽤简单脚本为输出赋值
2 s = s * 180 / ;
3 //使⽤复杂脚本为输出赋值
4 this.s["Degrees"].Value = ((double) this.["Radians"].Value) * 180 / ;
既然与toolGroup实现了相同的接⼝,toolBlock脚本基类的⽅法与toolGroup必然相同,功能基本⽆异,不再赘述。
2.3Job脚本类
Job脚本⽤于控制与图像获取相关的设备属性与参数,基类为CogJobBaseScript,实现ICogJobScript接⼝。
1 public class CogJobBaseScript : ICogJobScript
2 {
3 public virtual void Initialize(CogJob jobParam)
4 {
5 job = jobParam;
6 }
7 public virtual void AcqFifoConstruction(ICogAcqFifo fifo)
8 {}
9 public virtual void PreAcquisition()
10 {}
11 public virtual void PostAcquisition(ICogImage image)
12 {}
13 public virtual bool PostAcquisitionRef(ref ICogImage image)
14 {
15 PostAcquisition(image);
16 return true;
17 }
18 public virtual bool PostAcquisitionRefInfo(ref ICogImage image, ICogAcqInfo info)
19 {
20 return PostAcquisitionRef(ref image);
21 }
22 protected CogJob job = null;
23 }
24 }
Initialize() 初始化⽅法,获取当前job引⽤以及⽤户需要的初始化数据。
PreAcquisition() 在FIFO的StartAcquire()⽅法调⽤之前被调⽤,即在进⾏图像采集之前调⽤,如在图像采集之前设置曝光、增益、对⽐度等图像参数。
PostAcquisition() 在图像采集完成之后被调⽤。
PostAcquisitionRef() 该⽅法与 PostAcquisition 类似,不同之处在于 image 是以引⽤的⽅式传递,如果这个⽅法返回 Ture , VisionPro 将处理这个
image,如果这个⽅法返回 False ,这个 image 将不会被⽴即进⾏处理 ,⽽是采集下⼀幅图像,这可以使你能够在处理所取的多个 image 之前将它们联
合在⼀起.(如果 PostAcquisition 和 PostAcquisitionRef 都被重写,PostAcquisition 将被忽略)。例如你需要同⼀个相机采集多张不同曝光的图像进⾏合成,
并不是每次采集后都⽴即进⾏处理,⽽是采集到固定数量或者满⾜某⼀条件时进⾏处理。
PostAcquisitionRefInfo() 与PostAcquisiitonRef相似,多了⼀个参数,⽤户可以通过ICogAcqInfo获取图像的时间戳,重写该⽅法后 PostAcquisition 、
PostAcquisitionRef、 PostAcquisitionRef会被忽略。
三、脚本使⽤案例
3.1 job本实⽤实例-----⾃动调节曝光时间
setp1.新建Job,双击进⼊job中。
step2 配置->作业属性->编辑脚本->C#脚本,进⼊Job脚本编辑环境
1 using System;
2 using Pro;
3 using uild;
4 using rocessing;
5
6 public class UserScript : CogJobBaseScript
7 {
8 double exposure = 10;
9 #region "When an Acq Fifo Has Been Constructed and Assigned To The Job"
10 // This function is called when a new fifo is assigned to the job. This usually
11 // occurs when the "Initialize Acquisition" button is pressed on the image source
12 // control. This function is where you would perform custom setup associated
13 // with the fifo.
14 public override void AcqFifoConstruction(qFifo fifo)
15 {
16 }
17 #endregion
18
19 #region "When an Acquisition is About To Be Started"
20 // Called before an acquisition is started for manual and semi-automatic trigger
21 // models. If "Number of Software Acquisitions Pre-queued" is set to 1 in the
22 // job configuration, then no acquisitions should be in progress when this
23 // function is called.
24 public override void PreAcquisition()
25 {
26 // To let the execution stop in this script when a debugger is attached, uncomment the following lines.
27 // #if DEBUG
28 // if (ched) ();
29 // #endif
30 ICogAcqExposure IExposure = xposureParams;
31 re = exposure;
32 }
33 #endregion
34
35 #region "When an Acquisition Has Just Completed"
36 // Called immediately after an acquisition has completed.
37 // Return true if the image should be inspected.
38 // Return false to skip the inspection and acquire another image.
39 public override bool PostAcquisitionRefInfo(ref age image,
40 qInfo info)
41 {
42 // To let the execution stop in this script when a debugger is attached, uncomment the following lines.
43 // #if DEBUG
44 // if (ched) ();
45 // #endif
46 CogHistogram curImageHist = new CogHistogram();
47 CogHistogramResult curHistResult = e(image,null);
48 if(>150)
49 exposure *= 0.75;
50 if( < 50)
51 exposure *= 1.5;
52 if(exposure<0.1)
53 exposure = 0.1;
54 return true;
55 }
56 #endregion
57
58 //Perform any initialization required by your script here.
59 public override void Initialize(CogJob jobParam)
60 {
61 //DO NOT REMOVE - Call the base class implementation first - DO NOT REMOVE
62 base.Initialize(jobParam);
63 }
64 #endregion
65
66 }
3.2 toolBlock脚本使⽤实例-----显⽰Blob区域的中⼼坐标于当前Blob区域
toolBlock脚本的应⽤最为⼴泛,⽤于控制⼯具的运⾏逻辑,修改⽣成的record,拓展数据逻辑等。本例以最简单的⽅式介绍toolBloc脚本使⽤⽅法,本例的具体
应⽤为在各个独⽴的Blob区域显⽰其中⼼坐标值。
10 using ock;
11 using Pro3D;
12 using ;
13 using sAnalysis;
14 #endregion
15
16 public class CogToolBlockAdvancedScript : CogToolBlockAdvancedScriptBase
17 {
18 //==========================step2===================================
19 #region Private Member Variables
20 private lBlock mToolBlock;
21 private CogBlobTool mBlob;
22 private List
23
24 #endregion
25 ///
26 /// Called when the parent tool is run.
27 /// Add code here to customize or replace the normal run behavior.
28 ///
29 /// Sets the Message in the tool's RunStatus.
30 /// Sets the Result in the tool's RunStatus
31 ///
32 /// False if GroupRun customizes run behavior
33 public override bool GroupRun(ref string message, ref CogToolResultConstants result)
34 {
35 // To let the execution stop in this script when a debugger is attached, uncomment the following lines.
36 // #if DEBUG
37 // if (ched) ();
38 // #endif
39 //==========================step4===================================
40 ();
41 // Run each tool using the RunTool function
42 //foreach(ICogTool tool in )
43 //l(tool, ref message, ref result);
44 l(mBlob, ref message, ref result);
45 CogBlobResultCollection blobs = bs();
46 foreach(CogBlobResult blob in blobs)
47 {
48 CogGraphicLabel tempLabel = new CogGraphicLabel();
49 ent = neCenter;
50 ext(OfMassX, OfMassY, ng(OfMassX)+","+ng(OfMassY));
51 = ;
52 (tempLabel);
53 }
54 return false;
55 }
56
57 #region When the Current Run Record is Created
58 ///
59 /// Called when the current record may have changed and is being reconstructed
60 ///
61 ///
62 /// The new currentRecord is available to be initialized or customized.
63 public override void ModifyCurrentRunRecord(cord currentRecord)
64 {
65 }
87 ///
88 /// The host tool
89 public override void Initialize(lGroup host)
90 {
91 // DO NOT REMOVE - Call the base class implementation first - DO NOT REMOVE
92 base.Initialize(host);
93 // Store a local copy of the script host
94 //==========================step3===================================
95 this.mToolBlock = ((lBlock)(host));
96 mBlob = this.["CogBlobTool1"] as CogBlobTool;
97 mLabels = new List
98 }
99 #endregion
100 }
效果图为:
四、脚本进阶
4.1 脚本是“插件”程序集
⽆论你是通过Job脚本、ToolGroup脚本还是ToolBlock脚本拓展QuickBuild程序功能时,实际上是完善了继承于某⼀接⼝的脚本类(继承于
CogToolGroupBaseScript、CogJobBaseScript或者CogToolBlockAdvancedScriptBase类),在退出脚本编辑环境时QuickBuild对你完善的⼦类进⾏编译,
如果出现语法错误会报错提⽰,在语法错误改正前当前脚本的所有内容都不会被调⽤,因为没有通过编译。如果出现逻辑错误不会提⽰,需要在VS环境下进
⾏调试,调试⽅法后续会详细介绍。QuickBuild程序运⾏时通过接⼝实现对脚本⼦类成员函数的调⽤,从⽽将脚本函数的拓展功能进⾏实现。
关于脚本,你还需要明⽩以下⼏点:
⽤户在脚本中编写的代码会成为VisionPro程序的⼀部分,其中的bug也不可避免影响到VisionPro 的运⾏。
⽤户实现的脚本类会被编译为程序集加载到内存当中,⽽且每次对脚本进⾏编辑之后会重新编译,但是旧版本的程序集会⼀致在内存中直到你重新
启动QuickBuild,因此频繁修改脚本会增加⼀点点的内存消耗。
脚本程序集被加载到内存之后,VisionPro会创建⼀个该脚本类的接⼝对象。脚本重新编辑之后接⼝对象会释放Dispose之前对象,运⾏GC进⾏垃圾
回收,创建新脚本类的接⼝实例。
在进⾏脚本编辑时,如果脚本内容⽐较多,最好经常进⾏保存,保存时需要退出脚本编辑环境对整个QuickBuild⼯程进保存。补充⼀点,在
QuickBuild环境下进⾏⼯具编辑时亦需要进⾏随⼿保存,⼯具Block误删除之后好像是⽆法恢复的只有退出QuickBuild时选择不保存,前提是你误删
除之前刚好保存过,惨痛的经历已不⽌⼀次。
4.2 脚本实现事件与委托
事件响应函数中要增加异常处理机制(Try …Catch),否则容易导致VisionPro运⾏出现异常;
不要在事件处理函数中产⽣当前的事件,否则会造成⽆限循环
重写实现Dispose(),取消事件注册。脚本每次修改退出后都会进⾏编译,运⾏时重新注册事件,如果没有在Dispose总取消注册会造成多次注册。
当前事件的响应函数可能不⽌你在脚本中实现,在VisionPro内部机制中可能也有实现,这些事件的响应函数执⾏顺序是不确定的。


发布评论