关于visionPro9.0版本的c#高级脚本编写(4)

关于visionPro的OCR字符检测实战

好久没写脚本了,抽空来写一波,点点赞嘿嘿

项目需求:检测一个激光刻印上的字,而且有两种字体,比较麻烦,刻板边缘也有干扰的划痕,有时划痕还会连在字上,不过有一点比较好的是,它打印的位置总体上姿态比较稳定。

visionPro总体流程

这是总的流程,工具都比较常见。首先引用一下使用了这些工具的命名空间,再初始化一下工具

using Cognex.VisionPro.PMAlign;
using Cognex.VisionPro.CalibFix;
using Cognex.VisionPro.OCRMax;
using Cognex.VisionPro.Blob;
using Cognex.VisionPro.ImageFile;

CogIPOneImageTool ipo = mToolBlock.Tools["CogIPOneImageTool1"] as CogIPOneImageTool;
CogPMAlignTool pma1 = mToolBlock.Tools["CogPMAlignTool1"] as CogPMAlignTool;
CogBlobTool blob1 = mToolBlock.Tools["CogBlobTool1"] as CogBlobTool;
mToolBlock.Outputs["Result"].Value = false;
CogOCRMaxTool ocr1;
CogOCRMaxTool ocr2;

CogOCRMaxTool ocr1 这里为啥只是声明工具而已,因为后面有这个客户两种字体的需求,switchTo 变量是一个给客户自己切换的开放性按钮,批量生产哪种字体就切换哪种字体。看起来这个很麻烦,为啥不直接把两种字体都给放在一起训练呢?之前我也想过,但是这是两种字体可能会互相干扰识别,比如已混的有(2和Z,1和i等等),导致识别的重大性错误。

if((bool) mToolBlock.Inputs["switchTo"].Value)
{
   ocr1 = mToolBlock.Tools["CogOCRMaxTool1"] as CogOCRMaxTool;
   ocr2 = mToolBlock.Tools["CogOCRMaxTool2"] as CogOCRMaxTool;
}
else
{
   ocr1 = mToolBlock.Tools["CogOCRMaxTool3"] as CogOCRMaxTool;
   ocr2 = mToolBlock.Tools["CogOCRMaxTool4"] as CogOCRMaxTool;
}

对IPO的图像处理算法进行初始化,其中变化的是第一个和第五个,其他的不变。

ipo.Operators[0].Enabled = false;
ipo.Operators[4].Enabled = false;

在这里插入图片描述

foreach(ICogTool tool in mToolBlock.Tools)
      mToolBlock.RunTool(tool, ref message, ref result);
      
if(pma1.Results.Count == 1 && ocr1.LineResult.ResultString != null && ocr2.LineResult.ResultString != null)
{
      mToolBlock.Outputs["Result"].Value = true;
      mToolBlock.Outputs["str1"].Value = ocr1.LineResult.ResultString + "*" + ocr2.LineResult.ResultString + "*";
}

如果能找到模板,就直接输出字符串,然后呢,一个比较重要的是这个 ocr 识别的可能会报错,很大部分会直接识别不出来。

在这里插入图片描述

这个是我设置的OCR参数,对于间隙的设置当时报了很多错,有些数字间隔还有些不太一样(比如下面的这行字符有些间隙大有些间隙很小),这个需要注意一下,很多时候它会把两个字符识别成一个字符(当时特别是1这个数字),就会变成**?**成为未知字符。

在这里插入图片描述

为了保险一点有时后还会对字符串进行查验,在字段字符串那里打勾,然后打出刻印的字符与字段定义的一样。有时候字符数量还不一样,增加了很多不稳定的因素,这也是我为啥把 可变长度选项 给勾上,而且还把区段那里的 忽略边框片段 这个选项给去掉打勾了,这个选项勾上的作用可以去掉一些在工具自动提取字符时去掉一些边框的边缘干扰斑点(前面我说过这个刻印的板子会有一些小黑点)也可以去掉感兴趣区域那的搭边斑点,所以打上勾对于整体来说是比较重要的,但是这里因为字数还不一致,不得舍弃这个重要的去干扰选项。

