【VisionPro项目】多段圆弧融合圆心检测工具【含完整C#脚本可直接复制】
·
1.摘要
传统单一CogFindCircle全局找圆方式,对工件边缘毛刺、齿形结构、局部反光、边缘残缺、局部遮挡等场景适应性极差,极易出现圆心偏移、拟合失效、结果漂移等问题,无法满足齿轮、异形圆弧、半遮挡圆形工件的高精度定位需求。
为解决上述痛点,本方案采用八方向分段找圆+极值剔除均值滤波的优化策略:
- 将整圆轮廓均匀切分为八段独立圆弧区域,通过多组找圆工具分别拟合各段圆弧圆心,充分采集不同区域的轮廓特征点位;
- 同时通过RMSE拟合误差筛选有效点位,剔除噪声干扰数据;
- 再通过自定义算法去除两组最大、最小异常极值点,保留高一致性有效点位做均值计算;
该方式摒弃了单一找圆“全局拟合、单点定结果”的缺陷,利用多区域冗余采样+数据滤波优化,极大抵消了局部毛刺、缺陷、光影干扰带来的拟合误差,有效提升圆心定位的稳定性与重复精度,抗干扰能力远优于传统单工具找圆,适配工业现场复杂成像环境,可稳定满足自动化对位、抓取、精密测量等场景的使用要求。
2. 检测思路
- 8 个
CogFindCircleTool,共用基准圆心X/Y(输入端口TranslationX/Y)、均分起始角度; - 每个卡尺圆工具运行,RMSE<15 才保留有效圆心;
- 有效 XY 数组去掉 2 个最大值、2 个最小值,剩余数据求平均,输出最终平均圆心
newCenterX/newCenterY; - 内置自定义函数
arrayRemoveMinMax剔除极值求均值;
前置准备:ToolBlock 内建好【8 个 CogFindCircleTool:CogFindCircleTool1~8】、输入端口
TranslationX、TranslationY、AngleSpan、AngleStart,输出端口newCenterX、newCenterY
3.工具组

