Winform常用方法封装

 1、定时器用法                 

System.windows.Forms.Timer 占用主线程(常用)
System.Timers.Timer 占用子线程(常用)
System.Threading.Timer 占用子线程

 System.windows.Forms.Timer用法
private void timer1_Tick(object sender, EventArgs e)
        {
            //获得时间,并把时间显示在lab上
            string s = DateTime.Now.ToString();  //当前时间转为字符串
            this.lb_ShowTimeNow.Text = s;  //赋值给显示时间的lab的text属性
        }

System.Timers.Timer 用法
1. 首先,在你的代码中引入 System.Timers 命名空间
using System.Timers;
2. 创建一个 System.Timers.Timer 对象,并设置其间隔时间(以毫秒为单位)
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000; // 设置为每秒触发一次
3. 定义一个事件处理方法,该方法将在定时器触发时执行(子线程执行)
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
// 在这里编写定时器触发时要执行的代码
}
4、 将事件处理方法与定时器的 Elapsed 事件关联起来
timer.Elapsed += Timer_Elapsed;
5、启动定时器
timer.Start();
6. 如果需要停止定时器,可以使用 Stop 方法:
timer.Stop();

2、日志用法封装

 控件:listview(存放日志)
属性:
View: Details(细节显示)HeadStyle不能为None    如果想隐藏 把HeadStyle改成None
SmallImageList:选择添加哪个imagelist组件         
 Columns:添加列成员      FullRowSelect(是否支持当前选中行)
public void AddLog(int index, string log1)  //(新建方法)参数:索引号(图片索引),日志内容
        {
            if (lv_Log.InvokeRequired)   //返回值为true就是在不同线程创建
            {
                Invoke(new Action(() =>
                {
                    ListViewItem lvi = new ListViewItem(DateTime.Now.ToString(), index);  //第1列日志时间显示,附带图标index
                    lvi.SubItems.Add(log1);  //第2列添加日志内容
                    //lvi.SubItems.Add(log2);  //如果日志显示3列,在这里写后一列再次新增一列,参数加一个日志内容 log2
                    lvi.ForeColor = GetColorByIndex(index);  //根据图片索引改变颜色
                    lv_Log.Items.Insert(0, lvi);  //在listview插入日志信息,每次插入在第一行
                }));
            }
            else
            {
                ListViewItem lvi = new ListViewItem(DateTime.Now.ToString(), index);  //第1列日志时间显示,附带图标index
                lvi.SubItems.Add(log1);  //第2列添加日志内容
                //lvi.SubItems.Add(log2);  //如果日志显示3列,在这里写后一列再次新增一列,参数加一个日志内容 log2
                lvi.ForeColor = GetColorByIndex(index);  //根据图片索引改变颜色
                lv_Log.Items.Insert(0, lvi);  //在listview插入日志信息,每次插入在第一行
            }

        }
        public Color GetColorByIndex(int index)  //根据图片索引改变颜色
        {
            switch (index)
            {
                case 0:
                    return Color.Black;
                    case 1:
                    return Color.Red;
                    default: 
                    return Color.White;
            }
        }

 //在日志找某个内容并删除
            //foreach (ListViewItem item in lv_Log.Items)  //判断item是否在lv_Log这个日志里
            //{
            //    if (item.SubItems[1].Text=="串口通讯被加载")  //第2列有没有这个内容
            //    {
            //        MessageBox.Show("找到");  //显示消息窗口  提示找到了
            //        lv_Log.Items.Remove(item);  //移除这行消息
            //    }
            //}

// 清空日志
        private void button5_Click(object sender, EventArgs e)
        {
            lv_Log.Items.Clear();
        }

3、子窗体显示方法

子窗体在主窗体里面
 private void ShowChaildForm(Form fr)  //封装子窗体方法,参数是子窗体的对象
        {
            pl_Parent.Controls.Clear();  //打开这个控件前先清除里面内容
            fr.TopLevel = false;  //是否将窗体设为顶层窗口
            fr.Parent = this.pl_Parent;  //设置TCP窗口的父容器
            fr.Dock = DockStyle.Fill;  //设置停靠位置充满
            //this.pl_Parent.SetBounds(0, 0, tcpWindowsForm.Width, tcpWindowsForm.Height);
            fr.Show();  //最后显示窗体
        }

打开新的子窗体
Form2 form2=new Form2();  //成员new一个子窗体对象
form2.Show();  //点击控件显示

