基于C#调用halcon实现模板匹配【附部分源码】


前言

本文主要实现基于C#实现视觉定位的基础框架,与前面的python版、MFC版、Qt版一样,可供不同的开发者进行学习使用。
本文也是包括多模板算法匹配:基于形状、基于灰度、基于相关性、基于可变比例等。
编程环境:dotnet4.7
halcon20.05
IDE: VisualStudio 2022


演示视频

本次项目的效果视频:

C# 调用halcon实现模板匹配


一、项目文件目录讲解

在这里插入图片描述
从项目文件内容可以分为:
1、界面Calibration:这里是相机标定(像素坐标与机器人坐标映射)
2、界面CameraSetting:这里是相机设置(连接相机并把图像传递到主界面)
3、界面ImageMatching:这里是软件主界面
4、PublicFunc.cs:这里是自己封装的标准函数,方便自己调用
5、StructData.cs:这里是定义了标准的结构体,为了后边的变量使用


二、软件界面设置

C#版的基于winform是比较简单的,界面拖拉拽基本可以完成

1.CameraSetting.cs界面设置

如图设置相机设置界面即可:
在这里插入图片描述

2.Calibration.cs界面设置

这里是标定页面的设置,与前面的qt版、MFC版、python版界面类似:
在这里插入图片描述

3.主界面设置

这里按步骤进行界面设置即可:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里主界面基本设置完成,这里因为项目是使用4k屏幕设置的,因此显示有点问题,你们可以根据自己电脑设置即可,这个不是必须。


三、文件算法解析

这里会对上边项目工程的一些文件进行解释

1.StructData.cs文件的重要函数

这文件主要是定义了一系列用到的结构体:

//十字线
 public struct CenterLine
{
    public double center_X;
    public double center_Y;
    public double center_R;
    public double timer;
    public HObject Line1;
    public HObject Line2;
    public CenterLine(double default_x = -999.999, double default_y = -999.999, double default_r = -999.999, HObject line1 = null, HObject line2 = null, double t = 0)
    {
        center_X = default_x;
        center_Y = default_y;
        center_R = default_r;
        if (line1 == null)
            Line1 = new HObject();
        else
            Line1 = line1.Clone();
        if (line2 == null)
            Line2 = new HObject();
        else
            Line2 = line2.Clone();
        timer = t;
    }
}
//视觉识别的返回的结构数组
 public struct VisionPoint
{
    public double x;
    public double y;
    public double r;
    public double score;
    public double scale;
    public HObject shape;
    public HObject ROI_shape;
    public VisionPoint(double default_x = -999.999, double default_y = -999.999, double default_r = -999.999, double default_s = -999.999, HObject a = null, HObject b = null, double default_scale = -999.999)
    {
        x = default_x;
        y = default_y;
        r = default_r;
        scale = default_scale;
        score = default_s;
        shape = a;
        ROI_shape = b;
    }
};
//当前软件的鼠标状态
struct CurentMouseStatus
{
    public bool MouseMoveFlag;
    public bool MouseDownFlag;
    public bool MouseScaleFlag;
    public bool MouseBrushDrawingFlag;
    public double old_X;
    public double old_Y;
    public double Scale;
    public int MouseScaleNum;
};
//当前软件控制的一些变量信息
class CurrentControl
{
    public HWindow HalconWindow;
    public HObject ho_Image;
    public HTuple Image_Width;
    public HTuple Image_Height;
    public int ROIRunType;
    public HObject CurrentROI;
    public int TemplateAlgorithm;
    public int CurrentModelNum;
    public double setPartPosition;
    public CurentMouseStatus mouseStatus;
    public Queue<VisionPoint> dataRes;

    public CenterLine lineDataRes;

    public CurrentControl()
    {
        HalconWindow = null;
        HOperatorSet.GenEmptyObj(out ho_Image);
        HOperatorSet.GenEmptyRegion(out CurrentROI);
        Image_Width = new HTuple(-1);
        Image_Height = new HTuple(-1);
        ROIRunType = 0;
        TemplateAlgorithm = 0;
        CurrentModelNum = 0;
        setPartPosition = 0.0;
        mouseStatus = new CurentMouseStatus();
        mouseStatus.MouseMoveFlag = false;
        mouseStatus.MouseDownFlag = false;
        mouseStatus.MouseScaleFlag = false;
        mouseStatus.MouseBrushDrawingFlag = false;
        mouseStatus.old_X = 0.0;
        mouseStatus.old_Y = 0.0;
        mouseStatus.Scale = 0.95;
        mouseStatus.MouseScaleNum = 0;
        dataRes = new Queue<VisionPoint>();
    }
};
//相机变量属性
class CameraCom
{
    public HTuple hv_AcqHandle;
    public HObject CutROI;
    public HObject ho_Image;
    public HTuple ho_Width;
    public HTuple ho_Height; 
    public HWindow HalconWindow;

