基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】

文章目录

  • 前言
  • 演示视频
  • 一、项目文件目录讲解
    • 1.CtuVisionControlLibrary
    • 2.CtuVisionDLLTest_CSharp
    • 2.CtuVisionDLLTest_MFC
    • 2.CtuVisionDLLTest_QT
  • 二、CtuVisionControlLibrary界面设置
    • 1.CtuVisionControlLibrary.cs主窗体页面
    • 2.Camera.cs主窗体页面
    • 3.Calibration.cs主窗体页面
  • 三、调用CtuVisionControlLibrary.dll框架的二次开发页面
    • 1.CtuVisionDLLTest_CSharp主窗体页面
    • 2.CtuVisionDLLTest_CSharp主窗体页面
    • 3.CtuVisionDLLTest_QT主窗体页面
  • 四、CtuVisionControlLibrary项目解析
    • 1.Camera相机设置算法配置
      • 1.定义基本的类变量
      • 2.设置窗体关闭时只是隐藏而不是真的关闭
      • 3.搜索相机
      • 4.连接相机
      • 5.断开相机
      • 6.连接相机后获取相机配置参数
      • 7.修改相机参数
      • 8.线程显示照片,这里使用锁的方式
    • 2.Calibration标定坐标系算法配置
      • 1.标定算法
      • 2.调用标定数据
    • 3.CtuVisionControlLibrary主窗体算法配置
      • 1.这里先配置主结构体,后续会用到的结构体
      • 2.设置C++接口的函数
      • 3.在构造函数上方编写此段话
      • 4.对C++外露函数进行实现
      • 5.开始具体的算法实现
      • 6.打开图像
      • 7.保存图像
      • 8.ROI绘制及运算规则设置
      • 9.创建模板
      • 10.查找模板
      • 11.条形码识别
      • 12.二维码识别
      • 13.OCR识别
    • 4.CtuVisionDLLTest_CSharp主窗体调用算法控件dll
      • 1.定义指针结构体
      • 2.定义事件ID
      • 3.构造函数引入dll
      • 4.调用方法:以模板匹配为例
    • 5.CtuVisionDLLTest_MFC主窗体调用算法控件dll
      • 1.MFC注册dll
      • 2.编写加载ActiveX的函数
      • 3.注意控件的加载函数
      • 4.接口调用
    • 6.CtuVisionDLLTest_QT主窗体调用算法控件dll
      • 1.构造函数加载dll控件并且支持多控件加载,代表多相机使用
      • 2.调用方式
  • 总结及源码


前言

本文主要实现halcon二次开发,基于C#做视觉算法的编辑,已C#做用户空间,然后使用C#、C++(MFC、Qt)分别实现调用,从而实现多相机的使用。
换句话说就是:C#做算法及主界面开发,然后把生成的控件dll移交给C#或者MFC或者QT进行二次调用实现二次开发,这里主要想展示的是多语言之间的调用以及如何跨语言调用控件算法
编程环境:C# .net4.0
MFC
qt5.3
halcon12.0
IDE: VisualStudio 2010
备注:版本都基本不重要,本人测试过用VisualStudio2019 halcon20.05 .net4.7 qt5.15等版本测试过无问题


演示视频

本次项目的效果视频:

Halcon多相机模板匹配,多语言调用


一、项目文件目录讲解

基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第1张图片
本工程主要有4个项目:
1、CtuVisionControlLibrary:这里是最基本最终的算法部分,使用C#语言编写,用C#做一个用户控件
2、CtuVisionDLLTest_CSharp:使用C#做主软件的界面,调用上边项目的CtuVisionControlLibrary.dll,可实现多相机的使用
3、CtuVisionDLLTest_MFC:使用C++版的MFC框架做主软件的界面,,调用上边项目的CtuVisionControlLibrary.dll,可实现多相机的使用
4、CtuVisionDLLTest_QT:使用C++版的QT框架做主软件的界面,,调用上边项目的CtuVisionControlLibrary.dll,可实现多相机的使用


1.CtuVisionControlLibrary

基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第2张图片
这里是主体框架的目录,其中包括三个类窗体,分别是:
Calibration:标定窗体和算法
Camera:相机设置的主界面
CtuVisionControlLibrary:算法主界面(这里边还需要把C++接口暴露出去)

2.CtuVisionDLLTest_CSharp

基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第3张图片
这里的框架内容比较简单,因为主算法在CtuVisionControlLibrary.dll里边,这里可以理解为是基于CtuVisionControlLibrary.dll的二次开发

2.CtuVisionDLLTest_MFC

基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第4张图片
这里的框架内容比较简单,因为主算法在CtuVisionControlLibrary.dll里边,这里可以理解为是基于CtuVisionControlLibrary.dll的二次开发,这里主要是MFC对话框,想了解MFC单文档的视觉定位可看我之前写的一篇博客。

2.CtuVisionDLLTest_QT

基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第5张图片
这里的框架内容比较简单,因为主算法在CtuVisionControlLibrary.dll里边,这里可以理解为是基于CtuVisionControlLibrary.dll的二次开发,这里主要是MFC对话框,想了解MFC单文档的视觉定位可看我之前写的一篇博客。


二、CtuVisionControlLibrary界面设置

先上图,只需要按照这个来设置即可:

1.CtuVisionControlLibrary.cs主窗体页面

基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第6张图片
基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第7张图片
基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第8张图片
基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第9张图片
基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第10张图片
基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第11张图片

2.Camera.cs主窗体页面

基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第12张图片

3.Calibration.cs主窗体页面

基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第13张图片


三、调用CtuVisionControlLibrary.dll框架的二次开发页面

1.CtuVisionDLLTest_CSharp主窗体页面

C#界面仅仅做一个label窗体,后续代码引入dll写入控件
基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第14张图片

2.CtuVisionDLLTest_CSharp主窗体页面

MFC窗体不需要设置其他,只需要以及个页面即可,后续只需要代码写入位置和大小即可
基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第15张图片

3.CtuVisionDLLTest_QT主窗体页面

QT窗体不需要设置其他,只需要给定一个QLabel即可,后续直接把dll控件引入到label中即可
基于halcon实现视觉定位框架(C#做主算法,C#、MFC、Qt二次开发)【附源码】_第16张图片


四、CtuVisionControlLibrary项目解析

这里主要讲解主算法窗体项目的代码解析

1.Camera相机设置算法配置

1.定义基本的类变量

首先定义一系列类变量

bool GetPictureFlag = false;
bool ColorZoneFlag = false;
bool ROIFlag = false;
bool TenFlag = false;
public HTuple hv_AcqHandle;
HWindow HalconWindow;
string CameraType;
string CamreaName;
HObject ho_Image;
HTuple ho_Width, ho_Hight, hvRoi_width, hvRoi_hight;
private readonly object locker1 = new object();
private readonly object locker2 = new object();
public bool ConnectCameraFlag = false;

2.设置窗体关闭时只是隐藏而不是真的关闭

在窗体自带的事件xxx_Close()函数中设置:

private void Camera_FormClosing(object sender, FormClosingEventArgs e)
{
    this.Hide();
    e.Cancel = true;
}

3.搜索相机

这里是搜索相机功能,主要是DirectShow、Gige接口的相机

private void button3_Click(object sender, EventArgs e)
{
      comboBox1.Items.Clear();
      HTuple hv_Information = null, hv_ValueList = null;
      HTuple hv_Length = null;
      string[] deviceNames = { "GigEVision", "DirectShow", "GenICamTL" };

      foreach (string names in deviceNames)
      {
          try
          {
              HOperatorSet.InfoFramegrabber(names, "device", out hv_Information, out hv_ValueList);  // 获取设备信息  放到hv_ValueList
              HOperatorSet.TupleLength(hv_ValueList, out hv_Length);  //TupleLength获取元组的元素的数目 即元组长度
              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;
                  }
                  strDevice = names + ":" + strDevice;
                  comboBox1.Items.Add(strDevice);
              }
          }
          catch //(System.Exception ex)
          {
          }
      }
      if (comboBox1.Items.Count > 0)
          comboBox1.SelectedIndex = 0;
  }

