Halcon之感兴趣的区域

文章目录

  • 2、感兴趣的区域
    • 2.1 基本概念
      • 2.1.1 Create Region
      • 2.1.2 Create ROI
      • 2.1.3 A First Example
    • 2.2 扩展概念
      • 2.2.1 分割图像
      • 2.2.2 绘制区域
      • 2.2.3 创建区域
      • 2.2.4 处理区域
      • 2.2.5 对齐 ROI 或图像
      • 2.2.6 Create ROI
      • 2.2.7 可视化结果
    • 2.3 编程示例
      • 2.3.2 图像的交互式部分过滤
      • 2.3.3 检查工具的轮廓
    • 2.4 Selecting Operators
      • 2.4.1 分割图像
      • 2.4.2 绘制区域
      • 2.4.3 创建区域
      • 2.4.4 处理区域
      • 2.4.5 对齐 ROI 或图像
      • 2.4.6 创建ROI
      • 2.4.7 可视化结果
    • 2.5 与其他方法的关系
    • 2.6 提示与技巧
      • 2.6.1 复用ROI
      • 2.6.2 ROI 形状对加速的影响
    • 2.7 高级主题
      • 2.7.1 过滤掩码和ROIs
      • 2.7.2 二进制图像
      • 2.7.3 图像域外的灰度值引起的问题

2、感兴趣的区域

感兴趣区域 (ROI) 的概念对于一般机器视觉尤其是 HALCON 至关重要。 目的是将处理集中在图像的特定部分。 这种方法将区域信息与图像矩阵相结合:只有与区域对应的图像部分保持相关,从而减少了要处理的像素数量。
使用 ROI 的优势是多方面的。 首先,这是一种非常好的加速处理方法,因为需要处理的像素更少。 此外,它侧重于处理,例如,通常只计算图像的一部分的灰度值特征。 最后,ROI 用于定义模板,例如用于匹配。 HALCON 允许充分利用 ROI 的概念,因为它可以为区域使用任意形状。 这意味着您不限于矩形或多边形等标准形状,而是可以真正使用任何形式 - 解决给定问题的最佳形式。

2.1 基本概念

利用 ROI 分为两个简单的部分:创建区域并将它们与图像组合。

在这里插入图片描述

2.1.1 Create Region

HALCON 提供了多种创建区域的方法,然后可以将其用作 ROI。 传统的方法是生成标准形状,如圆形、椭圆形、矩形或多边形。 此外,可以通过将区域从其他数据类型(如 XLD)转换、分割图像或通过用户交互来导出区域。

2.1.2 Create ROI

通过将区域与图像组合,该区域承担了 ROI 的角色,即它定义了必须处理图像的哪一部分。 在 HALCON 中,ROI 也称为图像的域。 该术语来自数学,其中可以将图像视为将坐标映射到灰度值的函数。 ROI 将这个函数的域从完整图像缩小到相关部分。 因此,合并区域和图像的算子称为reduce_domain。 这个简单的操作符几乎可以在所有应用中完成所需的任务。

2.1.3 A First Example

作为基本概念的示例,以下程序显示了利用 ROI 的所有重要步骤。 图像是从文件中获取的。 在图像内部,只应处理围绕中心的圆形部分。 为此,使用 gen_circle 生成圆形区域。 该区域使用reduce_domain 与图像组合。 这具有在调用操作员时仅处理 ROI 的像素的效果。 例如,如果将算子edges_sub_pix 应用于该图像,则仅在圆内提取亚像素精确轮廓。 为了使其可见,一些可视化操作符被添加到示例程序的末尾。

read_image (Image, 'mreut')
gen_circle (ROI, 256, 256, 200)
reduce_domain (Image, ROI, ImageReduced)
edges_sub_pix (ImageReduced, Edges, 'lanser2', 0.5, 20, 40)
dev_display (Image)
dev_display(ROI)
dev_display(Edges)

Halcon之感兴趣的区域_第1张图片
仅在圆形 ROI 内处理图像
Halcon之感兴趣的区域_第2张图片

2.2 扩展概念

当我们仔细研究 ROI 时,如果应用程序需要更加灵活,额外的步骤就变得很重要。
Halcon之感兴趣的区域_第3张图片

2.2.1 分割图像

HALCON 非常典型的是通过分割步骤创建 ROI。 使用图像处理方法从图像中提取与进一步处理相关的图像部分,而不是具有预定义的 ROI。 这种方法是可行的,因为 ROI 只不过是普通的 HALCON 区域,因此共享它们的所有优点,例如高效处理和任意形状(有关 HALCON 区域的更多信息,请参阅第 18 页第 2.1.2.2 节中的快速指南)。 用于 ROI 的区域分割遵循与标准 blob 分析相同的方法。 有关更多详细信息,请参阅第 46 页上此步骤的说明。