    public CameraCom()
    {
        hv_AcqHandle = new HTuple();
        hv_AcqHandle.Dispose();
        HOperatorSet.GenEmptyObj(out ho_Image);
        HOperatorSet.GenEmptyRegion(out CutROI);
        ho_Width = new HTuple(-1);
        ho_Height = new HTuple(-1);
        HalconWindow = null;
    }
};
//模板参数变量,这里有序列化操作,因此有[Serializable]
[Serializable]
struct ModelCom
{
    public bool EffectiveFlag;                //-该模板号是否有模板            false
    public int TemplateAlgorithm;             //-该模板号使用的匹配算法        0
    public HObject h_OriginImg;               //-创建模板的原图                GenEmptyObj()
    public HObject h_OriginRegion;            //-创建模板的ROI                 GenEmptyRegion()
    public int startAngle;                    //-起始角度                      -180
    public int endAngle;                      //-最终角度                      180
    public int ModelLevel;                    //-模型对比度                    -1
    public int Score;                         //-匹配分数                      50
    public int DeformationNum;                //-允许变形
    public int MatchNum;                      //-期待匹配数,0代表全部匹配     1
    public HTuple hv_ModelID;                 //-模板ID
    public int FindModelTimeOut;              //-模板匹配超时                  5000
    public HObject ShapeModelRegions;         //-模板轮廓(形状匹配有)
    public HTuple hv_Orgin_Row;               //-模板锚点的行
    public HTuple hv_Orgin_Column;            //-模板锚点的列
    public HTuple hv_Orgin_Angle;             //-模板锚点的角度
    public HTuple hv_Target_Row;              //-修改后锚点的行                -1
    public HTuple hv_Target_Column;           //-修改后锚点的列                -1
    public HObject h_SearchROI;               //-搜索区域
};
//标定参数变量,这里有序列化操作,因此有[Serializable]
[Serializable]
public struct PositionData
 {
     public HTuple image_X;
     public HTuple image_Y;
     public HTuple Robot_X;
     public HTuple Robot_Y;
     public HHomMat2D RobotHommat;
     public int PointSum;
     public bool TransFlag;
 }
//解决方案变量,也是使用结构体数组
[Serializable]
class SlnModelCom
{
    public const int MaxModelNum = 10;
    public ModelCom[] MyModel = new ModelCom[MaxModelNum];
    public const int PositionDataNum = 5;
    public PositionData[] myPositionData = new PositionData[PositionDataNum];

    public SlnModelCom()
    {
        for(int i=0;i< PositionDataNum;i++)
        {
            myPositionData[i].image_X = new HTuple();
            myPositionData[i].image_Y = new HTuple();
            myPositionData[i].Robot_X = new HTuple();
            myPositionData[i].Robot_Y = new HTuple();
            myPositionData[i].RobotHommat = new HHomMat2D();
            myPositionData[i].PointSum = 0;
            myPositionData[i].TransFlag = false;
        }

        for (int i = 0; i < MaxModelNum; i++) 
        {
            MyModel[i].EffectiveFlag = false;
            MyModel[i].TemplateAlgorithm = 0;
            HOperatorSet.GenEmptyObj(out MyModel[i].h_OriginImg);
            HOperatorSet.GenEmptyObj(out MyModel[i].h_OriginRegion);
            MyModel[i].startAngle = -180;
            MyModel[i].endAngle = 180;
            MyModel[i].ModelLevel = -1;
            MyModel[i].Score = 50;
            MyModel[i].DeformationNum = 0;
            MyModel[i].MatchNum = 1;
            MyModel[i].hv_ModelID = null;
            MyModel[i].FindModelTimeOut = 5000;
            HOperatorSet.GenEmptyObj(out MyModel[i].ShapeModelRegions);
            MyModel[i].hv_Orgin_Row = new HTuple(-1);
            MyModel[i].hv_Orgin_Column = new HTuple(-1);
            MyModel[i].hv_Orgin_Angle = new HTuple(-1);
            MyModel[i].hv_Target_Row = new HTuple(-1);
            MyModel[i].hv_Target_Column = new HTuple(-1);
            HOperatorSet.GenEmptyObj(out MyModel[i].h_SearchROI);
        }
    }

}

2.PublicFunc.cs文件的重要函数

这里只是个人习惯的一些函数,不是必要的


3.CameraSetting.cs文件的重要函数

此文件主要是相机连接的参数

1.首先定义类成员

 public delegate bool CameraImageHW(HObject hImage);
        public event CameraImageHW CameraImageHWEvent;

        private CameraCom myCameraCom = new CameraCom();
        private bool ChangeValueFlag = false;
        private bool DrawROIFlag = false;

2.查找相机

