文章目录
前言
本文主要实现基于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;
}
总结
此工程主要实现多相机并且用类方式以及类接口使用,可快速移植和使用