当前位置: 首页 > news >正文

VisionPro联合编程相机拍照 九点标定实战

前言

机器视觉标定,也就是通常说的“手眼标定”,相机拍照的图像是基于像素坐标,而机器人用的是空间坐标系,所以手眼标定就是得到像素坐标系和机器人空间坐标系两者之间的坐标转换关系。
手眼标定的作用是,建立相机坐标系和机器人坐标系之间的变换关系,即给机器人装上眼睛,让它去哪就去哪。
为了确定像素坐标系和空间机械手坐标系的转换关系,我们介绍一种工业上广泛使用的二维手眼标定方法——九点标定法。在实际运动中,相机检测到目标在图像中的像素位置后,通过标定好的坐标转换矩阵,将相机的像素坐标,变换到机械手的空间坐标系中,然后根据机械手坐标系,计算出各个电机该如何运动,从而控制机械手到达指定位置。

九点标定就是通过九个点计算出像素坐标系到机械手坐标系下的一个仿射变换,(实际上空间中的二维平面的仿射变换只需要3个点就足够了)。在实际应用过程中,需要获取像素下特征点的坐标和对应机械手的坐标。联立方程组求解即可得到对应仿射变换的矩阵,实际应用场景主要分为眼在手上和眼在手外。
九点标定是常用的标定方法,在区域中均匀设定9个标定点,让机器人的工具末端去走这9个点得到在机器人坐标系中的坐标,同时用相机识别9个点得到像素坐标。这样就得到了9组对应的坐标,把数据代入到上述的公式中就能反推出转换系数,解得转换矩阵。
九点标定法的本质: 无需进行相机内参标定,只能识别x,y坐标,属于2D平面标定,在标定过程中z是未知的。

实现效果: 对相机拍下的物品通过图像像素坐标转换物理空间坐标 三个窗体分别是对拍的照片 找到他的像素坐标 在去九点标定工具添加九个点的像素坐标 在添加物理坐标 在计算RMS值 低于10以下就可以 