private void button_SearchCamera_Click(object sender, EventArgs e)
{
    if (IsConnectCamera() || button_ConnectCamera.Text == "断开")
    {
        button_ConnectCamera_Click(null, null);
    }
    Combox_CameraList.Items.Clear();

    HTuple hv_Information = new HTuple(), hv_ValueList = new HTuple();
    HTuple hv_Length = new HTuple();
    string[] deviceNames = { "GigEVision2"};

    foreach (string names in deviceNames)
    {
        try
        {
            HOperatorSet.InfoFramegrabber(names, "device", out hv_Information, out hv_ValueList);
            HOperatorSet.TupleLength(hv_ValueList, out hv_Length);
            int length1 = Convert.ToInt32(hv_Length.ToString());

            for (int i = 0; i < length1; i++)
            {
                string strDevice = hv_ValueList[i].S;
                if (strDevice.Equals("default"))
                {
                    break;
                }
                if (names == "GigEVision2")
                {
                    string[] datalist = strDevice.Split('|');
                    foreach (string data in datalist)
                    {
                        if (data.Contains("unique_name"))
                        {
                            strDevice = data.Replace(" ", "").Split(':')[1];
                            break;
                        }
                    }
                }
                strDevice = names + ":" + strDevice;
                Combox_CameraList.Items.Add(strDevice);
            }
        }
        catch
        {
        }
    }
    if (Combox_CameraList.Items.Count > 0)
    {
        Combox_CameraList.SelectedIndex = 0;
        button_ConnectCamera.Enabled = true;
    }
    else
        button_ConnectCamera.Enabled = false;
}

3.连接相机

private bool OpenCamrea()
{
    HTuple Information, ValueList;
    string selctCam = Combox_CameraList.SelectedItem.ToString();
    int StrSplit = selctCam.IndexOf(":");
    string CameraType = selctCam.Substring(0, StrSplit);
    string CamreaName = selctCam.Substring(StrSplit + 1).TrimEnd();

    try
    {
        HOperatorSet.InfoFramegrabber(CameraType, "defaults", out Information, out ValueList);
        HOperatorSet.OpenFramegrabber(CameraType, ValueList[0], ValueList[1], ValueList[2], ValueList[3], ValueList[4], ValueList[5], ValueList[6], ValueList[7], Combox_CameraColor.Text, ValueList[9], ValueList[10], ValueList[11], CamreaName, 0, ValueList[13], out myCameraCom.hv_AcqHandle);

        HOperatorSet.SetFramegrabberParam(myCameraCom.hv_AcqHandle, "clear_buffer", "enable");
        HOperatorSet.SetFramegrabberParam(myCameraCom.hv_AcqHandle, "[Stream]StreamAuxiliaryBufferCount", 0);
        HOperatorSet.SetFramegrabberParam(myCameraCom.hv_AcqHandle, "[Stream]StreamBufferHandlingMode", "NewestOnly");

        HOperatorSet.GrabImageStart(myCameraCom.hv_AcqHandle, -1);
        HOperatorSet.GrabImageAsync(out myCameraCom.ho_Image, myCameraCom.hv_AcqHandle, -1);
        HOperatorSet.GetImageSize(myCameraCom.ho_Image, out myCameraCom.ho_Width, out myCameraCom.ho_Height);
        CameraImageHWEvent(myCameraCom.ho_Image);
        if (checkBox_AutoSize.Checked == true)
        {
            myCameraCom.HalconWindow.SetPart(0, 0, myCameraCom.ho_Height.I - 1, myCameraCom.ho_Width.I - 1);
        }
        else
        {
            ImageFunc.MySetPart(ref hWindowControl, ref myCameraCom.HalconWindow, myCameraCom.ho_Height, myCameraCom.ho_Width);
        }

        return true;
    }
    catch
    {
        MessageBox.Show("相机连接失败");
        CloseCamera();
        return false;
    }
}

4.断开相机

private void CloseCamera()
{
    PublicFunc.Delay(500);
    try
    {
        HOperatorSet.GrabImage(out myCameraCom.ho_Image, myCameraCom.hv_AcqHandle);
        PublicFunc.Delay(200);
        HOperatorSet.CloseFramegrabber(myCameraCom.hv_AcqHandle);
        myCameraCom.hv_AcqHandle = new HTuple();
        myCameraCom.hv_AcqHandle.Dispose();
    }
    catch (HalconException HDevExpDefaultException)
    {
        throw HDevExpDefaultException;
    }
}

5.获取相机属性

获取相机的像素格式

private void GetCameraPixelFormat()
{
    try
    {
        HTuple hv_Value, hv_Length;
        HOperatorSet.GetFramegrabberParam(myCameraCom.hv_AcqHandle, "PixelFormat", out hv_Value);
        HOperatorSet.TupleLength(hv_Value, out hv_Length);
        int length = (int)hv_Length[0];
        if (length < 1)
        {
            comboBox_Combox_CameraPixelFormat.Enabled = false;
            comboBox_Combox_CameraPixelFormat.SelectedIndex = -1;
        }
        else
        {
            int index = 0;
            for (; index < comboBox_Combox_CameraPixelFormat.Items.Count; index++)
            {
                string data = comboBox_Combox_CameraPixelFormat.GetItemText(comboBox_Combox_CameraPixelFormat.Items[index]);
                if (data == hv_Value[0].S)
                {
                    comboBox_Combox_CameraPixelFormat.SelectedIndex = index;
                    break;
                }
            }
            if (index == comboBox_Combox_CameraPixelFormat.Items.Count)
            {
                comboBox_Combox_CameraPixelFormat.Items.Add(hv_Value[0].S);
                comboBox_Combox_CameraPixelFormat.SelectedIndex = comboBox_Combox_CameraPixelFormat.Items.Count - 1;
            }
        }
    }
    catch { }
}