4、关闭窗体

 private void button1_Click(object sender, EventArgs e)  //按钮点击时退出窗体
        {
            if (MessageBox.Show("是否确定退出", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
            {
                this.Close();  //或者写下一个
                Process.GetCurrentProcess().Kill();
                this.Hide();  隐藏窗口
            }
        }

5、移动无框窗体

字段:
    private bool isDown = false;  //鼠标是否按下
    private Point pointMouse;

#region 按下鼠标   //在控件的 MouseDown 事件中写代码
        private void lb_Title_MouseDown(object sender, MouseEventArgs e)
        {
            if (!isDown)
            {
                pointMouse = new Point(-e.X, -e.Y);  //获取窗体移动距离
                isDown = true;
            }
        }
        #endregion
        #region 松开鼠标  //在控件的 MouseUp 事件中写代码
        private void lb_Title_MouseUp(object sender, MouseEventArgs e)
        {
            if (isDown)
            {
                isDown = false;
            }
        }
        #endregion
        #region 移动鼠标  //在控件的 MouseMove 事件中写代码
        private void lb_Title_MouseMove(object sender, MouseEventArgs e)
        {
            if (isDown)
            {
                Point CurrentPoint = Control.MousePosition;  //移动后位置
                CurrentPoint.Offset(pointMouse);
                this.Location = CurrentPoint;  //窗体位置设为移动后位置
            }
        }
        #endregion

6、循环展示图片

控件:Timer(enabled使能为ture)    pictureBox
    准备一个图片文件夹放在bin文件夹里面
    字段:
    string[] imageUrl;  //定义一个图片的数组
    int index = 0;  //索引全局变量:用来迭代下一张,如果到了最后一张,就从第一张开始

构造函数写代码:
    //获取指定文件夹下的所有图片集合,
        imageUrl = System.IO.Directory.GetFiles("./autobahn");
        //指定显示第一张图片
        this.pictureBox1.ImageLocation = imageUrl[index];
    
     private void timer1_Tick(object sender, EventArgs e)  //定时器Tick事件
        {
            if (index < imageUrl.Length)  //判断是否达到最大值,没有继续下一张
            {
                this.pictureBox1.ImageLocation = imageUrl[index++];
            }
            else
            {
                index = 0;
                this.pictureBox1.ImageLocation = imageUrl[index++];
            }
        }

7、一个窗体展示完展示下一个窗体

比如,一个进度条窗体,进度条加载完(this.DialogResult = DialogResult.OK),展示登录窗体,点击登录,登录成功展示主窗体
    主程序mian方法里代码
            LoadForm loadForm = new LoadForm();  //加载窗体
            if (loadForm.ShowDialog() == DialogResult.OK)  //如果窗体返回值是OK
            {
                //登录窗体
                LoginForm loginForm = new LoginForm();
                if (loginForm.ShowDialog() == DialogResult.OK)
                {
                    //主窗体
                    Application.Run(new MainForm());
                }
            }

进度条窗体:两个panel容器,一个label显示 ''加载中...'',两个timer计时器(enabled使能为ture)
     private void timer1_Tick(object sender, EventArgs e)  //计时器1判断进度条
        {
            this.panel2.Width += 10;  //叠加进度条
            //判断达到最大值,就停止计时器
            if (this.panel2.Width > this.panel1.Width)
            {
                this.DialogResult= DialogResult.OK;
                this.timer1.Stop();
            }

        }

        //叠加次数
        int count = 0;
        private void timer2_Tick(object sender, EventArgs e)  //计时器2循环加.
        {
            this.label3.Text += ".";
            count++;
            if (count>=6)  //判断次数大于6次,回原继续
            {
                this.label3.Text = "下载中";
                count=0;
            }
            if (this.DialogResult==DialogResult.OK)
            {
                this.label3.Text = "加载成功";
                this.timer2.Stop();
            }
        }

登录窗口:
     private void button1_Click(object sender, EventArgs e)  //登录按钮
        {
            //这里写判断账号代码
            this.DialogResult = DialogResult.OK;  //窗体返回值(确定)
        }
     private void pictureBox2_Click(object sender, EventArgs e)  //取消按钮
        {
            this.DialogResult = DialogResult.Cancel;  //窗体返回值(取消)
        }

 8、获取随机颜色方法

static Color[] allColor = { Color.Pink, Color.Black, Color.Gray, Color.Brown, Color.Red, Color.LightCoral, Color.OrangeRed,         Color.Sienna, Color.Peru, Color.Orange, Color.DarkOrange, Color.Olive, Color.Yellow, Color.OliveDrab, Color.DarkOliveGreen, Color.Green, Color.ForestGreen, Color.Lime, Color.DarkGreen, Color.SpringGreen, Color.LightSeaGreen, Color.Teal, Color.Cyan, Color.Blue, Color.Indigo, Color.DeepPink, Color.Crimson }; 
        public static Color RandonColor()
        {
            Random rnd = new Random();
            int colorNum = rnd.Next(0, 27);
            return allColor[colorNum];
        }

9、CRC-16校验--返回一个字节数组(两个字节)

用法:
接收校验:接收字节 byte[] byte=[01 03 04 02 c8 01 BA 20]    验证CRC校验位前的数据 (01 03 04 02 c8 01)
    收到一个字节数组byte,验证前面7位返回的字节是不是和校验位一样
    byte[] crc16 = Crc16(byte,7)
    if(crc16[0]==byte[lenth-2]&&crc16[1]==byte[lenth-1])  --如果位true则校验通过
发送校验:发送字节 byte[] byte=[01 03 04 02 c8 01 ]
                byte[] crc16 = Crc16(byte,byte.Lenth)  获取校验位值
                把byte和crc16放到一个集合再转数组发送

private static readonly byte[] aucCRCHi = {
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40
         };
        private static readonly byte[] aucCRCLo = {
             0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
             0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
             0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
             0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
             0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
             0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
             0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
             0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
             0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
             0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
             0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
             0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
             0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
             0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
             0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
             0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
             0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
             0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
             0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
             0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
             0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
             0x41, 0x81, 0x80, 0x40
         };
        private byte[] Crc16(byte[] pucFrame, int usLen)
        {
            int i = 0;
            byte[] res = new byte[2] { 0xFF, 0xFF };

            UInt16 iIndex = 0x0000;

            while (usLen-- > 0)
            {
                iIndex = (UInt16)(res[0] ^ pucFrame[i++]);
                res[0] = (byte)(res[1] ^ aucCRCHi[iIndex]);
                res[1] = aucCRCLo[iIndex];
            }
            return res;
        }

10、工厂反射用法

 一般用法是写一个接口类抽象实现相机的基础功能,再写具体的相机类继承接口类实现功能,工厂类静态方法返回接口类对象(实际返回的子对象,也就是具体的相机类对象),对象调用接口方法实现不同相机的具体功能
//返回配置文件对应的value值
using System.Reflection;
using System.Configuration;
添加引用---选程序集--添加System.Configuration

       static string assName = ConfigurationManager.AppSettings["assName"];  //程序集名
       static string className = ConfigurationManager.AppSettings["className"];  //命名空间.类名

        public static ICam CreatrICam()
        {
            return  (ICam )Assembly.Load(assName).CreateInstance(className);  //通过程序集名和类名,返回对应实例对象
            //Assembly.LoadForm(assName).CreateInstance(className);  //LoadForm(),加载程序集路径,也可以使用
        }

<appSettings>
<add key="assName" value="CameraDo"/>  //可以写绝对路径
<add key="className" value="CameraDo.MVCamera"/>
</appSettings>

11、保存

// 检查是否有图像可保存
            if (ho_BImageBGR1 == null)
            {
                MessageBox.Show("没有可保存的图像");
                return;
            }

            // 选择保存文件的路径和文件名
            SaveFileDialog saveFileDialog = new SaveFileDialog();  //路径
            saveFileDialog.Filter = "JPEG图像|*.jpg";  //文件名
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                // 保存图像
                HOperatorSet.WriteImage(ho_BImageBGR1, "jpeg", 0, saveFileDialog.FileName);
                MessageBox.Show("图像保存成功");
            }

12、最大化最小化

        #region 最大化
        private void btn_WindowMax_Click(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Normal)  //如果窗口是默认大小窗口
            {
                this.WindowState = FormWindowState.Maximized;  //最大化窗口
                btn_WindowMax.BackgroundImage = 四轴贴合机604.Properties.Resources.最大化;  //更换图标
                btn_WindowMax.BackgroundImageLayout = ImageLayout.Zoom;
                imagepss.OpenWindow(pb_ImageShow.Width, pb_ImageShow.Height, pb_ImageShow.Handle);  //打开窗口
            }
            else
            {
                this.WindowState = FormWindowState.Normal;  //默认大小窗口
                btn_WindowMax.BackgroundImage = 四轴贴合机604.Properties.Resources.最大化__1_;  //更换图标
                btn_WindowMax.BackgroundImageLayout = ImageLayout.Zoom;
                imagepss.OpenWindow(pb_ImageShow.Width, pb_ImageShow.Height, pb_ImageShow.Handle);  //打开窗口
            }
        }
        #endregion
        #region 最小化
        private void btn_MinWindow_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;  //最小化窗口
        }
        #endregion