2.2.2 绘制区域

指定 ROI 的标准方法是使用鼠标以交互方式绘制形状。 为方便起见,HALCON 为标准形状和自由形状提供了特殊的运算符。 此类操作的所有运算符都以前缀 draw_ 开头。 绘制通过使用鼠标左键(绘制、拾取和拖动)执行,并通过单击鼠标右键完成。 对于每个这样的绘图运算符,HALCON 都提供了使用返回参数生成区域的运算符(请参阅第 33 页上的创建区域步骤的说明)。 鼠标交互操作符可以在参考手册的“图形”一章中找到。 画画”。 有关用户交互的更多信息,也可以在第 307 页的可视化一章中找到。

2.2.3 创建区域

标准方法是根据用户交互返回的坐标和尺寸或存储在文件中的坐标值生成区域。 在这种情况下,将使用 gen_circle、gen_rectangle2 或 gen_region_polygon_fill 等运算符。 更高级的是用于指导预处理步骤以节省执行时间的特殊形状。 典型的例子是线或点的网格或棋盘格。 使用这些形状,可以系统地覆盖图像并检查特定对象的出现。 如果你想分割,例如,给定最小尺寸的斑点,在第一步中使用比最小对象尺寸更细的搜索网格来定位碎片就足够了。 在第二步中,这些片段被扩大 (dilation_rectangle1) 并再次调用分割方法,现在在这个扩大的区域内。 如果对象仅覆盖图像的相对较小区域,则此方法可以显着加快该过程。

2.2.4 处理区域

有时,给定 ROI 的形状,无论是由程序生成还是由用户定义,都不能满足要求。 在这里,HALCON 提供了许多操作符来修改形状以进行相应的调整。 常用的操作符是,例如,fill_up 用于填充区域内的孔shape_trans 用于应用一般变换(如凸包或最小矩形),或形态学操作符(如erosion_circle 使区域变小或closure_circle 以填充间隙)。 有关更多详细信息,请参阅第 49 页上此步骤的说明。

2.2.5 对齐 ROI 或图像

有时,ROI 的坐标取决于图像中另一个对象的位置。 如果对象移动,则必须相应地移动(对齐)ROI。 这是通过首先使用模板匹配定位对象来实现的。 基于确定的位置和方向,然后变换 ROI 的坐标。
解决方案指南 II-B 第 42 页的 2.4.3.2 节中描述了如何使用基于形状的匹配来执行对齐。

2.2.6 Create ROI

这一步将区域和图像结合起来,利用区域作为图像的域。 推荐使用的标准方法是reduce_domain。 它的优点是安全且语义简单。 rectangle1_domain 是生成矩形 ROI 的快捷方式(而不是依次调用 gen_rectangle1 和 reduce_domain)。 对于高级应用程序,change_domain 可以用作比 reduce_domain 稍快的版本。 该算子不与现有域进行交集,也不检查该区域是否在图像之外,如果该区域部分位于图像之外,则在随后将算子应用于数据时会导致系统崩溃。 如果程序员确保输入区域定义良好,这是一种节省(一点)执行时间的方法。

2.2.7 可视化结果

最后,您可能希望显示 ROI 或缩小的图像。 使用运算符 get_domain,可以像任何其他区域一样访问和显示(和处理)图像当前使用的区域。 显示图像时,例如使用 disp_image,仅显示定义的像素。 图像域外的图形窗口中的像素不会被修改。
有关详细信息,请参阅第 307 页上对此方法的说明。

2.3 编程示例

本节简要介绍了在 HALCON 中对 ROI 进行编程。 两个例子展示了区域生成的原理,将这些与图像结合,然后处理数据。
Example: solution_guide/basics/critical_points.hdev

* critical_points.hdev: locate saddle point markers in an image
* 
dev_update_window ('off')
* ****
* step: acquire image
* ****
read_image (Image, 'landmarks')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
dev_set_part (0, 0, Height - 1, Width - 1)
dev_set_line_width (3)
dev_set_color ('blue')
dev_set_draw ('margin')
dev_display (Image)
set_display_font (WindowHandle, 20, 'mono', 'true', 'false')
* ****
* step: draw region
* ****
disp_message (WindowHandle, 'Draw with the mouse the region of interest', 'window', -1, -1, 'blue', 'false')
dev_set_color ('white')
draw_region (Region, WindowHandle)
dev_display (Region)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* ****
* step: create ROI
* ****
reduce_domain (Image, Region, ImageReduced)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* ****
* step: process image within ROI
* ****
critical_points_sub_pix (ImageReduced, 'facet', 1.5, 8, RowMin, ColumnMin, RowMax, ColumnMax, RowSaddle, ColSaddle)
dev_clear_window ()
dev_display (ImageReduced)
dev_set_color ('yellow')
for i := 0 to |RowSaddle| - 1 by 1
    gen_cross_contour_xld (Cross, RowSaddle[i], ColSaddle[i], 25, 0.785398)
    dev_display (Cross)
