目录
1、图像边缘提取原理
2、边缘提取算子介绍
3、图像的亚像素边缘提取
4、亚像素轮廓的特征分析
5、xld的分割及直线拟合
6、圆及椭圆的拟合
7、中心线的提取
网上搜索图像边缘提取,有很多详细的讲解,就是讲的都太深奥,很难看明白。图像边缘提取原理并不复杂,至于一些大牛提供的复杂变换公式,也没必要深入的去研究,halcon都已经在算子中将其封装好了,我们会用就行。
边缘的定义:边缘是图像中灰度发生明显变化的地方,是不同灰度区域之间的界限。
图像的每个像素点的灰度值用矩阵来表示,那么画竖线的位置就是边缘界限。
那么如何进行图像边缘的提取呢?采用掩模的方式,在图像矩阵上进行移动,然后利用掩模内的掩模值进行计算,进而实现边缘的求取。
举例:假如使用3*3的掩模来求取:
-1 0 1
-1 0 1
-1 0 1
掩模矩阵和红色圈出来的Value1计算:{(-1)*1+0*1+1*1}+{(-1)*1+0*1+1*1}+{(-1)*1+0*1+1*1}=0
掩模矩阵和蓝色圈出来的Value2计算:{(-1)*1+0*1+1*10}+{(-1)*1+0*1+1*10}+{(-1)*1+0*1+1*10}=27
我们可以设置一个边界值Value,则程序中可设置判断,当|Value2-Value1|>Value时就认为当前是图像边缘。
halcon常用的掩模:
Robert边缘
算子:roberts。边缘定位准,但是对噪声敏感;适用于边缘明显且噪声低的图像分割。边缘定位精确度低。
模板1:
1 0
0 -1
模板2:
0 1
-1 0
Prewitte边缘
算子:prewitt_amp。对噪声可以适当抑制,但是会起到边缘平滑,对边缘的平滑不如Robert算子。
x方向:
-1 0 1
-1 0 1
-1 0 1
y方向:
1 1 1
0 0 0
-1 -1 -1
Sobel边缘
算子:sobel_amp。Sobel算子对于像素的位置的影响做了加权,可以降低边缘模糊程度。
x方向:
-1 0 1
-2 0 2
-1 0 1
y方向:
1 2 1
0 0 0
-1 -2 -1
Canny边缘:非极大值抑制与阈值的思想,边缘的提取效果在目前边缘提取中是相对效果最好的。(原理复杂,会用就行)
其它边缘:拉普拉斯边缘等(用的少)。
Canny没有对应的算子,如edges_image (EdgeAmplitude, ImaAmp, ImaDir, 'canny', 1, 'nms', 20, 40),在参数中设置为canny。
弄清了边缘提取原理后,本节讲解边缘提取算子具体使用。
首先,读取图片,并灰度化转换
-
read_image (
Image1, '
1.bmp')
-
rgb1_to_gray (
Image1, GrayImage)
roberts边缘算子:
-
*
roberts边缘,边缘定位精准
-
roberts (GrayImage, ImageRoberts,
'gradient_sum')
prewitt_amp边缘算子,求出来的边缘要清晰很多了:
-
*prewitt_amp边缘,对噪声可以适当抑制。变换后图像有偏移
-
prewitt_amp
(GrayImage, ImageEdgeAmp)
sobel_amp边缘算子:
-
*
sobel_amp边缘,可以降低边缘模糊程度
-
sobel_amp (GrayImage, EdgeAmplitude,
'sum_abs',
3)
Canny求边缘(求图像边缘最好的方法):
-
*图像的边缘,参数
7:低阈值,参数
8:高阈值。一般高阈值是低阈值的
1
.5倍
-2倍
-
edges_image (EdgeAmplitude, ImaAmp, ImaDir,
'canny',
1,
'nms',
20,
40)
什么叫图像的亚像素?顾名思义,亚像素就是比普通像素精度更高。由原先的像素单位为1,变为比1小的精度。
亚像素原理:采用插值的方式,精确定位边缘的位置。
比如: (最邻近插值)
1、5 插值后 1 3 5
1、6 插值后 1 3.5 6
插值方法有:双线性插值、三次样条插值。
亚像素边缘,常用的方法是canny边缘方法,算子是edges_sub_pix(),可以直接得到亚像素边缘。
常用英文单词:
区域:region 轮廓:XLD
感兴趣区域:RIO
程序讲解:
读取图片,求取第三个区域的边缘。
-
read_image (
Image1, '
1.bmp')
-
rgb1_to_gray (
Image1, GrayImage)
通过阈值分割、形状筛选,将7个矩形区域从图像中分割出来
-
*缩小
ROI,阈值分割
-
fast_threshold (GrayImage, Region,
150,
255,
20)
-
*连通域
-
connection (Region, ConnectedRegions)
-
*区域排序
-
sort_region (ConnectedRegions, SortedRegions,
'first_point',
'true',
'row')
-
*选择矩形区域
-外接矩形
-
select_shape (SortedRegions, SelectedRegions, [
'rect2_len1',
'rect2_len2'],
'and', [
110,
50], [
160,
70])
对筛选出来的7个矩形区域排序,然后选择第三个区域。
-
*再排一次序:按列排序
-
sort_region (SelectedRegions, SortedRegions1,
'first_point',
'true',
'column')
-
*始终选择第三个区域:参数
3为要选择的哪一个区域
-
select_obj (SortedRegions1, ObjectSelected,
3)
区域筛选下来后要求矩形图像边缘,一定要先包含其边缘,只有将整个区域包含了,才能保证求的区域边缘在里面。可以先用膨胀。再将此区域从原图中裁剪下来。
-
*正常的膨胀需求用dilation_circle,如果想对一个区域进行平滑操作的时候用闭操作closing_circle
-
dilation_circle
(ObjectSelected, RegionDilation, 5)
-
*将选出来处理好的区域从原灰度图片上裁剪出来
-
reduce_domain
(GrayImage, RegionDilation, ImageReduced)
最后,对其进行求边缘
-
*边缘检测-canny
-
edges_sub_pix
(ImageReduced,
Edges,
'canny'
,
1
,
10
,
20
)
为什么要进行特征分析?如下图所示,是求取出来的边缘,周围的线条是真实需要的,而中间的的线条则是引入的干扰线条。需要根据特征来进行筛选,而这个特征就是亚像素的特征。
亚像素轮廓特征:和前面的区域特征一样,亚像素轮廓特征同样具有自己的特征,在亚像素轮廓中使用较多的特征包括:长度、角度、外接矩形的长宽等。还有一些其它使用很少的特征。
亚像素轮廓的长度:轮廓所占的像素数。
亚像素轮廓的角度:轮廓最小外接矩形中,长边所对应的方向。
亚像素轮廓的外接矩形:能包括整个轮廓的最小矩形就是最小外接矩形。
备注:在求取亚像素外接矩形时,算子要加上_xld
求取xld的最小外接矩形1:smallest_rectangle1_xld
求取xld的最小外接矩形2:smallest_rectangle2_xld
筛选xld:select_shape_xld
程序讲解:
接着前面一节的程序进行。
前面一节一节将边缘求取出来了,但是中间有干扰线条。需要将中间的干扰线条去掉,只保留边上需要的线条。可以通过线条周长的长度来进行筛选
-
*
XLD筛选,参数
3,周长
-
select_shape_xld (Edges, SelectedXLD,
'contlength',
'and',
80,
99999)
补充:通过软件工具,获取XLD线条周长
为什么要XLD分割和直线拟合,看前面的提取出来的轮廓线,线条有凸起、或者歪歪扭扭的,不是很规整。因此需要将其拟合,拟合前需要将相交的线分割出来,每条线单独拟合。
XLD的分割:根据XLD之间各个节点的连接情况以及设置条件,将一条或多条分割线分割成更多条线的情况,称为xld的分割。一般先的折点的地方称为分割点。
算子:segment_contours_xld
XLD的拟合:根据线条的预先模型,对线条进行重新成成。包括直线的拟合、圆的拟合、以及椭圆拟合等。
算子:
fit_line_contour_xld:直线的拟合
fit_circle_contour_xld:圆的拟合
fit_ellipse_contour_xld:椭圆的拟合
XLD的拟合原理:基于最小二乘法拟合、考虑权重的拟合方法。如下图所示意。
程序讲解:
接着上节程序,进行讲解,上一节存在的问题。
进行XLD轮廓线分割
-
*轮廓XLD的分割,参数3:分割方式,参数4:圆滑程度,参数5和参数6:最小和最大线的距离
-
segment_contours_xld
(UnionContours,
ContoursSplit,
'lines_circles'
,
5
,
4
,
2
)
然后再选择矩形下方的横线。
-
*选择矩形下部没连接到一起的水平线,根据线的角度来选择
-
select_shape_xld (SelectedXLD, SelectedXLD1,
'phi',
'and', -
0.1,
0.1)
对直线进行拟合
-
*对选出来的直线拟合,参数2,'tukey'是最小2乘拟合、'huber'是考虑权重拟合
-
fit_line_contour_xld
(SelectedXLD1,
'huber'
,
-1
,
0
,
5
,
2
,
RowBegin,
ColBegin,
RowEnd,
ColEnd,
Nr,
Nc,
Dist)
再对线左边延长
-
*拟合后的线不够长,将起始的列往左移动(减去5个像素点)
-
gen_contour_polygon_xld (
Contour,
[RowBegin,RowEnd],
[ColBegin-5,ColEnd])
拟合、延长后的
将新生成的线和别的线放到一起
-
*将其他的线也选择出来
-
select_shape_xld (SelectedXLD, SelectedXLD2,
'phi',
'and',
0.2,
3.14)
-
-
*将两次选出来的线放到一个集合中
-
concat_obj (SelectedXLD2, Contour, ObjectsConcat)
-
-
*将集合中的两个线,合并连接到一起
-
union_adjacent_contours_xld (ObjectsConcat, UnionContours1,
10,
1,
'attr_keep')
生成新的区域
-
*将线围起来的区域转换成轮廓
-
gen_region_contour_xld (UnionContours1, Region1,
'filled')
新生成的区域,边缘很圆滑。先腐蚀,再求边缘。
-
*使用腐蚀,将多出来的去掉
-
opening_circle (Region1, RegionOpening,
3.5)
-
*再求边缘
-
boundary (RegionOpening, RegionBorder,
'inner')
也不圆滑,再进行膨胀,膨胀后再从前面的区域中中裁剪
-
*求出来的边缘并不是太好,使用膨胀操作
-
dilation_circle
(RegionBorder, RegionDilation1, 3.5)
-
*膨胀后再从原图中进行裁剪
-
reduce_domain
(GrayImage, RegionDilation1, ImageReduced1)
然后再使用canny求边缘
-
*再用刚才的边缘,所求得的边缘就要好多了
-
edges_sub_pix
(ImageReduced1,
Edges1,
'canny'
,
1
,
20
,
40
)
最后再进行连接
-
*再进行连接
-
union_adjacent_contours_xld (Edges1, UnionContours2,
10,
1,
'attr_keep')
圆的拟合与直线的拟合,也包括线条的分割、筛选以及拟合。
直接以程序来讲解。
程序讲解:
打开图片
-
dev_close_window ()
-
dev_open_window (
0,
0,
512,
512, 'black', WindowHandle)
-
-
read_image (Image
1, '
1.bmp')
然后取图像中一个不规则的圆区域,将其裁剪下来
-
*画圆
-
draw_circle
(WindowHandle, Row, Column, Radius)
-
*生成圆
-
gen_circle
(Circle, Row, Column, Radius)
-
*裁剪
-
reduce_domain
(Image1, Circle, ImageReduced)
进行边缘提取,并选择外部的边缘轮廓
-
*提取边缘
-
edges_sub_pix (ImageReduced, Edges,
'canny',
1,
10,
20)
-
*选择轮廓形状
-
select_shape_xld (Edges, SelectedXLD,
'contlength',
'and',
80,
99999)
分割、筛选,因为轮廓线就一条,分割后还是一条
-
*对选出来的轮廓进行分割,然后求出分割最长的那条线
-
segment_contours_xld (SelectedXLD, ContoursSplit,
'lines_circles',
5,
4,
2)
-
*分割的
xld长度,长度值保存在
Length数组中
-
length_xld (ContoursSplit, Length)
-
*求数组最大值
-
tuple_max (Length, Max)
-
*选出分割最长的线
-
select_shape_xld (ContoursSplit, SelectedXLD1,
'contlength',
'and', Max-
1,
99999)
对分割、筛选后的线,用圆拟合
-
*对选出来的线,用圆的拟合。参数2:选择拟合方法,回归的形式
-
fit_circle_contour_xld
(SelectedXLD1,
'algebraic'
,
-1
,
0
,
0
,
3
,
2
,
Row1,
Column1,
Radius1,
StartPhi,
EndPhi,
PointOrder)
-
*生成圆轮廓-拟合好的分割线
-
gen_circle_contour_xld
(ContCircle,
Row1,
Column1,
Radius1,
0
,
6.28
,
'positive'
,
1
)
其它的,如椭圆拟合,分割、筛选方法跟圆一样,直接写出算子使用方法了
-
*椭圆拟合
-
*fit_ellipse_contour_xld
(SelectedXLD1,
'fitzgibbon'
,
-1
,
0
,
0
,
200
,
3
,
2
,
Row2,
Column2,
Phi,
Radius11,
Radius2,
StartPhi1,
EndPhi1,
PointOrder1)
-
*生成椭圆轮廓-拟合好的分割线
-
*gen_ellipse_contour_xld
(ContEllipse,
Row2,
Column2,
Phi,
Radius11,
Radius2,
StartPhi1,
StartPhi1,
'positive'
,
1.5
)
介绍::中心线是出于某区域中心的线,比如图中的道路中心,很多情况下需要求解中心。
求解方法:
方法1:求解区域的边缘,然后进而计算中心。
方法2:先求解区域,然后利用区域骨架求解中心。
方法3:利用lines-gauss算子求解。
程序讲解:
先去读取图片,然后灰度转换
-
read_image (
Image1, '
1.bmp')
-
rgb1_to_gray (
Image1, GrayImage)
示例1:中心线提取-亮的区域。
-
*中心线提取,亮的区域。
-
*参数
3:提取的中心线光滑程度,通常取
1
.2-1
.5。参数
4参数
5:边缘高低阈值,类似于
canny。参数
6:中心线是
dark还是
light
-
lines_gauss (GrayImage, Lines,
1.5,
3,
8,
'light',
'true',
'bar-shaped',
'true')
示例2:中心线提取-暗的区域。
-
*提取黑色的中心线
-
lines_gauss (GrayImage, Lines1,
1.5,
3,
8,
'dark',
'true',
'bar-shaped',
'true')
区域边缘提取和轮廓识别,案例应用见下一节:7、Halcon图像中识别多个矩形区域并对平均宽度测量。
https://blog.csdn.net/panjinliang066333/article/details/104431979