13、保存页面参数

第三方工具放一个类

把读参数和写参数封装起来
 #region 读入配置文件
        private void ReadIniFile()
        {
            if (!File.Exists("13.ini"))
            {

                AddLog(0, "配置文件不存在 ");
                return;
            }
            txt_StartSpeed.Text = IniFileConfigHelper.ReadIniData("运动参数", "初始速度", "", Application.StartupPath + "\\13.ini");
            txt_MaxSpeed.Text = IniFileConfigHelper.ReadIniData("运动参数", "最大速度", "", Application.StartupPath + "\\13.ini");
            txt_Dec.Text = IniFileConfigHelper.ReadIniData("运动参数", "加减时间", "", Application.StartupPath + "\\13.ini");
        }
        #endregion


        #region 写入配置文件
        public void SaveIniFile()
        {
            if (!File.Exists("13.ini"))  
            {
                FileStream fs = new FileStream("13.ini", FileMode.Create);
                fs.Close();
            }


            //要确保你有这个文件(ini)
            bool res = true;                         //  Application.StartupPath(获得exe文件的根目录)
            res &= IniFileConfigHelper.WriteIniData("运动参数", "初始速度", txt_StartSpeed.Text, Application.StartupPath + "\\13.ini");
            res &= IniFileConfigHelper.WriteIniData("运动参数", "最大速度", txt_MaxSpeed.Text, Application.StartupPath + "\\13.ini");
            res &= IniFileConfigHelper.WriteIniData("运动参数", "加减时间", txt_Dec.Text, Application.StartupPath + "\\13.ini");
            res &= IniFileConfigHelper.WriteIniData("报警参数", "初始速度", "500", Application.StartupPath + "\\13.ini");
            res &= IniFileConfigHelper.WriteIniData("报警参数", "最大速度", "1000", Application.StartupPath + "\\13.ini");
            res &= IniFileConfigHelper.WriteIniData("报警参数", "加减时间", "500", Application.StartupPath + "\\13.ini");
        }
        #endregion