获取相机的颜色空间

private void GetCameraColorSpace()
{
    try
    {
        HTuple hv_Value, hv_Length;
        HOperatorSet.GetFramegrabberParam(myCameraCom.hv_AcqHandle, "color_space", out hv_Value);
        HOperatorSet.TupleLength(hv_Value, out hv_Length);
        int length = (int)hv_Length[0];

        if (length < 1)
        {
            Combox_CameraColor.SelectedIndex = 0;
        }
        else
        {
            int index = 0;
            for (; index < Combox_CameraColor.Items.Count; index++)
            {
                string data = Combox_CameraColor.GetItemText(Combox_CameraColor.Items[index]);
                if (data == hv_Value[0].S)
                {
                    Combox_CameraColor.SelectedIndex = index;
                    break;
                }
            }
            if (index == Combox_CameraColor.Items.Count)
            {
                Combox_CameraColor.Items.Add(hv_Value[0].S);
                Combox_CameraColor.SelectedIndex = Combox_CameraColor.Items.Count - 1;
            }
        }
    }
    catch { }
}

获取相机的曝光时间

private void GetCameraExposure()
{
    try
    {
        HTuple hv_Value;
        HOperatorSet.GetFramegrabberParam(myCameraCom.hv_AcqHandle, "ExposureTime", out hv_Value);
        trackBar_ExposeTimeOut.Minimum = 0;
        trackBar_ExposeTimeOut.Maximum = 9999;
        trackBar_ExposeTimeOut.Value = Convert.ToInt32(hv_Value[0].D / 1000);
        label_ExposeTimeOut.Text = trackBar_ExposeTimeOut.Value.ToString();
        checkBox_AutoExposeTimeOut.Checked = false;
        
    }
    catch { }
}

获取相机的增益

private void GetCameraGain()
{
    try
    {
        HTuple hv_Value;
        HOperatorSet.GetFramegrabberParam(myCameraCom.hv_AcqHandle, "Gain", out hv_Value);
        trackBar_Gain.Minimum = 0;
        trackBar_Gain.Maximum = 17;
        trackBar_Gain.Value = Convert.ToInt32(hv_Value[0].D);
        label_Gain.Text = trackBar_Gain.Value.ToString();
    }
    catch
    {

    }
}

6.设置相机属性

设置相机的像素格式

private void comboBox_Combox_CameraPixelFormat_SelectionChangeCommitted(object sender, EventArgs e)
{
    if (IsConnectCamera())
    {
        try
        {
            HOperatorSet.GrabImage(out myCameraCom.ho_Image, myCameraCom.hv_AcqHandle);
            string data = comboBox_Combox_CameraPixelFormat.Text;
            HOperatorSet.SetFramegrabberParam(myCameraCom.hv_AcqHandle, "PixelFormat", data);
            HOperatorSet.GrabImageStart(myCameraCom.hv_AcqHandle, -1);
            HOperatorSet.GrabImageAsync(out myCameraCom.ho_Image, myCameraCom.hv_AcqHandle, -1);
        }
        catch { }
        GetCameraPixelFormat();
    }
}

设置相机颜色空间

private void Combox_CameraColor_SelectionChangeCommitted(object sender, EventArgs e)
{
     if (IsConnectCamera())
     {
         try
         {
             string data = Combox_CameraColor.Text;
             HOperatorSet.SetFramegrabberParam(myCameraCom.hv_AcqHandle, "color_space", data);
         }
         catch { }
         GetCameraColorSpace();
     }
 }

设置相机曝光时间

private void trackBar_ExposeTimeOut_Scroll(object sender, EventArgs e)
{
    if (checkBox_AutoExposeTimeOut.Checked == false && ChangeValueFlag == false)
    {
        ChangeValueFlag = true;
        string exposure = trackBar_ExposeTimeOut.Value.ToString();
        try
        {
            HOperatorSet.SetFramegrabberParam(myCameraCom.hv_AcqHandle, "ExposureTime", Convert.ToInt32(exposure) * 1000);
        }
        catch { }

        try
        {
            HTuple hv_Value;
            HOperatorSet.GetFramegrabberParam(myCameraCom.hv_AcqHandle, "ExposureTime", out hv_Value);
            trackBar_ExposeTimeOut.Value = Convert.ToInt32(hv_Value[0].D / 1000);
            label_ExposeTimeOut.Text = trackBar_ExposeTimeOut.Value.ToString();
        }
        catch { }

        ChangeValueFlag = false;
    }
}

设置相机自动曝光

private void checkBox_AutoExposeTimeOut_Click(object sender, EventArgs e)
{
    if (checkBox_AutoExposeTimeOut.Checked)
    {
        try
        {
            HOperatorSet.SetFramegrabberParam(myCameraCom.hv_AcqHandle, "ExposureAuto", "Once");
            PublicFunc.Delay(500);
            HOperatorSet.SetFramegrabberParam(myCameraCom.hv_AcqHandle, "ExposureAuto", "Off");
        }
        catch
        { }
        checkBox_AutoExposeTimeOut.Checked = false;
    }
    GetCameraExposure();
}

