ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

halcon之第4讲--亚像素以及相应算子学习

halcon之第4讲--亚像素以及相应算子学习 文章目录前言亚像素XLD介绍生成XLD的常用算子edges_sub_pixthreshold_sub_pixgen_contour_region_xld筛选、分割、拼接轮廓select_contours_xldsegment_contours_xldsplit_contours_xld拟合常用算子fit_line_contour_xldfit_circle_contour_xld算子fit_ellipse_contour_xld算子获取 XLD 数据get_contour_xld算子count_obj算子实例分析计算零件的半径测量齿轮零件中圆孔半径获取钻石的边缘以及顶角前言亚像素测量是halcon里面非常重要的一个模块掌握这一模块是学习halcon的必备技能亚像素XLD介绍亚像素是 Halcon 独有的亚像素轮廓数据结构不是图像、不是 Region像素级区域存储的是浮点型亚像素坐标的轮廓 / 边缘精度远高于整数像素。Region 像素级坐标都是整数最小单位 1 像素。XLD亚像素坐标是浮点数比如Row120.345, Column230.771可以做到 0.01 像素级测量。XLD 两类对象XLD Contour轮廓线边缘、边界点按顺序连成线最常用用于测量XLD Polygon多边形闭合轮廓围成亚像素精度的封闭形状生成 XLD 的常用算子亚像素边缘提取生成XLD的常用算子edges_sub_pix最经典提取亚像素边缘基于梯度输出XLD轮廓edges_sub_pix(Image : Edges : Filter, Alpha, Low, High : )功能提取亚像素 XLD 边缘轮廓输出对象是 XLD Contour不是 Region。参数解释Image输入图像单通道灰度图。如果传入彩色图会报错需先decompose3转灰度。Edges输出XLD 轮廓集合对象多条边缘存放在这个对象元组里。Filter 滤波器类型工业中绝大多数选择cannyAlpha 滤波系数Alpha 越大→ 图像平滑越强抑制噪声但边缘位置会轻微偏移细小边缘容易丢失。Alpha 越小→ 保留细节但噪声会生成大量碎小伪边缘。Low 低阈值。控制主要边缘调大 → 边缘变少调小 → 多出很多边缘High 高阈值。一般取 Low 0.4 ~ 0.6 * High经典配比。threshold_sub_pix基于阈值提取物体边界XLDthreshold_sub_pix(Image : Border : Threshold : )功能基于灰度阈值提取物体亚像素 XLD 边界轮廓。参数解释Image输入单通道灰度图像彩色图必须先转灰度Border输出XLD 轮廓对象集合物体的亚像素闭合边界Threshold灰度阈值算子在图像上找像素灰度跨过 Threshold 的位置gen_contour_region_xld从Region生成XLDgen_contour_region_xld(Regions : Contours : Mode : )功能该算子是把Region像素级区域的边界包装成 XLD 对象不会产生亚像素坐标仍然是整数像素仅用于可视化不可拿来做高精度尺寸测量。参数解释Regions输入Region 区域像素级坐标全是整数Contours输出XLD 轮廓对象。虽然数据类型是 XLD但底层点坐标为整数像素没有亚像素浮点精度Mode模式参数控制提取 Region 边界的方式常用border。注意region本身是像素转出来的XLD精度不会提升筛选、分割、拼接轮廓select_contours_xldselect_contours_xld(Contours : SelectedContours : Feature, Min1, Max1, Min2, Max2 : )作用对 XLD 轮廓集合做筛选过滤掉噪声碎边缘、不需要的轮廓保留符合条件的 XLDXLD 流水线几乎必用算子。参数解释Contours输入待筛选 XLD 轮廓集合edges_sub_pix /threshold_sub_pix 输出SelectedContours输出筛选后保留下来的 XLD 集合Feature筛选特征选择依据Min1, Max1特征 1 的最小、最大值Min2, Max2特征 2 的最小、最大值部分 Feature 不使用这两个参数填 -9999, 9999segment_contours_xldsegment_contours_xld(Contours : ContoursSplit : Mode, SmoothCont, MaxLineDist1, MaxLineDist2 : )作用把一条连续、可能混合直线 圆弧的 XLD 轮廓在拐点处断开分割成独立直线段、圆弧段 XLD。分割之后就可以用fit_line_contour_xld、fit_circle_contour_xld做拟合测量XLD 测量流水线核心算子参数解释Contours输入原始 XLD 轮廓集合ContoursSplit输出分割完成后的 XLD 段集合每一段要么是 line要么是 circle可用get_contour_attributes_xld读取类型Mode 分割模式lines全部拟合成直线段lines_circles分割成直线 圆弧【工业最常用】lines_ellipses分割成直线 椭圆弧SmoothCont 轮廓平滑点数对原始 XLD 轮廓做局部平滑用来抑制噪声造成的虚假拐点。取值0 ~ 200不平滑噪声大的轮廓会产生大量不必要的碎小段3~6工程常用噪声一般取 3‑5噪声大可以给到 6‑8过大10会抹平真实微小拐点几何形状失真MaxLineDist1: 轮廓与近似直线之间的最大容许距离第一次迭代默认4MaxLineDist2轮廓与近似直线之间的最大容许距离第二次迭代默认2split_contours_xldsplit_contours_xld(Polygons : Contours : Mode, Weight, Smooth : )作用在曲率变化剧烈的点分割亚像素轮廓参数解释Polygons输入 XLD 轮廓可以是闭合 / 开放 XLDContours输出切分之后的 XLD 轮廓集合Mode分割模式依据什么条件断开polygon为了把轮廓变成多边形折线在逼近顶点处切开圆弧也会被切为小段直线dominant只识别轮廓本身真实转角拐角只在这些位置断开平滑圆弧保持完整不被切碎。Weight曲率计算权重系数Smooth轮廓平滑点数抑制噪声造成伪拐点拟合常用算子fit_line_contour_xldfit_line_contour_xld(Contours : : Algorithm, MaxNumPoints, ClippingEndPoints, Iterations, ClippingFactor : RowBegin, ColBegin, RowEnd, ColEnd, Nr, Nc, Dist)功能对 XLD 轮廓做亚像素直线拟合工业尺寸测量核心算子支持普通最小二乘、鲁棒拟合可抵抗毛刺 / 离群点。参数解释一、输入对象二、输入控制参数Algorithm 可选值工程经验轮廓干净用 ‘regression’有少量噪声毛刺用 ‘huber’ClippingFactor≈1.5噪声/离群点较多且不确定用 ‘tukey’ClippingFactor≈2.0。三、输出参数fit_circle_contour_xld算子fit_circle_contour_xld(Contours : : Algorithm, MaxNumPoints, MaxClosureDist, ClippingEndPoints, Iterations, ClippingFactor : Row, Column, Radius, StartPhi, EndPhi, PointOrder)功能对 XLD 轮廓做亚像素圆拟合参数解释一、输入对象二、输入控制参数Algorithm 可选值经验完整圆用 ‘algebraic’开口弧段如只拍到 1/4~1/2 个圆用 ‘geometric’有噪声毛刺用 ‘tukey’ClippingFactor≈2.0。三、输出控制参数四、圆的参数方程与角度约定拟合出的圆用中心角参数化表示圆上任意点满足ColumnColumn Radius * cos(Φ)RowRow Radius * sin(Φ)其中 Φ 为角度以列坐标轴水平向右为 0°逆时针为正即 Φ 从 StartPhi 递增到 EndPhi 覆盖整个拟合弧段。约定要点StartPhi / EndPhi 只描述轮廓实际覆盖的那段弧。若轮廓被判定为闭合首末点距离PointOrder ‘positive’ 表示轮廓点逆时针排列Φ 递增‘negative’ 表示顺时针Φ 递减。轮廓只是弧还是整圆直接由 MaxClosureDist 决定——这在很多场景里是决定输出角度的关键开关。fit_ellipse_contour_xld算子fit_ellipse_contour_xld(Contours : : Algorithm, MaxNumPoints, MaxClosureDist, ClippingEndPoints, VossTabSize, Iterations, ClippingFactor : Row, Column, Phi, Radius1, Radius2, StartPhi, EndPhi, PointOrder)作用拟合椭圆参数解释一、输入对象二、输入控制参数Algorithm 可选值经验完整闭合椭圆用 ‘fitzgibbon’ 或 ‘fitzgibbon3’只拍到小段弧时用 ‘fitzgibbon4’ 或 ‘hyper’有噪声毛刺用 ‘tukey’ClippingFactor≈2.0。三、输出控制参数注意Radius1 是主轴方向上的半轴Radius2 是与之垂直的半轴拟合不完整弧段时二者的大小关系由 Phi 决定不保证 Radius1 ≥ Radius2这与 elliptic_axis 区域算子约定不同。四、椭圆的参数方程与角度约定椭圆的参数化以参数角 φ 表示椭圆上的点ColumnColumn Radius1·cos(Phi)·cos(φ)− Radius2·sin(Phi)·sin(φ)RowRow Radius1·sin(Phi)·cos(φ) Radius2·cos(Phi)·sin(φ)Phi 是一开始的朝向主轴相对列轴逆时针旋转角φ 是从 StartPhi 到 EndPhi 的参数角覆盖轮廓实际占用的那段弧约定与 fit_circle_contour_xld 一致以列轴为 0°、逆时针为正PointOrder‘positive’ 时参数角递增轮廓被判定为闭合整椭圆时StartPhi 与 EndPhi 相差约 2π。获取 XLD 数据get_contour_xld算子get_contour_xld(Contour : : : Row, Col)作用取出 XLD 所有亚像素点坐标 (Row,Col)拿到浮点数组自己计算参数解释Contour输入亚像素Row所有亚像素点的行坐标Col所有亚像素点的行坐标count_obj算子count_obj(Objects : : : Number)作用获取对象集合中对象的数量参数解释Objects输入对象Number对象数量实例分析计算零件的半径程序dev_update_off()dev_close_window()*读取官方零件测试图fabrikread_image(Image,rings_and_nuts)get_image_size(Image, W, H)dev_open_window(0,0, W, H,black, WindowHandle)dev_display(Image)*亚像素边缘提取 edges_sub_pixedges_sub_pix(Image, Edges,canny,1,20,40)*闭合轮廓过滤select_contours_xld(Edges, SelectedContours,closed,1,1,0,0)dev_clear_window()dev_display(SelectedContours)*循环逐条读取XLD的圆度count_obj(SelectedContours, ObjNum)gen_empty_obj(CirObject)circularity_xld(ObjectSelected, Circularity)*圆度越接近于1越接近正圆if(Circularity0.90)concat_obj(CirObject, ObjectSelected, CirObject)endif endfor dev_clear_window()dev_display(Image)*圆拟合fit_circle_contour_xld(CirObject,algebraic, -1,0,0,3,2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)disp_message(WindowHandle, Radius,window, Row, Column,black,true)运行结果该程序中涉及知识点1、如何向空元组添加变量Halcon 元组不能原地修改是通过拼接生成新元组。空元组T : []语法T : [ T, NewElement ]易错点1.把 XLD 对象往元组里塞错误;XLD、Region、Image 属于对象必须用对象容器.✅区分数值、坐标、半径、索引 → 元组 []追加 [T,val]XLD 轮廓、Region、Image 图像 → 对象集合gen_empty_obj concat_obj*Object就是合并后的新的元组gen_empty_obj(Object)concat_obj(Object, ObjectSelected, Object)测量齿轮零件中圆孔半径程序*读取图片并设置窗口read_image(Image,rim)dev_close_window()dev_open_window_fit_image(Image,0,0, -1, -1, WindowHandle)dev_set_color(white)dev_set_draw(fill)dev_display(Image)*获取亚像素edges_sub_pix(Image, Edges,canny,1,20,40)dev_clear_window()dev_display(Edges)*筛选长度去掉噪声碎边select_contours_xld(Edges, SelectedContours,contour_length,15,280, -0.5,0.5)dev_clear_window()dev_display(SelectedContours)*链接碎片XLDunion_cocircular_contours_xld(SelectedContours, UnionContours,0.5,0.1,0.2,30,10,10,true,1)dev_clear_window()dev_display(UnionContours)*通过圆度参数过滤出圆count_obj(UnionContours, Number)gen_empty_obj(CirObject)forIndex :1to Number by1select_obj(UnionContours, ObjectSelected, Index)circularity_xld(ObjectSelected, Circularity)if(Circularity0.90)concat_obj(CirObject, ObjectSelected, CirObject)endif endfor * dev_clear_window()* dev_display(CirObject)*拟合圆fit_circle_contour_xld(CirObject,algebraic, -1,0,0,3,2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)dev_display(Image)disp_message(WindowHandle, Radius,window, Row, Column,black,true)运行结果获取钻石的边缘以及顶角程序如下读取图片并设置窗口dev_update_off()dev_close_window()read_image(Image,diamond/diamond_01)get_image_size(Image, Width, Height)dev_open_window(0,0, Width, Height,black, WindowHandle)dev_display(Image)*分割threshold(Image, Region,128,255)dev_clear_window()dev_display(Region)*获取感兴趣区域clip_region_rel(Region, RegionClipped,0,290,0,0)dev_clear_window()dev_display(RegionClipped)*填充内部和边缘缺口shape_trans(RegionClipped, RegionTrans,convex)dev_clear_window()dev_display(RegionTrans)*获取钻石的两个边缘dilation_rectangle1(RegionTrans, RegionDilation,5,1)erosion_rectangle1(RegionTrans, RegionErosion,5,1)difference(RegionDilation, RegionErosion, RegionDifference)reduce_domain(Image, RegionDifference, ImageReduced)dev_clear_window()dev_display(ImageReduced)*获取亚像素edges_sub_pix(ImageReduced, Edges,canny,1,20,40)dev_clear_window()dev_display(Edges)*直线拟合union_collinear_contours_xld(Edges, UnionContours,50,1,2,0.1,attr_keep)* select_contours_xld(UnionContours, SelectedContours,contour_length,50,2000,0,0)dev_clear_window()dev_display(UnionContours)fit_line_contour_xld(UnionContours,tukey, -1,0,5,2, RowBegin, ColBegin, RowEnd, ColEnd, Nr, Nc, Dist)tuple_sort_index(RowBegin, Indices)RowBegin :subset(RowBegin,Indices)RowEnd :subset(RowEnd,Indices)ColBegin :subset(ColBegin,Indices)ColEnd :subset(ColEnd,Indices)Nr :subset(Nr,Indices)Nc :subset(Nc,Indices)Dist :subset(Dist,Indices)gen_contour_polygon_xld(LineEdge1,[Dist[0]/ Nr[0],0],[0,Dist[0]/ Nc[0]])gen_contour_polygon_xld(LineEdge2,[Dist[1]/ Nr[1],Width -1],[0,(Dist[1]-(Width -1)* Nr[1])/ Nc[1]])intersection_lines(RowBegin[0], ColBegin[0], RowEnd[0], ColEnd[0], RowBegin[1], ColBegin[1], RowEnd[1], ColEnd[1], RowTip, ColTip, IsOverlapping)gen_cross_contour_xld(Cross, RowTip, ColTip,20, rad(45))*展示结果dev_display(Image)dev_set_color(yellow)dev_display(LineEdge1)dev_display(LineEdge2)dev_set_color(blue)dev_display(Cross)运行结果该程序中涉及知识点1.tuple_sort_index( : : Tuple : Indices)作用将元组的全部元素按升序排序返回排序后元素在原始输入元组中对应的下标索引输出保存到 Indices。简单示例理解Tuple :[50,10,30]tuple_sort_index(Tuple,Indices)*输出 Indices[1,2,0]排序后数值[10,30,50]10在原元组下标130下标250下标0→ 所以Indices[1,2,0]工程搭配拿到 Indices 之后用subset(原元组,Indices)即可得到排好序的元组。2.subset(Tuple, Indices)作用按照下标索引从元组中提取指定的一批元素生成新元组拟合完得到一整套元组RowBegin,ColBegin,RowEnd,ColEnd做条件判断得到满足条件的下标集合Indices用find算子用subset把所有关联元组同步过滤一遍保证一一对应以上内容如果帮到您请点赞加收藏如果有错误欢迎指正
返回列表