传统提取边缘的方法即通过图像中的明暗进行过滤,其左右就是根据明暗区域找到像素边界。从数学角度,滤波器决定图像剃度,该图像剃度通常作为边缘幅度和边缘方法返回。通过选取所有边缘幅值高的像素点,可以提取区域间的轮廓。另一个提取边缘的方法是通过训练深度学习模型来寻找边缘。
1 使用边缘滤波器提取边缘
Halcon提供标准的边缘过滤器,如Sobel, Roberts, Robinson等滤波器。除此之外,还提供后期处理的算子,如果根据阈值进行提取。
2 基本概念
边缘滤波器由以下几步构成:
2.1 获取图像
读取图像
2.2 图像滤器
边缘滤波器获取图像后,边缘幅度是以图像字节形式存储,每个像素的灰度值代表局部边缘幅度,返回边缘方向,这些边缘方向的值是1~179表示角的度数除以2。
2.3 提取边缘
边缘滤波器的结果包含边缘幅度的图像。从该图像中,通过使用阈值算子选择具有给定最小边缘幅度的像素来提取边缘,形成的边缘通过就一个像素宽度。
2.4 一个示例
设计一个边缘滤波器,sobel_amp被应用于"thin_sum_abs"模式,以获得一个3x3的过滤器获取边缘。然后,使用算子阈值提取边缘幅度大于20的所有像素,得到的区域包含像素宽区域。
read_image(Image,'fuse')
sobel_amp(Image,EdgeAmplitude,'thin_sum_abs',3)
threshold(EdgeAmplitude,Region,20,255)
skeleton(Region,Skeleton)
3 扩展概念
3.1 获取感兴趣区域
感兴趣区域可以加快边缘提取,提取速度快,鲁棒性优越。
3.2 图像滤波
Halcon提供许多滤波器,最常用的滤波器是索贝尔滤波器。对应操作算子sobel_amp和sobel_dir。
最好的滤波器edges_image,这个滤波器可精细提取边缘,如果图像没噪点,可使用“sobel_fast”模式进行使用。
3.3 提取边缘
最简单的方法是从图像边缘复制中过滤像素点,此过程包含边缘点的区域。根据此区域可以提取一个像素的宽度。算子hysteresis_threshold可以消除不重要的边缘。提取边缘轮廓钱调用算子nonmax_suppression_dir,能生成更精确的边缘。
相比之下,滤波器edges_image包括抑制过滤阈值,可以简单的提前一个像素宽的边缘。
如果只需要边缘点作为一个区域,可以使用算子inspect_shape_model。此算子包含边缘滤波,过滤阈值,效率高。
3.4 边缘处理
如果想获取边缘的坐标,使用算子split_skeleton_lines是不错的选择。这个算子必须和连通域配合使用,返回线段的所有点。当然也可以使用霍夫变换获取线段。hough_lines_dir和hough_lines也可以使用。还可以使用算子gen_contours_skeleton_xld将边缘区域转换为XLD轮廓。
可以使用算子background_seg轻松提取边缘区域。如果该区域存在间隙,则可以先使用close_edges或close_edges_length算子关闭间隙。作为一种替代方法,可以使用形态学算子如opening_circle应用与background_seg输出区域。
3.5 可视化结果
将结果先说出来如边缘区域或分割的线段。
3.6 程序示例
* 提取边缘
dev_update_off()
dev_close_window()
* step:获取图像
read_image(Image,'D:/Halcon_Study/farm.jpg')
rgb1_to_gray(Image,Image)
get_image_size(Image,Width, Height)
dev_open_window_fit_image(Image,0,0,Width,Height,WindowHandle)
set_display_font(WindowHandle,16, 'mono', 'true', 'false')
dev_set_draw('margin')
dev_set_line_width(3)
dev_display(Image)
disp_continue_message(WindowHandle, 'black', 'true')
stop()
* step:图像过滤
edges_image(Image,ImaAmp,ImaDir,'lanser2',0.1,'nms',1,80)
dev_display(ImaAmp)
disp_continue_message(WindowHandle, 'black', 'true')
stop()
* step:提取边缘
threshold(ImaAmp,Region,1,255)
connection(Region,ConnectedRegions)
dev_clear_window()
dev_set_colored(12)
dev_display(ConnectedRegions)
disp_continue_message(WindowHandle, 'black', 'true')
stop()
* step:边缘处理
dev_clear_window()
count_obj(ConnectedRegions,Number)
gen_empty_obj(XLDContours)
for i:=1 to Number by 1
select_obj(ConnectedRegions,SingleEdgeObject,i)
split_skeleton_lines(SingleEdgeObject,2,BeginRow,BeginCol,EndRow,EndCol)
for k:=0 to |BeginRow|-1 by 1
gen_contour_polygon_xld(Contour,[BeginRow[k],EndRow[k]],[BeginCol[k],EndCol[k]])
concat_obj(XLDContours,Contour,XLDContours)
endfor
endfor
dev_display(XLDContours)
4 深度学习提取边缘
深度学习的边缘提取其实质是深度学习的语义分割。该模型设计提取边缘训练模型。该模型适应性强,可以在分割模型上再进行训练。
4.1 概念
基于深度学习的边缘提取与其他深度学习语义分割相似。
Halcon提供了特定的模型设计和训练以提取边缘。但是,并不能够保证模型能够处理各种问题。例如:第对比度和高噪声图像,模型可以使用,在这情况下,可以根据实际情况再训练模型,可以提高模型的性能。
4.2 程序示例
* 深度学习提取边缘提取低对比度和高噪声图像。
*
dev_update_off ()
dev_close_window ()
*
* 获取图像大小,所设置的值是必须能够被16整除
ImageWidth := 384
ImageHeight := 384
*
dev_disp_description_intro ()
stop ()
dev_close_window ()
*
* 深度学习所需硬件需求
* 需要时GPU或CPU
* 本程序是GPU推理部署
*
query_available_dl_devices (['runtime', 'runtime'], ['gpu', 'cpu'], DLDeviceHandles)
if (|DLDeviceHandles| == 0)
throw ('No supported device found to continue this example.')
endif
* Due to the filter used in query_available_dl_devices, the first device is a GPU, if available.
DLDevice := DLDeviceHandles[0]
*
* Read the deep learning model and set model parameters.读取深度学习模型和加载模型参数
read_dl_model ('pretrained_dl_edge_extractor.hdl', DLModelHandle)
set_dl_model_param (DLModelHandle, 'batch_size', 1)
set_dl_model_param (DLModelHandle, 'image_dimensions', [ImageWidth,ImageHeight,1])
set_dl_model_param (DLModelHandle, 'device', DLDevice)
create_dl_preprocess_param_from_model (DLModelHandle, 'none', 'full_domain', [], [], [], DLPreprocessParam)
*
* 读取图像并显示结果
read_image (Image, 'brake_disk/brake_disk_bike_01')
crop_rectangle1 (Image, Image, 25, 55, 470, 500)
zoom_image_size (Image, Image, ImageWidth, ImageHeight, 'constant')
dev_open_window (0, 0, ImageWidth, ImageHeight, 'black', WindowHandle)
set_display_font (WindowHandle, 15, 'mono', 'true', 'false')
dev_set_color ('cyan')
WaitSeconds := 0.7
DisplayDilation := 1
*
* 设置最小置信度值
MinConfidence := 0.8
*
* Example 1: 提取低对比度图像边缘
ScaleMult := [0.865, 0.43, 0.216, 0.085, 0.025]
ScaleAdd := [0, 60, 90, 120, 120]
for Index := 0 to |ScaleMult| - 1 by 1
scale_image (Image, ImageScaled, ScaleMult[Index], ScaleAdd[Index])
*
apply_dl_edge_extractor (ImageScaled, ConfidentEdgeRegion, DLModelHandle, DLPreprocessParam, MinConfidence)
skeleton (ConfidentEdgeRegion, DLEdges)
*
* 显示图像和结果
min_max_gray (ImageScaled, ImageScaled, 0, Min, Max, Range)
DisplayText := 'Contrast: ' + Range
dev_display (ImageScaled)
dev_disp_text ('Example 1', 'window', 'top', 'left', 'black', [], [])
dev_disp_text (DisplayText, 'window', 'top', 'right', 'black', [], [])
wait_seconds (WaitSeconds)
dev_clear_window ()
dev_display (ImageScaled)
dilation_circle (DLEdges, DLEdgesDisplay, DisplayDilation)
dev_display (DLEdgesDisplay)
dev_disp_text ('Example 1', 'window', 'top', 'left', 'black', [], [])
dev_disp_text (DisplayText, 'window', 'top', 'right', 'black', [], [])
wait_seconds (WaitSeconds)
endfor
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*
* Example 2: 提取图像模糊的边缘
BlurSizes := [2:2:10]
for Index := 0 to |BlurSizes| - 1 by 1
mean_image (Image, ImageBlur, BlurSizes[Index], BlurSizes[Index])
*
apply_dl_edge_extractor (ImageBlur, ConfidentEdgeRegion, DLModelHandle, DLPreprocessParam, MinConfidence)
skeleton (ConfidentEdgeRegion, DLEdges)
*
* 显示图像和结果
DisplayText := 'Blur size: ' + BlurSizes[Index]
dev_display (ImageBlur)
dev_disp_text ('Example 2', 'window', 'top', 'left', 'black', [], [])
dev_disp_text (DisplayText, 'window', 'top', 'right', 'black', [], [])
wait_seconds (WaitSeconds)
dev_clear_window ()
dev_display (ImageBlur)
dilation_circle (DLEdges, DLEdgesDisplay, DisplayDilation)
dev_display (DLEdgesDisplay)
dev_disp_text ('Example 2', 'window', 'top', 'left', 'black', [], [])
dev_disp_text (DisplayText, 'window', 'top', 'right', 'black', [], [])
wait_seconds (WaitSeconds)
endfor
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*
* Example 3: 提取高噪点图像边缘
NoiseTypes := ['white', 'gradient', 'scanline']
NoiseLevels := [30:30:150]
for TypeIndex := 0 to |NoiseTypes| - 1 by 1
for LevelIndex := 0 to |NoiseLevels| - 1 by 1
add_noise (Image, ImageNoise, NoiseTypes[TypeIndex], NoiseLevels[LevelIndex])
*
apply_dl_edge_extractor (ImageNoise, ConfidentEdgeRegion, DLModelHandle, DLPreprocessParam, MinConfidence)
skeleton (ConfidentEdgeRegion, DLEdges)
*
* 显示图像和结果
DisplayText := 'Noise type : ' + NoiseTypes[TypeIndex] + '\nNoise level: ' + NoiseLevels[LevelIndex]
dev_display (ImageNoise)
dev_disp_text ('Example 3', 'window', 'top', 'left', 'black', [], [])
dev_disp_text (DisplayText, 'window', 'top', 'right', 'black', [], [])
wait_seconds (WaitSeconds)
dev_clear_window ()
dev_display (ImageNoise)
dilation_circle (DLEdges, DLEdgesDisplay, DisplayDilation)
dev_display (DLEdgesDisplay)
dev_disp_text ('Example 3', 'window', 'top', 'left', 'black', [], [])
dev_disp_text (DisplayText, 'window', 'top', 'right', 'black', [], [])
wait_seconds (WaitSeconds)
endfor
endfor
*
disp_end_of_program_message (WindowHandle, 'black', 'true')
琐碎时间阅读基础知识,详情关注微信公众号“知识代码AI”。