C#联合HALCON之Blob分析算法实现

Blob是一个非常经典实用的算法,常用于定位及缺陷检测,关于Blob的详细介绍可以参考下面这篇博客。

Halcon之Blob分析_halcon blob分析-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_43488529/article/details/120509876?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171258364016800178514348%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=171258364016800178514348&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-120509876-null-null.142^v100^pc_search_result_base7&utm_term=blob%E5%88%86%E6%9E%90&spm=1018.2226.3001.4187开发环境VS2022 halcon23.11

一、效果展示

二、Blob分析流程

三、代码

关于ROI的绘制请看我上篇内容

Halcon联合c#之HDrawingObject实现可以自由移动拖动的ROI-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_45502016/article/details/137409727?spm=1001.2014.3001.5502

        1.界面控件

        2.变量声明

        HDrawingObject HD_Roi;
        HObject ho_Img,ho_DispObj;

        3.变量参数初始化

        public Form1()
        {
            InitializeComponent();
            InitParm();
        }
        public void InitParm()
        {
            //预处理参数控件初始化
            comboBox_Filter.SelectedIndex = 0;
            comboBox1.SelectedIndex = 0;
            label1.Visible = false;
            label2.Visible = false;
            textBox1.Visible = false;
            textBox2.Visible = false;
            comboBox1.Visible = false;
            //形态学参数控件初始化
            comboBox2.SelectedIndex = 0;
            comboBox3.SelectedIndex = 0;
            comboBox3.Visible = false;
            label6.Visible = false;
            textBox6.Visible = false;

            //变量初始化
            HOperatorSet.GenEmptyObj(out ho_Img);
            HOperatorSet.GenEmptyObj(out ho_DispObj);
            HD_Roi =new HDrawingObject();
            HD_Roi.CreateDrawingObjectRectangle1(0, 0, 100, 100);
        
        }

         4.界面控件交互代码

            //显示 隐藏ROI
           private void checkBox_DispRoi_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox_DispRoi.Checked)
            {     //显示roi至窗口
                hWindowControl1.HalconWindow.AttachDrawingObjectToWindow(HD_Roi);
            }
            else
            { 
                //隐藏roi
                hWindowControl1.HalconWindow.DetachDrawingObjectFromWindow(HD_Roi);
            }

        }
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                string imgPath;
                OpenFileDialog openFileDialog = new OpenFileDialog();
                openFileDialog.InitialDirectory = "c:\\";//注意这里写路径时要用c:\\而不是c:\
                openFileDialog.Filter = "jpg|*.jpg|bmp|*.bmp|*.png|*.png";
                openFileDialog.FilterIndex = 1;
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    int t = System.Environment.TickCount;
                    imgPath = openFileDialog.FileName;
                    HOperatorSet.ReadImage(out ho_Img, imgPath);
                    ShowImage();
                    ShowMessage("打开" + imgPath);
                    ShowRunTime(System.Environment.TickCount - t);
                }
            }
            catch (Exception ee)
            {
   
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            
                int parm;
                if (textBox1.Text == "")
                    textBox1.Text = 0.ToString();
                parm = int.Parse(textBox1.Text);
                if (parm < 0)
                    textBox1.Text = 0.ToString();
                if (parm >999999)
                    textBox1.Text = 255.ToString();
          
        }
        private void comboBox3_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox2.SelectedIndex == 0)
                return;
            if (comboBox3.SelectedIndex==0)
            {
                comboBox3.Visible = true;
                label6.Text = "结构元半径";
                label6.Visible = true;
                textBox6.Visible = true;
                textBox6.Text = "3";
                label7.Visible = false;
                textBox7.Visible = false;
            }
            else
            {
                comboBox3.Visible = true;
                label6.Text = "结构元宽";
                label6.Visible = true;
                textBox6.Visible = true;
                label7.Text = "结构元高";
                label7.Visible = true;
                textBox7.Visible = true;
                textBox6.Text = "3";
                textBox7.Text = "3";
            }
        }
        private void comboBox_Filter_SelectedIndexChanged(object sender, EventArgs e)
        {
            //先将控件隐藏
            label1.Visible = false;
            label2.Visible = false;
            textBox1.Visible = false;
            textBox2.Visible = false;
            comboBox1.Visible = false;
            switch (comboBox_Filter.SelectedIndex)
            {
                case 0:
                    break;
                case 1:
                    //显示中值滤波的参数控件
                    label1.Text = "掩模半径";
                    label1.Visible=true;
                    textBox1.Visible = true;
                    textBox1.Text = "1";
                    comboBox1.Visible = true;
                    break;
                case 2:
                    //显示均值滤波的参数控件
                    label1.Text = "掩模宽度";
                    label1.Visible = true;
                    textBox1.Visible = true;
                    textBox1.Text = "9";
                    label2.Text = "掩模高度";
                    label2.Visible = true;
                    textBox2.Visible = true;
                    textBox2.Text = "9";
                    break;
                case 3:
                    //显示高斯滤波的参数控件
                    label1.Text = "滤波器大小";
                    label1.Visible = true;
                    textBox1.Visible = true;
                    textBox1.Text = "5";
                    break;
                default:
                    break;
            }
        }
        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            //先将控件隐藏
            comboBox3.Visible = false;
            label6.Visible = false;
            textBox6.Visible = false;
            if (comboBox2.SelectedIndex == 0)
                return;

            comboBox3.Visible = true;
            label6.Text = "结构元半径";
            label6.Visible = true;
            textBox6.Visible = true;
            textBox6.Text = "3";


        }
        private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
            //如果不是数字、回车,则屏蔽
            if (!(Char.IsNumber(e.KeyChar)) && e.KeyChar != (char)8)
                e.Handled = true;
        }
        private void textBox2_KeyPress(object sender, KeyPressEventArgs e)
        {
            //如果不是数字、回车,则屏蔽
            if (!(Char.IsNumber(e.KeyChar)) && e.KeyChar != (char)8)
                e.Handled = true;
        }
        private void textBox1_TextChanged_1(object sender, EventArgs e)
        {
            int parm;
            switch (comboBox_Filter.SelectedIndex)
            {
                case 0:

                    break;
                case 1:
                    //中值滤波参数值限制
                    if (textBox1.Text == "")
                        textBox1.Text = 1.ToString();
                    parm= int.Parse(textBox1.Text);
                    if (parm<1)
                        textBox1.Text = 1.ToString();
                    if (parm > 4095)
                        textBox1.Text = 4095.ToString();
                    break;
                case 2:
                    //均值滤波参数值限制
                    if (textBox1.Text == "")
                        textBox1.Text = 1.ToString();
                    parm = int.Parse(textBox1.Text);
                    if (parm < 1)
                        textBox1.Text = 1.ToString();
                    if (parm > 501)
                        textBox1.Text = 501.ToString();
                    break;
                case 3:
                    //高斯滤波参数值限制
                    if (textBox1.Text == "")
                        textBox1.Text = 3.ToString();
                    parm = int.Parse(textBox1.Text);
                    if (parm < 3)
                        textBox1.Text = 3.ToString();
                    if (parm > 11)
                        textBox1.Text = 11.ToString();
                    break;

                default:
                    break;
            }
            int number = int.Parse(textBox1.Text);
            if ((number >= 1) && (number <= 8))
            {

            }
            else if (number < 1)
            {
                number = 1;
            }
            else if (number > 8)
            {
                number = 8;
            }
            textBox1.Text = number.ToString();
        }
        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            int parm;
            if (textBox2.Text == "")
                textBox2.Text = 1.ToString();
            parm = int.Parse(textBox2.Text);
            if (parm < 1)
                textBox2.Text = 1.ToString();
            if (parm > 501)
                textBox2.Text = 501.ToString();
        }
        private void textBox6_KeyPress(object sender, KeyPressEventArgs e)
        {
            //如果不是数字、回车,则屏蔽
            if (!(Char.IsNumber(e.KeyChar)) && e.KeyChar != (char)8)
                e.Handled = true;
        }
        private void textBox7_KeyPress(object sender, KeyPressEventArgs e)
        {
            //如果不是数字、回车,则屏蔽
            if (!(Char.IsNumber(e.KeyChar)) && e.KeyChar != (char)8)
                e.Handled = true;
        }
    
    
        private void textBox_MaxArea_KeyPress(object sender, KeyPressEventArgs e)
        {
            //如果不是数字、回车,则屏蔽
            if (!(Char.IsNumber(e.KeyChar)) && e.KeyChar != (char)8)
                e.Handled = true;
        }
        private void textBox_MinArea_KeyPress(object sender, KeyPressEventArgs e)
        {
            //如果不是数字、回车,则屏蔽
            if (!(Char.IsNumber(e.KeyChar)) && e.KeyChar != (char)8)
                e.Handled = true;
        }
        private void textBox6_TextChanged(object sender, EventArgs e)
        {
            int parm;
            if (textBox6.Text == "")
                textBox6.Text = 1.ToString();
            parm = int.Parse(textBox6.Text);
            if (parm < 1)
                textBox6.Text = 1.ToString();
            if (parm > 511)
                textBox6.Text = 501.ToString();
        }
        private void textBox7_TextChanged(object sender, EventArgs e)
        {
            int parm;
            if (textBox7.Text == "")
                textBox7.Text = 1.ToString();
            parm = int.Parse(textBox7.Text);
            if (parm < 1)
                textBox7.Text = 1.ToString();
            if (parm > 501)
                textBox7.Text = 501.ToString();
        }
        private void textBox_MaxArea_TextChanged(object sender, EventArgs e)
        {
            int parm;
            if (textBox_MaxArea.Text == "")
                textBox_MaxArea.Text = 0.ToString();
            parm = int.Parse(textBox_MaxArea.Text);
            if (parm < 0)
                textBox_MaxArea.Text = 0.ToString();
            if (parm > 999999)
                textBox_MaxArea.Text = 255.ToString();
        }
        private void textBox_MinArea_TextChanged(object sender, EventArgs e)
        {
            int parm;
            if (textBox_MinArea.Text == "")
                textBox_MinArea.Text = 0.ToString();
            parm = int.Parse(textBox_MinArea.Text);
            if (parm < 0)
                textBox_MinArea.Text = 0.ToString();
            if (parm > 999999)
                textBox_MinArea.Text = 255.ToString();
        }

        获取ROI参数信息

        /// <summary>
        /// 获取绘制对象参数参数
        /// </summary>
        /// <param name="drawid"></param>
        /// <param name="window"></param>
        /// <param name="type"></param>
        private void CallbackDrwingObjParm(HDrawingObject drawid, HWindow window, string type)
        {
            
            HTuple hv_Parms="";
            string[] parms;
            string text="";
            try
            {
                //矩形roi参数获取
                parms = new string[] { "row1", "column1", "row2", "column2" };
                hv_Parms = HD_Roi.GetDrawingObjectParams(parms);
                text = "\r\n行1:" + hv_Parms[0] + "\r\n列1:" + hv_Parms[1] + "\r\n行2:" + hv_Parms[2] + "\r\n列2:" + hv_Parms[3] ;     
                label1.Text = "Roi信息:" + text;
            }
            catch (Exception)
            {
            }
        }
        /// 

        显示图像以及图像处理结果

  /// <summary>
  /// 显示图片以及图像处理结果
  /// </summary>
  public void ShowImage()
  {
      try
      {
        
          if (!ho_Img.IsInitialized()) { return; }
          HTuple hW, hH;
          HOperatorSet.GetImageSize(ho_Img, out hW, out hH);
          HOperatorSet.SetPart(hWindowControl1.HalconWindow, 0, 0, hH, hW);
          hWindowControl1.HalconWindow.SetColor("green");
          hWindowControl1.HalconWindow.SetDraw("margin");
          hWindowControl1.HalconWindow.SetLineWidth(1);
          hWindowControl1.HalconWindow.ClearWindow();
          ho_Img.DispObj(hWindowControl1.HalconWindow);
          ho_DispObj.DispObj(hWindowControl1.HalconWindow);
      }
      catch (Exception ee)
      {


      }

  }