4. 源码
#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.Caliper;
using Cognex.VisionPro.Display;
#endregion
public class CogToolBlockAdvancedScript : CogToolBlockAdvancedScriptBase
{
#region 私有变量
private CogToolBlock mToolBlock;
CogGraphicCollection gc = new CogGraphicCollection();
// 用来在 GroupRun 和画图之间传递结果(必须加)
private double newCenterX = 0;//最终的圆心X
private double newCenterY = 0;//最终的圆心Y
#endregion
/// <summary>
/// 主运行逻辑:8方向找圆 + 去极值 + 求平均圆心
///
///
/// </summary>
public override bool GroupRun(ref string message, ref CogToolResultConstants result)
{
try
{
gc.Clear();
//==================== 1. 获取输入端口 =======================
double TranslationX = Convert.ToDouble(mToolBlock.Inputs["TranslationX"].Value);
double TranslationY = Convert.ToDouble(mToolBlock.Inputs["TranslationY"].Value);
int AngleStart = Convert.ToInt32(mToolBlock.Inputs["AngleStart"].Value);
int AngleSpan = Convert.ToInt32(mToolBlock.Inputs["AngleSpan"].Value);
//==================== 2. 获取8个找圆工具 ====================
CogFindCircleTool[] circleTools = new CogFindCircleTool[8];
for (int i = 0; i < 8; i++)
{
string toolName = string.Format("CogFindCircleTool{0}", i + 1);
circleTools[i] = mToolBlock.Tools[toolName] as CogFindCircleTool;
// 工具不存在直接报错
if (circleTools[i] == null)
{
message = "工具未找到:" + toolName;
result = CogToolResultConstants.Error;
return false;
}
}
ArrayList validX = new ArrayList();
ArrayList validY = new ArrayList();
//==================== 3. 循环运行8个找圆工具 ====================
for (int i = 0; i < 8; i++)
{
CogFindCircleTool tool = circleTools[i];
try
{
// 设置期望圆
tool.RunParams.ExpectedCircularArc.CenterX = TranslationX;
tool.RunParams.ExpectedCircularArc.CenterY = TranslationY;
tool.RunParams.ExpectedCircularArc.Radius = 200;
// 卡尺参数
tool.RunParams.CaliperProjectionLength = 0.6;
tool.RunParams.CaliperSearchLength = 100;
tool.RunParams.NumCalipers = 10;
tool.RunParams.NumToIgnore = 3;
// 角度(自动均分8份)
double radStart = (AngleStart + i * AngleSpan) * Math.PI / 180.0;
double radSpan = AngleSpan * Math.PI / 180.0;
tool.RunParams.ExpectedCircularArc.AngleStart = radStart;
tool.RunParams.ExpectedCircularArc.AngleSpan = radSpan;
// 运行
tool.Run();
// 只有拟合成功且精度高才加入有效点
if (tool.Results != null && tool.Results.GetCircle() != null && tool.Results.RMSError < 15)
{
validX.Add(tool.Results.GetCircle().CenterX);
validY.Add(tool.Results.GetCircle().CenterY);
}
}
catch
{
// 单个工具失败不影响整体
continue;
}
}
//==================== 4. 去2个最大、2个最小,求平均 ====================
newCenterX = RemoveMinMax(validX, 2, 2);
newCenterY = RemoveMinMax(validY, 2, 2);
//==================== 5. 输出结果 ====================
mToolBlock.Outputs["newCenterX"].Value = newCenterX;
mToolBlock.Outputs["newCenterY"].Value = newCenterY;
addPointMarker(newCenterX, newCenterY);
result = CogToolResultConstants.Accept;
message = string.Format("成功,有效点数:{0}", validX.Count);
}
catch (Exception ex)
{
message = "脚本异常:" + ex.Message;
result = CogToolResultConstants.Error;
}
return false;
}
public void addPointMarker(double x, double y)
{
CogPointMarker pointMarker = new CogPointMarker();
pointMarker.X = x;
pointMarker.Y = y;
pointMarker.Color = CogColorConstants.Red;
pointMarker.LineWidthInScreenPixels = 5;
pointMarker.SizeInScreenPixels = 100;
gc.Add(pointMarker);
}
/// <summary>
/// 移除指定数量最大、最小值,剩余数据求平均值
/// </summary>
/// <param name="list">原始数据ArrayList</param>
/// <param name="moveMinCount">要剔除的最小值个数</param>
/// <param name="moveMaxCount">要剔除的最大值个数</param>
/// <param name="center">输出最终平均值</param>
public double RemoveMinMax(ArrayList list, int moveMinNum, int moveMaxNum)
{
double sum = 0;
double center = 0;
// 复制新列表,不破坏原数据源
ArrayList tempList = new ArrayList(list);
tempList.Sort();
int allRemoveNum = moveMinNum + moveMaxNum;
// 数据量不足剔除数量,直接全量平均
if (tempList.Count <= allRemoveNum)
{
foreach (double val in tempList)
{
sum += val;
}
if (tempList.Count > 0)
{
center = sum / tempList.Count;
}
return center;
}
// 移除N个最小值
for (int i = 0; i < moveMinNum; i++)
{
tempList.RemoveAt(0);
}
// 移除N个最大值
for (int i = 0; i < moveMaxNum; i++)
{
tempList.RemoveAt(tempList.Count - 1);
}
// 剩余数据求和取平均
foreach (double val in tempList)
{
sum += val;
}
center = sum / tempList.Count;
return center;
}
#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
}
注意事项:
-
工具名必须严格对应
CogFindCircleTool1 ~ 8必须真实存在,少一个就报错。 -
找圆参数要根据工件调整
现在的参数:
tool.RunParams.CaliperProjectionLength = 0.6; tool.RunParams.CaliperSearchLength = 100; tool.RunParams.NumCalipers = 10; tool.RunParams.NumToIgnore = 3;齿轮、毛刺、反光、模糊,都要重新调。
-
RMSE 误差阈值不能太严也不能太松
现在用的是 15,非常宽松,适合齿轮。
如果是精密金属件,一般用 0.1~0.5。
-
必须加 try-catch
单个找圆工具失败,不能让整个程序崩溃。
优点:
-
8 方向找圆 = 抗干扰极强
比单工具找圆稳得多,适合:
- 齿轮
- 有缺口圆
- 局部遮挡
- 边缘毛刺
- 半遮挡圆弧
-
去极值平均 = 工业级鲁棒算法
去掉 2 个最大、2 个最小,是机器视觉里最常用、最稳定的圆心拟合方式。
-
容错性极强
- 单个工具异常不崩溃
- 有效点不足时自动全平均
- 工具缺失直接报错提示
-
适合自动化设备
输出稳定、不漂移、可重复精度高,非常适合:
- 对位
- 定位
- 抓取
- 测量
更多推荐

所有评论(0)