1. 摘要
检测需求:检测胶水宽度
检测逻辑:
- 如果胶水宽度在阈值范围内,OK
- 如果胶水宽度超过阈值,NG
2. 产品图象
3. 检测流程
思路:
- 先对产品进行定位
- 提取出胶水区域
- 使用caliper工具,循环遍历,检测胶水宽度
工具组
高级脚本
#regionnamespace importsusingSystem;usingSystem.Collections;usingSystem.Drawing;usingSystem.IO;usingSystem.Windows.Forms;usingCognex.VisionPro;usingCognex.VisionPro.ToolBlock;usingCognex.VisionPro3D;usingCognex.VisionPro.ImageProcessing;usingCognex.VisionPro.PMAlign;usingCognex.VisionPro.CalibFix;usingCognex.VisionPro.ColorExtractor;usingCognex.VisionPro.Blob;usingCognex.VisionPro.Caliper;#endregionpublicclassCogToolBlockAdvancedScript:CogToolBlockAdvancedScriptBase{#regionPrivate Member VariablesprivateCognex.VisionPro.ToolBlock.CogToolBlockmToolBlock;System.Collections.ArrayListLabelList=newSystem.Collections.ArrayList();#endregion/// <summary>/// Called when the parent tool is run./// Add code here to customize or replace the normal run behavior./// </summary>/// <param name="message">Sets the Message in the tool's RunStatus.</param>/// <param name="result">Sets the Result in the tool's RunStatus</param>/// <returns>True if the tool should run normally,/// False if GroupRun customizes run behavior</returns>publicoverrideboolGroupRun(refstringmessage,refCogToolResultConstantsresult){// To let the execution stop in this script when a debugger is attached, uncomment the following lines.// #if DEBUG// if (System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break();// #endif// Run each tool using the RunTool function//初始化工具CogImageConvertToolimageConvert=mToolBlock.Tools["CogImageConvertTool1"]asCogImageConvertTool;CogIPOneImageToolipo1=mToolBlock.Tools["CogIPOneImageTool1"]asCogIPOneImageTool;CogPMAlignToolpma1=mToolBlock.Tools["CogPMAlignTool1"]asCogPMAlignTool;CogFixtureToolfix1=mToolBlock.Tools["CogFixtureTool1"]asCogFixtureTool;CogColorExtractorToolcolorExtractor1=mToolBlock.Tools["CogColorExtractorTool1"]asCogColorExtractorTool;CogIPOneImageToolipo2=mToolBlock.Tools["CogIPOneImageTool2"]asCogIPOneImageTool;CogBlobToolblob1=mToolBlock.Tools["CogBlobTool1"]asCogBlobTool;CogCaliperToolcaliper1=mToolBlock.Tools["CogCaliperTool1"]asCogCaliperTool;//初始化InputsdoublepixPrecision=Convert.ToDouble(mToolBlock.Inputs["pixPrecision"].Value);//像素精度doublemaxWidthThreshold=Convert.ToDouble(mToolBlock.Inputs["maxWidthThreshold"].Value);//允许的卡尺最大宽度【物理距离】doubleminWidthThreshold=Convert.ToDouble(mToolBlock.Inputs["minWidthThreshold"].Value);//允许的卡尺最小宽度【物理距离】intTest=Convert.ToInt32(mToolBlock.Inputs["Test"].Value);//测试用doublestepDistance=Convert.ToDouble(mToolBlock.Inputs["stepDistance"].Value);//步长//初始化清空LabelList.Clear();//运行工具imageConvert.Run();ipo1.Run();pma1.Run();fix1.Run();colorExtractor1.Run();ipo2.Run();blob1.Run();//初始化参数boolResult=true;//胶路检测结果//OK的caliper的个数intcountOKCaliper=0;//NG的caliper的个数intcountNGCaliper=0;//获取最小卡尺宽度结果【物理距离】doubleminWidthResult=1000;//获取最大卡尺宽度结果【物理距离】doublemaxWidthResult=0;//设置Caliper的位置【只需手动设置blob区域就可以了,caliper可以跟随blob区域】CogCircularAnnulusSectioncircleSection=newCogCircularAnnulusSection();circleSection=(CogCircularAnnulusSection)blob1.Region;doublestartAngle=circleSection.AngleStart*180/Math.PI;doubleangleRange=circleSection.AngleSpan*180/Math.PI;//遍历整个Blob区域doubleR=circleSection.Radius*(1+circleSection.RadialScale)/2;for(inti=0;i<Convert.ToInt32(angleRange/stepDistance)&&i<Test;i++){//caliper1.Region.CenterX=circleSection.CenterX+R*Math.Cos((startAngle+i*stepDistance)/180*Math.PI);caliper1.Region.CenterY=circleSection.CenterY+R*Math.Sin((startAngle+i*stepDistance)/180*Math.PI);caliper1.Region.SideXLength=circleSection.Radius*(1-circleSection.RadialScale);caliper1.Region.SideYLength=5;caliper1.Region.Rotation=(startAngle+i*stepDistance)/180*Math.PI;caliper1.Run();try{if(caliper1.RunStatus.Result==CogToolResultConstants.Accept&&caliper1.Results.Count>0){//卡尺宽度大于最大值时NGif(Convert.ToDouble(caliper1.Results[0].Width*pixPrecision)>maxWidthThreshold){addText(caliper1.Region.CenterX,caliper1.Region.CenterY,"NG:"+(caliper1.Results[0].Width*pixPrecision).ToString("f1")+">"+maxWidthThreshold.ToString("f1"),CogColorConstants.Red,10);Result=false;countNGCaliper++;}//卡尺宽度小于最小值时NGelseif(Convert.ToDouble(caliper1.Results[0].Width*pixPrecision)<minWidthThreshold){addText(caliper1.Region.CenterX,caliper1.Region.CenterY,"NG:"+(caliper1.Results[0].Width*pixPrecision).ToString("f1")+"<"+minWidthThreshold.ToString("f1"),CogColorConstants.Cyan,10);Result=false;countNGCaliper++;}//OK时else{addText(caliper1.Region.CenterX,caliper1.Region.CenterY,(caliper1.Results[0].Width*pixPrecision).ToString("f1"),CogColorConstants.Green,10);countOKCaliper++;}//获取最小宽度if(caliper1.Results[0].Width*pixPrecision<minWidthResult){minWidthResult=caliper1.Results[0].Width*pixPrecision;}//获取最大宽度if(caliper1.Results[0].Width*pixPrecision>maxWidthResult){maxWidthResult=caliper1.Results[0].Width*pixPrecision;}}//卡尺未找到边缘对else{addText(caliper1.Region.CenterX,caliper1.Region.CenterY,"None",CogColorConstants.Yellow,10);Result=false;countNGCaliper++;}}//胶路超出Blob区域catch{addText(caliper1.Region.CenterX,caliper1.Region.CenterY,"Over",CogColorConstants.Orange,10);Result=false;countNGCaliper++;continue;}}intcountCaliper=(Convert.ToInt32(angleRange/stepDistance)<Test)?Convert.ToInt32(angleRange/stepDistance):Test;mToolBlock.Outputs["result"].Value=Result;//此段胶路检测结果mToolBlock.Outputs["countCaliper"].Value=countCaliper;//共检测了多少个CalipermToolBlock.Outputs["countOKCaliper"].Value=countOKCaliper;//共检测了多少个OK的CalipermToolBlock.Outputs["countNGCaliper"].Value=countNGCaliper;//共检测了多少个NG的CalipermToolBlock.Outputs["minWidthResult"].Value=minWidthResult;//检测到的最窄胶路宽度【物理距离】mToolBlock.Outputs["maxWidthResult"].Value=maxWidthResult;//检测到的最宽胶路宽度【物理距离】//显示结果if(Result){addText(circleSection.CenterX-200,circleSection.CenterY-200,""+"弧线-OK",CogColorConstants.Green,10);}else{addText(circleSection.CenterX-200,circleSection.CenterY-200,""+"弧线-NG",CogColorConstants.Red,10);}returnfalse;}publicvoidaddText(doublex,doubley,stringstr,CogColorConstantscolor,intsize){CogGraphicLabelMylabel=newCogGraphicLabel();Mylabel.SetXYText(x,y,str);Mylabel.Color=color;Mylabel.Font=newFont("黑体",size);Mylabel.SelectedSpaceName="Fixture";LabelList.Add(Mylabel);}#regionWhen the Current Run Record is Created/// <summary>/// Called when the current record may have changed and is being reconstructed/// </summary>/// <param name="currentRecord">/// The new currentRecord is available to be initialized or customized.</param>publicoverridevoidModifyCurrentRunRecord(Cognex.VisionPro.ICogRecordcurrentRecord){}#endregion#regionWhen the Last Run Record is Created/// <summary>/// Called when the last run record may have changed and is being reconstructed/// </summary>/// <param name="lastRecord">/// The new last run record is available to be initialized or customized.</param>publicoverridevoidModifyLastRunRecord(Cognex.VisionPro.ICogRecordlastRecord){if(LabelList.Count>0){for(inti=0;i<LabelList.Count;i++){mToolBlock.AddGraphicToRunRecord((CogGraphicLabel)LabelList[i],lastRecord,"CogImageConvertTool1.InputImage","script");}}}#endregion#regionWhen the Script is Initialized/// <summary>/// Perform any initialization required by your script here/// </summary>/// <param name="host">The host tool</param>publicoverridevoidInitialize(Cognex.VisionPro.ToolGroup.CogToolGrouphost){// DO NOT REMOVE - Call the base class implementation first - DO NOT REMOVEbase.Initialize(host);// Store a local copy of the script hostthis.mToolBlock=((Cognex.VisionPro.ToolBlock.CogToolBlock)(host));}#endregion}3.1 定位
实际场景中,胶水被涂在产品上边缘等位置。上料时,产品会有轻微的上料偏差,为了消除上料偏差,需要先对产品进行定位,然后胶水的检测区域才能跟随产品边缘位置调整
3.2 提取胶水
3.3 胶水图像预处理
3.4 胶水查找区域
3.5 卡尺检测胶水
3.5.1 CogCircularAnnulusSection区域
- CogCircularAnnulusSection区域圆弧形的中心:由右下脚绿色圆圈示意
- CogCircularAnnulusSection区域半径:绿色箭头示意
- CogCircularAnnulusSection区域径向缩放:红色箭头的长度 / 绿色箭头的长度
- CogCircularAnnulusSection区域的起始角度:x轴所在的方向就是0角度
- CogCircularAnnulusSection区域的角度范围:从x轴顺时针,旋转至y轴的方向为“角度增加的正方向”
//设置Caliper所需要搜索的【只需手动设置blob区域就可以了,caliper可以跟随blob区域】CogCircularAnnulusSectioncircleSection=newCogCircularAnnulusSection();circleSection=(CogCircularAnnulusSection)blob1.Region;doublestartAngle=circleSection.AngleStart*180/Math.PI;//弧度值-->角度doubleangleRange=circleSection.AngleSpan*180/Math.PI;3.5.2 CogCaliperTool的矩形区域,沿着CogBlobTool的CogCircularAnnulusSection区域移动
以CogBlobTool的区域为基准,设置CogCaliperTool的区域,使得CogCaliperTool的区域可以跟随CogBlobTool的区域移动,便于后续现场调试
卡尺区域的中心:
卡尺中心的位置:
caliper1.Region.CenterX=circleSection.CenterX+R*Math.Cos((startAngle)/180*Math.PI);caliper1.Region.CenterY=circleSection.CenterY+R*Math.Sin((startAngle)/180*Math.PI);caliper1.Region.SideXLength=circleSection.Radius*(1-circleSection.RadialScale);caliper1.Region.SideYLength=5;caliper1.Region.Rotation=(startAngle)/180*Math.PI;CogCaliperTool矩形区域的SideXLength:
caliper1.Region.SideXLength=circleSection.Radius*(1-circleSection.RadialScale)//由下图中“绿色箭头的长度、减去红色箭头的长度”SideXLength:如图所示的“蓝色箭头间距”
3.5.3 卡尺循环遍历逻辑
每次循环,caliper的移动方式:
caliper1.Region.CenterX=circleSection.CenterX+dbR*Math.Cos((startAngle+i*stepDistance)/180*Math.PI);caliper1.Region.CenterY=circleSection.CenterY+dbR*Math.Sin((startAngle+i*stepDistance)/180*Math.PI);caliper1.Region.SideXLength=circleSection.Radius*(1-circleSection.RadialScale);caliper1.Region.SideYLength=5;caliper1.Region.Rotation=(startAngle+i*stepDistance)/180*Math.PI;R:如下图所示黄色箭头的长度;
doubleR=circleSection.Radius*(1+circleSection.RadialScale)/2;卡尺的矩形区域中心点,移动的轨迹:CogCircularAnnulusSection区域中心的虚线
5. 总结
- 理解“CogCircularAnnulusSection区域的参数”。
- 理解“CogCaliperTool的矩形区域,沿着CogBlobTool的CogCircularAnnulusSection区域移动”,使得CogCaliperTool的区域可以跟随CogBlobTool的区域。实际生产中,胶水路径更加多样,会有多处弧线型胶水路径,能更好的复用此ToolBlock,减轻重复的工作量