官方例程学习分享-correct_measure_direction

功能介绍

这个程序演示了用于1D测量的测量对象的方向的自动细化。如果用户输入的测量ROI不完全垂直于被测量的结构,则程序估计正确的方向并相应地旋转ROI。如下图:

原图在这里插入图片描述结果图在这里插入图片描述

应用(个人想法)

应用在二次开发当中(上位机),例如用户随机画了一个检测区想抓边,那么可在抓边按钮中加入以下程序 自动的去根据区域内容调整roi,去适当地放大缩小或者旋转区域去抓边。相当于是提高易用性。

官方程序及注释和理解

* Display initializations
* 窗口显示初始化,变量初始化
Interactive := 0
dev_close_window ()
dev_update_window ('off')
read_image (Image, 'fuse')
* 这里获得的宽高是为了后面的gen_measure_rectangle2()
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_display (Image)
* 
if (Interactive == 0)
    * 生成一个测量矩形,下一步将会纠正错误的旋转
    disp_message (WindowHandle, 'Measure rectangle generated', 'window', 12, 12, 'black', 'true')
    disp_message (WindowHandle, 'Wrong rotation will be corrected in the next step', 'window', 50, 12, 'black', 'true')
    * 设置线的颜色和宽度
    dev_set_color ('blue')
    dev_set_line_width (2)
    * 任意生成一个带角度的矩形(85°)长80宽5,等下把它旋转纠正
    gen_rectangle2 (Rectangle, 292, 540, rad(85), 80, 5)
    dev_display (Rectangle)
    disp_continue_message (WindowHandle, 'black', 'true')
    stop ()
    * 任意方向地去包围某个区域的最小矩形,相当于把绘制的矩形的中心坐标和角度长宽存到变量当中
    smallest_rectangle2 (Rectangle, Row, Column, Phi, Length1, Length2)
else
    * User interaction: input measure rectangle
    disp_message (WindowHandle, 'Modify measure rectangle (arrow up, confirm with right mouse)', 'window', 12, 12, 'black', 'true')
    disp_message (WindowHandle, 'Eventually wrong rotations will be corrected', 'window', 50, 12, 'black', 'true')
    dev_set_color ('blue')
    dev_set_line_width (2)
    * 任意定向矩形的交互绘图
    draw_rectangle2_mod (WindowHandle, 292, 540, rad(85), 80, 5, Row, Column, Phi, Length1, Length2)
    gen_rectangle2 (Rectangle, Row, Column, Phi, Length1, Length2)