4.连接相机

根据搜索相机的一些配置参数连接相机

private void OpenCamrea()
{
    HTuple Information, ValueList;
    string ColorZone = "";
    HalconWindow = hWindowControl1.HalconWindow;
    HalconWindow.SetColor("red");
    string selctCam = comboBox1.SelectedItem.ToString();
    int StrSplit = selctCam.IndexOf(":");
    CameraType = selctCam.Substring(0, StrSplit);
    CamreaName = selctCam.Substring(StrSplit + 1).TrimEnd();

    if (comboBox2.Items.Count <= 0)
    {
        if (CameraType == "DirectShow")
        {
            ColorZone = "gray";
        }
        else if (CameraType == "GigEVision" || CameraType == "GenICamTL")
        {
            ColorZone = "default";
        }
    }
    else
    {
        ColorZone = comboBox2.Text;
    }
    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], ColorZone, ValueList[9], ValueList[10], ValueList[11], CamreaName, 0, ValueList[13], out hv_AcqHandle);
        HOperatorSet.GrabImageStart(hv_AcqHandle, -1);
        HOperatorSet.GrabImageAsync(out ho_Image, hv_AcqHandle, -1);
        HOperatorSet.GetImageSize(ho_Image, out ho_Width, out ho_Hight);
        HalconWindow.SetPart(0, 0, ho_Hight - 1, ho_Width - 1);
        if (button5.Text == "取消ROI")
            button5_Click(null, null);
        GetCarmerInfo(CameraType);
        button1.Text = "断开";
        //trackBar1.Enabled = true;
        trackBar2.Enabled = true;
        button2.Enabled = true;
        ConnectCameraFlag = true;
    }
    catch
    {
        MessageBox.Show("相机连接失败");
        CloseCamera();
    }
}

5.断开相机

既然连接了相机,就有断开相机的说法

private void CloseCamera()
{
     if (button2.Text == "停止预览")
         button2_Click(null, null);
     checkBox2.Checked = false;
     TenFlag = false;
     GetPictureFlag = false;
     checkBox5.Enabled = false;
     trackBar1.Enabled = false;
     trackBar2.Enabled = false;
     Delay(500);
     button2.Enabled = false;
     button1.Text = "连接";
     ConnectCameraFlag = false;
     try
     {
         HOperatorSet.CloseFramegrabber(hv_AcqHandle);
         hv_AcqHandle = null;
     }
     catch { }
 }

6.连接相机后获取相机配置参数

此代码段必须在相机连接后调用获取

private void GetCarmerInfo(string CameraType)
{
    //像素格式
    try
    {
        HTuple hv_Value, hv_Length;
        HOperatorSet.GetFramegrabberParam(hv_AcqHandle, "PixelFormat", out hv_Value);
        HOperatorSet.TupleLength(hv_Value, out hv_Length);
        int length = (int)hv_Length[0];
        for (int i = 0; i < length; i++)
        {
            comboBox3.Items.Add(hv_Value[0].S);
        }
        if (length > 0)
        {
            comboBox3.SelectedIndex = 0;
        }
    }
    catch
    {

    }

    //颜色空间
    try
    {
        if (comboBox2.Items.Count <= 0)
        {
            HTuple Information, ValueList, hv_Length;
            HOperatorSet.InfoFramegrabber(CameraType, "color_space", out Information, out ValueList);

            HOperatorSet.TupleLength(ValueList, out hv_Length);
            int length = (int)hv_Length[0];
            for (int i = 0; i < length; i++)
            {
                comboBox2.Items.Add(ValueList[i].S);
            }
            if (comboBox2.Items.Count > 0)
            {
                ColorZoneFlag = true;
                comboBox2.SelectedIndex = 0;
            }
        }
    }
    catch
    {

    }

    //曝光时间
    try
    {
        HTuple hv_Value;
        //曝光时间
        if (CameraType == "DirectShow")
        {
            trackBar1.Minimum = -13;
            trackBar1.Maximum = -1;
            trackBar1.Value = -1;
            label5.Text = trackBar1.Value.ToString();
            checkBox5.Enabled = true;
            checkBox5.Checked = true;
            trackBar1.Enabled = false;
            HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "exposure", "auto");
        }

        if (CameraType == "GigEVision")
        {
            HOperatorSet.GetFramegrabberParam(hv_AcqHandle, "ExposureTimeRaw", out hv_Value);    //shuoable
            int extime = Convert.ToInt32(hv_Value[0].D);
            trackBar1.Minimum = 0;
            trackBar1.Maximum = 4095;
            trackBar1.Value = extime;
            label5.Text = trackBar1.Value.ToString();
            trackBar1.Enabled = true;
            checkBox5.Checked = false;
            checkBox5.Enabled = false;
        }
    }
    catch
    {

    }

    //增益
    try
    {
        HTuple hv_Value;
        HOperatorSet.GetFramegrabberParam(hv_AcqHandle, "GainRaw", out hv_Value);
        int gain = Convert.ToInt32(hv_Value[0].D);
        trackBar2.Minimum = 8;
        trackBar2.Maximum = 63;
        trackBar2.Value = gain;
        label6.Text = trackBar2.Value.ToString();
        trackBar2.Enabled = true;
    }
    catch
    {

    }
}

7.修改相机参数

修改曝光时间

private void trackBar1_Scroll(object sender, EventArgs e)
{
    if (checkBox5.Checked == false)
    {
        string exposure = trackBar1.Value.ToString();
        label5.Text = exposure;
        try
        {
            if (CameraType == "DirectShow")
            {
                HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "exposure", Convert.ToInt32(exposure));
            }
            if (CameraType == "GigEVision")
            {
                HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "ExposureTimeRaw", Convert.ToInt32(exposure));
            }
        }
        catch
        {

        }
    }
}

修改增益

private void trackBar2_Scroll(object sender, EventArgs e)
{
    string gain = trackBar2.Value.ToString();
    label6.Text = gain;
    try
    {
        HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "GainRaw", Convert.ToInt32(gain));
    }
    catch
    {

    }
}