设置增益

private void trackBar_Gain_Scroll(object sender, EventArgs e)
{
    if (ChangeValueFlag == false)
    {
        ChangeValueFlag = true;
        string gain = trackBar_Gain.Value.ToString();
        try
        {
            HOperatorSet.SetFramegrabberParam(myCameraCom.hv_AcqHandle, "Gain", Convert.ToInt32(gain));
        }
        catch { }
        GetCameraGain();
        ChangeValueFlag = false;
    }
}

设置白平衡

private void checkBox_AutoWhiteBalence_Click(object sender, EventArgs e)
{
    if (checkBox_AutoWhiteBalence.Checked == true)
    {
        try
        {
            HOperatorSet.SetFramegrabberParam(myCameraCom.hv_AcqHandle, "white_balance", "auto");
        }
        catch
        {

        }
        PublicFunc.Delay(500);
        checkBox_AutoWhiteBalence.Checked = false;
    }
}

4.Calibration.cs文件的重要函数

这里主要是相机坐标与机器人坐标标定

1.生成标定数据

private void button_SaveTransData_Click(object sender, EventArgs e)
{
    int SelectedIndex = comboBox_Position.SelectedIndex;
    if (SelectedIndex <= -1)
    {
        MessageBox.Show("请选择工位编号");
        return;
    }

    int RowsCount = dataGridView_DataVision.Rows.Count - 1;
    int index = 0;
    for (; index < RowsCount; index++)
    {
        if (dataGridView_DataVision.Rows[index].Cells[0].Value == null ||
            dataGridView_DataVision.Rows[index].Cells[1].Value == null ||
            dataGridView_DataVision.Rows[index].Cells[2].Value == null ||
            dataGridView_DataVision.Rows[index].Cells[3].Value == null)
        {
            DataGridViewRow row = dataGridView_DataVision.Rows[index];
            dataGridView_DataVision.Rows.Remove(row);
            index--;
            RowsCount--;
        }
    }
    dataGridView_DataVision_RowsAdded(null, null);

    RowsCount = dataGridView_DataVision.Rows.Count - 1;

    myPositionData[SelectedIndex].image_X = new HTuple();
    myPositionData[SelectedIndex].image_Y = new HTuple();
    myPositionData[SelectedIndex].Robot_X = new HTuple();
    myPositionData[SelectedIndex].Robot_Y = new HTuple();

    for (index = 0; index < RowsCount; index++)
    {
        HOperatorSet.TupleConcat(myPositionData[SelectedIndex].image_X, new HTuple(Convert.ToDouble(dataGridView_DataVision.Rows[index].Cells[0].Value.ToString())), out myPositionData[SelectedIndex].image_X);
        HOperatorSet.TupleConcat(myPositionData[SelectedIndex].image_Y, new HTuple(Convert.ToDouble(dataGridView_DataVision.Rows[index].Cells[1].Value.ToString())), out myPositionData[SelectedIndex].image_Y);
        HOperatorSet.TupleConcat(myPositionData[SelectedIndex].Robot_X, new HTuple(Convert.ToDouble(dataGridView_DataVision.Rows[index].Cells[2].Value.ToString())), out myPositionData[SelectedIndex].Robot_X);
        HOperatorSet.TupleConcat(myPositionData[SelectedIndex].Robot_Y, new HTuple(Convert.ToDouble(dataGridView_DataVision.Rows[index].Cells[3].Value.ToString())), out myPositionData[SelectedIndex].Robot_Y);
    }
    myPositionData[SelectedIndex].PointSum = RowsCount;

    if (RowsCount < 3)
    {
        MessageBox.Show("数据量不够,最少3个点");
        myPositionData[SelectedIndex].RobotHommat = new HHomMat2D();
        myPositionData[SelectedIndex].TransFlag = false;
    }
    else
    {
        try
        {
            myPositionData[SelectedIndex].RobotHommat = new HHomMat2D();
            myPositionData[SelectedIndex].RobotHommat.VectorToHomMat2d(myPositionData[SelectedIndex].image_X, myPositionData[SelectedIndex].image_Y, myPositionData[SelectedIndex].Robot_X, myPositionData[SelectedIndex].Robot_Y);
            myPositionData[SelectedIndex].TransFlag = true;
            MessageBox.Show(string.Format("机器人标定完成,工位:{0}", SelectedIndex + 1));
        }
        catch
        {
            myPositionData[SelectedIndex].RobotHommat = new HHomMat2D();
            myPositionData[SelectedIndex].TransFlag = false;
            MessageBox.Show("数据异常");
        }
    }
    WriteData(SelectedIndex, SelectedIndex + 1);
    comboBox_Position.Items.Clear();
    for (int i = 0; i < SlnModelCom.PositionDataNum; i++)
        comboBox_Position.Items.Add("仿射矩阵:" + (i + 1).ToString() + "  <---->  " + (myPositionData[i].TransFlag ? "OK" : "NG"));
    comboBox_Position.SelectedIndex = SelectedIndex;

    CalibDataSendEvent(SelectedIndex, myPositionData[SelectedIndex]);
}

