Fixture DRI Training_Fixture讲解
目录
一、坐标转换介绍
坐标转换介绍
坐标转换示例
如何实现坐标转换
CogTransform2DLinear 的方法介绍
形状坐标转换的方法介绍
坐标转换的功能
二、转换坐标
图像转换坐标
脚本转换坐标
用脚本转换坐标(MapPoint):
三、Mapping工具
MappingToolBlock流程
介绍
MappingToolBlock 注意事项
Mapping特征——需要满足的条件
坐标转换实现映射功能
1、TB_Locate_Form
1.搭建2个cogtoolblock 利用标定板进行转换
2.导入图片 搭建流程
3.Unify坐标
4.TB_Loaction
5.TB_MappingBackTo_N_Point
6.TB_Mapping
7.TB_CreateShape
8.TB_Terminal_T4
9.TB_GraphicShow_NoSpec
10.界面显示
2.TB_ReCheck_To
1.TB_UnifyFixture
2.TB_Located
3.TB_Terminal_T4C
4.TB_Mapping
5.TB_CreateShape
6.TB_ReCheck_To
7.TB_GraphicShow_NoSpec
8.界面显示label
四、DesRobotPose=......公式讲解
练习
图片
一、坐标转换介绍
坐标转换介绍
一个二维(2D)转换数学映射点从一个二维空间到另一个二维空间。在VisionPro中,2D转换总是将点从源坐标空间(称为 from space)映射到第二个坐标空间(称为 to space)。例如,许多机器视觉任务要求你将图像坐标空间中的点与用户定义空间中的点关联起来。这两个坐标空间通常有不同的测量单位来表示坐标。使用2D转换将点正确地从像素空间映射到用户空间。
坐标转换示例
已知两个坐标系,("Cognex"中的"X")在两幅图像中是相同的。坐标转换将一个用户空间中的位置表达式映射到另一个用户空间。我们可以使用转换将任意点从一个用户空间映射到另一个用户空间
Q:假如将这个转换关系给予FixtureTool,那么FixtureTool的TranslationX,TranslationY为多少?
如何实现坐标转换
- VisionPro坐标空间树包含一些函数,可以让你获得一个转换对象,该对象映射坐标空间树中任意两个空间之间的点。从坐标空间树获取转换的最常见方法是调用 VisionPro image对象的GetTransform方法。GetTransform允许提取映射中任意两个空间之间的点的转换。
- 基本的 VisionPro 二维变换实现为 ICogTransform2D 接口。这个接口实现了一般的二维转换。基础变换可以是线性或者非线性变换。要在两个空间之间映射点,可以使用此对象的 MapPoint 方法。然而,一般来说,应用程序不需要关心是线性的还是非线性的。大多数情况下,只需使用 ICogTransform2D接口来映射空间之间的点。如果你知道 ICogTransform2D接口下的实际转换是线性的,并且希望使用特定于线性转换的功能,那么你可以使用 ICogTransform2D 接口的线性转换来获取新的 CogTransform2DLinear 对象。更改这个新转换的属性值并不会更改原始转换的值。如果你想从一个未知的转换类型进行转换,声明一个为 CogTransform2DLinear 对象。 CogTransform2DLinear 表示一个特定的2D线性变换。可以修改 CogTransform2DLinear 的属性,并且你可以使用它来映射点、向量和坐标空间之间的区域。
CogTransform2DLinear 的方法介绍
- Compose:返回一个线性变换,类似于矩阵相乘
- ComposeBase:同 Compose 函数类似,但是返回值类型与Compose不同
- Invert:返回一个线性变换,结果为逆。逆矩阵。
- InvertBase:同 Invert 函数类似,但是返回值类型与 Invert 不同
- MapAngle:通过这个转换映射给定的角度,并返回结果(以弧度为单位)
- MapPoint:通过这个变换映射给定的 x,y 点,并返回映射的 x,y 坐标
形状坐标转换的方法介绍
- (Line,Circle,RectangleAffine).Map:通过给定的变换映射形状
- (Line,Circle,RectangleAffine).MapLinear:通过线性变换映射直线,圆,仿射矩形,创建新直线
形状转换的返回结果为对应形状,而CogTransform2DLinear 返回结果为一个线性的转换关系
坐标转换的功能
- 计算偏移量
- 引导贴装定位功能
- 统一图像坐标系
- 统一Robot坐标系
- 映射功能,解决贴装后定位特征被遮挡的问题
- 模板跟随,获取 runtime 下的 shapemode 或者 region
二、转换坐标
图像转换坐标
通过同一个圆在不同的图像下运行,我们就可以拿到同一个点在不同空间下的坐标
脚本转换坐标
用脚本转换坐标(MapPoint):
//清空输出里面的值 foreach(CogToolBlockTerminal ss in mToolBlock.Outputs) { if(ss.ValueType == typeof(double)) { ss.Value = 999; } } ICogImage image0 = mToolBlock.Inputs["Image0"].Value as ICogImage; ICogImage image1 = mToolBlock.Inputs["Image1"].Value as ICogImage; double x = (double) mToolBlock.Inputs["X"].Value; double y = (double) mToolBlock.Inputs["Y"].Value; //public ICogTransform2D GetTransform(string toSpaceName,string fromSpaceName) //Returns a tranform that maps points from the 'From' coordinate space to the 'To' space //返回一个 CogTransform2DLinear 类型为2D坐标变换,该变换将点从 "From"坐标空间映射到"To"空间。 //特殊字符串“.” 被接收为该图像 所选空间名称的别名 CogTransform2DLinear transform = (CogTransform2DLinear) image1.GetTransform(image0.SelectedSpaceName, image1.SelectedSpaceName); double mapPointx,mapPointy; transform.MapPoint(x, y, out mapPointx, out mapPointy);//在建立的trans下进行Image1目标点map到image0上 mToolBlock.Outputs["MapPointX"].Value = mapPointx; mToolBlock.Outputs["MapPointY"].Value = mapPointy;三、Mapping工具
MappingToolBlock流程
介绍
在视觉项目中经常会遇到复检时由于贴装偏差,导致定位特征被覆盖,我们无法抓取所需特征来计算复检数据。此时有两种可以实现我们的需求。
- 将定位的结果直接传到复检。这种情况下对机构的要求很高,拍照视野不能有任何偏差,坐标空间无改变
- 通过map的方式,在定位特征的同时选取某些在贴装前后无变化的特征建立Mapping的坐标系,将需要的特征从原空间映射 Mapping坐标系下,同时将这些Map后的数据给到复检。在复检的时候我们将数据通过同样的Mapping空间转换到原空间,此时我们就可以得到那些无法直接抓取的特征。
MappingToolBlock 注意事项
- 定位与复检必须位于同一坐标空间下,不同相机之间时需要使用 N-Point空间。
- Mapping 特征的选取
- 定位与复检的MappingToolBlock的特征抓取必须完全保持一致
Mapping特征——需要满足的条件
- 特征必须来自于实际物料上
- 特征在定位与复检时无空间位置变动,不会受到贴装的影响,比如压力
- MappingFixture 距离所需要map的特征越近越好
坐标转换实现映射功能
1、TB_Locate_Form
1.搭建2个cogtoolblock 利用标定板进行转换
2.导入图片 搭建流程
3.Unify坐标
CogFixtureTool fixture = mToolBlock.Tools["CogFixtureTool_Unify"] as CogFixtureTool; CogImage8Grey image = mToolBlock.Inputs["InputImage"].Value as CogImage8Grey; CogTransform2DLinear tranform = (CogTransform2DLinear) image.GetTransform("Checkerboard Calibration", "#"); tranform.Scaling = 1; fixture.RunParams.UnfixturedFromFixturedTransform = tranform; fixture.Run(); mToolBlock.Outputs["OutputImage"].Value = fixture.OutputImage;4.TB_Loaction
//创造线 和label集合 private CogLine leftLine; private CogLine bottomLine; private CogGraphicCollection dt = new CogGraphicCollection(); //清空集合 赋值变量 dt.Clear(); foreach(CogToolBlockTerminal ss in mToolBlock.Outputs) { if(ss.ValueType == typeof(double)) { ss.Value = 999; } } double x = (double)mToolBlock.Inputs["Offset_x"].Value; double y = (double)mToolBlock.Inputs["Offset_y"].Value; CogLine left = mToolBlock.Inputs["GetLine_Left"].Value as CogLine; CogLine bottom = mToolBlock.Inputs["GetLine_Bottom"].Value as CogLine; CogIntersectLineLineTool intersect = mToolBlock.Tools["CogIntersectLineLineTool1"]as CogIntersectLineLineTool; intersect.Run(); CogCreateLineParallelTool parallel_left = mToolBlock.Tools["CogCreateLineParallelTool_left"]as CogCreateLineParallelTool; CogCreateLineParallelTool parallel_bottom = mToolBlock.Tools["CogCreateLineParallelTool_bottom"]as CogCreateLineParallelTool; //传递名称 以及平行线需要用的 x点 y点 和以谁为平行线的直线 leftLine = Runline(parallel_left, intersect.X+x , intersect.Y, left); bottomLine = Runline(parallel_bottom, intersect.X, intersect.Y-y, bottom); #region Create CogIntersectLineLineTool CogIntersectLineLineTool intersectlines = new CogIntersectLineLineTool(); intersectlines.InputImage = mToolBlock.Inputs["InputImage"].Value as ICogImage; intersectlines.LineA = leftLine; intersectlines.LineB = bottomLine; intersectlines.Run(); #endregion //在相交的点加入圆形图形 dt.Add(createcircle(intersectlines.X,intersectlines.Y,0.04,CogColorConstants.Red)); //赋值 输出 mToolBlock.Outputs["X"].Value = intersectlines.X; mToolBlock.Outputs["Y"].Value = intersectlines.Y; mToolBlock.Outputs["Angle"].Value =CogMisc.RadToDeg(bottomLine.Rotation); //创建 Circle图形 private CogCircle createcircle(double x,double y,double radius,CogColorConstants color) { CogCircle cir = new CogCircle(); cir.CenterX = x; cir.CenterY = y; cir.LineWidthInScreenPixels = 4; cir.Radius = radius; cir.Color = color; return cir; } //创建平行线 返回输出的被创建线 private CogLine Runline(CogCreateLineParallelTool tt, double x,double y,CogLine line) { tt.X = x; tt.Y = y; tt.Line = line; tt.Run(); return tt.GetOutputLine(); } //输出图标 foreach(ICogGraphic s in dt) { mToolBlock.AddGraphicToRunRecord(s, lastRecord, "CogIntersectLineLineTool1.InputImage", "script"); }5.TB_MappingBackTo_N_Point
CogImage8Grey image = mToolBlock.Inputs["InputImage"].Value as CogImage8Grey; //由于这里没有做标定 所以根本转换不了 N-Point 暂时使用"#" CogTransform2DLinear transform_N_Point = (CogTransform2DLinear) image.GetTransform("#", "#"); transform_N_Point.Scaling = 1; double MapPointx,MapPointy; transform_N_Point.MapPoint((double) mToolBlock.Inputs["X"].Value, (double) mToolBlock.Inputs["Y"].Value,out MapPointx,out MapPointy); double angle= transform_N_Point.MapAngle((double) mToolBlock.Inputs["Angle"].Value); mToolBlock.Outputs["X"].Value = MapPointx; mToolBlock.Outputs["Y"].Value = MapPointy; mToolBlock.Outputs["Angle"].Value = angle;6.TB_Mapping
7.TB_CreateShape
8.TB_Terminal_T4
//写入output需要添加的类型和参数 Dictionary < string,Type > terminalList = new Dictionary<string, Type> () { {"TB_Terminal_T4",typeof(CogToolBlockTerminalCollection)} }; //遍历字典 foreach(var item in terminalList) { CogToolBlockTerminal target = null; //判断字典key是否包含输出的变量名 foreach(CogToolBlockTerminal t in mToolBlock.Outputs) { if(t.Name == item.Key) { target = t; break; } } //不包含就创建 if(target == null) { target = new CogToolBlockTerminal(item.Key, item.Value); mToolBlock.Outputs.Add(target); } //将input里面收入一个集合并赋值 if(item.Value == typeof(CogToolBlockTerminalCollection)) { target.Value = (CogToolBlockTerminalCollection) CogSerializer.DeepCopyObject(mToolBlock.Inputs); } }9.TB_GraphicShow_NoSpec
声明label集合 private CogGraphicCollection dt = new CogGraphicCollection(); //清空 dt.Clear(); CogToolBlockTerminal terminal = null; int errorCode = 1; //判断inputs是否有名字是ErrorCode的 int类型的变量名 foreach(CogToolBlockTerminal input in mToolBlock.Inputs) { if(input.ValueType.Name == "Int32" && input.Name.ToString() == "ErrorCode") { errorCode = (int) mToolBlock.Inputs[input.Name].Value; } } int nRow = 0; foreach(CogToolBlockTerminal input in mToolBlock.Inputs) { //单位 遍历每个input是否是double类型 如果是 是否包含angle 如果包含用° 不包含用mm 否则用 "" string unit = input.ValueType.Name == "Double" ? (input.Name.Contains("Angle") ? " °" : " mm") : ""; //是否保存小数 string fmt = input.ValueType.Name == "Double" ? "f3" : "f0"; //创建label dt.Add(createlabel((errorCode == 1 ? input.Name + ": " + double.Parse(input.Value.ToString()).ToString(fmt) + unit : input.Name + ": 999.999" + unit), 16, 40, 40 + nRow * 40, errorCode == 1 ? CogColorConstants.Green : CogColorConstants.Red)); nRow++; } //判断outputs 是否有Graphic名字 没有创建 有则赋值 foreach(CogToolBlockTerminal output in mToolBlock.Outputs) { if(output.Name == "Graphic") { terminal = output; break; } } if(terminal == null) { mToolBlock.Outputs.Add(terminal = new CogToolBlockTerminal("Graphic", typeof(CogGraphicCollection))); } terminal.Value = (CogGraphicCollection) dt; //创建label方法 private CogGraphicLabel createlabel(string text, float size, double x, double y, CogColorConstants color) { CogGraphicLabel label = new CogGraphicLabel(); label.Font = new Font("Arial", size, FontStyle.Bold, GraphicsUnit.Pixel); label.SelectedSpaceName = "#"; label.Color = color; // label.BackgroundColor = CogColorConstants.White; label.Alignment = CogGraphicLabelAlignmentConstants.TopLeft; label.SetXYText(x, y, text); return label; }10.界面显示
//创建动态数组 ArrayList arraylist = new ArrayList(); //数组清空 获取声明 arraylist.Clear(); CogToolBlock tb_MappingBackTo_N_Point = mToolBlock.Tools["TB_MappingBackTo_N_Point"]as CogToolBlock; CogToolBlock tb_GraphicShow_NpSpec = mToolBlock.Tools["TB_GraphicShow_NoSpec"]as CogToolBlock; CogToolBlock tb_Terminal_T4 = mToolBlock.Tools["TB_Terminal_T4"]as CogToolBlock; //创建变量和类型 Dictionary<string,Type> terminallist = new Dictionary<string,Type>() { {"X",typeof(double)}, {"Y",typeof(double)}, {"Angle",typeof(double)}, {"TB_Terminal_T4",typeof(CogToolBlockTerminalCollection)}, {"Graphic",typeof(CogGraphicCollection)} }; //遍历字典key 看mToolBlock里面输出是否存在该名字 foreach(var item in terminallist) { CogToolBlockTerminal terminal = null; foreach(CogToolBlockTerminal output in mToolBlock.Outputs) { if(output.Name == item.Key) { terminal = output; break; } } //不存在直接创建对应名字和类型 if(terminal == null) { terminal = new CogToolBlockTerminal(item.Key, item.Value); mToolBlock.Outputs.Add(terminal); } //把对应类型进行赋默认值 switch(item.Value.Name) { case "Double": terminal.Value = 999.999; break; case "CogToolBlockTerminalCollection": terminal.Value = new CogToolBlockTerminalCollection(); break; case "CogGraphicCollection": terminal.Value = new CogGraphicCollection(); break; } } //等待工具运行完毕后 foreach(ICogTool tool in mToolBlock.Tools) mToolBlock.RunTool(tool, ref message, ref result); //获取它的label集合 添加到动态数组里面 CogGraphicCollection graphic = tb_GraphicShow_NpSpec.Outputs["Graphic"].Value as CogGraphicCollection; foreach(ICogGraphic grap in graphic) { arraylist.Add(grap); } //output 对应输出 mToolBlock.Outputs["X"].Value = tb_MappingBackTo_N_Point.Outputs["X"].Value; mToolBlock.Outputs["Y"].Value = tb_MappingBackTo_N_Point.Outputs["Y"].Value; mToolBlock.Outputs["Angle"].Value = tb_MappingBackTo_N_Point.Outputs["Angle"].Value; mToolBlock.Outputs["TB_Terminal_T4"].Value = tb_Terminal_T4.Outputs["TB_Terminal_T4"].Value; //显示图像名字圈 ICogRecord hold = lastRecord.SubRecords["TB_UnifyFixture.CogFixtureTool_Unify.OutputImage"]; lastRecord.SubRecords.Clear(); lastRecord.SubRecords.Add(hold); //显示label数据 foreach(ICogGraphic label in arraylist) { mToolBlock.AddGraphicToRunRecord(label, lastRecord, "TB_UnifyFixture.CogFixtureTool_Unify.OutputImage", "script"); }2.TB_ReCheck_To
1.TB_UnifyFixture
CogImage8Grey image = mToolBlock.Inputs["InputImage"].Value as CogImage8Grey; CogFixtureTool fixture = mToolBlock.Tools["CogFixtureTool_Unify"]as CogFixtureTool; CogTransform2DLinear tranform = (CogTransform2DLinear) image.GetTransform("Checkerboard Calibration", "#"); tranform.Scaling = 1; fixture.RunParams.UnfixturedFromFixturedTransform = tranform; fixture.Run(); mToolBlock.Outputs["OutputImage"].Value = fixture.OutputImage;2.TB_Located
3.TB_Terminal_T4C
//循环遍历Collection 如果存在名字 直接赋值 如果不存在直接new 赋值 foreach(CogToolBlockTerminal output in (CogToolBlockTerminalCollection) mToolBlock.Inputs["TB_Terminal_T4"].Value) { string name = output.Name + "T4C"; if (!mToolBlock.Outputs.Contains(name)) mToolBlock.Outputs.Add(new CogToolBlockTerminal(name, output.Value)); mToolBlock.Outputs[name].Value = output.Value; }4.TB_Mapping
5.TB_CreateShape
6.TB_ReCheck_To
7.TB_GraphicShow_NoSpec
声明label集合 private CogGraphicCollection dt = new CogGraphicCollection(); //清空 dt.Clear(); CogToolBlockTerminal terminal = null; int errorCode = 1; //判断inputs是否有名字是ErrorCode的 int类型的变量名 foreach(CogToolBlockTerminal input in mToolBlock.Inputs) { if(input.ValueType.Name == "Int32" && input.Name.ToString() == "ErrorCode") { errorCode = (int) mToolBlock.Inputs[input.Name].Value; } } int nRow = 0; foreach(CogToolBlockTerminal input in mToolBlock.Inputs) { //单位 遍历每个input是否是double类型 如果是 是否包含angle 如果包含用° 不包含用mm 否则用 "" string unit = input.ValueType.Name == "Double" ? (input.Name.Contains("Angle") ? " °" : " mm") : ""; //是否保存小数 string fmt = input.ValueType.Name == "Double" ? "f3" : "f0"; //创建label dt.Add(createlabel((errorCode == 1 ? input.Name + ": " + double.Parse(input.Value.ToString()).ToString(fmt) + unit : input.Name + ": 999.999" + unit), 16, 40, 40 + nRow * 40, errorCode == 1 ? CogColorConstants.Green : CogColorConstants.Red)); nRow++; } //判断outputs 是否有Graphic名字 没有创建 有则赋值 foreach(CogToolBlockTerminal output in mToolBlock.Outputs) { if(output.Name == "Graphic") { terminal = output; break; } } if(terminal == null) { mToolBlock.Outputs.Add(terminal = new CogToolBlockTerminal("Graphic", typeof(CogGraphicCollection))); } terminal.Value = (CogGraphicCollection) dt; //创建label方法 private CogGraphicLabel createlabel(string text, float size, double x, double y, CogColorConstants color) { CogGraphicLabel label = new CogGraphicLabel(); label.Font = new Font("Arial", size, FontStyle.Bold, GraphicsUnit.Pixel); label.SelectedSpaceName = "#"; label.Color = color; // label.BackgroundColor = CogColorConstants.White; label.Alignment = CogGraphicLabelAlignmentConstants.TopLeft; label.SetXYText(x, y, text); return label; }8.界面显示label
ArrayList arraylist = new ArrayList(); CogToolBlockTerminalCollection dt = new CogToolBlockTerminalCollection(); dt.Clear(); arraylist.Clear(); CogToolBlock tb_GraphicShow_nospec = mToolBlock.Tools["TB_GraphicShow_NoSpec"]as CogToolBlock; CogToolBlock tb_Recheck_Gap = mToolBlock.Tools["TB_Recheck_Gap"]as CogToolBlock; foreach(ICogTool tool in mToolBlock.Tools) mToolBlock.RunTool(tool, ref message, ref result); dt = (CogToolBlockTerminalCollection) CogSerializer.DeepCopyObject(tb_Recheck_Gap.Outputs); foreach(CogToolBlockTerminal output in dt) { string name = output.Name; if(!mToolBlock.Outputs.Contains(name)) { mToolBlock.Outputs.Add(new CogToolBlockTerminal(name, output.Value)); } mToolBlock.Outputs[name].Value = output.Value; } CogGraphicCollection graphic = (CogGraphicCollection) tb_GraphicShow_nospec.Outputs["Graphic"].Value as CogGraphicCollection; foreach(CogGraphicLabel label in graphic) { arraylist.Add(label); } ICogRecord hold = lastRecord.SubRecords["TB_UnifyFixture.CogFixtureTool_Unify.OutputImage"]; lastRecord.SubRecords.Clear(); lastRecord.SubRecords.Add(hold); foreach(ICogGraphic item in arraylist) { mToolBlock.AddGraphicToRunRecord(item, lastRecord, "TB_UnifyFixture.CogFixtureTool_Unify.OutputImage", "script"); }四、DesRobotPose=......公式讲解
DesRobotPose=DesPartPose.Compose(CurrentPartPose.Invert().Compose(CurRobotPose)) 注释
- A: Robot Space
- B: N-Point Space
- C: Camera Space
- CurRobotPose: Space B from A
- CurrentPartPose: Space B from C
- DesRobotPose: Space B from A
- DesPartPose: Space B from C
求DesRobotPose(Space B from A)
- 已知DesPartPose: Space B from C 只需求出 Space C form A
- Space C from A =CurrentPartPose.Invert().Compose(CurRobotPose)
- DesRobotPose=DesPartPose.Compose(Space C from A)
练习
分别通过图像与脚本两种方法来实现Mapping功能。FixtureA为MappingFixture,通过FixtureA来映射 L1,L2。