设置白平衡

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

         }
     }
     else
     {
         //HTuple hv_Value;
         //HOperatorSet.GetFramegrabberParam(hv_AcqHandle, "white_balance", out hv_Value);
         //HOperatorSet.SetFramegrabberParam(hv_AcqHandle, "white_balance", Convert.ToInt32(hv_Value.D));
     }
 }

8.线程显示照片,这里使用锁的方式

private void GetImage()
{
     while (GetPictureFlag)
     {
         try
         {
             lock (locker2)
             {
                 ho_Image.Dispose();    //释放
                 HOperatorSet.GrabImageAsync(out ho_Image, hv_AcqHandle, -1);
                 HalconWindow.DispObj(ho_Image);
                 Thread.Sleep(50);
             }
         }
         catch
         {

         }
     }
 }

2.Calibration标定坐标系算法配置

1.标定算法

这里可多点标定,在界面上设置即可,需要三点以上标定

private void AffineTran(int Affine_Num)
{
    HTuple concat = new HTuple(), concat1 = new HTuple(), concat2 = new HTuple(), concat3 = new HTuple();
    try
    {
        concat = concat.TupleConcat(VectorHam2D[Affine_Num].img_x1);
        concat1 = concat1.TupleConcat(VectorHam2D[Affine_Num].img_y1);
        concat2 = concat2.TupleConcat(VectorHam2D[Affine_Num].tar_x1);
        concat3 = concat3.TupleConcat(VectorHam2D[Affine_Num].tar_y1);

        concat = concat.TupleConcat(VectorHam2D[Affine_Num].img_x2);
        concat1 = concat1.TupleConcat(VectorHam2D[Affine_Num].img_y2);
        concat2 = concat2.TupleConcat(VectorHam2D[Affine_Num].tar_x2);
        concat3 = concat3.TupleConcat(VectorHam2D[Affine_Num].tar_y2);

        concat = concat.TupleConcat(VectorHam2D[Affine_Num].img_x3);
        concat1 = concat1.TupleConcat(VectorHam2D[Affine_Num].img_y3);
        concat2 = concat2.TupleConcat(VectorHam2D[Affine_Num].tar_x3);
        concat3 = concat3.TupleConcat(VectorHam2D[Affine_Num].tar_y3);
        RobotHommat[Affine_Num] = new HHomMat2D();
        RobotHommat[Affine_Num].VectorToHomMat2d(concat, concat1, concat2, concat3);
        VectorHam2D[Affine_Num].flag = true;
    }
    catch{}
}

2.调用标定数据

这里是标定数据的转换步骤

 public bool PixelToRobot(int Affine_Num, double img_x, double img_y, out double robot_x, out double robot_y)
{
    robot_x = robot_y = -1.0;
    if (VectorHam2D[Affine_Num].flag == true)
    {
        try
        {
            robot_x = RobotHommat[Affine_Num].AffineTransPoint2d(img_x, img_y, out robot_y);
            return true;
        }
        catch //(Exception e)
        {
            return false;
        }
    }
    return false;
}

3.CtuVisionControlLibrary主窗体算法配置

1.这里先配置主结构体,后续会用到的结构体

public struct VisionPoint
{
     public double x;
     public double y;
     public double r;
     public double score;
     public VisionPoint(double imgx, double imgy, double imgr, double s)
     {
         x = imgx;
         y = imgy;
         r = imgr;
         score = s;
     }
 }
 public struct CurrentControl
 {
     public int CurrentROIType;             //当前ROI的绘制方法
     public int CurrentRunROIType;          //当前ROI的运算方法
     public HObject H_CurrentROI;           //当前绘制的ROI
     public int TemplateAlgorithm;          //当前的模板算法
     public int CurrentModelNum;            //当前的模板编号
     public int Image_Width; 
     public int Image_Height;
     public CurrentControl(int a, int b, HObject c,int d,int e,int f,int g)
     {
         CurrentROIType = a;
         CurrentRunROIType = b;
         H_CurrentROI = c;
         TemplateAlgorithm = d;
         CurrentModelNum = e;
         Image_Width = f;
         Image_Height = g;
     }
 }
 public struct ModelCom
 {
     public bool EffectiveFlag;            //改模板是否有效 -
     public int modelNum;                  //模板号 -
     public int TemplateAlgorithm;         //匹配算法 -
     public HObject h_img;                 //创建模板的原图
     public HObject h_roi;                 //创建模板的ROI
     
     public int startAngle;             //起始角度 -
     public int endAngle;               //角度范围 -
     public int Level;                  //对比度 -
     public bool AutoContrast;          //自动对比度 -
     public int Score;               //匹配分数 -
     public int DeformationNum;         //允许变形 -
     public int MatchNum;               //期待匹配数,0代表全部匹配 -
     public HTuple hv_ModelID;          //模板ID
     public int FindModelTimeOut;       //模板匹配超时 -
     public HObject ShapeModelRegions;  //模板轮廓
     public HTuple hv_Orgin_Row;        //模板锚点的行 -
     public HTuple hv_Orgin_Column;     //模板锚点的列 -
     public HTuple hv_Orgin_Angle;      //模板锚点的角度 -
     public HTuple hv_Target_Row;       //锚点的行 -
     public HTuple hv_Target_Column;    //锚点的列 -
     public bool TargetFlag;            //设置锚点的标志 -
     public HObject h_SearchROI;        //搜索区域
     public bool SearchROIFlag;         //拥有搜索区域的标志 -
 }
 public struct BarCode
 {
     public HObject BarCodeROI;
     public bool BarCodeROIFlag;
     public HObject QRCodeROI;
     public bool QRCodeROIFlag;
     public HObject OCRROI;
     public bool OCRROIFlag;
 }

2.设置C++接口的函数

设置的c++接口代表外露的函数部分
Guid用IDE生成

public struct COPYDATASTRUCT
{
    public IntPtr dwData; //可以是任意值
    public int cbData;    //指定lpData内存区域的字节数
    [MarshalAs(UnmanagedType.LPStr)]
    public string lpData; //发送给目录窗口所在进程的数据
}
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
[Guid("147C71DB-62EE-44D9-9D5D-0D8D78A7F093")]
public interface VisionLibrary
{
    void SetAdapterDllPtr(IntPtr i_AdapterDllPtr,int num);
    void StringTest(string str1, out string str2);
    void GetImage(out bool res);
    void FindModel(int ModelNum,out double x,out double y,out double angle);
    void AffineVector2Hom(int Num, double image_x, double image_y, out double robot_x, out double robot_y);
    void ReadBarCode(out string Code);
    void ReadQRCode(out string Code);
    void ReadOCRCode(out string Code);
}

3.在构造函数上方编写此段话

[ProgId("CtuVisionControlLibrary.VisionLibrary")]
[ClassInterface(ClassInterfaceType.None)]
[Guid("37518F8E-21C9-4F51-9777-EFAD6B76ED63")]
public partial class CtuVisionControlLibrary : UserControl, VisionLibrary
{
	xxxx
}

4.对C++外露函数进行实现

弄完此处基本C++接口配置完成

