C#联合halcon开发多相机-直线拟合【附部分源码】


前言

本文主要实现基于C#联合halcon二次开发实现多相机的直线拟合功能


视频演示

C#联合halcon开发(4相机):找直线并拟合

脚本教学:halcon思路教学


一、整体工程目录介绍

工程目录:

在这里插入图片描述
项目介绍:
1.CRK_Calib:此工程是一个动态库,是一个窗体,主要功能实现标定
2.CRK_CameraIA:此工程是一个动态库,是一个窗体,主要给弄能是相机接口类
3.CRK_Library:此工程是一个动态库,一个方法类,主要编写经常用到的类及函数
4.ImageMatching:软件程序工程,结合上边三个工程使用


二、窗体设置

1.Calib窗体设置

工程目录如下:
在这里插入图片描述
如图,这里按照此图先把界面配置好
在这里插入图片描述
按照此图的控件进行配置即可


2.CameraIA窗体设置

工程目录如下:
在这里插入图片描述
如图,这里按照此图先把界面配置好
在这里插入图片描述
按照此图的控件进行配置即可


3.ImageMatching窗体设置

工程目录如下:
在这里插入图片描述
如图,主窗体为此形式
在这里插入图片描述
菜单栏设置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


三、各工程重点代码

1.Calib类

此工程主要实现放射变化,实现相机坐标转机器人坐标

1.获取相机标定对象

 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("数据异常");
     }
 }

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 >= 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;
}

2.CameraIA类

1.定义相机标准类

 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;
    }
};

2.打开相机

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_Width, myCameraCom.ho_Height, CameraID);
        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;
    }
}

3.关闭相机

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;
    }
}

4.采集图像

public bool GetOnceImage(out HObject img)
{
    HOperatorSet.GenEmptyObj(out img);
    if (IsConnectCamera())
    {
        try
        {
            HOperatorSet.GrabImageAsync(out img, myCameraCom.hv_AcqHandle, -1);
            return true;
        }
        catch
        {
            return false;
        }
    }
    return false;
}

3.ImageMatching类

1.定义属性变量

private const int CameraNum = 4;
private CameraCom[] ctu_Camera = new CameraCom[CameraNum];
CurrentControl MyCurrentControl = new CurrentControl();
private SlnModel mySlnModel;

2.属性变量初始化

for (int i = 0; i < CameraNum; i++)
{
    ctu_Camera[i] = new CameraCom(i + 1);
    ctu_Camera[i].CameraImageHWEvent += new CameraCom.CameraImageHW(CameraToVisionHW);
    ctu_Camera[i].hWindowControl = (HWindowControl)this.Controls.Find(string.Format("hWindowControl_Show_Camera{0}", i + 1),true)[0];
    ctu_Camera[i].HalconWindow = ctu_Camera[i].hWindowControl.HalconWindow;
    HOperatorSet.SetDraw(ctu_Camera[i].HalconWindow, "margin");
    HOperatorSet.SetColor(ctu_Camera[i].HalconWindow, "red");
    HOperatorSet.SetLineWidth(ctu_Camera[i].HalconWindow, 1);
    HOperatorSet.SetWindowParam(ctu_Camera[i].HalconWindow,"background_color", "gray");
    Combo_CameraNum.Items.Add(string.Format("相机:{0}", i + 1));
}
Combo_CameraNum.SelectedIndex = 0;

mySlnModel = new SlnModel("./VisionModel");

3.载入图像(以单相机和多相机为例)

private void Action_LoadImage_Camera_Click(object sender, EventArgs e)
{
    int CameraID = PublicFunc.GetCameraID(sender, "Action_LoadImage_Camera");
    HObject img;
    OpenFileDialog fd = new OpenFileDialog();
    fd.Filter = "图像(*.bmp)|*.bmp|All files(*.*)|*.*";
    if (fd.ShowDialog() == DialogResult.OK)
    {
        HTuple width, height;
        HOperatorSet.ReadImage(out img, fd.FileName);
        HOperatorSet.GetImageSize(img, out width, out height);
        if (CameraID != 0 && CameraID != -1)
        {
            ctu_Camera[CameraID - 1].ho_Image = img.Clone();
            ctu_Camera[CameraID - 1].Image_Height = height;
            ctu_Camera[CameraID - 1].Image_Width = width;
            ctu_Camera[CameraID - 1].mouseStatus.MouseScaleNum = 0;
            ctu_Camera[CameraID - 1].dataRes = new Queue<VisionPoint>();
            ctu_Camera[CameraID - 1].lineDataRes = new CenterLine();
            mySlnModel.upImageSize(width, height, ref ctu_Camera[CameraID - 1].hWindowControl, ref ctu_Camera[CameraID - 1].HalconWindow);
            HOperatorSet.GenEmptyObj(out ctu_Camera[CameraID - 1].CurrentROI);
            ReDraw(CameraID - 1,true);
            Combo_CameraNum.SelectedIndex = CameraID - 1;
        }
        else
        {
            for (int i = 0; i < CameraNum; i++)
            {
                ctu_Camera[i].ho_Image = img.Clone();
                ctu_Camera[i].Image_Height = height;
                ctu_Camera[i].Image_Width = width;
                ctu_Camera[i].mouseStatus.MouseScaleNum = 0;
                ctu_Camera[i].dataRes = new Queue<VisionPoint>();
                ctu_Camera[i].lineDataRes = new CenterLine();
                mySlnModel.upImageSize(width, height, ref ctu_Camera[i].hWindowControl, ref ctu_Camera[i].HalconWindow);
                HOperatorSet.GenEmptyObj(out ctu_Camera[i].CurrentROI);
                ReDraw(i,true);
            }
        }
    }
}