endfor
stop ()
dev_update_window ('on')

图 中 显示了带有标记的图像,这些标记用于 3D 应用程序中的相机校准。 在这里,我们假设必须仅在图像的给定部分提取标记。

绘制 ROI 的原始图像
Halcon之感兴趣的区域_第4张图片
具有提取点的缩小图像
Halcon之感兴趣的区域_第5张图片

为了实现这一点,用户用鼠标绘制一个感兴趣的区域。 对应的操作符是 draw_region。 它具有由 dev_open_window 返回的窗口句柄作为输入,并在按下鼠标右键时返回一个区域。 操作符 reduce_domain 将这个区域与图像结合起来。

draw_region (Region, WindowHandle) 
reduce_domain (Image, Region, ImageReduced)

当在这个缩小的图像上调用点提取算子 critical_points_sub_pix 时,只能找到 ROI 内的点。 程序的最后一部分展示了如何在图像上显示这些点。

2.3.2 图像的交互式部分过滤

Example: solution_guide/basics/median_interactive.hdev
任务是仅在用户用鼠标单击图像的点处使用中值滤波器过滤图像,即在显示图像的图形窗口中。
Halcon之感兴趣的区域_第6张图片
为此,使用了一个循环,在其中使用 get_mposition 连续请求鼠标位置。 因为如果鼠标在图形窗口之外,则此运算符会引发异常,因此调用受 dev_set_check 保护。

* median_interactive.hdev: react to mouse interaction
* 
dev_set_preferences ('graphics_window_context_menu', 'false')
dev_close_window ()
dev_update_off ()
* ****
* step: acquire image
* ****
read_image (Image, 'mreut')
get_image_size (Image, Width, Height)
dev_open_window_fit_image (Image, 0, 0, Width, Height, WindowHandle)
set_display_font (WindowHandle, 12, 'mono', 'true', 'false')
set_mshape (WindowHandle, 'arrow')
dev_set_draw ('margin')
dev_set_line_width (3)
dev_display (Image)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* ****
* step: react to mouse
* ****
Button := 0
while (Button != 4)
    Row := -1
    Column := -1
    dev_set_check ('~give_error')
    get_mposition (WindowHandle, Row, Column, Button)
    dev_set_check ('give_error')
    set_system ('flush_graphic', 'false')
    dev_display (Image)
    set_tposition (WindowHandle, Height - 40, 4)
    * check if mouse cursor is over window
    if (Row >= 0 and Column >= 0)
        gen_circle (Circle, Row, Column, 20)
        boundary (Circle, RegionBorder, 'inner')
        dev_display (RegionBorder)
        set_system ('flush_graphic', 'true')
        write_string (WindowHandle, 'Hold down mouse button to apply filter')
        if (Button == 1)
            * apply filter to circle if left button is pressed
            reduce_domain (Image, Circle, ImageReduced)
            median_image (ImageReduced, ImageMedian, 'circle', 5, 'mirrored')
            overpaint_gray (Image, ImageMedian)
        endif
    else
        set_system ('flush_graphic', 'true')
        write_string (WindowHandle, 'Please move mouse cursor over window')
    endif
endwhile
dev_display (Image)

如果鼠标悬停在窗口上,则会显示一个圆形区域,显示将应用过滤器的位置。

if (Row >= 0 and Column >= 0) 
gen_circle (Circle, Row, Column, 20) 
boundary (Circle, RegionBorder, 'inner') 
dev_display (RegionBorder)

如果按下鼠标左键,则必须在当前鼠标位置的局部邻域中应用中值图像。 这是通过使用 gen_circle 生成一个圆然后调用 reduce_domain 来完成的。

if (Button == 1) 
reduce_domain (Image, Circle, ImageReduced)

现在,使用这个缩小的图像调用过滤器,并将结果绘制回输入图像以进行可能的重复过滤。 单击鼠标右键时,循环将终止。

median_image (ImageReduced, ImageMedian, 'circle', 5, 'mirrored')
overpaint_gray (Image, ImageMedian)
endif