Form1代码展示

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using Microsoft.Win32;namespace 九点标定_像素坐标转换为物理坐标
{public partial class Form1 : Form{public Form1(){InitializeComponent();}CogToolBlock  tb1;CogToolBlock tb2;CogAcqFifoTool acqFifoTool;ICogAcqFifo acq { get { return acqFifoTool.Operator; } }private void 未校正TBlockToolStripMenuItem_Click(object sender, EventArgs e){Not_corrected not_Corrected = new Not_corrected(tb1);not_Corrected.Show();}private void 已校正TBlockToolStripMenuItem_Click(object sender, EventArgs e){double x = (double)tb1.Outputs["X"].Value;double y = (double)tb1.Outputs["Y"].Value;Corrected corrected = new Corrected(tb2 ,x,y);corrected.Show();}ICogImage image;private void Form1_Load(object sender, EventArgs e){//tb1 = CogSerializer.LoadObjectFromFile(@"未校正的坐标.vpp") as CogToolBlock; 9-1实验室图片//tb2 = CogSerializer.LoadObjectFromFile(@"已校正的坐标.vpp") as CogToolBlock;try{tb1 = CogSerializer.LoadObjectFromFile(@"未校正的积木坐标.vpp") as CogToolBlock;tb2 = CogSerializer.LoadObjectFromFile(@"已校正的积木坐标.vpp") as CogToolBlock;acqFifoTool = CogSerializer.LoadObjectFromFile(@"相机配置.vpp") as CogAcqFifoTool;}catch (Exception ex){MessageBox.Show("加载相机配置文件时出错:" + ex.Message);}}public CogImage8Grey myImage;private void Acq_Complete(object sender, CogCompleteEventArgs e){try{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); //获取图像cogRecordDisplay1.Image = image as CogImage8Grey;//显示图片myImage = image as CogImage8Grey;// 赋值全局图片tb1.Inputs["OutputImage"].Value = image;tb1.Run();tb2.Inputs["OutputImage"].Value = image;tb2.Run();ICogRecord record = tb2.CreateLastRunRecord().SubRecords[0];cogRecordDisplay1.Record = record;cogRecordDisplay1.Fit();}}catch (Exception){throw new Exception("采集信息失败");}}private void button1_Click(object sender, EventArgs e){if (openFileDialog1.ShowDialog() == DialogResult.OK){// 读取图像文件为位图对象Bitmap bitmap = new Bitmap(openFileDialog1.FileName);// 将位图对象转换为VisionPro的图像对象image = new CogImage8Grey(bitmap);// 设置ToolBlock的输入图像为当前选中的图像tb1.Inputs["OutputImage"].Value = image;// 将图像显示到图像控件cogRecordDisplay1.Image = image;cogRecordDisplay1.Fit();//ICogRecord record = tb2.CreateLastRunRecord().SubRecords[0];//cogRecordDisplay1.Record = record;}}private void Form1_FormClosing(object sender, FormClosingEventArgs e){CogSerializer.SaveObjectToFile(tb1,@"未校正的坐标.vpp");CogSerializer.SaveObjectToFile(tb2,@"已校正的坐标.vpp");CogSerializer .SaveObjectToFile(acqFifoTool, @"相机配置.vpp");acq?.FrameGrabber?.Disconnect(false); //false就是不创建新的}private void button2_Click(object sender, EventArgs e){if (cogRecordDisplay1.Image == null && openFileDialog1.ShowDialog() == DialogResult.OK){// 读取图像文件为位图对象Bitmap bitmap = new Bitmap(openFileDialog1.FileName);// 将位图对象转换为VisionPro的图像对象image = new CogImage8Grey(bitmap);// 设置ToolBlock的输入图像为当前选中的图像}tb2.Inputs["OutputImage"].Value = image;ICogRecord record = tb2.CreateLastRunRecord().SubRecords[2];cogRecordDisplay1.Record = record;cogRecordDisplay1.Fit();}private void button3_Click(object sender, EventArgs e){acq.StartAcquire();cogRecordDisplay1.Fit();acq.Complete += Acq_Complete;}private void 相机配置ToolStripMenuItem_Click(object sender, EventArgs e){Acq acq = new Acq(acqFifoTool);acq .Show();}}
}

未校正窗体 也就是像素坐标

已校正坐标也就是使用了九点标定工具 如下 这样得出的图片是基于物理坐标的 已经通过图像像素坐标转换和物理坐标转换 

代码展示

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Cognex.VisionPro.CalibFix;
using Cognex.VisionPro.ToolBlock;namespace 九点标定_像素坐标转换为物理坐标
{public partial class Corrected : Form{public Corrected(){InitializeComponent();}public CogToolBlock toolBlock;double x1;double y2;public Corrected(CogToolBlock cogToolBlock,double x,double y):this(){this.toolBlock = cogToolBlock;x1 = x;y2 = y;cogToolBlockEditV21.Subject=cogToolBlock;}private void button1_Click(object sender, EventArgs e){CogCalibNPointToNPointTool nPointTool = toolBlock.Tools["CogCalibNPointToNPointTool1"] as CogCalibNPointToNPointTool;// double outX = Convert.ToDouble(toolBlock.Inputs["X"].Value);//double outY = Convert.ToDouble(toolBlock.Inputs["Y"].Value);nPointTool.Calibration.AddPointPair(x1, y2, 0,0);}private void button2_Click(object sender, EventArgs e){CogCalibNPointToNPointTool nPointTool = toolBlock.Tools["CogCalibNPointToNPointTool1"] as CogCalibNPointToNPointTool;try{// 计算矫正nPointTool.Calibration.Calibrate();MessageBox.Show("计算完成,RMS误差:" + nPointTool.Calibration.ComputedRMSError);}catch (Exception ex){MessageBox.Show("计算失败:" + ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);}}}
}


文章转载自:

http://mSLxm7Om.Lsfbb.cn
http://7B3Eia40.Lsfbb.cn
http://DbKg2Wex.Lsfbb.cn
http://msAABtRs.Lsfbb.cn
http://a8STGW2M.Lsfbb.cn
http://nzp9xJ4o.Lsfbb.cn
http://se8tU5Gw.Lsfbb.cn
http://Rc7CiW9b.Lsfbb.cn
http://jWbQyxg3.Lsfbb.cn
http://bo9k3Z7Q.Lsfbb.cn
http://7vEohCjL.Lsfbb.cn
http://Gh2j96Su.Lsfbb.cn
http://b69IQ50d.Lsfbb.cn
http://JhX3EH8J.Lsfbb.cn
http://rXBhsLWr.Lsfbb.cn
http://LGoJvJC2.Lsfbb.cn
http://0rxqAvEe.Lsfbb.cn
http://eAUc2AET.Lsfbb.cn
http://ye07EDNx.Lsfbb.cn
http://yGk0RnEa.Lsfbb.cn
http://qLyKORQ8.Lsfbb.cn
http://iUVhEsaE.Lsfbb.cn
http://0417xFZ4.Lsfbb.cn
http://sEruUPP8.Lsfbb.cn
http://evz0ShVd.Lsfbb.cn
http://psvzHNVL.Lsfbb.cn
http://uTL6YnWc.Lsfbb.cn
http://HzJlNWMn.Lsfbb.cn
http://TNw69DCM.Lsfbb.cn
http://3rXUhKjg.Lsfbb.cn
http://www.dtcms.com/a/368159.html

相关文章:

  • c++工程如何提供http服务接口
  • Linux查看相机支持帧率和格式
  • 必知!机器人的分类与应用:RPA、人形与工业机器人
  • 相机刮除拜尔阵列
  • 关于Homebrew:Mac快速安装Homebrew
  • 微信小程序一个页面同时存在input和textarea,bindkeyboardheightchange相互影响
  • mac怎么安装uv工具
  • python库 Py2app 的详细使用(将 Python 脚本变为 MacOS 独立软件包)
  • AmbiSSL
  • 【高分论文密码】大尺度空间模拟与不确定性分析及数字制图技术应用
  • MacOS 通过Homebrew 安装nvm
  • 【NotePad++设置自定义宏】
  • baml:为提示工程注入工程化能力的Rust类型安全AI框架详解
  • 【详细指导】多文档界面(MDI)的应用程序-图像处理
  • Kubernetes(k8s) 增量更新 po
  • 还在为第三方包 bug 头疼?patch-package 让你轻松打补丁!
  • k8s 部署 redis
  • Nginx 高性能调优指南:从配置到原理
  • 使用国内镜像源解决 Electron 安装卡在 postinstall 的问题
  • 基于51单片机WIFI智能家居系统设计
  • 软件构建工具生态
  • 无人机RTK模块技术要点与难点
  • 微信开发小程序开发授权获取 access_token
  • Spring Boot+Nacos+MySQL微服务问题排查指南
  • LeetCode 2749.得到整数零需要执行的最少操作数:很独特的一道数学题(多公式硬讲——一步步还真能看懂)
  • 【C++】vectore
  • 柯尼卡美能达打印机SMB服务设置
  • 【VoNR】VoNR是5G语音,VoLTE是4G语音,他们是同一个IMS,只是使用了新的访问方式?
  • Android/Java 泛型全面详解
  • 国产化PDF处理控件Spire.PDF教程:如何在 Java 中通过模板生成 PDF