4.其他模板功能见其他博客的使用


5.识别找线拟合

public CenterLine FindLine1(HObject img,HTuple x,HTuple y,HTuple r)
{
    if (!CheckSoftFlag)
        return new CenterLine();
    CenterLine res_data = new CenterLine();
    int start_time = GetTickCount();
    try
    {
        for (int i = 0; i < SlnModelCom.MaxModelNum; i++)
        {
            if (MySlnData.MyModel[i].EffectiveFlag)
            {
                HTuple Check_Row = x;
                HTuple Check_Column = y;
                HTuple Check_Angle = r;

                HTuple Point1_Row = new HTuple();
                HTuple Point1_Col = new HTuple();
                HTuple Point2_Row = new HTuple();
                HTuple Point2_Col = new HTuple();
                int CheckLength = 10;
                int CheckHeight = 200;
                int stratLength = 100;

                HTuple H, W;
                HOperatorSet.GetImageSize(img, out W, out H);

                for (int Index = 0; Index < 100000; Index = Index + CheckLength * 2)
                {
                    if (Check_Row.D + (stratLength + Index) * Math.Cos(Check_Angle.D / 57.3) > H.D - CheckLength * 2 ||
                        Check_Row.D + (stratLength + Index) * Math.Cos(Check_Angle.D / 57.3) < CheckLength * 2)
                        break;
                    HTuple MeasureHandle; HObject AA;
                    HOperatorSet.GenMeasureRectangle2(Check_Row.D + (stratLength + Index) * Math.Cos(Check_Angle.D / 57.3), Check_Column.D + (stratLength + Index) * Math.Sin(Check_Angle.D / 57.3), Check_Angle.D / 57.3, CheckHeight, CheckLength, W, H, "nearest_neighbor", out MeasureHandle);
                    HTuple RowEdge, ColumnEdge, Amplitude, Distance;
                    HOperatorSet.MeasurePos(img, MeasureHandle, 1, 40, "all", "all", out RowEdge, out ColumnEdge, out Amplitude, out Distance);
                    HTuple PointSize;
                    HOperatorSet.TupleLength(RowEdge, out PointSize);
                    if (PointSize.I > 0)
                    {
                        HOperatorSet.TupleConcat(Point1_Row, RowEdge[0], out Point1_Row);
                        HOperatorSet.TupleConcat(Point1_Col, ColumnEdge[0], out Point1_Col);
                    }
                    HOperatorSet.CloseMeasure(MeasureHandle);
                }

                for (int Index = 0; Index < 100000; Index = Index + CheckLength * 2)
                {
                    if (Check_Column.D + (stratLength + Index) * Math.Cos(-Check_Angle.D / 57.3) > W.D - CheckLength * 2 ||
                        Check_Column.D + (stratLength + Index) * Math.Cos(-Check_Angle.D / 57.3) < CheckLength * 2)
                        break;
                    HTuple MeasureHandle;
                    HOperatorSet.GenMeasureRectangle2(Check_Row.D + (stratLength + Index) * Math.Sin(-Check_Angle.D / 57.3), Check_Column.D + (stratLength + Index) * Math.Cos(-Check_Angle.D / 57.3), (Check_Angle.D + 90) / 57.3, CheckHeight, CheckLength, W, H, "nearest_neighbor", out MeasureHandle);
                    HTuple RowEdge, ColumnEdge, Amplitude, Distance;
                    HOperatorSet.MeasurePos(img, MeasureHandle, 1, 40, "all", "all", out RowEdge, out ColumnEdge, out Amplitude, out Distance);
                    HTuple PointSize;
                    HOperatorSet.TupleLength(RowEdge, out PointSize);
                    if (PointSize.I > 0)
                    {
                        HOperatorSet.TupleConcat(Point2_Row, RowEdge[0], out Point2_Row);
                        HOperatorSet.TupleConcat(Point2_Col, ColumnEdge[0], out Point2_Col);
                    }
                    HOperatorSet.CloseMeasure(MeasureHandle);
                }

                HObject Contour;
                HTuple RowBegin1, ColBegin1, RowEnd1, ColEnd1, Nr1, Nc1, Dist1, p1_row, p1_col, p2_row, p2_col, IsOverlapping;
                HTuple RowBegin2, ColBegin2, RowEnd2, ColEnd2, Nr2, Nc2, Dist2, p3_row, p3_col, p4_row, p4_col;
                HOperatorSet.GenContourPolygonXld(out Contour, Point1_Row, Point1_Col);
                HOperatorSet.FitLineContourXld(Contour, "tukey", -1, 0, 5, 2, out RowBegin1, out ColBegin1, out RowEnd1, out ColEnd1, out Nr1, out Nc1, out Dist1);
                HOperatorSet.IntersectionLines(RowBegin1, ColBegin1, RowEnd1, ColEnd1, 0, 0, 0, W.D, out p1_row, out p1_col, out IsOverlapping);
                HOperatorSet.IntersectionLines(RowBegin1, ColBegin1, RowEnd1, ColEnd1, H.D, 0, H.D, W.D, out p2_row, out p2_col, out IsOverlapping);

                HOperatorSet.GenContourPolygonXld(out Contour, Point2_Row, Point2_Col);
                HOperatorSet.FitLineContourXld(Contour, "tukey", -1, 0, 5, 2, out RowBegin2, out ColBegin2, out RowEnd2, out ColEnd2, out Nr2, out Nc2, out Dist2);
                HOperatorSet.IntersectionLines(RowBegin2, ColBegin2, RowEnd2, ColEnd2, 0, 0, H.D, 0, out p3_row, out p3_col, out IsOverlapping);
                HOperatorSet.IntersectionLines(RowBegin2, ColBegin2, RowEnd2, ColEnd2, 0, W.D, H.D, W.D, out p4_row, out p4_col, out IsOverlapping);

                HTuple Line1Data_Row = new HTuple(), Line1Data_Col = new HTuple(), Line2Data_Row = new HTuple(), Line2Data_Col = new HTuple();
                HOperatorSet.TupleConcat(Line1Data_Row, p1_row, out Line1Data_Row);
                HOperatorSet.TupleConcat(Line1Data_Row, p2_row, out Line1Data_Row);
                HOperatorSet.TupleConcat(Line1Data_Col, p1_col, out Line1Data_Col);
                HOperatorSet.TupleConcat(Line1Data_Col, p2_col, out Line1Data_Col);

                HOperatorSet.TupleConcat(Line2Data_Row, p3_row, out Line2Data_Row);
                HOperatorSet.TupleConcat(Line2Data_Row, p4_row, out Line2Data_Row);
                HOperatorSet.TupleConcat(Line2Data_Col, p3_col, out Line2Data_Col);
                HOperatorSet.TupleConcat(Line2Data_Col, p4_col, out Line2Data_Col);

                HObject LineEdge1, LineEdge2;
                HTuple CenterPoint_Row, CenterPoint_Col, CenterPoint_Angle;
                HOperatorSet.GenContourPolygonXld(out LineEdge1, Line1Data_Row, Line1Data_Col);
                HOperatorSet.GenContourPolygonXld(out LineEdge2, Line2Data_Row, Line2Data_Col);
                HOperatorSet.IntersectionLines(RowBegin1, ColBegin1, RowEnd1, ColEnd1, RowBegin2, ColBegin2, RowEnd2, ColEnd2, out CenterPoint_Row, out CenterPoint_Col, out IsOverlapping);
                HOperatorSet.AngleLx(RowBegin2, ColBegin2, RowEnd2, ColEnd2, out CenterPoint_Angle);
                res_data.center_X = CenterPoint_Row.D;
                res_data.center_Y = CenterPoint_Col.D;
                res_data.center_R = CenterPoint_Angle.D * 57.3;
                res_data.Line1 = LineEdge1.Clone();
                res_data.Line2 = LineEdge2.Clone();
                break;
                
            }
        }
    }
    catch
    {
        res_data = new CenterLine();
    }
    int end_time = GetTickCount();
    res_data.timer = end_time - start_time;
    return res_data;
}

总结

此工程主要实现多相机并且用类方式以及类接口使用,可快速移植和使用

  • 4
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱学习的广东仔

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

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

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

打赏作者

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

抵扣说明:

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

余额充值