1.前言
1.1什么是圆弧
圆上任意两点间的部分叫做圆弧。由于圆弧有正反的特性,即为有顺时针方向和逆时针方向,在确定圆弧时,也需要确定圆弧的方向。
1.2halcon实现方式
针对圆弧的问题。1:它与圆是相似的,都具备中心坐标和半径,还有起始和终点角度;2:定义一个圆弧方向,以顺时针为测量方向。
2.halcon程序
2.1halcon程序
read_image (Image, 'D:/1NewWork/work/2.26/圆.png')
get_image_size (Image, Width, Height)
*获得圆上初始采样点
row:=[296,949,2046]
column:=[2555,3063,1192]
********************************拟合弧形采样ROI*****************
gen_contour_polygon_xld (Contour, row, column)
fit_circle_contour_xld (Contour, 'algebraic', -1, 0, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)
gen_circle_contour_xld (ContCircle, Row, Column, Radius, EndPhi,StartPhi, 'positive', 1)
*gen_circle_contour_xld (ContCircle, Row, Column, Radius, 1,EndPhi, 'positive', 1)
dev_display (Image)
dev_display (ContCircle)
row1:=[]
column1:=[]
gen_empty_obj (EmptyObject)
gen_empty_obj (EmptyObject2)
phi:=3.14*2-StartPhi
tuple_abs (StartPhi-EndPhi+3.14*2, Abs)
tuple_ceil (Abs/3.1415926*90, Ceil)
**********************************弧形采样*********************
for Index := 0to Ceil-1 by 1
tuple_sin(phi+rad(Index*2),Sin)
tuple_cos(phi+rad(Index*2),Cos)
*创建测量矩形
gen_measure_rectangle2 (Row+Radius*Sin, Column+Radius*Cos, -Index*3.1415926/180*2-phi, 50, 5, Width, Height, 'nearest_neighbor', MeasureHandle)
*绘制测量矩形轮廓用于显示
gen_rectangle2_contour_xld (Rectangle,Row+Radius*Sin, Column+Radius*Cos, -Index*3.1415926/180*2-phi, 50, 5)
*开启测量
measure_pos (Image, MeasureHandle, 2, 20, 'all', 'last', RowEdge, ColumnEdge, Amplitude, Distance)
*绘制测量结果
gen_cross_contour_xld (Cross, RowEdge, ColumnEdge, 20, 1)
concat_obj (Cross, EmptyObject, EmptyObject)
concat_obj (EmptyObject2, Rectangle, EmptyObject2)
row1:=[row1,RowEdge]
column1:=[column1,ColumnEdge]
endfor
gen_contour_polygon_xld (Contour1, row1, column1)
*********************输出结果横纵坐标与半径,起始与结束的角度*****************
fit_circle_contour_xld (Contour1, 'algebraic', -1, 0, 0, 3, 2, Row2, Column2, Radius2, StartPhi2, EndPhi2, PointOrder2)
gen_circle_contour_xld (ContCircle2, Row2, Column2, Radius2,EndPhi2, StartPhi2, 'positive', 1)
dev_display (Image)
dev_display (ContCircle)
dev_display (EmptyObject2)
dev_display (EmptyObject)
dev_display (ContCircle2)
2.2halcon程序讲解
2.2.1读取图像和绘制ROI
read_image (Image, 'D:/1NewWork/work/2.26/圆.png')
get_image_size (Image, Width, Height)
*获得圆上初始采样点
row:=[296,949,2046]
column:=[2555,3063,1192]
********************************拟合弧形采样ROI*****************
gen_contour_polygon_xld (Contour, row, column)
fit_circle_contour_xld (Contour, 'algebraic', -1, 0, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)
找圆弧与找圆是类似的,都需要一个基准的ROI区域,但是圆弧在于,它需要起始点和终点,中间点为圆心位置。根据3点绘制圆的方式,所以ROI选取,3个采样点即可
2.2.2拟合采样点,并绘制弧线ROI
gen_contour_polygon_xld (Contour, row, column)
fit_circle_contour_xld (Contour, 'algebraic', -1, 0, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)
gen_circle_contour_xld (ContCircle, Row, Column, Radius, EndPhi,StartPhi, 'positive', 1)
*gen_circle_contour_xld (ContCircle, Row, Column, Radius, 1,EndPhi, 'positive', 1)
dev_display (Image)
dev_display (ContCircle)
通过选取的3点ROI拟合一个圆,获取到圆心坐标,半径,圆弧的起始和终点
2.2.3圆弧检测
row1:=[]
column1:=[]
gen_empty_obj (EmptyObject)
gen_empty_obj (EmptyObject2)
phi:=3.14*2-StartPhi
tuple_abs (StartPhi-EndPhi+3.14*2, Abs)
tuple_ceil (Abs/3.1415926*90, Ceil)
**********************************弧形采样*********************
for Index := 0to Ceil-1 by 1
tuple_sin(phi+rad(Index*2),Sin)
tuple_cos(phi+rad(Index*2),Cos)
*创建测量矩形
gen_measure_rectangle2 (Row+Radius*Sin, Column+Radius*Cos, -Index*3.1415926/180*2-phi, 50, 5, Width, Height, 'nearest_neighbor', MeasureHandle)
*绘制测量矩形轮廓用于显示
gen_rectangle2_contour_xld (Rectangle,Row+Radius*Sin, Column+Radius*Cos, -Index*3.1415926/180*2-phi, 50, 5)
*开启测量
measure_pos (Image, MeasureHandle, 2, 20, 'all', 'last', RowEdge, ColumnEdge, Amplitude, Distance)
*绘制测量结果
gen_cross_contour_xld (Cross, RowEdge, ColumnEdge, 20, 1)
concat_obj (Cross, EmptyObject, EmptyObject)
concat_obj (EmptyObject2, Rectangle, EmptyObject2)
row1:=[row1,RowEdge]
column1:=[column1,ColumnEdge]
endfor
gen_contour_polygon_xld (Contour1, row1, column1)
*********************输出结果横纵坐标与半径,起始与结束的角度*****************
fit_circle_contour_xld (Contour1, 'algebraic', -1, 0, 0, 3, 2, Row2, Column2, Radius2, StartPhi2, EndPhi2, PointOrder2)
gen_circle_contour_xld (ContCircle2, Row2, Column2, Radius2,EndPhi2, StartPhi2, 'positive', 1)
dev_display (Image)
dev_display (ContCircle)
dev_display (EmptyObject2)
dev_display (EmptyObject)
dev_display (ContCircle2)
根据定义的圆弧,以初始点为起始点,顺时针旋转,旋转指定角度,并使用测量矩形对每个采样区域进行采样,将所有采样点重新拟合为圆即可得到最终结果
2.2.4注意事项
尤为要注意圆弧是有方向的,文中预先定义圆弧方向为顺时针方向
3.C#程序工具实现
#region // 圆弧测量
/// <summary>
/// 圆弧测量
/// </summary>
/// <param name="image">输入图像</param>
/// <param name="Row1">点1横坐标</param>
/// <param name="Column1">点1列坐标</param>
/// <param name="Row2">点2横坐标</param>
/// <param name="Column2">点2列坐标</param>
/// <param name="Row3">点3横坐标</param>
/// <param name="Column3">点3列坐标</param>
/// <param name="Sigma">高斯滤波值</param>
/// <param name="Threshold">最小二值化</param>
/// <param name="Measure_Set">选择拟合边1(“all”:最接近ROI轮廓的拟合边;“positive”:由亮到暗,“negative”:由暗到亮)</param>
/// <param name="Measure_Place">选择拟合边2(“first”:所有轮廓的第一条边,“last”:所有轮廓的最后一个边,“all”:最接近ROI轮廓的拟合边)</param>
/// <param name="ConCircle">输出弧形轮廓</param>
/// <param name="CenterRow">输出圆弧中心横坐标</param>
/// <param name="CenterColumn">输出圆弧中心列坐标</param>
/// <param name="ResultR">输出圆弧半径</param>
/// <param name="StartPhi">输出圆弧起始角度</param>
/// <param name="EndPhi">输出圆弧最终角度</param>
/// <returns></returns>
public static bool ArcMeasure(HObject image,HTuple Row1,HTuple Column1,HTuple Row2,HTuple Column2,
HTuple Row3,HTuple Column3, HTuple Sigma, HTuple Threshold,HTuple Measure_Set,HTuple Measure_Place,
out HObject ConCircle,out HTuple CenterRow,out HTuple CenterColumn,out HTuple ResultR,
out HTuple StartPhi,out HTuple EndPhi)
{
HOperatorSet.GenEmptyObj(out ConCircle);
CenterRow = -1;
CenterColumn = -1;
ResultR = -1;
StartPhi = -1;
EndPhi = -1;
try
{
HOperatorSet.GetImageSize(image, out HTuple width, out HTuple height);
HTuple Row = new HTuple(),Column=new HTuple();
Row[0] = Row1; Row[1] = Row2; Row[2] = Row3;
Column[0]= Column1; Column[1]= Column2; Column[2] = Column3;
HOperatorSet.GenContourPolygonXld(out HObject Contour, Row, Column);
HOperatorSet.FitCircleContourXld(Contour, "algebraic", -1, 0, 0, 3, 2, out HTuple row,
out HTuple column, out HTuple radius, out HTuple startPhi, out HTuple endPhi, out HTuple pointOrder);
HTuple row1=new HTuple(),column1=new HTuple(),phi=0;
HOperatorSet.GenEmptyObj(out HObject emptyObject);
HOperatorSet.GenEmptyObj(out HObject emptyObject2);
phi = Math.PI*2 - startPhi;
HOperatorSet.TupleAbs(startPhi - endPhi+Math.PI*2, out HTuple abs);
HOperatorSet.TupleCeil(abs / Math.PI * 90, out HTuple ceil);
for (int i = 0; i < ceil-1; i++)
{
HOperatorSet.TupleSin(phi + i * 2 * Math.PI / 180 , out HTuple sin);
HOperatorSet.TupleCos(phi + i * 2 * Math.PI / 180 , out HTuple cos);
HOperatorSet.GenMeasureRectangle2(row + radius * sin, column + radius * cos, ((((-i) * 3.1415926) / 180) * 2) - phi ,
50, 5, width, height, new HTuple("nearest_neighbor"), out HTuple measureHandle);
HOperatorSet.MeasurePos(image, measureHandle, Sigma, Threshold, Measure_Set, Measure_Place, out HTuple rowEdge,
out HTuple columnEdge, out HTuple amplitude, out HTuple distance);
row1 = row1.TupleConcat(rowEdge);
column1 = column1.TupleConcat(columnEdge);
}
HOperatorSet.GenContourPolygonXld(out HObject contour, row1, column1);
HOperatorSet.FitCircleContourXld(contour, new HTuple("algebraic"), -1, 0, 0, 3, 2, out CenterRow, out CenterColumn,
out ResultR, out StartPhi, out EndPhi , out HTuple pointOrder2);
HOperatorSet.TupleLength(CenterRow, out HTuple length);
if (length == 0)
{
return false;
}
HOperatorSet.GenCircleContourXld(out ConCircle, CenterRow, CenterColumn, ResultR, EndPhi, StartPhi, new HTuple("positive"), 1);
return true;
}
catch (Exception)
{
return false;
}
}
#endregion
#region // 单点查找
/// <summary>
/// 单个点查找
/// </summary>
/// <param name="Image">输入图像</param>
/// <param name="Row1">输入直线起始横坐标</param>
/// <param name="Column1">输入直线起始列坐标</param>
/// <param name="Row2">输入直线终点横坐标</param>
/// <param name="Column2">输入直线终点列坐标</param>
/// <param name="MeasureWide">输入测量矩形宽度</param>
/// <param name="Sigma">输入测量矩形的高斯滤波值</param>
/// <param name="Thrashold">输入最小边缘对比度</param>
/// <param name="ResultRow">输出结果横坐标</param>
/// <param name="ResultColumn">输出结果列坐标</param>
/// <returns>拟合成功返回true,拟合失败返回false</returns>
static public bool PointMeasure_(HObject Image, HTuple Row1, HTuple Column1,HTuple Row2,HTuple Column2,
HTuple MeasureWide, HTuple Sigma, HTuple Thrashold,
out HTuple ResultRow, out HTuple ResultColumn)
{
ResultRow = -1; ResultColumn = -1;
try
{
HTuple hv_TmpCtrl_Row, hv_TmpCtrl_Column, hv_TmpCtrl_Dr, hv_TmpCtrl_Dc, hv_TmpCtrl_Phi,
hv_TmpCtrl_Len1;
HOperatorSet.GetImageSize(Image, out HTuple width, out HTuple height);
hv_TmpCtrl_Row = 0.5 * (Row1 + Row2);
hv_TmpCtrl_Column = 0.5 * (Column1 + Column2);
hv_TmpCtrl_Dr = Row1 - Row2;
hv_TmpCtrl_Dc = Column2 - Column1;
hv_TmpCtrl_Phi = hv_TmpCtrl_Dr.TupleAtan2( hv_TmpCtrl_Dc);
hv_TmpCtrl_Len1 = 0.5 * ((((hv_TmpCtrl_Dr * hv_TmpCtrl_Dr) + (hv_TmpCtrl_Dc * hv_TmpCtrl_Dc))).TupleSqrt());
HOperatorSet.GenMeasureRectangle2(hv_TmpCtrl_Row, hv_TmpCtrl_Column, hv_TmpCtrl_Phi,
hv_TmpCtrl_Len1, MeasureWide, width, height, "nearest_neighbor", out HTuple measureHandle);
HOperatorSet.MeasurePos(Image, measureHandle, Sigma, Thrashold, new HTuple("all"), new HTuple("first"), out ResultRow,
out ResultColumn, out HTuple amplitude, out HTuple distance);
HOperatorSet.TupleLength(ResultRow, out HTuple length);
if (length==0)
{
return false;
}
return true;
}
catch (Exception)
{
return false;
}
}
#endregion
总结
弧形检测,与圆检测依旧类型,都是通过一定量的采样点去拟合出几何图形。