public void SetAdapterDllPtr(IntPtr i_AdapterDllPtr,int num)
{
    AdapterDllPtr = i_AdapterDllPtr;
    VisionNum = num;
    //初始化数据
    filePath = string.Format("./VisionModel{0}", VisionNum);
    if (!Directory.Exists(filePath))
    {
        Directory.CreateDirectory(filePath);
    }

   // HOperatorSet.SetSystem("clip_region", "fasle");
    ReadModel(0, MaxModelNum);
    ReadCodeROI();
    VisionCamera = new Camera();
    ctuPosition = new Calibration(filePath);
    HalconWindow = hWindowControl1.HalconWindow;
    HDevWindowStack.Push(HalconWindow);
    HOperatorSet.SetDraw(HDevWindowStack.GetActive(), "margin");

    updateModelComboBox(0);
    comboBox3.SelectedIndex = 0;
    comboBox4.SelectedIndex = 1;

}

public void StringTest(string str1, out string str2)
{
    str2 = str1;
    byte[] sarr = System.Text.Encoding.Default.GetBytes(str2);
    int len = sarr.Length;
    COPYDATASTRUCT cds;
    cds.dwData = (IntPtr)0;
    cds.cbData = len + 1;
    cds.lpData = str2;
    SendMessage(AdapterDllPtr.ToInt32(), DOT_NET_BUTTON_PRESSED, 0,ref cds);
}

public void GetImage(out bool res)
{
    if (VisionCamera.ConnectCameraFlag == true)
    {
        AcquisitionFlag = false;
        bool Res = VisionCamera.HDevImg(out ho_img);
        if (Res)         //采集单张图像成功
        {
            HOperatorSet.GetImageSize(ho_img, out ho_Width, out ho_Hight);
            MySetPart();
            //HalconWindow.SetPart(0, 0, ho_Hight - 1, ho_Width - 1);
            //hWindowControl1.ImagePart = new System.Drawing.Rectangle((int)0, (int)0, (int)ho_Width[0].I, (int)ho_Hight[0].I);
            MyCurrentControl.Image_Height = (int)ho_Hight[0].I;
            MyCurrentControl.Image_Width = (int)ho_Width[0].I;
            HalconWindow.DispObj(ho_img);
            res = true;
        }
        else
        {
            HalconWindow.ClearWindow();
            res = false;
        }
    }
    else
    {
        HalconWindow.ClearWindow();
        res = false;
    }
}

public void FindModel(int ModelNum, out double x, out double y, out double angle)
{
    if (ModelNum < 0 || ModelNum >= MaxModelNum)
    {
        x = y = angle = -1;
        return;
    }
    string mes = RunFindModel(ModelNum);
    string[] meslist = mes.Split(',');
    x = Convert.ToDouble(meslist[0]);
    y = Convert.ToDouble(meslist[1]);
    angle = Convert.ToDouble(meslist[2]);
    return;
}

public void AffineVector2Hom(int Num, double image_x, double image_y, out double robot_x, out double robot_y)
{
    int PositionDataNum = Calibration.PositionDataNum;
    if (Num < 0 || Num >= PositionDataNum)
    {
        robot_x = robot_y = -1;
        return;
    }
    ctuPosition.PixelToRobot(Num, image_x, image_y, out robot_x, out robot_y);
}

public void ReadBarCode(out string Code)
{
    Code = FindBarCode();
    if (Code != "-1")
    {
        toolStripStatusLabel1.Text = Code;
    }
    else
    {
        toolStripStatusLabel1.Text = "读码失败!";
    }
}

public void ReadQRCode(out string Code)
{
    Code = FindQRCode();
    if (Code != "-1")
    {
        toolStripStatusLabel1.Text = Code;
    }
    else
    {
        toolStripStatusLabel1.Text = "读码失败!";
    }
}

public void ReadOCRCode(out string Code)
{
    Code = ReadOCR();
    if (Code != "-1")
    {
        toolStripStatusLabel1.Text = Code;
    }
    else
    {
        toolStripStatusLabel1.Text = "读码失败!";
    }
}

5.开始具体的算法实现

先定义类变量

private Camera VisionCamera;
private Calibration ctuPosition;
HWindow HalconWindow;
HObject ho_img;          //图像用于显示(原图)
HTuple ho_Width, ho_Hight;     //原图的长宽
bool AcquisitionFlag = false;       //连续采集变量
private readonly object locker1 = new object();       //线程加锁
private bool ChangeImageFlag = false;     //图片缩放功能
private bool ShowTenFlag = false;    //显示十字线功能
private bool MouseDownFlag = false;   //移动的过程中是否按下
CurrentControl MyCurrentControl = new CurrentControl(0, 0, null, 0, 0, 0, 0);
private static int MaxModelNum = 40;
ModelCom[] MyModel = new ModelCom[MaxModelNum];
BarCode MyBarCode = new BarCode();
string filePath = "";
private static int EraserSize = 40;
HObject brush_region1 = new HObject();   //画笔:用于画区域
HObject brush_region2 = new HObject();   //画笔:用于擦除区域

6.打开图像

这里是打开图像的按钮功能

private void toolStripSplitButton2_ButtonClick(object sender, EventArgs e)
{
    string strFilePath = null;
    OpenFileDialog fd = new OpenFileDialog();
    fd.Filter = "All files(*.*)|*.*|图片(*.bmp)|*.bmp";
    if (fd.ShowDialog() != DialogResult.OK)
    {
        return;
    }
    strFilePath = fd.FileName;
    HOperatorSet.ReadImage(out ho_img, strFilePath);
    HOperatorSet.GetImageSize(ho_img, out ho_Width, out ho_Hight);
    MySetPart();
    //HalconWindow.SetPart(0, 0, ho_Hight - 1, ho_Width - 1);
    //hWindowControl1.ImagePart = new System.Drawing.Rectangle((int)0, (int)0, (int)ho_Width[0].I, (int)ho_Hight[0].I);
    MyCurrentControl.Image_Height = (int)ho_Hight[0].I;
    MyCurrentControl.Image_Width = (int)ho_Width[0].I;
    HalconWindow.DispObj(ho_img);
}

7.保存图像

这里是保存图像的按钮功能

private void 保存图像ToolStripMenuItem_Click(object sender, EventArgs e)
{
    if (ho_img == null)
        return;
    SaveFileDialog sfd = new SaveFileDialog();
    sfd.Filter = "图片(*.bmp)|*.bmp|图片(*.tif)|*.tif";
    sfd.FilterIndex = 1;
    sfd.RestoreDirectory = true;
    if (sfd.ShowDialog().ToString() == "OK")
    {
        string FILE_NAME = sfd.FileName.ToString();         //获得文件路径 
        string[] mes = FILE_NAME.Split('.');
        if (mes[mes.Length - 1] == "bmp" || mes[mes.Length - 1] == "tif")
        {
            if (mes[mes.Length - 1] == "bmp")
            {
                HOperatorSet.WriteImage(ho_img, "bmp", 0, FILE_NAME);
            }
            if (mes[mes.Length - 1] == "tif")
            {
                HOperatorSet.WriteImage(ho_img, "tif", 0, FILE_NAME);
            }
        }
    }
    
}

8.ROI绘制及运算规则设置

这里包括ROI绘制方式以及运算规则设置