分别在窗体关闭时调用(SaveIniFile() 写入配置文件),构造函数调用(ReadIniFile()读入配置文件)

14、日志溯源

资料位置:D:\日志溯源dll库
1、拷贝dll库bin下 并且添加引用log4net.dll
2、添加 log4net.config文件到你的工程目录下 (直接赋值到项目下面)  设置成始终复制(右键-属性-设置为始终复制) 在bin下要有这个文件,没有复制一份
3、AssemblyInfo.cs文件中(在Properties) 增加一句
[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", ConfigFileExtension = "config", Watch = true)]
4、添加一个类(LogHelper.cs)到你的工程目录下
前面四步已经在通用框架封装好了,直接调用第5步就行
5、在打印日志方法后面调用   LogHelper.Info("正确日志")   LogHelper.Error("错误日志")
日志文件夹生成在bin--debug文件夹下

15、PictureBox组件和hWindowControl组件显示图像区别

PictureBox组件需要先打开窗口设置为图片宽高和句柄,再显示
        cam.GrabImage(out image, cam.SureCamHandle(0));  //采图
        imagepss.OpenWindow(pb_ImageShow.Width, pb_ImageShow.Height,pb_ImageShow.Handle);  //打开窗口
        imagepss.ShowImage(image);  //显示图像
hWindowControl组件只需要填组件句柄,不需要打开新窗口
        cam.GrabImage(out image, cam.GetCam(0));    //相机采图
        impro.ImageShow(image, hWindowControl1.HalconWindow);  //显示图片

16、验证字符串格式

public static bool TryParse(string s, out Int32 result);
用法:
int a= 0;
if (int.TryParse(s, out a)==false)    //将字符串s的值解析为整数。如果解析失败,返回false
{
        错误提示
}
一般int,double类型用的比较多

17、标定常用技巧

平移旋转缩放补偿

触发条件:标定位和拍照位不在同一位置,在标定位九点标定
1、只发生平移
先算出标定位到拍照位的平移矩阵,再用拍照位识别出mark点的实际坐标*这个矩阵得到新的坐标
10  10  0  0  标定位
20   20  0  0  拍照位   拍照位实际坐标Qx,Qy

hom_mat2d_identity (HomMat2DIdentity)  //生成一个空矩阵
hom_mat2d_translate (HomMat2DRotate, 20-10, 20-10,HomMat2DTranslate)  //平移矩阵
affine_trans_point_2d (HomMat2DTranslate, Qx, Qy, Qxnew, Qynew)  //实际坐标*矩阵
Qxnew, Qynew发给机器人

2、只发生旋转
先算出标定位到拍照位的旋转矩阵,再用拍照位识别出mark点的实际坐标*这个矩阵得到新的坐标
10  10  0  50  标定位
10   10  0  80  拍照位   拍照位实际坐标Qx,Qy

 hom_mat2d_identity (HomMat2DIdentity)
hom_mat2d_rotate (HomMat2DIdentity,80-50,10 ,10, HomMat2DRotate)
affine_trans_point_2d (HomMat2DRotate, Qx, Qy, Qxnew, Qynew)

3、旋转+平移
先算出标定位到拍照位的旋转平移矩阵,再用拍照位识别出mark点的实际坐标*这个矩阵得到新的坐标
10  10  0  50  标定位
20   20  0  80  拍照位   拍照位实际坐标Qx,Qy

矩阵先旋转再平移,这是旋转中心是标定位(常用)
hom_mat2d_identity (HomMat2DIdentity)
hom_mat2d_rotate (HomMat2DIdentity,80-50,10 ,10, HomMat2DRotate)//旋转矩阵
hom_mat2d_translate (HomMat2DRotate, 20-10, 20-10, HomMat2DTranslate)//平移矩阵
affine_trans_point_2d (HomMat2DTranslate, Qx, Qy, Qxnew, Qynew)

矩阵先平移再旋转,这是旋转中心是拍照位
hom_mat2d_identity (HomMat2DIdentity)
hom_mat2d_translate (HomMat2DRotate, 20-10, 20-10, HomMat2DTranslate)//平移矩阵
hom_mat2d_rotate (HomMat2DIdentity,80-50,20 ,20, HomMat2DRotate)//旋转矩阵
affine_trans_point_2d (HomMat2DTranslate, Qx, Qy, Qxnew, Qynew)

高度变化补偿

触发条件:标定位和拍照位不在同一高度,在标定位九点标定
标定位高度10mm,拍照位高度变化
1、先求出标定位mark点像素坐标 Row1  Column1
2、再求出拍照位mark点像素坐标 Row2  Column2
3、计算拍照位mark点到标定位mark点仿射变换矩阵
vector_to_hom_mat2d (Row2  , Column2, Row1  , Column1, HomMat2DGo)
4、在拍照位拍照后先把像素点变换到标定位的位置,再用标定位的九点矩阵,这样就不用加偏差了

18、斜拍

1、首先斜着标定,标定第一张图片标定板坐标系要是正的

然后标定得到内外参
2、设置标定板描述文件
gen_caltab (7, 7, 0.004, 0.5, 'D:/实战课/斜拍.descr', 'caltab.ps')
3、计算比例当量(物体实际距离/像素距离)
Pixcle:=0.05/261
4、转换外参
set_origin_pose (CameraPose, -0.098, -0.05, 0.001, Newpose)
原始外参    坐标系往X方向平移量   坐标系往Y方向平移量   标定板厚度    新的外参

显示出原始外参坐标系和新的外参坐标系
把新外参坐标系平移到左上角,自己慢慢改参数试
disp_3d_coord_system (WindowHandle1, CameraParameters, CameraPose, 0.05)
disp_3d_coord_system (WindowHandle1, CameraParameters, Newpose, 0.05)


5、生成映射图
gen_image_to_world_plane_map (Map, CameraParameters, Newpose, 2048, 1536, 2048, 1536, Pixcle, 'bilinear')
输出map图   内参   新外参  要转换图像宽高   map图像宽高   比例当量   映射类型 
6、斜拍图片转正
map_image (GrayImage, Map, ImageMapped)
原图   映射图    转正后图像

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值