Halcon 曲线追踪(边缘检测、xld分割、xld筛选、线段合并)
图片数据与程序
链接:https://pan.baidu.com/s/1feGOa0A7dvCeBjQivr6TvA
提取码:f2ws
原图
起点终点方向
* 1.加载图片 ***************************************************
dev_update_off ()
dev_close_window ()
read_image (Image, './die/die_01')
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_colored (12)
dev_set_line_width (2)* 2.设置参数 **************************************************
* 线宽
WireWidths := [1.8, 0, 0, 8, 6, 1.7, 7.5]* 最短分割曲线长度
MinSegmentLength := 5
* 曲线搜索角度
AngleTolerance := rad(35)* 最小搜索半径
MinSearchRadius := 10
MinWireDeviation := 5* 判定曲线是否成功 -- 距离终点距离
AcceptanceRadius := 5
* 最短线长
MinWireLength := 80* 3.循环处理图片 **************************************************
for Img := 1 to 7 by 1* 4.读取曲线参数 *************************************************** 读取文件(曲线起点坐标,搜索方向,终点坐标,搜索方向)try* 文件路径DataFilePath := './para/die_' + Img$'02' + '_params.tup'read_tuple (DataFilePath, Parameters)catch (Exception)continueendtry* 读取数据个数NPads := Parameters[0]* 曲线起点坐标StartPadRows := Parameters[1:NPads]StartPadCols := Parameters[NPads + 1:2 * NPads]* 搜索方向StartInitOrientation := Parameters[2 * NPads + 1:3 * NPads]* 读取曲线终点坐标EndPadRows := Parameters[3 * NPads + 1:4 * NPads]EndPadCols := Parameters[4 * NPads + 1:5 * NPads]* 读取搜索方向EndInitOrientation := Parameters[5 * NPads + 1:6 * NPads]* 曲线起点与搜索方向gen_cross_contour_xld (CrossStart, StartPadRows, StartPadCols, 6, 0.785398)start_row := StartPadRows - 30 * sin(StartInitOrientation)start_column := StartPadCols + 30 * cos(StartInitOrientation)gen_arrow_contour_xld (ArrowStart, StartPadRows, StartPadCols, start_row, start_column, 5, 5)* 曲线终点与搜索方向gen_cross_contour_xld (CrossEnd, EndPadRows, EndPadCols, 6, 0.785398) end_row := EndPadRows - 30 * sin(EndInitOrientation)end_column := EndPadCols + 30 * cos(EndInitOrientation)gen_arrow_contour_xld (ArrowEnd, EndPadRows, EndPadCols, end_row, end_column, 5, 5)* 显示读取曲线参数read_image (Image, 'die/die_' + Img$'02')dev_display (Image) dev_set_color ('red')dev_display (CrossEnd)dev_display (ArrowEnd)dev_set_color ('blue')dev_display (CrossStart)dev_display (ArrowStart)stop()* 初始化线gen_empty_obj (Wires)* 5.循环搜索曲线 **************************************************for Pad := 0 to |StartPadRows| - 1 by 1* 最大线段距离MaxDistSegment := 17 * WireWidths[Img - 1]* 6.正向搜索 *************************************************** 曲线追踪--正向搜索track_wire (Image, FwdWireSegments, StartPadRows[Pad], StartPadCols[Pad],\StartInitOrientation[Pad], EndPadRows[Pad], EndPadCols[Pad], \WireWidths[Img - 1], AngleTolerance, MinSegmentLength, MaxDistSegment)* 合并线段fuse_wire_segments (FwdWireSegments, Wire, \StartPadRows[Pad], StartPadCols[Pad], \EndPadRows[Pad], EndPadCols[Pad], \MinWireLength, MaxDistSegment, MinWireDeviation)* 计算与终点的距离distance_pc (Wire, EndPadRows[Pad], EndPadCols[Pad], DistanceMin, DistanceMax)if (DistanceMin > AcceptanceRadius)* 选择正向搜索 最后一段count_obj (FwdWireSegments, NXLDs)select_obj (FwdWireSegments, ObjectSelected, NXLDs)get_contour_xld (ObjectSelected, Row, Column)* 7.反向搜索 *************************************************** 曲线追踪-- 反向搜索track_wire (Image, BckWireSegments, EndPadRows[Pad], EndPadCols[Pad], \EndInitOrientation[Pad], StartPadRows[Pad], StartPadCols[Pad], \WireWidths[Img - 1], AngleTolerance, MinSegmentLength, MaxDistSegment)* 合并线段fuse_wire_segments (BckWireSegments, WireBck, \StartPadRows[Pad], StartPadCols[Pad],\EndPadRows[Pad], EndPadCols[Pad], \DistanceMin, MaxDistSegment, MinWireDeviation)count_obj (WireBck, WiresFound)if (WiresFound > 0)* 获取正向线段* 8.正反向距离判定-截取正向有效部分*************************************************** 计算正向与反向接续处distance_contours_xld (Wire, WireBck, ContourOut, 'point_to_segment')query_contour_attribs_xld (ContourOut, Attribs)get_contour_attrib_xld (ContourOut, 'distance', Distance)MinDistIdx := sort_index(Distance)[0]get_contour_xld (Wire, WireRow, WireCol)* 截取正向有效部分gen_contour_polygon_xld (WireFwdPart, WireRow[0:MinDistIdx], WireCol[0:MinDistIdx])* 9.正反向距离判定-截取反向有效部分 *************************************************** 获取反向线段坐标get_contour_xld (WireBck, WireBckRow, WireBckCol)* 计算距离distance_pp (WireBckRow, WireBckCol, \gen_tuple_const(|WireBckRow|,WireRow[MinDistIdx]), \gen_tuple_const(|WireBckCol|,WireCol[MinDistIdx]), DistancePP)MinDistBckIdx := sort_index(DistancePP)[0]* 截取反向有效部分gen_contour_polygon_xld (WireBckPart,\WireBckRow[MinDistBckIdx + 1:|WireBckRow| - 1],\WireBckCol[MinDistBckIdx + 1:|WireBckRow| - 1])* 合并正向与反向线段concat_obj (WireFwdPart, WireBckPart, WireSegments)else* 未找到逆向直线* 使用正向线段count_obj (FwdWireSegments, NSegments)Sequence := [1:NSegments]select_obj (FwdWireSegments, WireSegments, Sequence)endif* 10.合并正反线段 **************************************************length_xld (WireSegments, Length)* 合并正反线段union_adjacent_contours_xld (WireSegments, FusedSegments, max(Length), max(Length) / max([min(Length),1]), 'attr_keep')* 合并到曲线数组中smooth_contours_xld (FusedSegments, Wire, 11)concat_obj (Wires, Wire, Wires)else* 距离终点合格 合并到曲线数组中smooth_contours_xld (Wire, SmoothedContours1, 11)concat_obj (Wires, SmoothedContours1, Wires)endifendfor* 11.显示结果 **************************************************dev_display (Image)dev_set_color ('red')dev_display (Wires)if (Img < 7)disp_continue_message (WindowHandle, 'black', 'true')stop ()endif
endfor
搜索子函数
gen_empty_obj (Wire)
get_image_size (Image, Width, Height)
* Coordinates of the point at which to resume the tracking of the wire
StartPointRow := StartPadRows
StartPointCol := StartPadColsRefOrientation := StartInitOrientationSearchRadius := 30 * WireWidths
MinSearchRadius := 5 * WireWidths
* 距离退出
DistSegmentThreshold := min([SearchRadius / 3.0, MaxDistSegment])
while (1)* 起点与终点距离distance_pp (StartPointRow, StartPointCol, EndPadRows, EndPadCols, Distance)* 生成搜索区域gen_search_region (SearchRegion, StartPointRow, StartPointCol,\RefOrientation, min([SearchRadius, Distance]), AngleTolerance)reduce_domain (Image, SearchRegion, ImageReduced)NXLDs := 0HighThreshold := 1* 循环修改 HighThreshold 搜索线边缘while (NXLDs == 0 and HighThreshold >= 0.1)* 高斯搜索线边缘lines_gauss (ImageReduced, Lines, WireWidths / sqrt(3), 0.05, HighThreshold, 'dark', 'true', 'true', 'true')* 生成边缘线gen_polygons_xld (Lines, Polygons, 'ramer', 1)* 拆分边缘split_contours_xld (Polygons, Contours, 'polygon', 1, 5)* 长度筛选select_contours_xld (Contours, SelectedContours, 'contour_length', MinSegmentLength, max([Width,Height]) / 2.0, -0.5, 0.5)count_obj (SelectedContours, NXLDs)HighThreshold := 0.5 * HighThresholdendwhileif (NXLDs == 0)breakendif* 计算角度筛选范围 LowerLimit := [RefOrientation - AngleTolerance,\RefOrientation - AngleTolerance + rad(180),\RefOrientation - AngleTolerance - rad(180)]UpperLimit := [RefOrientation + AngleTolerance,\RefOrientation + AngleTolerance + rad(180),\RefOrientation + AngleTolerance - rad(180)]* 角度筛选select_shape_xld (SelectedContours, ObjectSelected,\['phi_points', 'phi_points', 'phi_points'], \'or', LowerLimit, UpperLimit)count_obj (ObjectSelected, NContours)if (NContours > 1)* 尝试链接线段union_collinear_wire_segments (ObjectSelected, UnionContours, 5, 0.5)count_obj (UnionContours, NUCont)* 计算与起点的距离DistMin := []for C := 1 to NUCont by 1select_obj (UnionContours, ObjectSelected1, C)distance_pc (ObjectSelected1, StartPointRow, StartPointCol, DistanceMin, DistanceMax)DistMin := [DistMin,DistanceMin]endfortuple_find (DistMin, min(DistMin), IndMin)* 线段距离超出设置范围if (DistMin[IndMin[0]] > DistSegmentThreshold)breakendifselect_obj (UnionContours, WireSegment, IndMin[0] + 1)elseif (NContours == 0)breakelse* 只有一个线段copy_obj (ObjectSelected, WireSegment, 1, 1)endifconcat_obj (Wire, WireSegment, Wire)* 更新起点与终点update_search_parameters (WireSegment, StartPointRow, StartPointCol, RefOrientation, MinSearchRadius, MaxDistSegment, \StartPointRow, StartPointCol, RefOrientation, SearchRadius, DistSegmentThreshold)* 确认起点与终点 是否退出V1 := [EndPadRows - StartPointRow, EndPadCols - StartPointCol]V1 := V1 / sqrt(sum(V1 * V1))V2 := [-sin(RefOrientation), cos(RefOrientation)]if (V1[0] * V2[0] + V1[1] * V2[1] < 0)breakendif
endwhile
return ()