1、创建测量的模型
create_metrology_model (MetrologyHandle)
2、设置测量模型图像的大小,主要是为了提高效率
set_metrology_model_image_size(MetrologyHandle,Width, Height)
3、添加测量的对象,比如:圆 、矩形 、椭圆等
下面添加计量对象的算子分别为:圆,椭圆,矩形,线
最后一个算子add_metrology_object_generic可以由用户自己指定shape,取值 ('circle', 'ellipse', 'line', 'rectangle2')
add_metrology_object_circle_measure for circles
add_metrology_object_ellipse_measure for ellipses
add_metrology_object_rectangle2_measure for rectangles
add_metrology_object_line_measure for lines
add_metrology_object_generic
4、修改模型的参数
5、修改测量对象的参数
、set_metrology_model_param (MetrologyHandle, 'reference_system', [Rows[0],Columns[0],0])设置参考点
* 设置卡尺的数量
set_metrology_object_param (MetrologyHandle, 'all', 'num_measures', 10)
6、对齐模型
align_metrology_model
7、使用测量
8、获得测量的结果
get_metrology_object_result_contour (Contour2, MetrologyHandle, 0, 'all', 1.5)
*得到半径
get_metrology_object_result (MetrologyHandle, Index, 'all', 'result_type', 'radius', Parameter)
*显示结果
get_metrology_object_result 查询对象的适应几何形状的参数
get_metrology_object_measures 访问所有定位边的行和列坐标
get_metrology_object_result_contour 提供了作为XLD轮廓的适应几何形状的可视化
9、清理掉第一步创建的测量模型
代码显示:
* This example shows the usage of the metrology model
* to measure circles and rectangles with subpixel
* accuracy under challenging conditions easily.
*
* Display initializations
dev_update_off ()
read_image (Image, 'pads')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
*
* Define the approximate position and the measure
* tolerance for the circles
RowCircle := [52:89:500]
CircleInitRow := [RowCircle,RowCircle]
CircleInitColumn := [gen_tuple_const(6,348),gen_tuple_const(6,438)]
gen_cross_contour_xld (Cross1, CircleInitRow, CircleInitColumn, 6, 0.785398)
CircleInitRadius := [gen_tuple_const(6,23),gen_tuple_const(6,23)]
CircleRadiusTolerance := 12
* Define the approximate position and the measure
* tolerance for the rectangles
RectangleInitRow := [410,410]
RectangleInitColumn := [215,562]
RectangleInitPhi := [0,0]
RectangleInitLength1 := [85,85]
RectangleInitLength2 := [88,88]
RectangleTolerance := 10
*
* Prepare the metrology model data structure
create_metrology_model (MetrologyHandle)
* Setting the image width in advance is not
* necessary, but improves the runtime of the
* first measurement.
*set_metrology_model_image_size (MetrologyHandle, Width, Height)
set_metrology_model_image_size (MetrologyHandle, Width, Height)
* Add the metrology rectangle objects to the model
* as defined above
add_metrology_object_rectangle2_measure (MetrologyHandle, RectangleInitRow, RectangleInitColumn, RectangleInitPhi, RectangleInitLength1, RectangleInitLength2, RectangleTolerance, 5, .5, 1, [], [], MetrologyRectangleIndices)
* Add the metrology circle objects to the model
* as defined above
add_metrology_object_circle_measure (MetrologyHandle, CircleInitRow, CircleInitColumn, CircleInitRadius, CircleRadiusTolerance, 5, 1.5, 2, [], [], MetrologyCircleIndices)
* It is possible to measure more than one circle/rectangle/line/ellipse
* instance per metrology object in one call.
* Since we like to measure two circles per object,
* we set 'num_instances' to 2.
set_metrology_object_param (MetrologyHandle, MetrologyCircleIndices, 'num_instances', 2)
* Setting 'measure_transition' to 'uniform' assures
* that only consistent circles are returned, that have
* either only edges from bright to dark or vice versa.
* Since the consistency check increases runtime, it is
* switched of by default.
* In this example however, it is safer to switch it on,
* because both negative and positive edges are present.
set_metrology_object_param (MetrologyHandle, MetrologyCircleIndices, 'measure_transition', 'uniform')
* Setting the minimum score can make the results more robust
set_metrology_object_param (MetrologyHandle, MetrologyCircleIndices, 'min_score', .9)
*
* Perform the measurement
*
align_metrology_model (MetrologyHandle, 0, 0, 0)
apply_metrology_model (Image, MetrologyHandle)
*
get_metrology_object_result (MetrologyHandle, MetrologyRectangleIndices, 'all', 'result_type', 'all_param', RectangleParameter)
* Extract the parameters for better readability
Sequence := [0:5:|RectangleParameter| - 1]
RectangleRow := RectangleParameter[Sequence]
RectangleColumn := RectangleParameter[Sequence + 1]
RectanglePhi := RectangleParameter[Sequence + 2]
RectangleLength1 := RectangleParameter[Sequence + 3]
RectangleLength2 := RectangleParameter[Sequence + 4]
*
* Access the results of the circle measurement
get_metrology_object_result (MetrologyHandle, MetrologyCircleIndices, 'all', 'result_type', 'all_param', CircleParameter)
* Extract the parameters for better readability
Sequence := [0:3:|CircleParameter| - 1]
CircleRow := CircleParameter[Sequence]
CircleColumn := CircleParameter[Sequence + 1]
CircleRadius := CircleParameter[Sequence + 2]
*
* Display the results
*
* Get measured contours
get_metrology_object_result_contour (Contours, MetrologyHandle, 'all', 'all', 1.5)
* Get the contours of the measure regions
* and the coordinates of the edge points
* that were the basis for fitting the circles and rectangles
get_metrology_object_measures (Contour, MetrologyHandle, 'all', 'all', Row1, Column1)
gen_cross_contour_xld (Cross, Row1, Column1, 6, 0.785398)
* Display everything
Color := ['gray','cyan','green']
dev_display (Image)
dev_set_line_width (1)
dev_set_color (Color[0])
dev_display (Contour)
dev_set_color (Color[1])
dev_display (Cross)
dev_set_line_width (2)
dev_set_color (Color[2])
dev_display (Contours)
Message := Color[2] + ': Measurement result'
Message[1] := Color[1] + ': Edge candidate points'
Message[2] := Color[0] + ': Measure regions'
disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
clip_region_rel( )
Region是输入区域;
RegioonClipped是减掉后的输出区域;
Top,Bottom,Left,Right
本来是在现有区域的基础上,减去一个现有区域的最小外接矩形的每一条边,通过上下左右这四个参数的大小,把四条边变成了区域,如下图;左边减去的是10个像素宽度的区域,右边是20个像素宽度的区域,上边是10个像素大小的区域,下边是一个边;
fit_line_contour_xld( Contours : : Algorithm, MaxNumPoints, ClippingEndPoints, Iterations, ClippingFactor : RowBegin, ColBegin, RowEnd, ColEnd, Nr, Nc, Dist )
对一些线段的XLD做近似计算直线计算
Contours(in):输入轮廓
Algorithm(in):形成线的算法
regression:回归,标准的最小二乘法拟合
huber:加权的最小二乘法拟合,异常值的影响被减小基于Huber方法
tukey:加权的最小二乘法拟合,异常值的影响被减小基于Tukey方法
drop:加权的最小二乘法拟合,异常值的影响被消除
gauss:加权的最小二乘法拟合,异常值的影响被减小基于最逼近线上的所有其轮廓点的平均值和距离标准方差
MaxNumPoints(in):用于计算的最大轮廓点个数 -1 表示全部的点
ClippingEndPoints(in):拟合直线时,需要忽略轮廓起始处点个数。(一个XLD轮廓会被线分割成很多个小轮廓)
Iterations(in): 最大迭代次数。(不适用于’regression’)
ClippingFactor(in):消除异常值的裁剪因子:( 1.0 for 'huber' and 'drop' and 2.0 for 'tukey')
RowBegin(out):线段开始点的行坐标
ColBegin(out):线段开始的列坐标
RowEnd(out):线段结尾的行坐标
ColEnd(out):线段结尾的列坐标
Nr (output_control) :直线方程法线式x相乘系数
Nc (output_control) :直线方程法线式y相乘系数
Dist (output_control) :坐标系原点到线段的距离
针对’huber’, ‘tukey’, 'drop’这三种算法,首先是根据所有点近似拟合一条直线,然后计算原始轮廓上每一点到拟合直线的距离,再根据统计学中标准差方式去除异常点。
假设有100个点参与拟合直线,其中有20个点是偏离直线的异常点,那么通过标准差的方式100个点对应100个统计值,按照距离直线远近从大到小排序。如果都参与拟合直线,拟合的直线和实际会有偏差,原因是其中混杂了异常值,所以为了确保拟合的准确度,可以通过参数 ClippingFactor 控制要排除的异常点数量,值越小,参与拟合的异常值越多,拟合的准确度越低。
为了进一步提高拟合精度,参数Iterations 控制迭代次数,也就是说每次都会重复以上步骤
需要注意的是这个值对方法’regression’ 不起作用;方法’tukey’在拟合直线时去除了所有的异常值;异常值对方法’huber’依然会存在影响。
Particularly, for outliers the optimization is influenced linearly and for points with a smaller distance it is influenced to the square. In practice, the approach of Tukey is recommended.
虽然可以通过计算标准差、参数ClippingFactor 控制异常值个数、Iterations 增加迭代次数尽可能避免异常值对拟合直线的影响。但求解最优直线方程始终是有限的,只能说无限逼近。有的小伙伴会说,不是有ClippingFactor 、Iterations 这两个参数可以控制吗,那这两个参数如何组合才是最优?ClippingFactor 、Iterations 大了,会造成拟合的点变少,而且也许去掉的所谓‘异常值’,实际是正常值呢;值太小也会有同样的问题,所以只能说是无限接近,始终会存在误差。Halcon推荐使用Tukey 方法。
创建不带圆角的多边形轮廓,坐标同样可以使用数组的形式指定。
gen_contour_polygon_rounded_xld
创建带圆角的多边形轮廓,坐标和圆角可以通过数组的形式指定。
dev_set_color ('green')
dev_set_line_width (3)
*坐标数组
rows1:=[20,100,100,20,20]
cols1:=[20,20,250,250,20]
radius:=[20,20,20,20,20]
rows2:=[20,20,100,100,20]
cols2:=[320,550,550,320,320]
*带圆角的多边形轮廓
gen_contour_polygon_rounded_xld (Contour, rows1, cols1, radius, 1)
*不带圆角的多边形轮廓
gen_contour_polygon_xld (Contour1, rows2, cols2)
halcon——缺陷检测常用方法总结(测量拟合) - 1024搜-程序员专属的搜索引擎
dist_rectangle2_contour_points_xld 这个算子求实际轮廓与理论轮廓点对点的距离,只要这个距离超过了我们的设定值,就认为边缘有缺陷了
* 检测这个缺陷 利用dist_rectangle2_contour_points_xld 这个算子求实际轮廓与理论轮廓点对点的距离,只要这个距离超过了我们的设定值,就认为边缘有缺陷了
dev_update_off ()
read_image (Image, 'D:/OpenCVandImages/opencv_images/632.png')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (Image)
*快速二值化(增加了被提取区域最小尺寸10个像素)
fast_threshold (Image, Region, 128, 255, 10)
*形态学求边界,inner代表内边界。内边界=原图-腐蚀后的图,外边界=膨胀后的图-原图
boundary (Region, Border, 'inner')
dilation_rectangle1 (Border, EdgeROI, 7, 7)
*抠图
reduce_domain (Image, EdgeROI, ImageReduced)
*边缘提取,输出XLD轮廓,平滑系数1.7
edges_sub_pix (ImageReduced, Edges, 'canny', 1.7, 40, 120)
* 选择周长在500-100000像素内的边界
select_shape_xld (Edges, RectangleEdges, 'contlength', 'and', 500, 100000)
* 拟合一个矩形的亚像素轮廓xld
fit_rectangle2_contour_xld (RectangleEdges, 'tukey', -1, 0, 0, 3, 2, Row, Column, Phi, Length1, Length2, PointOrder)
* 形成一个矩形的亚像素轮廓xld
gen_rectangle2_contour_xld (Rectangles, Row, Column, Phi, Length1, Length2)
dev_set_color ('yellow')
dev_display (Rectangles)
*计算所有边界的数量
count_obj (RectangleEdges, Number)
*开始计算轮廓上的点和最小外接矩形上的点之间的距离(会排除4个叫的距离)
for I := 0 to Number - 1 by 1
*开始选中第一个轮廓,索引从1开始
select_obj (RectangleEdges, RectangleEdge, I + 1)
*通过轮廓,得到轮廓上的点的坐标。会有很多点,这是实际边界上的点
get_contour_xld (RectangleEdge, Rows, Cols)
*形成XLD亚像素轮廓
gen_rectangle2_contour_xld (Rect, Row[I], Column[I], Phi[I], Length1[I], Length2[I])
* 获得拟合的轮廓上的点。这是标准矩形上的点
get_contour_xld (Rect, RowC, ColC)
*下面是横坐标的平方和+纵坐标的平方和,开跟号
*求的就是实际边界上的点和拟合矩形边界上的点的距离
*RowC,ColC从0-3,代表的是拟合的矩形的4个角的坐标值
D1 := sqrt((Rows - RowC[0]) * (Rows - RowC[0]) + (Cols - ColC[0]) * (Cols - ColC[0]))
D2 := sqrt((Rows - RowC[1]) * (Rows - RowC[1]) + (Cols - ColC[1]) * (Cols - ColC[1]))
D3 := sqrt((Rows - RowC[2]) * (Rows - RowC[2]) + (Cols - ColC[2]) * (Cols - ColC[2]))
D4 := sqrt((Rows - RowC[3]) * (Rows - RowC[3]) + (Cols - ColC[3]) * (Cols - ColC[3]))
* 轮廓上的点到最小外接矩形4个角点,上最小距离值
DistCorner := min2(min2(D1,D2),min2(D3,D4))
*求的是轮廓上的点到最小外接矩形间的距离。0代表不忽略任何点
dist_rectangle2_contour_points_xld (RectangleEdge, 0, Row[I], Column[I], Phi[I], Length1[I], Length2[I], Dist)
*假设距离都在规格范围内
* RectangleOK := true
* for J := 0 to |Dist| - 1 by 1
*从0开始,对于上面计算出的距离值进行判断
*对于某个点而言,到最近的角点的距离超过了7个像素,说明我们对于角落的部分点进行了筛选
*做对应计算的是不在角落7个像素以内的点
*如果这些点和最小外接矩形的区域距离超过1个像素,说明该点是NG的
* if (DistCorner[J] > 7.0 and Dist[J] > 1.0)
* RectangleOK := false
* break
* endif
* endfor
* sgn是符号函数,括号里面的值=0,Mask就等于0.里面的值>0,Mask就等于1。里面的值<0,Mask就等于-1。
*max2(DistCorner - 7.0,0.0),就代表角点的坐标,如果有超过7个像素的值,那么就>0;Mask就等于1
*如果没有超过7个像素的值,那么<0。max2(DistCorner - 7.0,0.0)就等于0,Mask就等于0
Mask := sgn(max2(DistCorner - 7.0,0.0))
* 如果等于1的话,1这个距离。如果距离的最大值<=1成立,就说明ok
RectangleOK := max(Dist * Mask) <= 1.0
* 显示那个孔洞是OK的
if (RectangleOK)
dev_set_color ('green')
*取一个字符串的空间大小
get_string_extents (WindowHandle, 'OK', Ascent, Descent, Width, Height)
*设置光标的位置
set_tposition (WindowHandle, Row[I] - Height / 2, Column[I] - Width / 2)
*写一个ok字符串
write_string (WindowHandle, 'OK')
else
dev_set_color ('red')
get_string_extents (WindowHandle, 'Not OK', Ascent, Descent, Width, Height)
set_tposition (WindowHandle, Row[I] - Height / 2, Column[I] - Width / 2)
write_string (WindowHandle, 'Not OK')
endif
endfor
案例2:
read_image (Image660, 'D:/OpenCVandImages/opencv_images/660.png')
get_image_size (Image660, Width, Height)
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_display (Image660)
* 创建测量模型
create_metrology_model (MetrologyHandle)
* 设置测量图像的大小
set_metrology_model_image_size (MetrologyHandle, Width, Height)
rgb1_to_gray (Image660, GrayImage)
threshold (GrayImage, Region, 128, 255)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ['area','roundness'], 'and', [4553.03,0.18409], [10000,1])
area_center (SelectedRegions, Area, Row, Column)
r:=[60,60,60,60]
* 显示图像
dev_set_draw ('margin')
dev_display (Image660)
gen_circle (Circle, Row[0], Column[0], 60)
add_metrology_object_circle_measure (MetrologyHandle, Row, Column, r, 30, 5, 1.5, 30, ['measure_transition','min_score'], ['all',0.4], Index)
*测量并拟合几何形状], [], Index)
set_metrology_object_param (MetrologyHandle, 'all', 'num_measures', 10)
apply_metrology_model (GrayImage, MetrologyHandle)
get_metrology_object_result_contour (Contour, MetrologyHandle, 'all', 'all', 1.5)
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'result_type', 'radius', Parameter)
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row1, Column1)
gen_cross_contour_xld (Cross, Row1, Column1, 60, 0.785398)
dev_display (Contour)
set_tposition (WindowHandle,0, 0)
write_string (WindowHandle, Parameter)
clear_metrology_model(MetrologyHandle)
案例三:
read_image (Image661, 'D:/OpenCVandImages/opencv_images/661.png')
get_image_size (Image661, Width, Height)
dev_set_draw ('margin')
row:=[59,178,296]
col:=[334,334,334]
r1:=[50,50,50]
dev_set_color ('green')
gen_circle (Circle, row[0], col[0], r1[0])
gen_circle (Circle1, row[1], col[1], r1[1])
gen_circle (Circle2, row[2], col[2], r1[2])
* 拿去外部的圆
create_metrology_model (MetrologyHandle)
add_metrology_object_circle_measure(MetrologyHandle, row, col, r1, 15, 5, 1, 4, ['measure_transition','min_score'], ['all',0.2], Index)
apply_metrology_model(Image661, MetrologyHandle)
get_metrology_object_result(MetrologyHandle, 0, 'all', 'result_type', 'radius', Parameter1)
get_metrology_object_result(MetrologyHandle, 1, 'all', 'result_type', 'radius', Parameter2)
get_metrology_object_result(MetrologyHandle, 2, 'all', 'result_type', 'radius', Parameter3)
get_metrology_object_result_contour(Contour1, MetrologyHandle, 0, 'all', 1.5)
get_metrology_object_result_contour(Contour2, MetrologyHandle, 1, 'all', 1.5)
get_metrology_object_result_contour(Contour3, MetrologyHandle, 2, 'all', 1.5)
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row1, Column1)
gen_cross_contour_xld (Cross, Row1, Column1, 6, 0.785398)
dev_set_color ('gray')
*get_metrology_object_measures(ContoursD, MetrologyHandle, 'all', 'all', Row, Column)
dev_set_color ('green')
dev_display(Contour1)
dev_display(Contour2)
dev_display(Contour3)
clear_metrology_model(MetrologyHandle)
*取内圆
create_metrology_model(MetrologyHandle)
set_metrology_model_image_size(MetrologyHandle, Width, Height)
r2:=[29,29,29]
* gen_circle(Circle4, row[0], col[0], r2[0])
* gen_circle(Circle5, row[1], col[1], r2[1])
* gen_circle(Circle6, row[2], col[2], r2[2])
add_metrology_object_circle_measure(MetrologyHandle, row, col, r2, 15, 5, 1, 4, ['measure_transition','min_score'], ['all',0.2], Index)
apply_metrology_model(Image661, MetrologyHandle)
get_metrology_object_result(MetrologyHandle, 0, 'all', 'result_type', 'radius', Parameter4)
get_metrology_object_result(MetrologyHandle, 1, 'all', 'result_type', 'radius', Parameter5)
get_metrology_object_result(MetrologyHandle, 2, 'all', 'result_type', 'radius', Parameter6)
get_metrology_object_result_contour(Contour4, MetrologyHandle, 0, 'all', 1.5)
get_metrology_object_result_contour(Contour5, MetrologyHandle, 1, 'all', 1.5)
get_metrology_object_result_contour(Contour6, MetrologyHandle, 2, 'all', 1.5)
dev_set_color ('gray')
get_metrology_object_measures(ContoursD2, MetrologyHandle, 'all', 'all', Row, Column)
dev_set_color ('green')
dev_display(Contour4)
dev_display(Contour5)
dev_display(Contour6)
clear_metrology_model(MetrologyHandle)
*找矩形
row1:=180
col1:=160
phi:=0
len1:=110
len2:=110
create_metrology_model(MetrologyHandle)
set_metrology_model_image_size(MetrologyHandle, Width, Height)
add_metrology_object_rectangle2_measure(MetrologyHandle, row1, col1, phi, len1, len2, 15, 5, 1, 3, ['min_score'], [0.2], Index3)
apply_metrology_model(Image661, MetrologyHandle)
get_metrology_object_result(MetrologyHandle, 0, 'all', 'result_type', 'all_param', Parameter4)
get_metrology_object_result_contour(Contour6, MetrologyHandle, 0, 'all', 1.5)
dev_set_color ('gray')
get_metrology_object_measures(ContoursD3, MetrologyHandle, 'all', 'all', Row, Column)
dev_set_color ('green')
dev_display(Contour6)
clear_metrology_model(MetrologyHandle)