【VisionPro项目】检测磁铁有无【旋转坐标系】【含完整C#脚本可直接复制】
·
1. 摘要
- 检测需求:检测磁铁有无
- 检测逻辑:
- 方式1:使用多个CogBlobTool工具,和磁铁一一对应,检测有无
- 方式2:利用磁铁对称的性质,旋转坐标系的角度,用1个CogBlobTool工具,就能查找所有的磁铁【本文重点讲述方式2】
2. 产品图象

3.检测流程
思路:
-
先对工件进行定位【实际生产时,会有轻微的上料偏差】
-
再使用工件中心的“圆形”做二次定位
-
以“圆形”的中心,作为旋转中心,旋转坐标系。产品中有6组磁铁,360度一共有6组磁铁,所以坐标系每次旋转60度数.
工具组流程:

高级脚本:
#region namespace imports
using System;
using System.Collections;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using Cognex.VisionPro3D;
using Cognex.VisionPro.ImageProcessing;
using Cognex.VisionPro.PMAlign;
using Cognex.VisionPro.CalibFix;
using Cognex.VisionPro.Caliper;
using Cognex.VisionPro.Blob;
#endregion
public class CogToolBlockAdvancedScript : CogToolBlockAdvancedScriptBase
{
#region Private Member Variables
private Cognex.VisionPro.ToolBlock.CogToolBlock mToolBlock;
CogGraphicCollection gc = new CogGraphicCollection();
private double[] allBlobsX = new double[6];//保存blob在局部坐标系下的位置
private double[] allBlobsY = new double[6];//保存blob在局部坐标系下的位置
#endregion
public override bool GroupRun(ref string message, ref CogToolResultConstants result)
{
try
{
gc.Clear();
mToolBlock.Outputs["result"].Value = true;
Array.Clear(allBlobsX, 0, allBlobsX.Length);
Array.Clear(allBlobsY, 0, allBlobsY.Length);
// 获取工具
CogImageConvertTool convert = mToolBlock.Tools["CogImageConvertTool1"] as CogImageConvertTool;
CogPMAlignTool pma1 = mToolBlock.Tools["CogPMAlignTool1"] as CogPMAlignTool;
CogFixtureTool fix1 = mToolBlock.Tools["CogFixtureTool1"] as CogFixtureTool;
CogFindCircleTool findCircle1 = mToolBlock.Tools["CogFindCircleTool1"] as CogFindCircleTool;
CogFixtureTool fix2 = mToolBlock.Tools["CogFixtureTool2"] as CogFixtureTool;
CogBlobTool blob1 = mToolBlock.Tools["CogBlobTool1"] as CogBlobTool;
// 运行基础工具
convert.Run();
pma1.Run();
fix1.Run();
findCircle1.Run();
// 6方向循环检测
for (int i = 0; i < 6; i++)
{
CogTransform2DLinear newTrans = new CogTransform2DLinear();
newTrans.TranslationX = findCircle1.Results.GetCircle().CenterX;
newTrans.TranslationY = findCircle1.Results.GetCircle().CenterY;
newTrans.Rotation = pma1.Results[0].GetPose().Rotation + i * (Math.PI / 3);//!!!每次旋转60度
fix2.RunParams.UnfixturedFromFixturedTransform = newTrans;
fix2.Run();
blob1.Run();
double dx = 0;
double dy = 0;
if (blob1.Region != null && blob1.Region is CogRectangleAffine)
{
CogRectangleAffine rec1 = (CogRectangleAffine) blob1.Region;
newTrans.MapPoint(rec1.CenterX, rec1.CenterY, out dx, out dy);//!!!把【局部坐标系】的点 → 转换回【图像像素坐标系】。(rec1.CenterX, rec1.CenterY)是blob在局部坐标系中的值;(dx, dy)是blob在图像像素坐标系中的值
}
// 赋值OK / NG
if (blob1.Results.GetBlobs().Count == 1)
{
addText(dx, dy, "OK", CogColorConstants.Green, 10);
allBlobsX[i] = dx;
allBlobsY[i] = dy;
}
else
{
addText(dx, dy, "NG", CogColorConstants.Red, 10);
mToolBlock.Outputs["result"].Value = false;
allBlobsX[i] = -9999;
allBlobsY[i] = -9999;
}
}
// 数组每个元素单独格式化保留2位小数
mToolBlock.Outputs["strX"].Value = string.Join(",", Array.ConvertAll(allBlobsX, x => x.ToString("0.00")));//Array.ConvertAll:把allBlobsX数组里每一个数字x,都变成保留 2 位小数的字符串
mToolBlock.Outputs["strY"].Value = string.Join(",", Array.ConvertAll(allBlobsY, y => y.ToString("0.00")));
}
catch (Exception ex)
{
message = ex.Message;
result = CogToolResultConstants.Error;
mToolBlock.Outputs["result"].Value = false;
for (int k = 0; k < 6; k++)
{
allBlobsX[k] = -9999;
allBlobsY[k] = -9999;
}
// catch里同样用ConvertAll格式化
mToolBlock.Outputs["strX"].Value = string.Join(",", Array.ConvertAll(allBlobsX, x => x.ToString("0.00")));
mToolBlock.Outputs["strY"].Value = string.Join(",", Array.ConvertAll(allBlobsY, y => y.ToString("0.00")));
}
return false;
}
public void addText(double x, double y, string str, CogColorConstants color, int size)
{
CogGraphicLabel label = new CogGraphicLabel();
label.SetXYText(x, y, str);
label.Color = color;
label.Font = new Font("黑体", size);
gc.Add(label);
}
#region When 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>
public override void ModifyCurrentRunRecord(Cognex.VisionPro.ICogRecord currentRecord)
{
}
#endregion
#region When 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>
public override void ModifyLastRunRecord(Cognex.VisionPro.ICogRecord lastRecord)
{
if(gc.Count > 0)
{
foreach(ICogGraphic item in gc)
{
”mToolBlock.AddGraphicToRunRecord(item, lastRecord, lastRecord.SubRecords[0].RecordKey, "");
}
}
}
#endregion
#region When the Script is Initialized
/// <summary>
/// Perform any initialization required by your script here
/// </summary>
/// <param name="host">The host tool</param>
public override void Initialize(Cognex.VisionPro.ToolGroup.CogToolGroup host)
{
// DO NOT REMOVE - Call the base class implementation first - DO NOT REMOVE
base.Initialize(host);
// Store a local copy of the script host
this.mToolBlock = ((Cognex.VisionPro.ToolBlock.CogToolBlock) (host));
}
#endregion
}
注意事项:
-
每次运行必须清空数组
这句非常关键:
Array.Clear(allBlobsX, 0, 6);如果不清空 → 上一次的结果会留在数组里,导致数据错乱。
-
NG 必须给数组赋值(不能空着)
allBlobsX[i] = -9999;不赋值 → 数组是 0,不知道是真 0 还是没检测到。
-
Blob.Region 必须判空**
if (blob1.Region != null)不判空 → 没检测到目标时直接报错。
-
6 次循环必须每次都运行 fix2 + blob1
fix2.Run(); blob1.Run();少一个 Run → 坐标不刷新,6 个位置全一样。
-
把【局部坐标系】的点 → 转换回【图像像素坐标系】,否则文本标签的显示位置会出问题
newTrans.MapPoint(rec1.CenterX, rec1.CenterY, out dx, out dy);//!!!把【局部坐标系】的点 → 转换回【图像像素坐标系】。(rec1.CenterX, rec1.CenterY)是blob在局部坐标系中的值;(dx, dy)是blob在图像像素坐标系中的值 -
数组不能直接 ToString (“0.00”)
错误写法:
allBlobsX.ToString("0.00"); // ❌ 报错正确写法:
Array.ConvertAll(allBlobsX, x => x.ToString("0.00")); // ✅因为:数组不能格式化,只有数字才能格式化。
-
string.Join 才能把数组变成逗号字符串
string.Join(",", 数组)不加 Join → 输出的是
System.Double[],不是数字。
-
文本标签永远输出在第一个工具的图像上
”mToolBlock.AddGraphicToRunRecord(item, lastRecord, lastRecord.SubRecords[0].RecordKey, "");“这句话啥意思?AddGraphicToRunRecord函数:
mToolBlock.AddGraphicToRunRecord( item, // 你要画的东西(圆、点、线) lastRecord, // 往“上次运行结果”里画//lastRecord = 上一次运行的结果记录所有图像、结果都存在这里。 路径, // 画在哪一张图像上 "" // 图层名字(空=默认图层) );lastRecord.SubRecords[0].RecordKey:
1. lastRecord 上次运行完的所有结果大箱子。里面装了:图像、工具结果、数据、图层…… 一切东西。 2. SubRecords[0] - 大箱子里的【第一张图片】 - SubRecords = 所有子结果 - [0] = 第 0 号(第 1 个) 几乎永远 = 你正在看的这张输入图 / 输出图 你可以理解成:SubRecords [0] = 当前画面 3. RecordKey 这张图片的 “唯一身份证号” VisionPro 必须靠这个 ID 才能找到
更多推荐

所有评论(0)