private void toolStripSplitButton3_ButtonClick(object sender, EventArgs e)
{
    if (ho_img == null)
        return;
    HObject ROITemp = new HObject();
    HTuple hv_Row1 = null, hv_Column1 = null, hv_Row2 = null, hv_Column2 = null, hv_Phi1 = null, hv_Length1 = null, hv_Length2 = null, hv_Radius1 = null, hv_Radius2 = null, hv_Area = null;
    HOperatorSet.SetColor(HalconWindow, "red");
    toolStrip1.Enabled = false;
    switch (MyCurrentControl.CurrentROIType)
    {
        case 0:      //绘制矩形
            HOperatorSet.DrawRectangle1(HalconWindow, out hv_Row1, out hv_Column1, out hv_Row2, out hv_Column2);
            HOperatorSet.GenRectangle1(out ROITemp, hv_Row1, hv_Column1, hv_Row2, hv_Column2);
            break;
        case 1:      //绘制旋转矩形
            HOperatorSet.DrawRectangle2(HalconWindow, out hv_Row1, out hv_Column1, out hv_Phi1, out hv_Length1, out hv_Length2);
            HOperatorSet.GenRectangle2(out ROITemp, hv_Row1, hv_Column1, hv_Phi1, hv_Length1, hv_Length2);
            break;
        case 2:      //绘制圆形
            HOperatorSet.DrawCircle(HalconWindow, out hv_Row1, out hv_Column1, out hv_Radius1);
            HOperatorSet.GenCircle(out ROITemp, hv_Row1, hv_Column1, hv_Radius1);
            break;
        case 3:      //绘制椭圆
            HOperatorSet.DrawEllipse(HalconWindow, out hv_Row1, out hv_Column1, out hv_Phi1, out hv_Radius1, out hv_Radius2);
            HOperatorSet.GenEllipse(out ROITemp, hv_Row1, hv_Column1, hv_Phi1, hv_Radius1, hv_Radius2);
            break;
        case 4:      //绘制任意区域
            HOperatorSet.DrawRegion(out ROITemp, HalconWindow);
            break;
    }
    if (MyCurrentControl.H_CurrentROI == null)
    {
        MyCurrentControl.H_CurrentROI = ROITemp;
    }
    else 
    {
        switch (MyCurrentControl.CurrentRunROIType)
        {
            case 0:
                HOperatorSet.Union2(MyCurrentControl.H_CurrentROI, ROITemp, out MyCurrentControl.H_CurrentROI);
                break;
            case 1:
                HOperatorSet.Intersection(MyCurrentControl.H_CurrentROI, ROITemp, out MyCurrentControl.H_CurrentROI);
                break;
            case 2:
                HOperatorSet.Difference(MyCurrentControl.H_CurrentROI, ROITemp, out MyCurrentControl.H_CurrentROI);
                break;
        }
    }
    
    HOperatorSet.AreaCenter(MyCurrentControl.H_CurrentROI, out hv_Area, out hv_Row1, out hv_Column1);
    HalconWindow.ClearWindow();
    HalconWindow.DispObj(ho_img);
    HalconWindow.DispObj(MyCurrentControl.H_CurrentROI);
    HOperatorSet.SetColor(HalconWindow, "blue");
    HOperatorSet.DispCross(HalconWindow, hv_Row1, hv_Column1, MyCurrentControl.Image_Width == 0 ? 20 : MyCurrentControl.Image_Width / 24, 0);
    toolStrip1.Enabled = true;
}

9.创建模板

创建模板主入口

private void 创建模板ToolStripMenuItem_Click(object sender, EventArgs e)
{
    if (MyModel[MyCurrentControl.CurrentModelNum].EffectiveFlag == true)
    {
        DialogResult result = MessageBox.Show("已经存在模板是否替换?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
        if (result == DialogResult.Cancel)
        {
            MyCurrentControl.H_CurrentROI = null;
            return;
        }
    }
    if (MyCurrentControl.H_CurrentROI == null || ho_img == null)
    {
        MessageBox.Show("无原图或者ROI");
        return;
    }
    InitMyModel(MyCurrentControl.CurrentModelNum, MyCurrentControl.CurrentModelNum + 1);    //删除当前模板
    //把当前的参数保存下来
    MyModel[MyCurrentControl.CurrentModelNum].h_img = ho_img.Clone();
    MyModel[MyCurrentControl.CurrentModelNum].h_roi = MyCurrentControl.H_CurrentROI.Clone();
    MyModel[MyCurrentControl.CurrentModelNum].startAngle = Convert.ToInt32(slider2.Value.ToString());
    MyModel[MyCurrentControl.CurrentModelNum].endAngle = Convert.ToInt32(slider3.Value.ToString());
    MyModel[MyCurrentControl.CurrentModelNum].Level = Convert.ToInt32(slider4.Value.ToString());
    MyModel[MyCurrentControl.CurrentModelNum].AutoContrast = checkBox2.Checked;
    MyModel[MyCurrentControl.CurrentModelNum].FindModelTimeOut = Convert.ToInt32(textBox6.Text);
    MyModel[MyCurrentControl.CurrentModelNum].Score = Convert.ToInt32(slider5.Value.ToString());
    MyModel[MyCurrentControl.CurrentModelNum].MatchNum = Convert.ToInt32(comboBox4.Text);
    MyModel[MyCurrentControl.CurrentModelNum].DeformationNum = Convert.ToInt32(comboBox3.Text);
    MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm = MyCurrentControl.TemplateAlgorithm;
    MyModel[MyCurrentControl.CurrentModelNum].modelNum = MyCurrentControl.CurrentModelNum;

    bool Res = false;
    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);    //删除当前模板
        MyCurrentControl.H_CurrentROI = null;
        toolStripStatusLabel1.Text = "模板创建失败!";
        return;
    }
    else {
        toolStripStatusLabel1.Text = "模板创建成功!";
    }

    updateModelComboBox(MyCurrentControl.CurrentModelNum);

    WriteData(MyCurrentControl.CurrentModelNum);
    WriteImageROI(MyCurrentControl.CurrentModelNum);
}

以创建灰度模板为例

private bool CreateGrayModel()
{
    if (MyCurrentControl.H_CurrentROI == null || ho_img == null)
        return false;

    toolStripStatusLabel1.Text = "正在创建模板...";
    HObject hv_ImageReduced;
    HTuple hv_pi = ((new HTuple(0.0)).TupleAcos()) * 2;
    HOperatorSet.ReduceDomain(MyModel[MyCurrentControl.CurrentModelNum].h_img, MyModel[MyCurrentControl.CurrentModelNum].h_roi, out hv_ImageReduced);
    //创建灰度模板
    try
    {
        HOperatorSet.CreateTemplateRot(hv_ImageReduced, 4, (new HTuple(MyModel[MyCurrentControl.CurrentModelNum].startAngle)).TupleRad(), (new HTuple(MyModel[MyCurrentControl.CurrentModelNum].endAngle)).TupleRad(), 0.0982, "sort", "original", out MyModel[MyCurrentControl.CurrentModelNum].hv_ModelID);
    }
    catch { return false; }
    
    //清除显示
    HalconWindow.ClearWindow();
    HalconWindow.DispObj(MyModel[MyCurrentControl.CurrentModelNum].h_img);
    HOperatorSet.AreaCenter(MyModel[MyCurrentControl.CurrentModelNum].h_roi, out MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Angle, out MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Row, out MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Column);
    HalconWindow.SetColor("blue");
    HalconWindow.DispObj(MyModel[MyCurrentControl.CurrentModelNum].h_roi);
    HalconWindow.SetColor("green");
    HOperatorSet.DispCross(HalconWindow, MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Row, MyModel[MyCurrentControl.CurrentModelNum].hv_Orgin_Column, MyCurrentControl.Image_Width == 0 ? 20 : MyCurrentControl.Image_Width / 24, 0);
    MyCurrentControl.H_CurrentROI = null;
    MyModel[MyCurrentControl.CurrentModelNum].EffectiveFlag = true;
    return true;
}