2.3.3 检查工具的轮廓

Example: hdevelop/Applications/Measuring-2D/circles.hdev

* 
* The edges in the image are segmented into lines and circles.
* For the edges that are part of a circle, the circle parameters
* are estimated and the resulting circle is displayed.
read_image (Image, 'double_circle')
* 
* Init window
dev_close_window ()
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
* 
* Segment a region containing the edges
fast_threshold (Image, Region, 0, 120, 7)
boundary (Region, RegionBorder, 'inner')
clip_region_rel (RegionBorder, RegionClipped, 5, 5, 5, 5)
dilation_circle (RegionClipped, RegionDilation, 2.5)
reduce_domain (Image, RegionDilation, ImageReduced)
* 
* In the subdomain of the image containing the edges,
* extract subpixel precise edges.
edges_sub_pix (ImageReduced, Edges, 'canny', 2, 20, 60)
segment_contours_xld (Edges, ContoursSplit, 'lines_circles', 5, 4, 3)
count_obj (ContoursSplit, Number)
dev_display (Image)
dev_set_draw ('margin')
dev_set_color ('white')
dev_update_window ('off')
for I := 1 to Number by 1
    select_obj (ContoursSplit, ObjectSelected, I)
    get_contour_global_attrib_xld (ObjectSelected, 'cont_approx', Attrib)
    * Fit a circle to the line segment that are arcs of a circle
    if (Attrib > 0)
        fit_circle_contour_xld (ObjectSelected, 'ahuber', -1, 2, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)
        gen_circle_contour_xld (ContCircle, Row, Column, Radius, 0, rad(360), 'positive', 1.0)
        dev_display (ContCircle)
    endif
endfor
dev_set_colored (12)
dev_set_line_width (3)
dev_display (ContoursSplit)

此示例的任务是检查图 3.4 中描绘的工具的轮廓。
由于亚像素精确轮廓提取非常耗时,因此第一步通过标准斑点分析创建 ROI(请参阅第 45 页上的斑点分析):使用阈值算子提取要测量的对象。 该区域被转换为其边界,省略图像边界处的像素。

fast_threshold (Image, Region, 0, 120, 7) 
boundary (Region, RegionBorder, 'inner')
clip_region_rel (RegionBorder, RegionClipped, 5, 5, 5, 5)

Halcon之感兴趣的区域_第7张图片
将圆拟合到工具的轮廓

结果是靠近对象边缘的小区域。 区域的边界,即边缘,被扩大作为边缘提取的 ROI。 现在,亚像素精确边缘提取器被调用,轮廓被分割成直线和圆弧。

dilation_circle (RegionClipped, RegionDilation, 2.5) 
reduce_domain (Image, RegionDilation, ImageReduced) 
edges_sub_pix (ImageReduced, Edges, 'canny', 2, 20, 60) 
segment_contours_xld (Edges, ContoursSplit, 'lines_circles', 5, 4, 3)

对于表示圆弧的线段,确定相应的圆参数。 出于检查目的,会生成具有相同参数的圆圈并将其叠加在图像上(另请参阅第 97 页的轮廓处理)。

get_contour_global_attrib_xld (ObjectSelected, 'cont_approx', Attrib) 
if (Attrib > 0) 
fit_circle_contour_xld (ObjectSelected, 'ahuber', -1, 2, 0, 3, 2,Row, Column, Radius, StartPhi, EndPhi, PointOrder)
gen_circle_contour_xld (ContCircle, Row, Column, Radius, 0, rad(360), 'positive', 1.0)
dev_display (ContCircle)
endif

2.4 Selecting Operators

2.4.1 分割图像

请参阅第 58 页上的步骤 Segment Image(s) 的详细操作员列表。

2.4.2 绘制区域

Standard: 
draw_circle, draw_rectangle1, draw_rectangle2, draw_region
Advanced:
draw_circle_mod, draw_rectangle1_mod, draw_rectangle2_mod, draw_xld, draw_xld_mod

2.4.3 创建区域

Standard: 
gen_circle, gen_ellipse, gen_rectangle2, gen_region_polygon_filled
Advanced: 
gen_checker_region, gen_grid_region

更多用于生成区域的运算符可以在参考手册的“Regions.Creation”一章中找到。

2.4.4 处理区域

请参阅第 58 页上的处理区域步骤的详细操作员列表。

2.4.5 对齐 ROI 或图像

解决方案指南 II-B 中描述了用于对齐 ROI 或图像的运算符。

2.4.6 创建ROI