ocr

这里要把接受阈值分数弄的高一点,因为前面我用了 IPO 工具,让它不要与易混的字符识别错误。

在这里插入图片描述

ArrayList ab = new ArrayList();
Regex rg = new Regex("[0-9a-zA-Z]"); 
string s = ocr1.LineResult.ResultString + ocr2.LineResult.ResultString;
int length = 0;
for (int i = 0; i < s.Length; i++)
{
   if (rg.IsMatch(s[i].ToString()))
      length++;
   else
      ab.Add(i);
}

这里是为了找出一些未识别字符。

   int n = 0;
   int start = ocr1.LineResult.ResultString.Length;
   int end = s.Length + 1;
   Regex rg1 = new Regex(@"(\?)"); 
   string imagePath = @"D:\\可能NG的图片\\" + DateTime.Today.ToString("yyyy-MM-dd");
   while(n < 3)
   {
      if(length == 13 && ab.Count == 0) break;
      switch (n)
      {
        case 0:
          ipo.Operators[0].Enabled = true;
          ipo.Operators[4].Enabled = true;
          break;
        case 1:
          ipo.Operators[0].Enabled = true;
          ipo.Operators[4].Enabled = false;
          break;
        case 2:
          ipo.Operators[0].Enabled = false;
          ipo.Operators[4].Enabled = true;
          break;
      }
      ipo.Run();  blob1.Run();  ocr1.Run();  ocr2.Run();
      string s1 = ocr1.LineResult.ResultString + ocr2.LineResult.ResultString;

循环运行,打开 IPO 工具里面的参数,进行多次处理。

 		if(s1.Length == s.Length)
        {
        for (int z = 0,j = 0; z - j < ab.Count; z++)
        {
          if(!rg1.IsMatch(s1[(int) ab[z - j]].ToString()))
          {
            s = rg1.Replace(s, s1[(int) ab[z - j]].ToString(), 1, (int)ab[z-j]);
            ab.RemoveAt(z - j);
            j++;
          }
        }
      }
      else if(s1.Length > s.Length)
      {
        s = s1;
        start = ocr1.LineResult.ResultString.Length;
        end = s1.Length + 1;
        ab.Clear();
        for (int i = 0; i < s.Length; i++)
        {
          if (rg.IsMatch(s[i].ToString()))
            length++;
          else
            ab.Add(i);
        }
      }

这里的操作是可以将不同 IPO 处理识别出的字符用以替代上次识别不出来的字符。

 	  mToolBlock.Outputs["str1"].Value = s.Insert(start, "*").Insert(end, "*");
 	  CogImageFile ImageFile = new CogImageFile();
           
      if(n == 2)
      {
        length = 0;
        for (int z = 0; z < s.Length; z++)
        {
          if (rg.IsMatch(s[z].ToString()))
            length++;
        }
        if (length != 18)
        {
          CogGraphicLabel label = new CogGraphicLabel();
          label.SetXYText(300, 100 + 100 * labelList.Count, DateTime.Now.ToString());
          label.Color = CogColorConstants.Red;
          labelList.Add(label);
          
          try 
          {	        
            if(!System.IO.Directory.Exists(imagePath))
            {
              System.IO.Directory.CreateDirectory(imagePath);
            }
            ICogImage image = pma2.InputImage;
            ImageFile.Open(imagePath + "\\" + DateTime.Now.ToString("HH-mm-ss-fff") + ".bmp", CogImageFileModeConstants.Write);
            ImageFile.Append(image);
          }
          catch{}
          finally
          {
            ImageFile.Close();
          }
        }
      }
      n++;
    }
    return false;
}

保存NG图片方便调整参数。

总体上,对字符做 IPO 多次处理,是比较无奈的选择。但我却也省去了对字符多次训练的麻烦,对单个字符训练基本就是四个就OK了,不会因为一报错就要去训练字符。而且实战良率能达99.999%,跑差不多3000个不同料且字体变化才报一两个,效果良好。

兄弟姐妹们,如果觉得这篇文章能帮助到你的话,给我点点赞吧,一起成长!

  • 26
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值