10.查找模板

查找模板主入口

private void 执行ToolStripMenuItem_Click(object sender, EventArgs e)
{
    if (!MyModel[MyCurrentControl.CurrentModelNum].EffectiveFlag)
    {
        MessageBox.Show("当前模板号无模板");
        return;
    }
    Queue<VisionPoint> pp = new Queue<VisionPoint>();
    if (MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm == 0)
        pp = FindModel_Shape(MyCurrentControl.CurrentModelNum);
    else if (MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm == 1)
        pp = FindModel_Gray(MyCurrentControl.CurrentModelNum);
    else if (MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm == 2)
        pp = FindModel_NCC(MyCurrentControl.CurrentModelNum);
    else if (MyModel[MyCurrentControl.CurrentModelNum].TemplateAlgorithm == 3)
        pp = FindModel_ChangeShape(MyCurrentControl.CurrentModelNum);

    if (pp.Count() != 0)
    {
        string mes = "";
        toolStripStatusLabel1.Text = "";
        while (pp.Count() != 0)
        {
            VisionPoint p = pp.Dequeue();
            mes = mes + p.x.ToString("0.000") + "," + p.y.ToString("0.000") + "," + p.r.ToString("0.000") + ":" + p.score.ToString("0.000") + ";";
        }
        string[] visionTargets = mes.Split(';');
        toolStripStatusLabel1.Text = "模板匹配成功:" + visionTargets[0];
    }
    else
    {
        toolStripStatusLabel1.Text = "模板匹配失败!";
    }
}

以查找灰度模板为例

private Queue<VisionPoint> FindModel_Gray(int ModelNum)
{
    Queue<VisionPoint> pp = new Queue<VisionPoint>();
    if (ho_img == null || MyModel[ModelNum].hv_ModelID == null)
        return pp;

    HTuple hv_RowCheck = null, hv_ColumnCheck = null, hv_AngleCheck = null, hv_Error = null;
    HTuple hMat2D = null;
    HObject ho_ImageAffinTrans;

    double Score = MyModel[ModelNum].Score / 100.0;

    HObject hv_img = ho_img;
    if (MyModel[ModelNum].SearchROIFlag)
        HOperatorSet.ReduceDomain(hv_img, MyModel[ModelNum].h_SearchROI, out hv_img);

    HOperatorSet.BestMatchRotMg(hv_img, MyModel[ModelNum].hv_ModelID, (new HTuple(MyModel[ModelNum].startAngle)).TupleRad(), (new HTuple(MyModel[ModelNum].endAngle)).TupleRad(), 100 - Score, "true", 4, out hv_RowCheck, out hv_ColumnCheck, out hv_AngleCheck, out hv_Error);
    if (0 < (int)((new HTuple(hv_Error.TupleLength()))))
    {
        try
        {
            if (Score > (100 - hv_Error[0].D))
                return pp;
            if (MyModel[ModelNum].TargetFlag == true)
            {
                HTuple RowTrans = null, ColumnTrans = null;

                HOperatorSet.VectorAngleToRigid(MyModel[ModelNum].hv_Orgin_Row, MyModel[ModelNum].hv_Orgin_Column, 0, hv_RowCheck[0].D, hv_ColumnCheck[0].D, hv_AngleCheck[0].D, out hMat2D);
                HOperatorSet.AffineTransPixel(hMat2D, MyModel[ModelNum].hv_Target_Row, MyModel[ModelNum].hv_Target_Column, out RowTrans, out ColumnTrans);
                HalconWindow.SetColor("green");
                HOperatorSet.DispCross(HalconWindow, RowTrans[0].D, ColumnTrans[0].D, MyCurrentControl.Image_Width / 24, hv_AngleCheck[0].D);
                HOperatorSet.AffineTransRegion(MyModel[ModelNum].h_roi, out ho_ImageAffinTrans, hMat2D, "constant");
                HalconWindow.SetColor("blue");
                HalconWindow.DispObj(ho_ImageAffinTrans);
                pp.Enqueue(new VisionPoint(RowTrans[0].D, ColumnTrans[0].D, hv_AngleCheck[0].D * 57.3, 100 - hv_Error[0].D));
            }
            else
            {
                HalconWindow.SetColor("green");
                HOperatorSet.DispCross(HalconWindow, hv_RowCheck[0].D, hv_ColumnCheck[0].D, MyCurrentControl.Image_Width / 24, hv_AngleCheck[0].D);
                HOperatorSet.VectorAngleToRigid(MyModel[ModelNum].hv_Orgin_Row, MyModel[ModelNum].hv_Orgin_Column, 0, hv_RowCheck[0].D, hv_ColumnCheck[0].D, hv_AngleCheck[0].D, out hMat2D);
                HOperatorSet.AffineTransRegion(MyModel[ModelNum].h_roi, out ho_ImageAffinTrans, hMat2D, "constant");
                HalconWindow.SetColor("blue");
                HalconWindow.DispObj(ho_ImageAffinTrans);
                pp.Enqueue(new VisionPoint(hv_RowCheck[0].D, hv_ColumnCheck[0].D, hv_AngleCheck[0].D * 57.3, 100 - hv_Error[0].D));
            }
            if (MyModel[ModelNum].SearchROIFlag)
            {
                HalconWindow.SetColor("orange");
                HalconWindow.DispObj(MyModel[ModelNum].h_SearchROI);
            }
        }
        catch { }
    }
    return pp;
}

11.条形码识别

识别条形码,也就是一维码