5.Blob算法的实现

   public bool Blob(HObject image, out HObject obj)
   {
       string []parms = new string[] { "row1", "column1", "row2", "column2" };
       HTuple hv_Area,hv_RoiParms,hv_Row1,hv_Col1, hv_Row2, hv_Col2, hv_Threshold,hv_Dist;
       HObject obj2, ho_Cross,ho_Rect;
       HOperatorSet.GenEmptyObj(out obj2);
       HOperatorSet.GenEmptyObj(out ho_Cross);
       HOperatorSet.GenEmptyObj(out ho_Rect);
       obj = obj2;
       try
       {             
           //没有图像返回false
           if (image.CountObj() == 0 || !image.IsInitialized())
           {
               obj = obj2;
               return false;
           }
           // -------------2.分割ROI-------------------
           //获取ROI参数    
           hv_RoiParms = HD_Roi.GetDrawingObjectParams(parms);
           HOperatorSet.GenRectangle1(out ho_Rect, hv_RoiParms[0], hv_RoiParms[1], hv_RoiParms[2], hv_RoiParms[3]);
           HOperatorSet.ReduceDomain(image, ho_Rect, out image);
           // -------------2.预处理 滤波-------------------
           switch (comboBox_Filter.SelectedIndex)
           {
               case 0://不处理
                   break;
               case 1://中值滤波
                   HTuple maskTyple;
                   maskTyple = "circle";
                   if (comboBox1.SelectedIndex==2)
                       maskTyple = "square";
                   HOperatorSet.MedianImage(image, out image, maskTyple, int.Parse(textBox1.Text), "mirrored");
                   break;
               case 2://均值滤波
                   HOperatorSet.MeanImage(image, out image, int.Parse(textBox1.Text), int.Parse(textBox2.Text));
                   break;
               case 3://高斯滤波
                   HOperatorSet.GaussFilter(image, out image, int.Parse(textBox1.Text));
                   break;

               default:
                   break;
           }
           // -------------3.二值化-------------------
           //这里为了简单一点用的BinaryThreshold算子,大家可以根据自己的实际情况选择
           if (radioButton_Black.Checked)
           {
               //黑色目标
               //HOperatorSet.Threshold(image, out obj2, 0, int.Parse(textBox_Threshold.Text));
               HOperatorSet.BinaryThreshold(image, out obj2, "max_separability", "dark",out hv_Threshold);
           }
           else
           {
               //白色目标
               //HOperatorSet.Threshold(image, out obj2,int.Parse(textBox_Threshold.Text),255);
               HOperatorSet.BinaryThreshold(image, out obj2, "max_separability", "light", out hv_Threshold);
           }
           // -------------4.形态学-------------------
           switch (comboBox2.SelectedIndex)
           {
               case 0://不处理
                   break;
               case 1://腐蚀
                   if (comboBox3.SelectedIndex == 0)//圆形腐蚀
                       HOperatorSet.ErosionCircle(obj2, out obj2, int.Parse(textBox6.Text));
                   else//矩形腐蚀
                       HOperatorSet.ErosionRectangle1(obj2, out obj2, int.Parse(textBox6.Text),int.Parse(textBox7.Text));
                   break;
               case 2://膨胀
                   if (comboBox3.SelectedIndex == 0)//圆形膨胀
                       HOperatorSet.DilationCircle(obj2, out obj2, int.Parse(textBox6.Text));
                   else//矩形膨胀
                       HOperatorSet.DilationRectangle1(obj2, out obj2, int.Parse(textBox6.Text), int.Parse(textBox7.Text));
                   break;
               case 3://开运算
                   if (comboBox3.SelectedIndex == 0)//圆形开运算
                       HOperatorSet.OpeningCircle(obj2, out obj2, int.Parse(textBox6.Text));
                   else//矩形开运算
                       HOperatorSet.OpeningRectangle1(obj2, out obj2, int.Parse(textBox6.Text), int.Parse(textBox7.Text));
                   break;
               case 4://闭运算
                   if (comboBox3.SelectedIndex == 0)//圆形闭运算
                       HOperatorSet.ClosingCircle(obj2, out obj2, int.Parse(textBox6.Text));
                   else//矩形闭运算
                       HOperatorSet.ClosingRectangle1(obj2, out obj2, int.Parse(textBox6.Text), int.Parse(textBox7.Text));
                   break;
               default:
                   break;
           }
           // -------------5.筛选-------------------
           //二值化后的区域是一块整体,先要将它打散变成多个区域
           HOperatorSet.Connection(obj2, out obj2);
           //这里为了方便演示 只使用面积进行筛选
           //实际项目中 会用到其他特征 比如圆度 矩形度这些,这里根据自己实际情况来修改即可
           HOperatorSet.SelectShape(obj2, out obj2, "area", "and", int.Parse(textBox_MinArea.Text), int.Parse(textBox_MaxArea.Text));
           //生成一个小十字架用来显示             
          
           HOperatorSet.SmallestRectangle1(obj2, out hv_Row1, out hv_Col1, out hv_Row2, out hv_Col2);
           HOperatorSet.DistancePp(hv_Row1, hv_Col1, hv_Row2, hv_Col2, out hv_Dist);
           HOperatorSet.AreaCenter(obj2, out hv_Area, out hv_Row1, out hv_Col1);
           HOperatorSet.GenCrossContourXld(out ho_Cross, hv_Row1, hv_Col1, hv_Dist/5, 0);
           HOperatorSet.ConcatObj(obj2, ho_Cross, out obj);
           obj2.Dispose(); ho_Cross.Dispose(); ho_Rect.Dispose();
           if (hv_Row1.TupleLength()<1)
           {
               return false;
           }
           return true;
       }
       catch (Exception)
       {
           obj2.Dispose(); ho_Cross.Dispose(); ho_Rect.Dispose();
           return false;
       }
      
   }

        执行按钮的单击事件

    private void button2_Click(object sender, EventArgs e)
    {
        ho_DispObj.Dispose();
        int t = System.Environment.TickCount;
        ShowRunTime(System.Environment.TickCount - t);
        bool b = Blob(ho_Img, out ho_DispObj);
        if (!b)
            Console.WriteLine("执行失败");
        label_RunTime.Text = (System.Environment.TickCount - t).ToString() + "ms";
        ShowImage();
    }

如果这篇内容对你有帮助的话,请给我点个赞让我开心一下吧。关注我后续会更新更多c#以及halcon方面的内容

  • 29
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

放牛娃王二狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值