2.获取标定数据

public bool PixelToRobot(int ID, double img_x, double img_y, out double robot_x, out double robot_y)
{
    robot_x = robot_y = -999.999;
    if (ID < 0 || ID >= SlnModelCom.PositionDataNum)
        return false;
    if (myPositionData[ID].TransFlag == true)
    {
        try
        {
            robot_x = myPositionData[ID].RobotHommat.AffineTransPoint2d(img_x, img_y, out robot_y);
            return true;
        }
        catch
        {
            return false;
        }
    }
    return false;
}

5.ImageMatching.cs文件的重要函数

1.定义类变量及一些属性

[DllImport("kernel32.dll",CallingConvention = CallingConvention.Winapi)]
extern static int GetTickCount();

private string FilePath;
CurrentControl MyCurrentControl = new CurrentControl();
SlnModelCom MySlnData = null;
CameraSetting MyCameraSetting;
Calibration MyCalibration;
SoftKeyPWD myDog = null;
TcpServer RobotTcp;

private void Check(bool res)
{
    if (res == false)
    {
        System.Environment.Exit(System.Environment.ExitCode);
    }
}

2.初始化halcon控件

HOperatorSet.SetSystem("clip_region", new HTuple("false"));
ReadModel(0, SlnModelCom.MaxModelNum);
HOperatorSet.SetSystem("clip_region", new HTuple("true"));
updateModelComboBox(0);

MyCurrentControl.HalconWindow = hWindowControl_Show.HalconWindow;
HDevWindowStack.Push(MyCurrentControl.HalconWindow);
HOperatorSet.SetDraw(HDevWindowStack.GetActive(), "margin");
MyCurrentControl.HalconWindow.SetColor("red");
MyCurrentControl.HalconWindow.SetLineWidth(1);
MyCurrentControl.HalconWindow.SetWindowParam("background_color", "gray");
HOperatorSet.SetWindowAttr("background_color", "gray");

3.载入方案

Object tempData;
DataSave.DeSerializeObject(fd.FileName.ToString(), out tempData);
MySlnData = (SlnModelCom)tempData;
for (int i = 0; i < SlnModelCom.PositionDataNum; i++)
{
    MyCalibration.SlnUpdateCalib(i, MySlnData.myPositionData[i]);
}
updateModelComboBox(0);
ShowMessageLabel.Text = "载入方案成功!";

4.保存方案

DataSave.SerializeObject(sfd.FileName, MySlnData);
ShowMessageLabel.Text = "保存方案成功!";

5.绘制ROI区域

主入口

private void DrawRegion(int DrawROIType)
{
    MyCurrentControl.dataRes = new Queue<VisionPoint>();
    MyCurrentControl.lineDataRes = new CenterLine();
    if (ImageFunc.IsEmptyImage(MyCurrentControl.ho_Image))
        return;
    MyCurrentControl.mouseStatus.MouseBrushDrawingFlag = true;
    menuStrip1.Enabled = false;
    HObject ROITemp = new HObject();
    ShowMessageLabel.Text = "左键绘制,右键确定";
    ReDraw(true);
    HOperatorSet.SetColor(MyCurrentControl.HalconWindow, "red");

    switch (DrawROIType)
    {
        case 0:      //绘制矩形
            HTuple row1, row2, col1, col2;
            HOperatorSet.DrawRectangle1(MyCurrentControl.HalconWindow, out row1, out row2, out col1, out col2);
            HOperatorSet.GenRectangle1(out ROITemp, row1, row2, col1, col2);
            break;
        case 1:      //绘制旋转矩形
            HTuple row, col, length1, length2, phi;
            HOperatorSet.DrawRectangle2(MyCurrentControl.HalconWindow, out row, out col, out phi, out length1, out length2);
            HOperatorSet.GenRectangle2(out ROITemp, row, col, phi, length1, length2);
            break;
        case 2:      //绘制圆形
            HTuple row_1, col_1, radius_1;
            HOperatorSet.DrawCircle(MyCurrentControl.HalconWindow, out row_1, out col_1, out radius_1);
            HOperatorSet.GenCircle(out ROITemp, row_1, col_1, radius_1);
            break;
        case 3:      //绘制椭圆
            HTuple row_e, col_e, phi_e, radius_e1, radius_e2;
            HOperatorSet.DrawEllipse(MyCurrentControl.HalconWindow, out row_e, out col_e, out phi_e, out radius_e1, out radius_e2);
            HOperatorSet.GenEllipse(out ROITemp, row_e, col_e, phi_e, radius_e1, radius_e2);
            break;
        case 4:      //绘制任意区域
            HOperatorSet.DrawRegion(out ROITemp, MyCurrentControl.HalconWindow);
            break;
    }

    switch (MyCurrentControl.ROIRunType)
    {
        case 0:
            HOperatorSet.Union2(MyCurrentControl.CurrentROI, ROITemp, out MyCurrentControl.CurrentROI);
            break;
        case 1:
            HOperatorSet.Difference(MyCurrentControl.CurrentROI, ROITemp, out MyCurrentControl.CurrentROI);
            break;
        case 2:
            HOperatorSet.Intersection(MyCurrentControl.CurrentROI, ROITemp, out MyCurrentControl.CurrentROI);
            break;
    }
    menuStrip1.Enabled = true;
    ReDraw(true);
    ShowMessageLabel.Text = "绘制完成";
    MyCurrentControl.mouseStatus.MouseBrushDrawingFlag = false;
}