private string FindBarCode()
{
     if (ho_img == null)
         return "-1";
     HTuple hv_BarCodeHandle = null, hv_DecodedDataStrings = null, hv_BarCodeResults1 = null;
     HObject ho_SymbolRegions;

     HObject hv_img = ho_img;
     if (MyBarCode.BarCodeROIFlag)
         HOperatorSet.ReduceDomain(hv_img, MyBarCode.BarCodeROI, out hv_img);

     HOperatorSet.CreateBarCodeModel(new HTuple(), new HTuple(), out hv_BarCodeHandle);
     HOperatorSet.SetBarCodeParam(hv_BarCodeHandle, "element_size_min", 1);
     HOperatorSet.FindBarCode(hv_img, out ho_SymbolRegions, hv_BarCodeHandle, "auto", out hv_DecodedDataStrings);
     HOperatorSet.GetBarCodeResult(hv_BarCodeHandle, "all", "orientation", out hv_BarCodeResults1);
     HOperatorSet.ClearBarCodeModel(hv_BarCodeHandle);

     if (MyBarCode.BarCodeROIFlag)
     {
         HalconWindow.SetColor("orange");
         HalconWindow.DispObj(MyBarCode.BarCodeROI);
     }

     HalconWindow.SetColor("green");
     HalconWindow.DispObj(ho_SymbolRegions);

     if ((int)((new HTuple(hv_DecodedDataStrings.TupleLength()))) > 0)
     {
         HTuple hv_Area = null, hv_Row1 = null, hv_Column1 = null;
         string barCode = hv_DecodedDataStrings[0].S;
         double Angle = hv_BarCodeResults1[0].D;
         HOperatorSet.AreaCenter(ho_SymbolRegions, out hv_Area, out hv_Row1, out hv_Column1);
         double BaseLength = MyCurrentControl.Image_Width == 0 ? 50 : MyCurrentControl.Image_Width / 10;
         double BaseArrow = MyCurrentControl.Image_Width == 0 ? 50 : MyCurrentControl.Image_Width / 320;
         HalconWindow.SetColor("red");
         HOperatorSet.DispArrow(HalconWindow, hv_Row1, hv_Column1, hv_Row1 - (((((hv_BarCodeResults1 / 57.3) - 1.57)).TupleCos()) * BaseLength), hv_Column1 - (((((hv_BarCodeResults1 / 57.3) - 1.57)).TupleSin()) * BaseLength), BaseArrow);
         return string.Format("{0}:{1}", barCode, Angle.ToString());
     }
     else
         return "-1";
 }

12.二维码识别

识别二维码

private string FindQRCode()
{
    if (ho_img == null)
        return "-1";

    HObject ho_SymbolXLDs;
    HTuple hv_DataCodeHandle = null, hv_ResultHandles = null, hv_DecodedDataStrings = null;
    HObject hv_img = ho_img;
    if (MyBarCode.QRCodeROIFlag)
        HOperatorSet.ReduceDomain(hv_img, MyBarCode.QRCodeROI, out hv_img);
    
    HOperatorSet.CreateDataCode2dModel("QR Code", new HTuple(), new HTuple(), out hv_DataCodeHandle);
    HOperatorSet.FindDataCode2d(hv_img, out ho_SymbolXLDs, hv_DataCodeHandle, new HTuple(), new HTuple(), out hv_ResultHandles, out hv_DecodedDataStrings);
    HOperatorSet.ClearDataCode2dModel(hv_DataCodeHandle);

    if (MyBarCode.QRCodeROIFlag)
    {
        HalconWindow.SetColor("orange");
        HalconWindow.DispObj(MyBarCode.QRCodeROI);
    }

    if ((int)((new HTuple(hv_DecodedDataStrings.TupleLength()))) > 0)
    {
        string Code = hv_DecodedDataStrings[0].S;
        HalconWindow.SetColor("green");
        HalconWindow.DispObj(ho_SymbolXLDs);
        return Code;
    }
    else 
    {
        return "-1";
    }
}

13.OCR识别

识别OCR

private string ReadOCR()
{
     if (ho_img == null)
         return "-1";
     HObject ho_Region2, ho_ConnectedRegions1, ho_SelectedRegions1, ho_SortedRegions;
     HTuple hv_UsedThreshold2, hv_OCRHandle, hv_Class, hv_Confidence;

     HObject hv_img = ho_img;
     if (MyBarCode.OCRROIFlag)
         HOperatorSet.ReduceDomain(hv_img, MyBarCode.OCRROI, out hv_img);

     HOperatorSet.BinaryThreshold(hv_img, out ho_Region2, "max_separability", "dark", out hv_UsedThreshold2);
     HOperatorSet.Connection(ho_Region2, out ho_ConnectedRegions1);
     HOperatorSet.SelectShape(ho_ConnectedRegions1, out ho_SelectedRegions1, "area", "and", 150, 99999);
     HOperatorSet.SortRegion(ho_SelectedRegions1, out ho_SortedRegions, "character", "true", "row");
     HOperatorSet.ReadOcrClassMlp("./genicam/Industrial.omc",out hv_OCRHandle);
     HOperatorSet.DoOcrMultiClassMlp(ho_SortedRegions, hv_img, hv_OCRHandle, out hv_Class, out hv_Confidence);
     HOperatorSet.ClearOcrClassMlp(hv_OCRHandle);

     if (MyBarCode.OCRROIFlag)
     {
         HalconWindow.SetColor("orange");
         HalconWindow.DispObj(MyBarCode.OCRROI);
     }

     if ((int)((new HTuple(hv_Class.TupleLength()))) > 0)
     {
         string OCRCode = hv_Class[0].S;
         return OCRCode;
     }
     else
     {
         return "-1";
     }
 }

4.CtuVisionDLLTest_CSharp主窗体调用算法控件dll

1.定义指针结构体

public struct COPYDATASTRUCT
{
    public IntPtr dwData; //可以是任意值
    public int cbData;    //指定lpData内存区域的字节数
    [MarshalAs(UnmanagedType.LPStr)]
    public string lpData; //发送给目录窗口所在进程的数据
}

2.定义事件ID

private static uint DOT_NET_BUTTON_PRESSED = 0x0800;

3.构造函数引入dll

这里就是通过代码把dll的窗体引入到界面中

public CtuVisionDLLTest_CSharp()
{
    InitializeComponent();
    IntPtr intPtr = this.Handle;
    ctuVisionControlLibrary1.SetAdapterDllPtr(intPtr, 0);
    ctuVisionControlLibrary2.SetAdapterDllPtr(intPtr, 1);
}

4.调用方法:以模板匹配为例

这里只使用其中一个调用方法,其他方法调用方式一样,里面包含了标定转换

 private void 模板匹配ToolStripMenuItem_Click(object sender, EventArgs e)
 {
     int ModelNum = 0;
     double image_x ,image_y ,image_angle;
     ctuVisionControlLibrary1.FindModel(ModelNum, out image_x, out image_y, out image_angle);   //调用外露函数,模板匹配

     double robot_x, robot_y;
     int PositionNum = 0;
     ctuVisionControlLibrary1.AffineVector2Hom(PositionNum, image_x, image_y, out robot_x, out robot_y);   //调用外露函数,坐标转换
 }

5.CtuVisionDLLTest_MFC主窗体调用算法控件dll

1.MFC注册dll

BOOL CCtuVisionDLLTest_MFCDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码

	
	char filePath[MAX_PATH];
	GetModuleFileNameA(GetModuleHandle(0), filePath, MAX_PATH);
	char* pos = strrchr(filePath, '\\');
	if(NULL != pos)
		*pos = 0;
	
	char dllPath[MAX_PATH]="";
	sprintf(dllPath, "%s\\CtuVisionControlLibrary.dll", filePath);

	//注册ActiveX
	char bufGUIDModel[1024];
	memset(bufGUIDModel, 0, sizeof(bufGUIDModel));
	GUIDToString(CtuVisionControlLibrary::CLSID_CtuVisionControlLibrary, bufGUIDModel);
	RegisterActiveX(dllPath, bufGUIDModel);

	CRect rectModel;
	GetDlgItem(IDC_Vision)->GetWindowRect(&rectModel);
	ScreenToClient(&rectModel);

	LoadActiveX(this->m_hWnd,TEXT("CtuVisionControlLibrary.VisionLibrary"), __uuidof(CtuVisionControlLibrary::VisionLibrary), rectModel.left, rectModel.top, rectModel.Width(), rectModel.Height());

	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

