1.前言
1.1什么是圆度
圆度是指工件的横截面接近理论圆的程度,最大半径与最小半径之差为0时,圆度为0,测量工具为圆度仪,用途是测环形工件的圆度。圆度是限制实际圆对理想圆变动量的一项指标,其公差带是以公差值t为半径差的两同心圆之间的区域。圆度公差属于形状公差,圆度误差值不大于相应的公差值,则认为合格
1.2圆度评价方式
最小外接圆法:只适用于外圆。以包容被测圆轮廓且半径为最小的外接圆圆心为圆心,所作包容被测圆轮廓的两同心圆半径差即为圆度误差。
最大内接圆法:只适用于内圆。以内接于被测圆轮廓且半径为最大的内接圆圆心为圆心,所作包容被测圆轮廓两同心圆的半径差即为圆度误差。
1.3halcon实现方式
针对圆度的评价方式进行圆度测量。1:先对初始圆进行圆形测量,精准的判断出当前圆的圆心坐标,和半径。2:根据圆心坐标和半径,以2度的角度为间隔进行圆形测量矩形逐个测量,用于判断圆度的误差
2.halcon程序
2.1halcon程序
read_image (Image, 'D:/1NewWork/work/2.26/屏幕截图 2024-02-29 171735.png')
*创建圆ROI
gen_circle (ROI_0, 268.42, 263.387, 198.583)
**************************************进行圆形测量******************
create_metrology_model (MetrologyHandle)
add_metrology_object_generic (MetrologyHandle, 'circle', [268.42, 263.387, 198.583], 50, 5, 2, 30, [], [], test1)
*将句柄添加在图像中
set_metrology_object_param (MetrologyHandle, 'all', ['measure_transition','measure_select'], ['uniform','first'])
set_metrology_object_param (MetrologyHandle, 'all', ['min_score'], [0.5])
apply_metrology_model (Image, MetrologyHandle)
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'used_edges', 'row', UsedRow)
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'used_edges', 'column', UsedColumn)
*生成测量矩形
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row1, Column1)
*创建测量矩形中点
gen_cross_contour_xld (UsedEdges, UsedRow, UsedColumn, 10, 0)
*创建圆形
get_metrology_object_result_contour (ResultContours, MetrologyHandle, 'all', 'all', 1.5)
dev_display (Image)
dev_display (UsedEdges)
dev_display (Contours)
dev_display (ResultContours)
*对结果类型进行获取,获取角度,中心X值和Y值
*RadiusC1角度值,Row9行坐标,column9纵坐标
get_metrology_object_result (MetrologyHandle, test1, 'all', 'result_type', 'radius', RadiusC1)
get_metrology_object_result (MetrologyHandle, test1, 'all', 'result_type', 'row', Row9)
get_metrology_object_result (MetrologyHandle, test1, 'all', 'result_type', 'column', column9)
get_metrology_object_result (MetrologyHandle, test1, 'all', 'result_type', 'score', score)
*创建圆形轮廓
Dis:=[]
row:=[]
column:=[]
*存储最大圆度偏差
Circle_Max:=0
*创建显示参数
gen_empty_obj (EmptyObject)
gen_empty_obj (EmptyObject2)
get_image_size (Image, Width, Height)
*绘制圆状测量矩形
for Index := 0 to 180 by 1
tuple_sin(rad(Index*2),Sin)
tuple_cos(rad(Index*2),Cos)
*创建测量矩形
gen_measure_rectangle2 (Row9+RadiusC1*Sin, column9+RadiusC1*Cos, -Index*3.1415926/180*2, 50, 5, Width, Height, 'nearest_neighbor', MeasureHandle)
*绘制测量矩形轮廓用于显示
gen_rectangle2_contour_xld (Rectangle,Row9+RadiusC1*Sin, column9+RadiusC1*Cos, -Index*3.1415926/180*2, 50, 5)
*开启测量
measure_pos (Image, MeasureHandle, 2, 20, 'all', 'first', RowEdge, ColumnEdge, Amplitude, Distance)
*绘制测量结果
gen_cross_contour_xld (Cross, RowEdge, ColumnEdge, 20, 1)
concat_obj (Cross, EmptyObject, EmptyObject)
concat_obj (EmptyObject2, Rectangle, EmptyObject2)
distance_pp (RowEdge, ColumnEdge, Row9, column9, Distance1)
*输出差值数组
Dis:=[Dis,Distance1-RadiusC1]
row:=[row,RowEdge]
column:=[column,ColumnEdge]
endfor
tuple_max (Dis, Max)
tuple_min (Dis, Min)
tuple_abs (Min, Abs)
if (Max>=Abs)
Circle_Max:=Max
else
Circle_Max:=Abs
endif
dev_display (Image)
dev_display (EmptyObject2)
dev_display (EmptyObject)
2.2halcon程序讲解
2.2.1读取图像和绘制ROI
read_image (Image, 'D:/1NewWork/work/2.26/屏幕截图 2024-02-29 171735.png')
*创建圆ROI
gen_circle (ROI_0, 268.42, 263.387, 198.583)
**************************************进行圆形测量******************
create_metrology_model (MetrologyHandle)
add_metrology_object_generic (MetrologyHandle, 'circle', [268.42, 263.387, 198.583], 50, 5, 2, 30, [], [], test1)
*将句柄添加在图像中
绘制ROI时,应该尽可能的绘制完好,贴合圆形。但是如何绘制不好时也没有问题,在下一步圆形测量中会对ROI的坐标进行矫正。
2.2.2圆形测量矫正
**************************************进行圆形测量******************
create_metrology_model (MetrologyHandle)
add_metrology_object_generic (MetrologyHandle, 'circle', [268.42, 263.387, 198.583], 50, 5, 2, 30, [], [], test1)
*将句柄添加在图像中
*
set_metrology_object_param (MetrologyHandle, 'all', ['measure_transition','measure_select'], ['uniform','first'])
set_metrology_object_param (MetrologyHandle, 'all', ['min_score'], [0.5])
apply_metrology_model (Image, MetrologyHandle)
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'used_edges', 'row', UsedRow)
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'used_edges', 'column', UsedColumn)
*生成测量矩形
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row1, Column1)
*创建测量矩形中点
gen_cross_contour_xld (UsedEdges, UsedRow, UsedColumn, 10, 0)
*创建圆形
get_metrology_object_result_contour (ResultContours, MetrologyHandle, 'all', 'all', 1.5)
dev_display (Image)
dev_display (UsedEdges)
dev_display (Contours)
dev_display (ResultContours)
*对结果类型进行获取,获取角度,中心X值和Y值
*RadiusC1角度值,Row9行坐标,column9纵坐标
get_metrology_object_result (MetrologyHandle, test1, 'all', 'result_type', 'radius', RadiusC1)
get_metrology_object_result (MetrologyHandle, test1, 'all', 'result_type', 'row', Row9)
get_metrology_object_result (MetrologyHandle, test1, 'all', 'result_type', 'column', column9)
*获取圆分数
get_metrology_object_result (MetrologyHandle, test1, 'all', 'result_type', 'score', score)
对获取到的ROI进行圆形测量,用于对圆ROI的矫正,和获取到基准测量圆。
2.2.3圆度差值检测
*创建圆形轮廓
Dis:=[]
row:=[]
column:=[]
*存储最大圆度偏差
Circle_Max:=0
*创建显示参数
gen_empty_obj (EmptyObject)
gen_empty_obj (EmptyObject2)
get_image_size (Image, Width, Height)
*绘制圆状测量矩形
for Index := 0 to 180 by 1
tuple_sin(rad(Index*2),Sin)
tuple_cos(rad(Index*2),Cos)
*创建测量矩形
gen_measure_rectangle2 (Row9+RadiusC1*Sin, column9+RadiusC1*Cos, -Index*3.1415926/180*2, 50, 5, Width, Height, 'nearest_neighbor', MeasureHandle)
*绘制测量矩形轮廓用于显示
gen_rectangle2_contour_xld (Rectangle,Row9+RadiusC1*Sin, column9+RadiusC1*Cos, -Index*3.1415926/180*2, 50, 5)
*开启测量
measure_pos (Image, MeasureHandle, 2, 20, 'all', 'first', RowEdge, ColumnEdge, Amplitude, Distance)
*绘制测量结果
gen_cross_contour_xld (Cross, RowEdge, ColumnEdge, 20, 1)
concat_obj (Cross, EmptyObject, EmptyObject)
concat_obj (EmptyObject2, Rectangle, EmptyObject2)
distance_pp (RowEdge, ColumnEdge, Row9, column9, Distance1)
*输出差值数组
Dis:=[Dis,Distance1-RadiusC1]
row:=[row,RowEdge]
column:=[column,ColumnEdge]
endfor
tuple_max (Dis, Max)
tuple_min (Dis, Min)
tuple_abs (Min, Abs)
if (Max>=Abs)
Circle_Max:=Max
else
Circle_Max:=Abs
endif
这个不同于圆形测量在于,圆形测量会判断当前点是否符合拟合参数,如果不符合时则会自动剔除,但是我们需要获取到全部的拟合点,才能有效的判断圆度是否正确。
最终结果输出最大圆度。
2.2.3注意事项
如上面所述,圆度评价方式包含内接圆评价和外接圆评价。
上面的程序块展现的是内接圆评价,如果要修改为外接圆评价时,将下列2个函数进行修改。将参数“first”更换成last“”即可
set_metrology_object_param (MetrologyHandle, 'all', ['measure_transition','measure_select'], ['uniform','first'])
measure_pos (Image, MeasureHandle, 2, 20, 'all', 'first', RowEdge, ColumnEdge, Amplitude, Distance)
3.C#程序工具实现
//圆形测量工具
#region // 圆形测量
/// <summary>
/// 圆形测量
/// </summary>
/// <param name="image">输入图像</param>
/// <param name="Row">输入ROI的中心行坐标</param>
/// <param name="Column">输入ROI的中心列坐标</param>
/// <param name="R">输入ROI的半径</param>
/// <param name="MeasureHeight">输入测量矩形高度</param>
/// <param name="MeasureWide">输入测量矩形宽度</param>
/// <param name="Sigma">输入测量矩形的高斯滤波值</param>
/// <param name="Threshold">输入最小边缘对比度</param>
/// <param name="MinScore">输入最小拟合弧形的比例(当前拟合点/测量矩形数量)</param>
/// <param name="Measure_Set">选择拟合边1(“uniform”:最接近ROI轮廓的拟合边;“positive”:由亮到暗,“negative”:由暗到亮)</param>
/// <param name="Measure_Place">选择拟合边2(“first”:所有轮廓的第一条边,“last”:所有轮廓的最后一个边,“all”:最接近ROI轮廓的拟合边)</param>
/// <param name="ResultContour">结果轮廓</param>
/// <param name="RResult">结果轮廓的半径</param>
/// <param name="RowResult">结果轮廓的中心横坐标</param>
/// <param name="ColumnResult">结果轮廓的中心列坐标</param>
/// <returns>拟合失败返回false,拟合成功返回true</returns>
static public bool CircleMeasure_(HObject image, HTuple Row, HTuple Column, HTuple R,
HTuple MeasureHeight, HTuple MeasureWide, HTuple Sigma, HTuple Threshold,
HTuple Measure_Set,HTuple Measure_Place, out HObject ResultContour,
out HTuple RResult, out HTuple RowResult,out HTuple ColumnResult)
{
HOperatorSet.GenEmptyObj(out ResultContour);
RowResult = null;
ColumnResult = null;
RResult = null;
HTuple Row1=new HTuple(),Column1=new HTuple();
try
{
HOperatorSet.GetImageSize(image, out HTuple width, out HTuple height);
int k = 0;
for (int j = 0; j < 180; j++)
{
HOperatorSet.TupleSin(j * 2 * Math.PI / 180, out HTuple Sin);
HOperatorSet.TupleCos(j * 2 * Math.PI / 180, out HTuple Cos);
HOperatorSet.GenMeasureRectangle2(Row + R * Sin, Column + R * Cos, -j * 2 * Math.PI / 180,
MeasureHeight, MeasureWide, width, height, new HTuple("nearest_neighbor"), out HTuple measureHandle);
HOperatorSet.MeasurePos(image, measureHandle, Sigma, Threshold, new HTuple("all"), Measure_Place, out HTuple rowEdge,
out HTuple columnEdge, out HTuple amplitude, out HTuple distance);
HOperatorSet.TupleLength(rowEdge, out HTuple length1);
if (length1 == 0)
{
continue;
}
Row1[k] = rowEdge;
Column1[k] = columnEdge;
k++;
}
HOperatorSet.GenContourPolygonXld(out HObject contours, Row1, Column1);
HOperatorSet.FitCircleContourXld(contours, "atukey", -1, 0, 0, 3, 2,
out RowResult, out ColumnResult, out RResult, out HTuple StartPhi,
out HTuple EndPhi, out HTuple PointOrder);
HOperatorSet.GenCircleContourXld(out ResultContour, RowResult, ColumnResult, RResult, 0, Math.PI * 2, new HTuple("positive"), 1);
return true;
}
catch (Exception ex)
{
return false;
}
}
#endregion
//圆度工具
#region // 计算圆度
/// <summary>
/// 计算圆度(圆度:代表圆的边缘在拟合圆半径上的波动值【单位形式:距离】)
/// </summary>
/// <param name="image">输入图像</param>
/// <param name="ROIR">输入圆ROI半径</param>
/// <param name="ROIRow">输入圆ROI横坐标</param>
/// <param name="ROICloumn">输入圆ROI列坐标</param>
/// <param name="FastSet">快速阈值</param>
/// <param name="CircleContour">输出圆轮廓</param>
/// <param name="ResultR">输出圆半径</param>
/// <param name="rowResult">输出圆中心横坐标</param>
/// <param name="columnResult">输出圆中心列坐标</param>
/// <param name="circularity">输出圆度(绝对值最大的参数)</param>
/// <param name="Distances">输出圆度数组(圆边缘波动值与拟合圆半径差值)</param>
/// <returns></returns>
public static bool Circularity(HObject image, HTuple ROIRow, HTuple ROICloumn, HTuple ROIR,
bool FastSet, out HObject CircleContour, out HTuple ResultR, out HTuple rowResult,
out HTuple columnResult,out double circularity,out double[] Distances)
{
HOperatorSet.GenEmptyObj(out CircleContour);
ResultR = -1;
rowResult = -1; columnResult = -1; circularity = -1;
Distances=new double[0];
try
{
bool circle = false;
if (FastSet)
{
HOperatorSet.GetImageSize(image, out HTuple width, out HTuple height);
Distances = new double[180];
for (int j = 0; j < 180; j++)
{
HOperatorSet.TupleSin(j * 2 * Math.PI / 180, out HTuple Sin);
HOperatorSet.TupleCos(j * 2 * Math.PI / 180, out HTuple Cos);
HOperatorSet.GenMeasureRectangle2(ROIRow + ROIR * Sin, ROICloumn + ROIR * Cos, -j*2 * Math.PI / 180,
20, 5, width, height, new HTuple("nearest_neighbor"), out HTuple measureHandle);
HOperatorSet.MeasurePos(image, measureHandle, 2, 20, new HTuple("all"), new HTuple("first"), out HTuple rowEdge,
out HTuple columnEdge, out HTuple amplitude, out HTuple distance);
HOperatorSet.DistancePp(rowEdge, columnEdge, rowResult, columnResult, out HTuple distance1);
HOperatorSet.TupleLength(distance1, out HTuple length1);
if (length1 == 0)
{
Distances[j] = ResultR;
}
else
{
Distances[j] = distance1 - ResultR;
}
}
}
if (!circle)
{
return false;
}
double circularity1 = Math.Abs(Distances.Min());
double circularity2 = Math.Abs(Distances.Max());
if (circularity1 > circularity2)
{
circularity = circularity1;
}
else
{
circularity = circularity2;
}
return true;
}
catch (Exception)
{
return false;
}
}
#endregion
总结
圆度在机械设计及其制造方面的检测非常常见,尤其涉及到高精度的检测上面。使用视觉对圆度进行检测可以在极短的时间内,完成圆度测量,精确度高。