6.创建模板

主创建模板入口

private void Action_CreateModel_Click(object sender, EventArgs e)
{
    MyCurrentControl.dataRes = new Queue<VisionPoint>();
    MyCurrentControl.lineDataRes = new CenterLine();
    if (ImageFunc.IsEmptyImage(MyCurrentControl.ho_Image) || ImageFunc.IsEmptyRegion(MyCurrentControl.CurrentROI))
    {
        ShowMessageLabel.Text = "无原图或者ROI";
        return;
    }
    if (MySlnData.MyModel[MyCurrentControl.CurrentModelNum].EffectiveFlag == true)
    {
        DialogResult result = MessageBox.Show("已经存在模板是否替换?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
        if (result == DialogResult.Cancel)
        {
            return;
        }
    }
    
    InitMyModel(MyCurrentControl.CurrentModelNum, MyCurrentControl.CurrentModelNum + 1);

    MySlnData.MyModel[MyCurrentControl.CurrentModelNum].h_OriginImg = MyCurrentControl.ho_Image.Clone();
    MySlnData.MyModel[MyCurrentControl.CurrentModelNum].h_OriginRegion = MyCurrentControl.CurrentROI.Clone();
    MySlnData.MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm = MyCurrentControl.TemplateAlgorithm;
    updateVisionParams(MyCurrentControl.CurrentModelNum);

    bool Res = false;
    ShowMessageLabel.Text = "正在创建模板...";
    if (MyCurrentControl.TemplateAlgorithm == 0)
        Res = CreateShapeModel();
    else if (MyCurrentControl.TemplateAlgorithm == 1)
        Res = CreateGrayModel();
    else if (MyCurrentControl.TemplateAlgorithm == 2)
        Res = CreateNCCModel();
    else if (MyCurrentControl.TemplateAlgorithm == 3)
        Res = CreateChangeShapeModel();
    else
    { }
    if (Res == false)
    {
        InitMyModel(MyCurrentControl.CurrentModelNum, MyCurrentControl.CurrentModelNum + 1);
        ShowMessageLabel.Text = "模板创建失败!";
    }
    else
    {
        DataSave.SerializeObject(FilePath + string.Format(@"/Model_{0}.dat", MyCurrentControl.CurrentModelNum + 1), MySlnData.MyModel[MyCurrentControl.CurrentModelNum]);
        ShowMessageLabel.Text = "模板创建成功!";
    }
    updateModelComboBox(MyCurrentControl.CurrentModelNum);
}

以灰度匹配为例

private bool CreateGrayModel()
{
    if (ImageFunc.IsEmptyImage(MySlnData.MyModel[MyCurrentControl.CurrentModelNum].h_OriginImg) || ImageFunc.IsEmptyRegion(MySlnData.MyModel[MyCurrentControl.CurrentModelNum].h_OriginRegion))
        return false;
    HObject CreateModelImage = MySlnData.MyModel[MyCurrentControl.CurrentModelNum].h_OriginImg.Clone();
    
    HObject hv_ImageReduced;
    HTuple hv_pi = ((new HTuple(0.0)).TupleAcos()) * 2;
    HOperatorSet.ReduceDomain(CreateModelImage, MySlnData.MyModel[MyCurrentControl.CurrentModelNum].h_OriginRegion, out hv_ImageReduced);
    try
    {
        HOperatorSet.CreateTemplateRot(hv_ImageReduced, 4, (new HTuple(slider_StartAngel.Value)).TupleRad(), (new HTuple(slider_EndAngel.Value)).TupleRad(), 0.0982, "sort", "original", out MySlnData.MyModel[MyCurrentControl.CurrentModelNum].hv_ModelID);
    }
    catch { return false; }
    MySlnData.MyModel[MyCurrentControl.CurrentModelNum].EffectiveFlag = true;
    HOperatorSet.AreaCenter(MySlnData.MyModel[MyCurrentControl.CurrentModelNum].h_OriginRegion, out MySlnData.MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Angle, out MySlnData.MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Row, out MySlnData.MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Column);
    HOperatorSet.GenEmptyRegion(out MyCurrentControl.CurrentROI);

    ReDraw(true);
    MyCurrentControl.HalconWindow.SetColor("blue");
    HObject XLD_Region;
    HOperatorSet.GenContourRegionXld(MySlnData.MyModel[MyCurrentControl.CurrentModelNum].h_OriginRegion, out XLD_Region, "border");
    MyCurrentControl.HalconWindow.DispObj(XLD_Region);
    HObject Cross;
    HOperatorSet.GenCrossContourXld(out Cross, MySlnData.MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Row, MySlnData.MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Column, MyCurrentControl.Image_Width / 24, 0);
    MyCurrentControl.HalconWindow.DispObj(Cross);
    return true;
}

7.查找模板

查找模板主入口

private Queue<VisionPoint> FindModelRes(HObject img, int model_num)
{
    Queue<VisionPoint> pp = new Queue<VisionPoint>();
    MyCurrentControl.lineDataRes = new CenterLine();
    HOperatorSet.GenEmptyRegion(out MyCurrentControl.CurrentROI);
    MyCurrentControl.CurrentModelNum = model_num;
    if (MySlnData.MyModel[model_num].TemplateAlgorithm == 0)
        pp = FindModel_Shape(img, model_num);
    else if (MySlnData.MyModel[model_num].TemplateAlgorithm == 1)
        pp = FindModel_Gray(img, model_num);
    else if (MySlnData.MyModel[model_num].TemplateAlgorithm == 2)
        pp = FindModel_NCC(img, model_num);
    else if (MySlnData.MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm == 3)
        pp = FindModel_ChangeShape(img, model_num);
    else { }
    return pp;
}

以灰度匹配为例查找模板

private Queue<VisionPoint> FindModel_Gray(HObject img, int currentModelNum)
{
    Queue<VisionPoint> pp = new Queue<VisionPoint>();
    MyCurrentControl.lineDataRes = new CenterLine();
    if (ImageFunc.IsEmptyImage(img) || !MySlnData.MyModel[currentModelNum].EffectiveFlag || currentModelNum < 0 || currentModelNum > SlnModelCom.MaxModelNum)
    {
        ShowMessageLabel.Text = "无模板或无原图或模板号错误";
        return pp;
    }
    HTuple row1 = 0, col1 = 0, row2 = 0, col2 = 0;
    HObject CreateModelImage = img.Clone();
    
    if (!ImageFunc.IsEmptyRegion(MySlnData.MyModel[currentModelNum].h_SearchROI))
    {
        HOperatorSet.ReduceDomain(CreateModelImage, MySlnData.MyModel[currentModelNum].h_SearchROI, out CreateModelImage);
        HOperatorSet.CropDomain(CreateModelImage, out CreateModelImage);
    }
    HTuple hv_RowCheck = null, hv_ColumnCheck = null, hv_AngleCheck = null, hv_Error = null;
    try
    {
        HOperatorSet.BestMatchRotMg(CreateModelImage, MySlnData.MyModel[currentModelNum].hv_ModelID, (new HTuple(MySlnData.MyModel[currentModelNum].startAngle)).TupleRad(), (new HTuple(MySlnData.MyModel[currentModelNum].endAngle)).TupleRad(), 100 - MySlnData.MyModel[currentModelNum].Score / 100.0, "true", 4, out hv_RowCheck, out hv_ColumnCheck, out hv_AngleCheck, out hv_Error);
    }
    catch
    {
        return pp;
    }

    if (0 < (int)((new HTuple(hv_Error.TupleLength()))))
    {
        try
        {
            if (MySlnData.MyModel[currentModelNum].Score / 100.0 > (100 - hv_Error[0].D))
                return pp;

            HObject ho_ImageAffinTrans;
            HTuple hMat2D = null;
            HOperatorSet.VectorAngleToRigid(MySlnData.MyModel[currentModelNum].hv_Orgin_Row, MySlnData.MyModel[currentModelNum].hv_Orgin_Column, 0, hv_RowCheck[0].D, hv_ColumnCheck[0].D, hv_AngleCheck[0].D, out hMat2D);
            HOperatorSet.AffineTransRegion(MySlnData.MyModel[currentModelNum].h_OriginRegion, out ho_ImageAffinTrans, hMat2D, "constant");
            HTuple RowTrans = hv_RowCheck[0], ColumnTrans = hv_ColumnCheck[0];
            if (MySlnData.MyModel[currentModelNum].hv_Target_Row[0].D != -1 && MySlnData.MyModel[currentModelNum].hv_Target_Column[0].D != -1)
                HOperatorSet.AffineTransPixel(hMat2D, MySlnData.MyModel[currentModelNum].hv_Target_Row, MySlnData.MyModel[currentModelNum].hv_Target_Column, out RowTrans, out ColumnTrans);

            if (!ImageFunc.IsEmptyRegion(MySlnData.MyModel[currentModelNum].h_SearchROI))
            {
                RowTrans = RowTrans + row1;
                ColumnTrans = ColumnTrans + col1;
                HOperatorSet.MoveRegion(ho_ImageAffinTrans, out ho_ImageAffinTrans, row1, col1);
            }
            pp.Enqueue(new VisionPoint(RowTrans.D, ColumnTrans.D, hv_AngleCheck[0].D * 57.3, 100 - hv_Error[0].D, null, ho_ImageAffinTrans));

        }
        catch { }
    }
    return pp;
}

总结

该工程篇幅比较多,不过具体的函数在文章中已经表标明,具体的查看源码使用。

  • 17
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱学习的广东仔

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

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

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

打赏作者

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

抵扣说明:

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

余额充值