Standard: 
reduce_domain, rectangle1_domain
Advanced:
change_domain, full_domain, add_channels

2.4.7 可视化结果

请参阅方法可视化的操作员列表(参见第 315 页的 19.4 节)。

2.5 与其他方法的关系

一类操作符不遵循 ROI 处理的标准规则:测量工具的操作符(请参阅第 63 页上的此方法的说明)。 此处,ROI 是在创建工具(gen_measure_arc 和 gen_measure_rectangle2)期间通过将坐标指定为数值来定义的。 在这种情况下,为图像定义的域将被忽略。

2.6 提示与技巧

2.6.1 复用ROI

如果一个 ROI 被多次使用,将区域保存到文件并在应用程序开始时加载它会很有用。 使用 write_region 完成存储到文件,使用 read_region 加载。

2.6.2 ROI 形状对加速的影响

ROI 是节省执行时间的完美方式:ROI 越小,应用程序越快。 这可以用作一般规则。 如果我们更详细地考虑这一点,我们还需要考虑 ROI 的形状。 因为 ROI 基于 HALCON 区域,所以它们使用游程编码(有关 HALCON 区域的更多信息,请参阅第 18 页上的 2.1.2.2 节中的快速指南)。 如果运行时间很长,这种类型的编码是完美的。 因此,水平线可以比垂直线更有效地存储和处理。 这也适用于 ROI 的处理时间。 显然,这种类型的开销非常小,并且只能对像阈值这样的非常快的操作符很重要。

2.7 高级主题

2.7.1 过滤掩码和ROIs

如果过滤器应用于缩小域,沿 ROI 边界的结果可能会令人惊讶,因为边界外的灰度值被用作过滤过程的输入。 要理解这一点,您必须在此上下文中考虑域的定义:域为必须计算输入像素输出像素的滤波器定义。 但是域外的像素(位于图像矩阵内)可用于处理。 如果不需要这种行为,可以使用操作符 expand_domain_gray 向外传播边界灰度值。 结果看起来好像边界以越来越大的距离被多次复制。

2.7.2 二进制图像

在某些应用程序中,可能需要使用可用作二进制图像的 ROI。 要将这些转换为 HALCON 区域,您必须使用 gen_image1 将它们转换为 HALCON 图像,然后使用阈值来生成区域。 使用 region_to_bin 后跟 get_image_pointer1 可以轻松实现转换回来。 也可以使用 read_region 导入二进制图像文件。

2.7.3 图像域外的灰度值引起的问题

将图像作为输出的运算符(例如,大多数过滤器运算符)仅返回与输入域的像素对应的像素。
出于性能原因,位于图像域之外的像素变为“未定义”。这意味着,如果系统参数 init_new_image 设置为 true(= 默认值),则它们要么被分配一个随机灰度值,要么被分配一个灰度值 0。在某些情况下,这些“未定义”像素可能会导致问题,但很容易处理。
使用 full_domain 将生成的图像扩展到完整域,将导致出现在前一个图像域之外的伪影。如果按顺序使用多个过滤器,则问题的另一个原因是域外的未定义值,因为过滤器也会考虑靠近域边界的未定义值。这意味着随着每个后续过滤器的误差增加,从边界开始到中间。以下段落提出了解决这些问题的四种策略。
由未定义像素引起的错误可以很容易地防止,例如,选择一个比实际需要的图像部分大得多的域,并将图像域(例如,使用运算符erosion_rectangle1 和reduce_domain)减少一半之前的滤波器宽度应用下一个过滤器。这样做时,图像中包含不正确值的那些部分将被切除,因此不会增加下一次过滤操作的误差。
另一种选择是选择与图像中感兴趣部分完全相同大小的域,然后在应用过滤器之前调用运算符 expand_domain_gray。该算子将边界内的像素复制到边界外,从而避免由域外未定义的像素引起的错误。随后,域可以再次缩小到其原始大小。应该对每个后续过滤操作重复此过程。但是请注意,此选项会显着增加运行时间。
如果运行时间不是问题,则可以在将第一个过滤器应用于图像之前调用运算符 full_domain。这样整个图像被定义为域,并且可以完全避免未定义的像素。
获得没有未定义像素的图像的另一种可能性是在应用过滤器之前调用运算符crop_domain。运算符crop_domain 将图像裁剪为域的大小,这意味着该域随后覆盖了完整的较小图像。但是请注意,对于裁剪后的图像,相对于原始图像的坐标系已发生变化,这将影响所有后续应用程序,具体取决于图像坐标系(例如,计算重心)

你可能感兴趣的:(HALCON,python,windows,matlab)