VisionProC#联合编程相机实战开发

前言

上章已经讲过C#连接相机的方法 本章讲一个相机实战开发示例 通过C#连接的相机拍去照片然后进行图片检测分析 结果展示窗体上 和选择指定图片显示(弹出文件夹选择) 和拍去的照片保存 以及相机参数配置窗体 和TBlock作业配置使用了Menu菜单栏

还封装了LoadVpp<T>方法 是为了以后我们加载多个vp对象 以及我们如果项目文件下没有这个vp可以重新创建vp 类型泛型

不在VisionPro创建新的vp好处: 1如果用户在不小心删除或传输文件丢失的情况 没有这个vp那我们加载这个vp就会报错 还需在VisionPro重新在创建新的vp在保存很不友好

而且当我们对不同的照片进行不同的新的工具检测可直接重新创建新的 所以如果程序运行没有原先vp 或 使用新的工具 可重新创建vp 不需在VisionPro在创建vp进行工具拖拽

界面展示

环境配置

在写程序之前我们要先配置相机保持连接正常

1..打开康耐视的配置器 把以太网改成相机的Ip 注意域名一致

相机

以太网

巨型帧: 找到你的以太网ipv4找到属性 点高级 修改9014即可

程序生成改x64

拍照检测

在拍照检测之前 我们要先加载配置好的vp方案 在创建相机配置对象工具 在监听拍完照事件 在开启拍照即可