endif
* 
* Apply a first measurement
* 准备提取垂直于矩形长轴的直边
* Width:随后要处理的图像宽度; Heigth:随后要处理的图形高度
gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height, 'bicubic', MeasureHandle)
* 提取与矩形或者环状弧垂直的直线边缘
* Transition='all': 返回具有亮暗亮或者暗亮暗的边缘对,适用于不同背景具有不同亮度的物体
* 如果Transition='positive': First返回沿着矩形长轴方向的暗到亮过渡的边缘点,Second返回亮到暗的边缘点;'negative'反之
* RowEdgeFirst: 边缘到第一条边的中心的row坐标
* ColumnEdgeFirst: 边缘到第一条边的中心的col坐标
* RowEdgeSecond: 边缘到第二条边的中心的row坐标
* ColumnEdgeSecond: 边缘到第二条边的中心的col坐标
* IntraDistance: 边缘对之间的距离
* InterDistance: 连续边缘之间的距离
measure_pairs (Image, MeasureHandle, 1, 30, 'all', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)
* 
* Extract edges and edge directions within a slightly extended ROI
gen_rectangle2 (RectangleROI, Row, Column, Phi, Length1, 4 * Length2)
reduce_domain (Image, RectangleROI, ImageReduced)
* 使用Deriche,Shen,或Canny等滤波器去提取子像素的精确边缘
* edges_sub_pix( , , 滤波器, 平滑强度, 对比度最小阈值, 对比度最大阈值)
edges_sub_pix (ImageReduced, Edges, 'canny', 1, 20, 40)
* 为每个轮廓计算一个xld轮廓方向
get_contour_angle_xld (Edges, 'abs', 'regress', 3, Angles)
* 
* Use the mean edge direction to estimate the correct orientation
* of the measure rectangle.
* 使用平均边缘方向去估计这个测量矩形的正确方向
* rad()是把角度换成弧度; deg()是把弧度换成角度
MeanAngle := mean(Angles) - rad(90)
MeanAngleDeg := deg(MeanAngle)
* 
* Correct the orientation of the measure rectangle
gen_measure_rectangle2 (Row, Column, MeanAngle, Length1, Length2, Width, Height, 'bicubic', MeasureHandle)
gen_rectangle2 (Rectangle2, Row, Column, MeanAngle, Length1, Length2)
measure_pairs (Image, MeasureHandle, 1, 30, 'all', 'all', RowEdgeFirst2, ColumnEdgeFirst2, AmplitudeFirst2, RowEdgeSecond2, ColumnEdgeSecond2, AmplitudeSecond2, IntraDistance2, InterDistance2)
* 
* Display results
dev_display (Image)
dev_set_draw ('margin')
p_disp_edge_marker (RowEdgeFirst, ColumnEdgeFirst, Phi, Length2, 'red', 2)
p_disp_edge_marker (RowEdgeSecond, ColumnEdgeSecond, Phi, Length2, 'red', 2)
dev_set_color ('red')
dev_display (Rectangle)
p_disp_edge_marker (RowEdgeFirst2, ColumnEdgeFirst2, MeanAngle, Length2, 'green', 2)
p_disp_edge_marker (RowEdgeSecond2, ColumnEdgeSecond2, MeanAngle, Length2, 'green', 2)
dev_set_color ('green')
dev_display (Rectangle2)
disp_message (WindowHandle, 'Measure direction corrected from ' + deg(Phi)$'.3' + ' deg to ' + MeanAngleDeg$'.3' + ' deg', 'window', 12, 12, 'black', 'true')
LastCommonIndex := min([|RowEdgeFirst|,|RowEdgeSecond|,|RowEdgeFirst2|,|RowEdgeSecond2|]) - 1
disp_message (WindowHandle, 'Width [px]: ' + IntraDistance[0:LastCommonIndex]$'.3' + ', corrected: ' + IntraDistance2[0:LastCommonIndex]$'.3', 'window', (RowEdgeFirst[0:LastCommonIndex] + RowEdgeSecond[0:LastCommonIndex]) / 2 - 10, 150, 'black', 'false')
* 子函数:p_disp_edge_marker()内容如下:
* 
* Determine the number of edges
NumRows := |Rows|
NumCols := |Cols|
Num := min([NumRows,NumCols])
* 
* Loop over the edges
for i := 0 to Num - 1 by 1
    Row := Rows[i]
    Col := Cols[i]
    * 
    * Determine start and end point of the edge marker.
    * Length边是最开始的smartest_rectangle2得到的矩形短边,然后通过三角函数计算
    RowStart := Row + Length * cos(Phi)
    RowEnd := Row - Length * cos(Phi)
    ColStart := Col + Length * sin(Phi)
    ColEnd := Col - Length * sin(Phi)
    * 
    * Generate a contour that connects the start and end point.
    * 根据一个多边形(以元组形式给出)创建一个xld
    gen_contour_polygon_xld (Marker, [RowStart,RowEnd], [ColStart,ColEnd])
    * 
    * Display the contour with  the specified style.
    dev_set_color (Color)
    dev_set_line_width (LineWidth)
    dev_display (Marker)
endfor
return ()

理解后编写的

流程步骤:
第①步:初始化窗口和变量
第②步:随机生成一个矩形,并记录长宽角度坐标
第③步:在原图上提取矩形区域内的边缘过渡线上的中心边缘点
第④步:使用canny直接提取ROI内的边缘过渡线,并求出边缘线的角
度(针对矩形长边),针对这个角度绘制矩形
第⑤步:在原图中提取新的矫正后的矩形的边缘点
第⑥步:分别绘制原来的矩形和纠正后的矩形的边缘线,把重复部分封装为一个函数
第⑦步:总结结果并展示

* 第一步:初始化窗口和变量
Interactive := 0
dev_close_window ()
dev_update_off ()
read_image (Image, 'D:/halcon/官方例程练习/correct_measure_direction/fuse.png')
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_set_draw ('margin')
dev_set_color ('blue')
dev_set_line_width (2)
dev_display (Image)

* 第二步:随机生成一个矩形,并记录长宽角度坐标
gen_rectangle2 (Rectangle, 292, 540, rad(80), 80, 5)
smallest_rectangle2 (Rectangle, Row, Column, Phi, Length1, Length2)
gen_cross_contour_xld (Cross, Row, Column, 6, Phi)

* 第三步:在原图上提取矩形区域内的边缘过渡线上的中心边缘点
gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height, 'bicubic', MeasureHandle)
measure_pairs (Image, MeasureHandle, 1, 30, 'all', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)
* 把提取到的点显示在图上
dev_set_color ('green')
gen_cross_contour_xld (Cross1, RowEdgeFirst, ColumnEdgeFirst, 4, Phi)
dev_set_color ('forest green')
gen_cross_contour_xld (Cross2, RowEdgeSecond, ColumnEdgeSecond, 4, Phi)