2.编写加载ActiveX的函数

void CCtuVisionDLLTest_MFCDlg::LoadActiveX(HWND hParentWnd, LPCTSTR strActiveXName, REFIID riidOfActiveX, int x, int y, int nWidth, int nHeight)
{
	//Initialize ATL control containment code.
	BOOL (WINAPI *m_AtlAxWinInit)();
	m_AtlAxWinInit = (BOOL (WINAPI *)(void))::GetProcAddress(hATLLib, "AtlAxWinInit");
	m_AtlAxWinInit();
	// Get the dimensions of the main window's client
	// area, and enumerate the child windows. Pass the
	// dimensions to the child windows during enumeration.
	m_hActiveXSelf = ::CreateWindowEx(WS_EX_CLIENTEDGE,TEXT("AtlAxWin"),strActiveXName,WS_CHILD | WS_VISIBLE | WS_EX_RTLREADING,x, y, nWidth, nHeight,hParentWnd,NULL,NULL,NULL);
	if (!m_hActiveXSelf)
	{
		::MessageBox( NULL, TEXT("Can not load AtlAxWin!"),TEXT(""), MB_OK | MB_ICONSTOP);
		throw int(106901);
	}
	HRESULT (WINAPI *m_AtlAxGetControl) (HWND h, IUnknown** pp);
	m_AtlAxGetControl = (HRESULT (WINAPI *)(HWND, IUnknown**))::GetProcAddress(hATLLib, "AtlAxGetControl");
	m_AtlAxGetControl(m_hActiveXSelf, &m_pUnk);
	m_pUnk->QueryInterface(riidOfActiveX, (LPVOID *) &m_pDotNetCOMPtr);
	if (m_pDotNetCOMPtr != NULL)
	{
		m_pDotNetCOMPtr->SetAdapterDllPtr((long)hParentWnd,0);
	}
	else
	{
	// Get the dimensions of the main window's client
	// area, and enumerate the child windows. Pass the
	// dimensions to the child windows during enumeration.
	::DestroyWindow(m_hActiveXSelf);
	m_hActiveXSelf = ::CreateWindowEx(WS_EX_CLIENTEDGE,TEXT("AtlAxWin"),TEXT("MSHTML:Please register ActiveX control before using this plugin."),WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |WS_EX_RTLREADING,x, y, nWidth, nHeight,hParentWnd,NULL,NULL,NULL);
	}
}

3.注意控件的加载函数

CRect rectModel;
GetDlgItem(IDC_Vision)->GetWindowRect(&rectModel);
ScreenToClient(&rectModel);

LoadActiveX(this->m_hWnd,TEXT("CtuVisionControlLibrary.VisionLibrary"), __uuidof(CtuVisionControlLibrary::VisionLibrary), rectModel.left, rectModel.top, rectModel.Width(), rectModel.Height());

4.接口调用

这里以StringTest外部接口进行展示

void CCtuVisionDLLTest_MFCDlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	char *strColumn_ID = "ctu"; 
	_bstr_t bstrColumn_ID(strColumn_ID);
	BSTR pDataCode = NULL;
	m_pDotNetCOMPtr->StringTest(bstrColumn_ID, &pDataCode);
	_bstr_t bDataCode = pDataCode;
	char buf[128];
	sprintf_s(buf, "%s", (char*)bDataCode);
}

6.CtuVisionDLLTest_QT主窗体调用算法控件dll

由于Qt与MFC都是基于C++的,因此调用方法与MFC类似

1.构造函数加载dll控件并且支持多控件加载,代表多相机使用

CtuVisionDLLTest_QT::CtuVisionDLLTest_QT(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	char filePath[MAX_PATH];
	GetModuleFileNameA(GetModuleHandle(0), filePath, MAX_PATH);
	char* pos = strrchr(filePath, '\\');
	if(NULL != pos)
		*pos = 0;
	
	char dllPath[MAX_PATH]="";
	sprintf(dllPath, "%s\\CtuVisionControlLibrary.dll", filePath);

	//注册ActiveX
	char bufGUIDModel[1024];
	memset(bufGUIDModel, 0, sizeof(bufGUIDModel));
	GUIDToString(CtuVisionControlLibrary::CLSID_CtuVisionControlLibrary, bufGUIDModel);
	RegisterActiveX(dllPath, bufGUIDModel);

	HWND h_Wnd[CameraNum];
	QRect rect[CameraNum];
	h_Wnd[0] = (HWND)ui.VisionLab1->winId();
	h_Wnd[1] = (HWND)ui.VisionLab2->winId();
	h_Wnd[2] = (HWND)ui.VisionLab3->winId();
	rect[0] = ui.VisionLab1->frameGeometry();
	rect[1] = ui.VisionLab2->frameGeometry();
	rect[2] = ui.VisionLab3->frameGeometry();

	for(int i=0;i<CameraNum;i++)
	{
		LoadActiveX(h_Wnd[i],m_pDotNetCOMPtr[i],i,TEXT("CtuVisionControlLibrary.VisionLibrary"), __uuidof(CtuVisionControlLibrary::VisionLibrary), 0, 0, rect[i].width(), rect[i].height());
	}
}

2.调用方式

这里以模板匹配+坐标转换为例子展示

void CtuVisionDLLTest_QT::on_pushButton_2_clicked()
{
	int ModelNum = ui.lineEdit->text().toInt();
	double image_x,image_y,r;
	image_x = image_y = r = 0.0;
	m_pDotNetCOMPtr[0]->FindModel(ModelNum,&image_x,&image_y,&r);
	QString mes = QString("%1,%2,%3").arg(image_x).arg(image_y).arg(r);
	if(image_x !=-1.0)
	{
		int CaliNum = ui.lineEdit_4->text().toInt();
		double robot_x,robot_y;
		robot_x=robot_y = 0.0;
		VARIANT_BOOL res = VARIANT_FALSE;
		m_pDotNetCOMPtr[0]->AffineVector2Hom(CaliNum,image_x,image_y,&robot_x,&robot_y);
		if(robot_x!=-1.0)
		{
			mes = QString("%1,%2,%3").arg(robot_x).arg(robot_y).arg(r);
		}
	}
	ui.statusBar->showMessage(mes);
}

总结及源码

该工程篇幅比较多,不过具体的函数在文章中已经表标明,具体的查看源码使用。
C#做算法及主界面开发,然后把生成的控件dll移交给C#或者MFC或者QT进行二次调用实现二次开发,这里主要想展示的是多语言之间的调用以及如何跨语言调用控件算法

本次项目的源码:(私聊)

你可能感兴趣的:(机器视觉-halcon,c#,c++,计算机视觉,视觉检测,开发语言)