cs 复制代码
 public CogAcqFifoTool acqFifoTool;//相机配置工具对象
 //取相机对象 从相机对象配置工具中自动获取
 ICogAcqFifo acq { get { return acqFifoTool.Operator; } }
  //因为有时创建新的vp会用之前的 所以要减去事件在重新走事件 不然会触发多次
  acq.StartAcquire();
  cogRecordDisplay1.Fit();
  acq.Complete -= Acq_Complete;
  acq.Complete += Acq_Complete;
 private void Acq_Complete(object sender, CogCompleteEventArgs e)
 {
     //注意:这个拍完照事件是在分线程执行的 因此对控件的操作无效 必须使用BeginInvoke或 Invoke 是VisionPro封装的方法 有时候我们会出现卡退的问题但没有报错 其实就是已经报错了
     //拍照完成的事件触发 
     //取相
     int numPending, numReady;//等待状态,准备状态
     bool isBusy;//繁忙状态
     acq.GetFifoState(out numPending,out numReady,out isBusy);
     if (numReady > 0) //判断相机是否准备好
     {
         CogAcqInfo info = new CogAcqInfo();//创建acqinfo对象
         ICogImage image = acq.CompleteAcquireEx(info);//获取图像
         //因为我们有的是拍照检测和选择图片检测 所以创建一个方法传入不同图片
         ImageParcamer(image);
         //cogRecordDisplay1.Image=image as CogImage8Grey;//显示图片
         // myImage = image as CogImage8Grey;//赋值全局图片
         //cogRecordDisplay1.Fit()//;自适应
     }
     MessageBox.Show("拍照完成");

因为项目有拍取图片检测和选择图片 所以封装了一个方法 参数图片

cs 复制代码
  private void ImageParcamer(ICogImage img)
  {
      //InvokeRequired 当这个属性为true 表示当前不在主线程 要对控件的操作必须使用BeginInvoke或者Invoke
      //如果需要调用BeginInvoke或者Invoke
      //他俩区别BeginInvoke是不等待其他线程直接运行到底也就是不会卡线程 Invoke是等待上一个线程完成在执行下一步
      //所以我们需要使用Invoke 不然对象为空就会程序卡退
      if (InvokeRequired)
      {
          //使用Invoke重新执行当前方法
          Invoke(new Action(() =>
          {
              ImageParcamer(img);
          }));
      }
      try
      {
          //展示图像
          cogRecordDisplay1.Image = img;
          cogRecordDisplay1.Fit();//图像根据控件大小适应
          toolBlock.Inputs["OutputImage"].Value=img;//给图片赋值
          toolBlock.Run();//运行ToolBlock
          //获取ToolBlock的运行状态
        //  ICogRunStatus status=toolBlock.RunStatus;
          //如果运行状态的代码不等于 "接受"则说明ToolBlock 运行出现错误
         // if (status.Result != CogToolResultConstants.Accept)
        //  {
              //MessageBox.Show(status.Message);//显示运行状态的提示信息
             // return;
         // }
        //显示运行结果
      ICogRecord record = toolBlock.CreateLastRunRecord().SubRecords[0];
      cogRecordDisplay1.Record = record;
      cogRecordDisplay1.Fit();
          if (toolBlock.Outputs["R"].Value != null && toolBlock.Outputs["Count"].Value!=null) //这是根据你的vp有多少个输出参数进行判断 可自己设置多个
          {
              //更新结果
              label4.Text = ((double)toolBlock.Outputs["R"].Value).ToString("F2");
              //第二种写法 VisionPro写法
              //(工具类型)CogBobTool blob(CogBobTool)toolBlock.Tools["CogBobTool1"]
              label5.Text = toolBlock.Outputs["Count"].Value.ToString(); ;
          }
      }

      catch (Exception ex) 
      {
          MessageBox.Show("采集信息识别"+ex.Message);
      }
  }

选择图像并识别

cs 复制代码
 //选择图片识别
 private void button2_Click(object sender, EventArgs e)
 {
     if (openFileDialog1.ShowDialog() == DialogResult.OK)
     {
         Bitmap bitmap=new Bitmap(openFileDialog1.FileName);
         ICogImage image= new CogImage8Grey(bitmap);
         ImageParcamer(image);
         cogRecordDisplay1.Fit();
     }
 }

实时预览

cs 复制代码
  private void button3_Click(object sender, EventArgs e)
  {
      cogRecordDisplay1.StartLiveDisplay(acq);
  }

保存图片

cs 复制代码
   private void button4_Click(object sender, EventArgs e)
   {
       if (cogRecordDisplay1.Image != null)
       {
           // 改用绝对路径(或确认相对路径有效),优先推荐系统临时目录/程序可写路径
           string saveDir = Path.Combine(Application.StartupPath, "Debug");
           // 确保文件夹存在(关键!)
           Directory.CreateDirectory(saveDir);

           string fileName = textBox1.Text.Trim();
           // 过滤非法字符(避免文件名含 \ / : * ? " < > | 等)
           fileName = Regex.Replace(fileName, @"[^\w\.]", "");
           string savePath = Path.Combine(saveDir, $"{fileName}.png");

           try
           {
               cogRecordDisplay1.Image.ToBitmap().Save(savePath);
               MessageBox.Show("保存成功");
               this.textBox1.Text = null;
           }
           catch (Exception ex)
           {
               // 详细报错,替代原来的静默异常
               MessageBox.Show($"保存失败:{ex.Message}\n路径:{savePath}", "错误",
                               MessageBoxButtons.OK, MessageBoxIcon.Error);
           }
       }
       else
       {
           MessageBox.Show("图像数据无效,无法保存");
       }
   }

窗体加载事件 加载的相机参数配置vp和TBlock vp

在这封装了LoadVpp方法当我们需要加载多个vp的时候直接创建对应的类型即可 类型是泛型

cs 复制代码
 private void Form1_Load(object sender, EventArgs e)
 {
     //窗体加载事件之后读取两个vpp
         acqFifoTool = CogSerializer.LoadObjectFromFile(Settings.CameraPath) as CogAcqFifoTool;
         toolBlock = CogSerializer.LoadObjectFromFile(Settings.TBpath) as CogToolBlock;
 
    // acqFifoTool =LoadVpp<CogAcqFifoTool>(Settings.CameraPath);
   // toolBlock = LoadVpp<CogToolBlock>(Settings.TBpath) ;
    
 }
 //封装这个方法 是为了以后我们加载多个vp对象 以及我们如果项目文件下没有这个vp可以重新创建vp
 //不在VisionPro创建新的vp好处: 1如果用户在不小心删除或传输文件丢失的情况 没有这个vp那我们加载这个vp就会报错 还需在VisionPro重新在创建新的vp在保存很不友好
 //而且当我们对不同的照片进行不同的新的工具检测可直接重新创建新的 所以如果程序运行没有原先vp 或 使用新的工具 可重新创建vp 不需在VisionPro在创建vp进行工具拖拽
 /// <summary>
 /// 用于加载vpp方法
 /// </summary>
 /// <typeparam name="T">vpp类型</typeparam>
 /// <param name="path">vpp路径</param>
 /// <returns>该类型的vsionPro对象</returns>
 //private T LoadVpp<T>(string path) where T : class, new()
 //{
 //    try
 //    {
 //        return CogSerializer.LoadObjectFromFile(Settings.TBpath) as T;
 //    }
 //    catch
 //    {
 //        return new T();
 //    }
 //}

相机参数配置窗体

在这里我们传的主窗体的vp 不需要在新窗体在创建 不然降低性能损耗以及创建新的等问题

好处:整个程序就用这一个对象 既能降低性能损耗 不会出现问题等 相当于单例模式 一个程序运用同一个类 (前几章火花塞的项目之前说过加载TBlock编辑窗体的时候保持程序使用同一个vpp)

cs 复制代码
  private void 相机配置ToolStripMenuItem_Click(object sender, EventArgs e)
  {
      EditAcg editAcg = new EditAcg(acqFifoTool);
      editAcg.Show();
  }

cogAcqFifoEditV21控件

注:有时候会初始化失败 会弹窗警告 等待一会再去选择 或者一直点 就行

这种情况重新运行就好了 或者从新配置就会一直弹警告

cs 复制代码
  //接收传递参数
  public EditAcg(CogAcqFifoTool acqFifoTool):this()
  {
    
      cogAcqFifoEditV21.Subject = acqFifoTool;
  }

TBlock作业窗体

cs 复制代码
 private void toolBlock配置ToolStripMenuItem_Click(object sender, EventArgs e)
 {
     EditTB editTB = new EditTB(toolBlock);
      editTB.Show();
 }
cs 复制代码
 public EditTB(CogToolBlock toolBlock):this()
 {
     cogToolBlockEditV21.Subject = toolBlock;
 }

效果展示

完整代码

cs 复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;

namespace VisionPro相机联合编程开发
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public CogToolBlock toolBlock; //ToolBlock作业对象
        public CogAcqFifoTool acqFifoTool;//相机配置工具对象
        //取相机对象 从相机对象配置工具中自动获取
        ICogAcqFifo acq { get { return acqFifoTool.Operator; } }
        private void Form1_Load(object sender, EventArgs e)
        {
            //窗体加载事件之后读取两个vpp
                acqFifoTool = CogSerializer.LoadObjectFromFile(Settings.CameraPath) as CogAcqFifoTool;
                toolBlock = CogSerializer.LoadObjectFromFile(Settings.TBpath) as CogToolBlock;
        
           // acqFifoTool =LoadVpp<CogAcqFifoTool>(Settings.CameraPath);
          // toolBlock = LoadVpp<CogToolBlock>(Settings.TBpath) ;
           
        }
        //封装这个方法 是为了以后我们加载多个vp对象 以及我们如果项目文件下没有这个vp可以重新创建vp
        //不在VisionPro创建新的vp好处: 1如果用户在不小心删除或传输文件丢失的情况 没有这个vp那我们加载这个vp就会报错 还需在VisionPro重新在创建新的vp在保存很不友好
        //而且当我们对不同的照片进行不同的新的工具检测可直接重新创建新的 所以如果程序运行没有原先vp 或 使用新的工具 可重新创建vp 不需在VisionPro在创建vp进行工具拖拽
        /// <summary>
        /// 用于加载vpp方法
        /// </summary>
        /// <typeparam name="T">vpp类型</typeparam>
        /// <param name="path">vpp路径</param>
        /// <returns>该类型的vsionPro对象</returns>
        //private T LoadVpp<T>(string path) where T : class, new()
        //{
        //    try
        //    {
        //        return CogSerializer.LoadObjectFromFile(Settings.TBpath) as T;
        //    }
        //    catch
        //    {
        //        return new T();
        //    }
        //}

        //相机配置界面
        private void 相机配置ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //在这里我们传的主窗体的vp 不需要在新窗体在创建 不然降低性能损耗以及创建新的等问题
            //好处:整个程序就用这一个对象 既能降低性能损耗 不会出现问题等 相当于单例模式 一个程序运用同一个类
            EditAcg editAcg = new EditAcg(acqFifoTool);
            editAcg.Show();
        }
        //作业界面
        private void toolBlock配置ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            EditTB editTB = new EditTB(toolBlock);
             editTB.Show();
        }
        //拍照
        private void button1_Click(object sender, EventArgs e)
        {
            // 停止实时预览
           // cogRecordDisplay1.StopLiveDisplay();
            //监听拍完照事件
            //因为有时创建新的vp会用之前的 所以要减去事件在重新走事件 不然会触发多次
            acq.StartAcquire();
            cogRecordDisplay1.Fit();
            acq.Complete -= Acq_Complete;
            acq.Complete += Acq_Complete;
        }
        public CogImage8Grey myImage;
        private void Acq_Complete(object sender, CogCompleteEventArgs e)
        {
            //注意:这个拍完照事件是在分线程执行的 因此对控件的操作无效 必须使用BeginInvoke或 Invoke 是VisionPro封装的方法 有时候我们会出现卡退的问题但没有报错 其实就是已经报错了
            //拍照完成的事件触发 
            //取相
            int numPending, numReady;//等待状态,准备状态
            bool isBusy;//繁忙状态
            acq.GetFifoState(out numPending,out numReady,out isBusy);
            if (numReady > 0) //判断相机是否准备好
            {
                CogAcqInfo info = new CogAcqInfo();//创建acqinfo对象
                ICogImage image = acq.CompleteAcquireEx(info);//获取图像
                //因为我们有的是拍照检测和选择图片检测 所以创建一个方法传入不同图片
                ImageParcamer(image);
                //cogRecordDisplay1.Image=image as CogImage8Grey;//显示图片
                // myImage = image as CogImage8Grey;//赋值全局图片
                //cogRecordDisplay1.Fit()//;自适应
            }
            MessageBox.Show("拍照完成");
        }
        //选择图片识别
        private void button2_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                Bitmap bitmap=new Bitmap(openFileDialog1.FileName);
                ICogImage image= new CogImage8Grey(bitmap);
                ImageParcamer(image);
                cogRecordDisplay1.Fit();
            }
        }

        private void ImageParcamer(ICogImage img)
        {
            //InvokeRequired 当这个属性为true 表示当前不在主线程 要对控件的操作必须使用BeginInvoke或者Invoke
            //如果需要调用BeginInvoke或者Invoke
            //他俩区别BeginInvoke是不等待其他线程直接运行到底也就是不会卡线程 Invoke是等待上一个线程完成在执行下一步
            //所以我们需要使用Invoke 不然对象为空就会程序卡退
            if (InvokeRequired)
            {
                //使用Invoke重新执行当前方法
                Invoke(new Action(() =>
                {
                    ImageParcamer(img);
                }));
            }
            try
            {
                //展示图像
                cogRecordDisplay1.Image = img;
                cogRecordDisplay1.Fit();//图像根据控件大小适应
                toolBlock.Inputs["OutputImage"].Value=img;//给图片赋值
                toolBlock.Run();//运行ToolBlock
                //获取ToolBlock的运行状态
              //  ICogRunStatus status=toolBlock.RunStatus;
                //如果运行状态的代码不等于 "接受"则说明ToolBlock 运行出现错误
               // if (status.Result != CogToolResultConstants.Accept)
              //  {
                    //MessageBox.Show(status.Message);//显示运行状态的提示信息
                   // return;
               // }
              //显示运行结果
            ICogRecord record = toolBlock.CreateLastRunRecord().SubRecords[0];
            cogRecordDisplay1.Record = record;
            cogRecordDisplay1.Fit();
                if (toolBlock.Outputs["R"].Value != null && toolBlock.Outputs["Count"].Value!=null) //这是根据你的vp有多少个输出参数进行判断 可自己设置多个
                {
                    //更新结果
                    label4.Text = ((double)toolBlock.Outputs["R"].Value).ToString("F2");
                    //第二种写法 VisionPro写法
                    //(工具类型)CogBobTool blob(CogBobTool)toolBlock.Tools["CogBobTool1"]
                    label5.Text = toolBlock.Outputs["Count"].Value.ToString(); ;
                }
            }

            catch (Exception ex) 
            {
                MessageBox.Show("采集信息识别"+ex.Message);
            }
        }
        //关闭窗体事件 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //保存Vpp 不需要在编辑窗体保存 因为我们整个程序用的是同一个
            CogSerializer.SaveObjectToFile(acqFifoTool,Settings.CameraPath);
            CogSerializer.SaveObjectToFile(toolBlock,Settings.TBpath);
            //释放相机资源
            //先判断有没有这个对象 不然就会释放不掉 报错
            acq?.FrameGrabber?.Disconnect(false); //false就是不创建新的
        }
        //实时预览
        private void button3_Click(object sender, EventArgs e)
        {
            cogRecordDisplay1.StartLiveDisplay(acq);
        }
        //保存图片
        private void button4_Click(object sender, EventArgs e)
        {
            if (cogRecordDisplay1.Image != null)
            {
                // 改用绝对路径(或确认相对路径有效),优先推荐系统临时目录/程序可写路径
                string saveDir = Path.Combine(Application.StartupPath, "Debug");
                // 确保文件夹存在(关键!)
                Directory.CreateDirectory(saveDir);

                string fileName = textBox1.Text.Trim();
                // 过滤非法字符(避免文件名含 \ / : * ? " < > | 等)
                fileName = Regex.Replace(fileName, @"[^\w\.]", "");
                string savePath = Path.Combine(saveDir, $"{fileName}.png");

                try
                {
                    cogRecordDisplay1.Image.ToBitmap().Save(savePath);
                    MessageBox.Show("保存成功");
                    this.textBox1.Text = null;
                }
                catch (Exception ex)
                {
                    // 详细报错,替代原来的静默异常
                    MessageBox.Show($"保存失败:{ex.Message}\n路径:{savePath}", "错误",
                                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
            {
                MessageBox.Show("图像数据无效,无法保存");
            }
        }
    }
}
相关推荐
listhi5206 小时前
C# 操作 Excel
c#·excel·mfc
要做朋鱼燕6 小时前
【C++ 】string类:深拷贝与浅拷贝解析
java·开发语言·c++·职场和发展
c#上位机6 小时前
wpf之WrapPanel
c#·wpf
~央千澈~7 小时前
Objective-C 的坚毅与传承:在Swift时代下的不可替代性优雅草卓伊凡
开发语言·ios·objective-c
不做超级小白8 小时前
Python os.makedirs 报错:OSError: [WinError 123] 文件名、目录名或卷标语法不正确 的解决方案
开发语言·python·学习
Joy-鬼魅8 小时前
Qt 项目文件(.pro)中添加 UI 文件相关命令
开发语言·qt·ui
zimoyin8 小时前
C# FlaUI win 自动化框架,介绍
microsoft·c#·自动化
c#上位机8 小时前
wpf之StackPanel
c#·wpf
钢铁男儿8 小时前
【C#实战】使用ListBox控件与生成器模式构建灵活多变的金融资产管理系统
开发语言·c#