联合编程:基于HALCON的机器视觉圆测量(C#)

引言

在现代工业自动化领域,机器视觉技术已成为质量检测的关键手段。本文将详细介绍如何使用HALCON实现高精度的圆测量,分享我在工业视觉项目中的实践经验。

一、项目背景

在机械零件检测中,圆形特征的尺寸精度直接影响产品质量。传统的人工检测方式存在效率低、一致性差等问题。我们开发的这套视觉系统可以实现:

  • 自动检测多个圆形零件
  • 实时测量半径尺寸
  • 自动判断合格与否
  • 结果记录与追溯

 二、代码实现

点击助手,打开新的Image Acquisition

点击选择路径,选择文件夹

点击代码生成,插入代码

 第二句替换一下,以便于后面获取图像的宽度和高度

获取图像宽高,打开新窗口,将图片显示在新窗口,画圆

完整代码

*测量
list_files ('img', ['files','follow_links'], ImageFiles)
read_image (Image, ImageFiles[0])

*获取图像大小
get_image_size (Image, Width, Height)

dev_open_window (0, 0, Width/4, Height/4, 'black', WindowHandle)

*创建测量模型
create_metrology_model (MetrologyHandle)
*设置测量模型的大小
set_metrology_model_image_size (MetrologyHandle, Width, Height)
dev_display (Image)
*画一个圆,获取圆的半径,后面以这个圆的半径来测量零件是否合格
draw_circle (WindowHandle, Row, Column, Radius)

*对多张图像进行测量
for Index := 0 to |ImageFiles|-1 by 1
    read_image (ResultImage, ImageFiles[Index])
    *阈值分割,挑选出来配件部分
    threshold (ResultImage, ResultRegions, 3, 60)
    *连通性
    connection (ResultRegions, ResultConnectedRegions)
    *特征提取:用面积,和圆两个指标提取  area
    select_shape (ResultConnectedRegions, ResultSelectedRegions1, ['area','roundness'], 'and', [250000,0.9], [320000,1])
    *获取
    area_center (ResultSelectedRegions1, ResultArea, ResultRow, ResultColumn)
    *设置输出的颜色
    dev_set_color ('green')
    dev_set_draw ('margin')
    dev_display (ResultImage)
    *生成圆:注意,这里借助了上方两个特征提取出来的坐标
    gen_circle (ResultCircle, ResultRow, ResultColumn, Radius)
    *把圆添加到模型中
    add_metrology_object_circle_measure (MetrologyHandle, ResultRow, ResultColumn, Radius,100, 5, 1.5, 30, ['measure_transition','min_score'], ['all',0.4], MetrologyCircleIndice)
    *测量并拟合集合形状
    apply_metrology_model (ResultImage, MetrologyHandle)
    *获取测量模型中的测量轮廓,方便后期显示
    get_metrology_object_result_contour (ResultContour, MetrologyHandle,'all', 'all', 1.5)
    *在轮廓基础上获得此次测量的结果:第二个参数是每个图象的索引
    get_metrology_object_result (MetrologyHandle, MetrologyCircleIndice, 'all', 'result_type', 'radius',CircleRadiusResult)
    
    *显示图像
    dev_display (ResultImage)
    *显示测量轮廓
    dev_display (ResultContour)
    
    *设置文字位置
    set_tposition (WindowHandle, 0, 0)
    *在指定位置显示信息
    write_string (WindowHandle, '圆的半径:'+CircleRadiusResult)
    stop ()
endfor
*清除测量模型
clear_metrology_model (MetrologyHandle)






    
    

三、导出代码,配置文件

点击文件,导出

四、创建Winfrom窗体应用

找到halcon的文件夹,在dotnet35中找到 halcondotnet.dll  在x64里面找到halcon.dll文件

将这两个文件复制到项目的debug目录下

取消勾选32位

设置完成后将测量.cs拖入项目中

画出winfrom窗体

五、代码写入

引入命名空间

using HalconDotNet;
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.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

这些命名空间包含了应用程序所需的类和方法,如Halcon操作符、Windows窗体控件、文件操作等。

类和变量定义

namespace 摄像头
{
    public partial class Form1 : Form
    {
        HObject Image;
        HTuple windowID;
        Thread t1;
        HObject[] imageArr = new HObject[8];
        bool t1_Stop = false;

  • HObject 和 HTuple 是Halcon库中用于处理图像和元组数据的类。
  • Image 用于存储单个图像。
  • windowID 用于标识Halcon窗口。
  • t1 是一个线程,用于执行图像测量任务。
  • imageArr 是一个包含8个图像对象的数组。
  • t1_Stop 是一个布尔变量,用于控制线程的停止状态。

图像加载方法

private void LoadBateImage()
{
    for (int i = 0; i < 8; i++)
    {
        HOperatorSet.ReadImage(out imageArr[i], $"img/{i}.bmp");
    }
}

  • LoadBateImage 方法用于从指定路径加载8张图像,并存储到 imageArr 数组中。

显示单个图像

private void LoadImage()
{
    HOperatorSet.ReadImage(out Image, "img/0.bmp");
    HTuple Width = null, Height = null;
    HOperatorSet.GetImageSize(Image, out Width, out Height);
    HOperatorSet.SetColor(windowID, "green");
    HOperatorSet.SetPart(windowID, 0, 0, Height, Width);
    HOperatorSet.DispObj(Image, windowID);
}

  • LoadImage 方法用于加载并显示第一张图像(img/0.bmp)。

创建Halcon窗口

private void CreateHalconWindow()
{
    HTuple winforms = this.pictureBox1.Handle;
    HOperatorSet.SetWindowAttr("background_color", "black");
    HOperatorSet.OpenWindow(0, 0, this.pictureBox1.Width, this.pictureBox1.Height, winforms, "", "", out windowID);
}

  • CreateHalconWindow 方法用于在窗体的 pictureBox1 控件中创建一个Halcon窗口,并设置背景颜色为黑色。

按钮点击事件处理

停止测量
private void button2_Click(object sender, EventArgs e)
{
    t1_Stop = true;
    if (!Directory.Exists(dicPatj))
    {
        Directory.CreateDirectory(dicPatj);
    }
    else
    {
        string filePath2 = Path.Combine(dicPatj, filePath);
        File.AppendAllText(filePath2, "停止测量" + Environment.NewLine);
    }
}

  • 当点击 button2 时,设置 t1_Stop 为 true,以停止测量线程,并记录“停止测量”信息到文件。
测量半径
private void button3_Click(object sender, EventArgs e)
{
    radiu();
}

private double radiu()
{
    HOperatorSet.DrawCircle(windowID, out hv_Row, out hv_Column, out hv_Radius);
    double radius = hv_Radius;
    MessageBox.Show("半径" + radius);
    return radius;
}

  • 当点击 button3 时,调用 radiu 方法。
  • radiu 方法用于绘制一个圆并获取其半径,随后通过消息框显示半径值。
开始测量
private void button1_Click(object sender, EventArgs e)
{
    string fullFilePath = Path.Combine(dicPatj, filePath);
    File.WriteAllText(fullFilePath, string.Empty, Encoding.UTF8);
    if (t1.ThreadState == ThreadState.Unstarted)
    {
        t1.Start();
    }
    if (t1.ThreadState == ThreadState.Stopped || t1.ThreadState == ThreadState.Aborted)
    {
        t1 = new Thread(new ThreadStart(PlayThread));
        t1.Start();
    }
    if (!Directory.Exists(dicPatj))
    {
        Directory.CreateDirectory(dicPatj);
    }
    else
    {
        string filePath2 = Path.Combine(dicPatj, filePath);
        File.AppendAllText(filePath2, "开始测量" + Environment.NewLine);
    }
}

  • 当点击 button1 时,清空文件内容并开始测量线程 t1
  • 如果线程已经停止或中止,则重新创建并启动线程。
  • 记录“开始测量”信息到文件。
退出应用程序
private void button4_Click(object sender, EventArgs e)
{
    this.Close();
    if (!Directory.Exists(dicPatj))
    {
        Directory.CreateDirectory(dicPatj);
    }
    else
    {
        string filePath2 = Path.Combine(dicPatj, filePath);
        File.AppendAllText(filePath2, "退出" + Environment.NewLine);
    }
}

  • 当点击 button4 时,关闭应用程序,并记录“退出”信息到文件。

测量线程

private void PlayThread()
{
    int i = 0;
    t1_Stop = false;
    HTuple width = null, height = null;

    while (!t1_Stop)
    {
        try
        {
            HOperatorSet.DispObj(imageArr[i], windowID);
            HOperatorSet.GetImageSize(imageArr[i], out width, out height);
            HOperatorSet.SetPart(windowID, 0, 0, height, width);

            double CriRad = ImageMeasure(imageArr[i]);

            if (dataGridView1.InvokeRequired)
            {
                dataGridView1.Invoke(new Action(() =>
                {
                    bool isOK = (CriRad > hv_Radius.D - 4 && CriRad < hv_Radius.D + 4);
                    var a = isOK ? "OK" : "NG";
                    dataGridView1.Rows.Add(i, CriRad.ToString("F2"), isOK ? "OK" : "NG");
                    dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.Rows.Count - 1;

                    if (!Directory.Exists(dicPatj))
                    {
                        Directory.CreateDirectory(dicPatj);
                    }
                    else
                    {
                        string filePath2 = Path.Combine(dicPatj, filePath);
                        File.AppendAllText(filePath2, "编号" + i + " 半径" + CriRad.ToString("F2") + " 结果" + a + Environment.NewLine);
                    }
                }));
            }

            Thread.Sleep(1000);
            i = (i + 1) % 7; // 循环0-6
        }
        catch (Exception ex)
        {
            if (!this.IsDisposed)
            {
                this.Invoke(new Action(() =>
                {
                    MessageBox.Show($"发生错误: {ex.Message}");
                }));
            }
            break;
        }
    }
}

  • PlayThread 方法在一个独立的线程中循环显示和测量 imageArr 中的图像。
  • 每次循环中,显示图像、获取图像尺寸并设置显示区域,然后调用 ImageMeasure 方法测量图像中圆的半径。
  • 测量结果被添加到 dataGridView1 中,并同时记录到文件中。
  • 如果发生异常,显示错误信息并停止线程。

测量图像中的圆的半径

private double ImageMeasure(HObject ho_ResultImage)
{
    HObject ho_Image, ho_ResultRegions = null, ho_Connection = null;
    HObject ho_SelectedRegions = null, ho_Circle = null, ho_Contour = null;
    HTuple hv_ImageFiles = null, hv_Width = null, hv_Height = null, hv_WindowHandle = null, hv_MetrologyHandle = null;
    HTuple hv_NewRadius = null, hv_CirCleRadiusTolerance = null;
    HTuple hv_Index = null, hv_Area = new HTuple(), hv_Row = new HTuple();
    HTuple hv_Column = new HTuple(), hv_MetrologyCircleIndice = new HTuple();
    HTuple hv_Parameter = new HTuple();

    HOperatorSet.GenEmptyObj(out ho_Image);
    HOperatorSet.GenEmptyObj(out ho_ResultRegions);
    HOperatorSet.GenEmptyObj(out ho_Connection);
    HOperatorSet.GenEmptyObj(out ho_SelectedRegions);
    HOperatorSet.GenEmptyObj(out ho_Circle);
    HOperatorSet.GenEmptyObj(out ho_Contour);

    HOperatorSet.GetImageSize(ho_ResultImage, out hv_Width, out hv_Height);
    HOperatorSet.CreateMetrologyModel(out hv_MetrologyHandle);
    HOperatorSet.SetMetrologyModelImageSize(hv_MetrologyHandle, hv_Width, hv_Height);

    hv_NewRadius = hv_Radius.D;
    hv_CirCleRadiusTolerance = 100;

    ho_ResultRegions.Dispose();
    HOperatorSet.Threshold(ho_ResultImage, out ho_ResultRegions, 2, 58);
    ho_Connection.Dispose();
    HOperatorSet.Connection(ho_ResultRegions, out ho_Connection);
    ho_SelectedRegions.Dispose();
    HOperatorSet.SelectShape(ho_Connection, out ho_SelectedRegions, (new HTuple("area")).TupleConcat("roundness"), "and", (new HTuple(249155)).TupleConcat(0.8473), (new HTuple(316723)).TupleConcat(1));

    HOperatorSet.AreaCenter(ho_SelectedRegions, out hv_Area, out hv_Row, out hv_Column);
    HOperatorSet.SetColor(windowID, "green");
    HOperatorSet.SetDraw(windowID, "margin");
    HOperatorSet.DispObj(ho_SelectedRegions, windowID);

    ho_Circle.Dispose();
    HOperatorSet.GenCircle(out ho_Circle, hv_Row, hv_Column, hv_NewRadius);
    HOperatorSet.AddMetrologyObjectCircleMeasure(hv_MetrologyHandle, hv_Row, hv_Column, hv_NewRadius, hv_CirCleRadiusTolerance, 5, 1.5, 30, (new HTuple("measure_transition")).TupleConcat("min_score"), (new HTuple("all")).TupleConcat(0.4), out hv_MetrologyCircleIndice);
    HOperatorSet.ApplyMetrologyModel(ho_ResultImage, hv_MetrologyHandle);
    ho_Contour.Dispose();
    HOperatorSet.GetMetrologyObjectResultContour(out ho_Contour, hv_MetrologyHandle, "all", "all", 1.5);
    HOperatorSet.GetMetrologyObjectResult(hv_MetrologyHandle, hv_MetrologyCircleIndice, "all", "result_type", "radius", out hv_Parameter);
    HOperatorSet.DispObj(ho_ResultImage, windowID);
    HOperatorSet.DispObj(ho_Contour, windowID);
    HOperatorSet.SetTposition(windowID, 0, 0);
    HOperatorSet.WriteString(windowID, "圆的半径:" + hv_Parameter);

    HOperatorSet.ClearMetrologyModel(hv_MetrologyHandle);
    ho_Image.Dispose();
    ho_ResultRegions.Dispose();
    ho_Connection.Dispose();
    ho_SelectedRegions.Dispose();
    ho_Circle.Dispose();
    ho_Contour.Dispose();
    return hv_Parameter;
}

CopyInsert

  • ImageMeasure 方法用于测量给定图像中的圆的半径。
  • 首先对图像进行阈值分割、连接和形状选择,以提取感兴趣的圆区域。
  • 然后创建一个测量模型,并将提取的圆区域添加到模型中。
  • 应用测量模型,获取测量结果,并显示在Halcon窗口中。
  • 最后,清空测量模型中的数据,释放资源并返回测量结果。

六、完整代码

using HalconDotNet;
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.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 摄像头
{
    public partial class Form1 : Form
    {

        HObject Image;
        HTuple windowID;
        Thread t1;
        //优化了Halcon中的数组
        HObject[] imageArr = new HObject[8];
        bool t1_Stop = false;//线程的状态
        private void LoadBateImage()
        {
            for (int i = 0; i < 8; i++)
            {
                HOperatorSet.ReadImage(out imageArr[i], $"img/{i}.bmp");
            }
        }
        private void LoadImage()
        {
            HOperatorSet.ReadImage(out Image, "img/0.bmp");
            HTuple Width = null, Height = null;
            HOperatorSet.GetImageSize(Image, out Width, out Height);
            HOperatorSet.SetColor(windowID, "green");
            HOperatorSet.SetPart(windowID, 0, 0, Height, Width);
            HOperatorSet.DispObj(Image, windowID);

        }
        private void CreateHalconWindow()
        {
            //注意这里没有hWindowControl控件了,变成了pictureBox
            HTuple winforms = this.pictureBox1.Handle;
            HOperatorSet.SetWindowAttr("background_color", "black");
            //这句代码决定了现在所有视图在picture展示,教育windowsID控制picture
            HOperatorSet.OpenWindow(0, 0, this.pictureBox1.Width, this.pictureBox1.Height, winforms, "", "", out windowID);
        }
        private void button2_Click(object sender, EventArgs e)
        {
            t1_Stop = true;
            if (!Directory.Exists(dicPatj))
            {
                Directory.CreateDirectory(dicPatj);
            }
            else
            {
                string filePath2 = Path.Combine(dicPatj, filePath);
                File.AppendAllText(filePath2, "停止测量" + Environment.NewLine);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //读图
            LoadBateImage();
            //加载窗体
            CreateHalconWindow();
            LoadImage();
            t1 = new Thread(new ThreadStart(PlayThread));
        }
        
        HTuple hv_ImageFiles = null, hv_Index = null, hv_Area = new HTuple();
        HTuple hv_Row = new HTuple(), hv_Column = new HTuple();
        HTuple hv_Row2 = new HTuple(), hv_Column2 = new HTuple();
        HTuple hv_Radius = new HTuple();
        HTuple hv_Parameter = new HTuple();
        private void button3_Click(object sender, EventArgs e)
        {
            radiu();

        }
        private double radiu()
        {
            HOperatorSet.DrawCircle(windowID, out hv_Row, out hv_Column, out hv_Radius);
            double radius = hv_Radius;
            MessageBox.Show("半径"+radius);
            return radius;
        }
        public Form1()
        {
            InitializeComponent();
        }
        #region 开始测量
        private void button1_Click(object sender, EventArgs e)
        {
            string fullFilePath = Path.Combine(dicPatj, filePath);
            File.WriteAllText(fullFilePath, string.Empty, Encoding.UTF8);
            if (t1.ThreadState == ThreadState.Unstarted)
            {
                t1.Start();
            }
            //如果线程停止或者线程为空
            if (t1.ThreadState == ThreadState.Stopped ||
                 t1.ThreadState == ThreadState.Aborted)
            {
                //开启线程进行测量
                t1 = new Thread(new ThreadStart(PlayThread));
                t1.Start();
            }
            if (!Directory.Exists(dicPatj))
            {
                Directory.CreateDirectory(dicPatj);
            }
            else
            {
                string filePath2 = Path.Combine(dicPatj, filePath);
                File.AppendAllText(filePath2, "开始测量"+ Environment.NewLine);
            }
        }
        string dicPatj = @"测量";
        string filePath = @"OKorNG.txt";
        private void PlayThread()
        {
            int i = 0;
            t1_Stop = false;
            HTuple width = null, height = null;

            while (!t1_Stop)
            {
                try
                {
                    // 显示图像
                    HOperatorSet.DispObj(imageArr[i], windowID);

                    // 获取图像尺寸并设置显示区域
                    HOperatorSet.GetImageSize(imageArr[i], out width, out height);
                    HOperatorSet.SetPart(windowID, 0, 0, height, width);

                    // 测量半径
                    double CriRad = ImageMeasure(imageArr[i]);

                    // 安全更新UI
                    if (dataGridView1.InvokeRequired)
                    {
                        dataGridView1.Invoke(new Action(() =>
                        {
                            // 检查半径是否在允许范围内
                            bool isOK = (CriRad > hv_Radius.D - 4 && CriRad < hv_Radius.D + 4);
                            var a = isOK ? "OK" : "NG";
                            // 添加数据到DataGridView
                            dataGridView1.Rows.Add(
                                i,                               // 序号
                                CriRad.ToString("F2"),           // 半径值(保留2位小数)
                                isOK ? "OK" : "NG"               // 结果
                            );
                            // 自动滚动到最后一行
                            dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.Rows.Count - 1;

                        if (!Directory.Exists(dicPatj))
                        {
                            Directory.CreateDirectory(dicPatj);
                        }
                        else
                        {
                            string filePath2 = Path.Combine(dicPatj, filePath);
                            File.AppendAllText(filePath2,"编号"+i+" 半径"+ CriRad.ToString("F2")+" 结果"+a  + Environment.NewLine);
                            }
                            
                        }));
                    }

                    Thread.Sleep(1000);
                    i = (i + 1) % 7; // 循环0-6
                }
                catch (Exception ex)
                {
                    // 错误处理
                    if (!this.IsDisposed)
                    {
                        this.Invoke(new Action(() =>
                        {
                            MessageBox.Show($"发生错误: {ex.Message}");
                        }));
                    }
                    break;
                }
            }
        }


        //获取模型测量的结果
        private double ImageMeasure(HObject ho_ResultImage)
        {
            HObject ho_Image, ho_ResultRegions = null, ho_Connection = null;
            HObject ho_SelectedRegions = null, ho_Circle = null, ho_Contour = null;

            // Local control variables 

            HTuple hv_ImageFiles = null, hv_Width = null;
            HTuple hv_Height = null, hv_WindowHandle = null, hv_MetrologyHandle = null;
            HTuple hv_NewRadius = null, hv_CirCleRadiusTolerance = null;
            HTuple hv_Index = null, hv_Area = new HTuple(), hv_Row = new HTuple();
            HTuple hv_Column = new HTuple(), hv_MetrologyCircleIndice = new HTuple();
            HTuple hv_Parameter = new HTuple();
            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_Image);
            HOperatorSet.GenEmptyObj(out ho_ResultRegions);
            HOperatorSet.GenEmptyObj(out ho_Connection);
            HOperatorSet.GenEmptyObj(out ho_SelectedRegions);
            HOperatorSet.GenEmptyObj(out ho_Circle);
            HOperatorSet.GenEmptyObj(out ho_Contour);
         

            HOperatorSet.GetImageSize(ho_ResultImage, out hv_Width, out hv_Height);
            HOperatorSet.CreateMetrologyModel(out hv_MetrologyHandle);
            //设置测量模型的大小
            HOperatorSet.SetMetrologyModelImageSize(hv_MetrologyHandle, hv_Width, hv_Height);
            //定义圆的半径:注意,变得是这个值

            hv_NewRadius = hv_Radius.D;
            //也可以配置其他的参数,例如测量对象的宽度允许范围
            hv_CirCleRadiusTolerance = 100;

            //阈值分割,挑选出来配件部分
            ho_ResultRegions.Dispose();
            HOperatorSet.Threshold(ho_ResultImage, out ho_ResultRegions, 2, 58);
            ho_Connection.Dispose();
            HOperatorSet.Connection(ho_ResultRegions, out ho_Connection);
            ho_SelectedRegions.Dispose();
            HOperatorSet.SelectShape(ho_Connection, out ho_SelectedRegions, (new HTuple("area")).TupleConcat(
         "roundness"), "and", (new HTuple(249155)).TupleConcat(0.8473), (new HTuple(316723)).TupleConcat(
         1));
            //获取
            HOperatorSet.AreaCenter(ho_SelectedRegions, out hv_Area, out hv_Row, out hv_Column);
            HOperatorSet.SetColor(windowID, "green");
            HOperatorSet.SetDraw(windowID, "margin");
            HOperatorSet.DispObj(ho_SelectedRegions, windowID);

            //生成圆
            ho_Circle.Dispose();
            HOperatorSet.GenCircle(out ho_Circle, hv_Row, hv_Column, hv_NewRadius);
            //把圆添加到模型中 ['measure_transition','min_score']允许小范围的缩放平移旋转 后面[]是分数
            HOperatorSet.AddMetrologyObjectCircleMeasure(hv_MetrologyHandle, hv_Row, hv_Column,
                hv_NewRadius, hv_CirCleRadiusTolerance, 5, 1.5, 30, (new HTuple("measure_transition")).TupleConcat(
                "min_score"), (new HTuple("all")).TupleConcat(0.4), out hv_MetrologyCircleIndice);
            //测量并拟合集合形状
            HOperatorSet.ApplyMetrologyModel(ho_ResultImage, hv_MetrologyHandle);
            //获取测量模型中的测量轮廓,方便后期显示
            ho_Contour.Dispose();
            HOperatorSet.GetMetrologyObjectResultContour(out ho_Contour, hv_MetrologyHandle,
                "all", "all", 1.5);
            //在轮廓基础上获得此次测量的结果:第二个参数是每个图像的索引
            HOperatorSet.GetMetrologyObjectResult(hv_MetrologyHandle, hv_MetrologyCircleIndice,
                "all", "result_type", "radius", out hv_Parameter);
            HOperatorSet.DispObj(ho_ResultImage, windowID);
            HOperatorSet.DispObj(ho_Contour, windowID);
            HOperatorSet.SetTposition(windowID, 0, 0);
            HOperatorSet.WriteString(windowID, "圆的半径:" + hv_Parameter);

            //清除测量模型
            HOperatorSet.ClearMetrologyModel(hv_MetrologyHandle);
            ho_Image.Dispose();
            ho_ResultRegions.Dispose();
            ho_Connection.Dispose();
            ho_SelectedRegions.Dispose();
            ho_Circle.Dispose();
            ho_Contour.Dispose();
            //返回结果
            return hv_Parameter;
        }
       #endregion
        private void button4_Click(object sender, EventArgs e)
        {
            //退出
            this.Close();
            if (!Directory.Exists(dicPatj))
            {
                Directory.CreateDirectory(dicPatj);
            }
            else
            {
                string filePath2 = Path.Combine(dicPatj, filePath);
                File.AppendAllText(filePath2, "退出" + Environment.NewLine);
            }
        }
    }
}

七、效果展示

先点交互测量,点击鼠标左键在图像中画圆,右键结束

获取到半径

点击开始,按照获取到的半径,检测圆是否合格,并将结果显示在左侧

在项目debug目录下可以查看日志

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值