* 第四步:使用canny直接提取ROI内的边缘过渡线,并求出边缘线的角度(针对矩形长边),针对这个角度绘制矩形
dev_set_color ('blue')
* 扩大矩形宽度目的:为了找很多的Edges,免得后面纠正回去的矩形与Edges没有交集,就看着尴尬
gen_rectangle2 (Rectangle1, Row, Column, Phi, Length1, 4 * Length2)
reduce_domain (Image, Rectangle1, ImageReduced)
* 灰度差在20-40之间都看作为边缘线
edges_sub_pix (ImageReduced, Edges, 'canny', 1, 20, 40)
get_contour_angle_xld (Edges, 'abs', 'range', 3, Angles)
* 获取每条边缘线的平均角度,去作为正确的角度
* 这个度数相对于矩形长轴来说,确实是接近90度
MeanAngle := mean(Angles) - rad(90)
MeanAngleDeg := deg(MeanAngle)
gen_rectangle2 (Rectangle2, Row, Column, MeanAngle, Length1, Length2)

* 第五步:在原图中提取新的矫正后的矩形的边缘点
gen_measure_rectangle2 (Row, Column, MeanAngle, Length1, Length2, Width, Height, 'bicubic', MeasureHandle1)
measure_pairs (Image, MeasureHandle1, 1, 30, 'all', 'all', RowEdgeFirst1, ColumnEdgeFirst1, AmplitudeFirst1, RowEdgeSecond1, ColumnEdgeSecond1, AmplitudeSecond1, IntraDistance1, InterDistance1)
dev_set_color ('red')
gen_cross_contour_xld (Cross5, Row, Column, 6, Phi)
dev_set_color ('green')
gen_cross_contour_xld (Cross3, RowEdgeFirst1, ColumnEdgeFirst1, 4, Phi)
dev_set_color ('forest green')
gen_cross_contour_xld (Cross4, RowEdgeSecond1, ColumnEdgeSecond1, 4, Phi)

* 第六步:分别绘制原来的矩形和纠正后的矩形的边缘线,把重复部分封装为一个函数
dev_clear_window ()
dev_set_color ('blue')
dev_display (Image)
dev_display (Rectangle)
dev_set_color ('red')
*gen_cross_contour_xld (Cross6, RowEdgeFirst, ColumnEdgeFirst, 6, Phi)
stop ()
p_dis_edges_maker (RowEdgeFirst,ColumnEdgeFirst,Phi,Length2,'red',2)
p_dis_edges_maker (RowEdgeSecond, ColumnEdgeSecond, Phi, Length2, 'red', 2)
dev_set_color ('pink')
dev_display (Rectangle2)
p_dis_edges_maker (RowEdgeFirst1,ColumnEdgeFirst1,MeanAngle,Length2,'green',2)
p_dis_edges_maker (RowEdgeSecond1, ColumnEdgeSecond1, MeanAngle, Length2, 'green', 2)

* 第七步:总结结果并展示
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
disp_message (WindowHandle, 'Measure direction corrected from ' + deg(Phi)$'.3' + ' deg to ' + MeanAngleDeg$'.3' + ' deg', 'window', 12, 12, 'black', 'true')

NumberRow := |Rows|
NumberCol := |Columns|
num := min2(NumberRow, NumberCol)

for i := 0 to num - 1 by 1
    row1 := Rows[i] + Length * cos(Phi)
    row2 := Rows[i] - Length * cos(Phi)
    col1 := Columns[i] + Length * sin(Phi)
    col2 := Columns[i] - Length * sin(Phi)
    
    dev_set_color (Color)
    dev_set_draw ('margin')
    dev_set_line_width (LineWidth)
    gen_contour_polygon_xld (Maker, [row1, row2], [col1, col2])
    dev_display (Maker)  
endfor
return ()

结果图在这里插入图片描述

学习心得

①学习算子gen_measure_rectangle2():

  • 准备提取垂直于矩形长轴的直边
  • Width:随后要处理的图像宽度; Heigth:随后要处理的图形高度
gen_measure_rectangle2 (Row, Column, Phi, Length1, Length2, Width, Height, 'bicubic', MeasureHandle)

②学习算子measure_pairs()

  • 提取与矩形或者环状弧垂直的直线边缘
  • Transition=‘all’: 返回具有亮暗亮或者暗亮暗的边缘对,适用于不同背景具有不同亮度的物体
  • 如果Transition=‘positive’: First返回沿着矩形长轴方向的暗到亮过渡的边缘点,Second返回亮到暗的边缘点;'negative’反之
  • RowEdgeFirst: 边缘到第一条边的中心的row坐标
  • ColumnEdgeFirst: 边缘到第一条边的中心的col坐标
  • RowEdgeSecond: 边缘到第二条边的中心的row坐标
  • ColumnEdgeSecond: 边缘到第二条边的中心的col坐标
  • IntraDistance: 边缘对之间的距离
  • InterDistance: 连续边缘之间的距离
measure_pairs (Image, MeasureHandle, 1, 30, 'all', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)

③子函数的创建和调用
相对而言,还是很easy的:
根据传入函数的类型去设置,image\region\tuple。函数调用的话,直接在main函数中或者其他子函数当中调用即可
在这里插入图片描述分析有不到位的,请各位点评指正~

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值