1.摘要

传统单一CogFindCircle全局找圆方式,对工件边缘毛刺、齿形结构、局部反光、边缘残缺、局部遮挡等场景适应性极差,极易出现圆心偏移、拟合失效、结果漂移等问题,无法满足齿轮、异形圆弧、半遮挡圆形工件的高精度定位需求。

为解决上述痛点,本方案采用八方向分段找圆+极值剔除均值滤波的优化策略:

  • 将整圆轮廓均匀切分为八段独立圆弧区域,通过多组找圆工具分别拟合各段圆弧圆心,充分采集不同区域的轮廓特征点位;
  • 同时通过RMSE拟合误差筛选有效点位,剔除噪声干扰数据;
  • 再通过自定义算法去除两组最大、最小异常极值点,保留高一致性有效点位做均值计算;

该方式摒弃了单一找圆“全局拟合、单点定结果”的缺陷,利用多区域冗余采样+数据滤波优化,极大抵消了局部毛刺、缺陷、光影干扰带来的拟合误差,有效提升圆心定位的稳定性与重复精度,抗干扰能力远优于传统单工具找圆,适配工业现场复杂成像环境,可稳定满足自动化对位、抓取、精密测量等场景的使用要求。

2. 检测思路

  1. 8 个CogFindCircleTool,共用基准圆心X/Y(输入端口TranslationX/Y)、均分起始角度;
  2. 每个卡尺圆工具运行,RMSE<15 才保留有效圆心
  3. 有效 XY 数组去掉 2 个最大值、2 个最小值,剩余数据求平均,输出最终平均圆心newCenterX/newCenterY
  4. 内置自定义函数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

}

注意事项:

  1. 工具名必须严格对应

    CogFindCircleTool1 ~ 8 必须真实存在,少一个就报错。

  2. 找圆参数要根据工件调整

    现在的参数:

    tool.RunParams.CaliperProjectionLength = 0.6;
    tool.RunParams.CaliperSearchLength = 100;
    tool.RunParams.NumCalipers = 10;
    tool.RunParams.NumToIgnore = 3;
    

    齿轮、毛刺、反光、模糊,都要重新调。

  3. RMSE 误差阈值不能太严也不能太松

    现在用的是 15,非常宽松,适合齿轮。

    如果是精密金属件,一般用 0.1~0.5。

  4. 必须加 try-catch

    单个找圆工具失败,不能让整个程序崩溃

优点:

  1. 8 方向找圆 = 抗干扰极强

    比单工具找圆稳得多,适合:

    • 齿轮
    • 有缺口圆
    • 局部遮挡
    • 边缘毛刺
    • 半遮挡圆弧
  2. 去极值平均 = 工业级鲁棒算法

    去掉 2 个最大、2 个最小,是机器视觉里最常用、最稳定的圆心拟合方式。

  3. 容错性极强

    • 单个工具异常不崩溃
    • 有效点不足时自动全平均
    • 工具缺失直接报错提示
  4. 适合自动化设备

    输出稳定、不漂移、可重复精度高,非常适合:

    • 对位
    • 定位
    • 抓取
    • 测量

更多推荐