按功能分类介绍:
1D边缘提取的基本流程:
step1: 沿着指定方向获取灰度值(灰度值取指定宽度线上的平均灰度值,如果指定方向存在角度,需要指定插值法)。
step2: 将获取的灰度值序列生成函数,并使用高斯滤波器抑制噪声;
step3: 使用一阶导数的极值点作为边缘候选点,将这些极值点出大于指定阈值的点作为边缘点。
gen_measure_rectangle2(................., MeasureHandle)
measure_projection(Image, MeasureHandle, GrayValues)
create_funct_1d_arry(GrayValues,Function) // 将数组转换为函数
smooth_funct_1d_gauss(Function,Sigma,SmoothFunction) // 平滑处理
// 通常使用函数的一阶导数、二阶导数进行处理获取极大值极小值等。
// 可以使用funct_1d_to_pairs(SmoothFunction,XValues,YValues)离散化函数
推荐使用正则化的模糊逻辑函数创建算子(可以适用于尺寸可变的测量对象):
set_fuzzy_measure_norm_pair();
案例的目的,检测下面带有红色标记图像中缺失的部分。
整体的代码逻辑(几乎可以视为1D测量的通用方案):
step1: 创建黄色区域图像的shape模板,同时在蓝色区域创建1D测量矩形。
step2: 使用基于形状的模板匹配方法在带有缺陷的图像中进行匹配,匹配到目标后,将创建的测量矩形和模板区域放射变换到匹配位置。
step3: 自行选择使用任意一种1D测量方法进行边缘直线的提取。
step4: 根据应用需求对测量结果进行处理。
step5: 释放测量对象和模板对象。
* step1: 读取用于创建模板的图像
dev_get_window(WindowHandle);
read_image(ModelImage,'razors1')
get_image_size(ModelImage,Width,Height)
*step2:创建用于创建模板的区域对,使用对的模板精度和速度较于单个region更好。
draw_rectangle1(WindowHandle,row11,column11,row12,column12);
draw_rectangle1(WindowHandle,row21,column21,row22,column22);
gen_rectangle1(ROIpart1,row11,column11,row12,column12)
gen_rectangle1(ROIpart2,row21,column21,row22,column22)
union2(ROIpart1,ROIpart2,ModelROI)
* step3:创建定位模板
reduce_domain(ModelImage,ModelROIO,ImageROI)
create_shape_model(ImageROI,4,0,0,'auto','none','use_polarity',30,10,ModelID)
* step4:获取创建模板的contours轮廓,最后一个参数表示的是金字塔的第几层
get_shape_model_contours(ShapeModel,ModelID,1)
* step5: 创建1D测量区域,使用蓝色区域
gen_rectangle2(MeasureROI1,Rect1Row, Rect1Col, RectPhi, RectLength1, RectLength2)
gen_rectangle2(MeasureROI2,Rect2Row, Rect2Col, RectPhi, RectLength1, RectLength2)
* 为了便于测量对象后续的反复使用,需要用到仿射变换,以及与模板共用同一个仿射变换矩阵,所以通常需要将生成的区域与位于
图像原点的模板保持相对位置不变使用。
area_center(ModelROI,Area,CenterRow,CenterColumn)
move_region(MeasureROI1, MeasureROI1Ref,-CenterRow,-CenterColumn)
move_region(MeasureROIO2,MeasureROI2Ref,-CenterRow,-CenterColumn)
* 这一段代码有点不好理解:下面所得结果为模板中心点与测量矩形中心点之间的偏移距离;
* 1D测量模板移动到原点后,如果直接使用模板后的仿射矩阵,那么移动后的1D模板并不在目标位置,而是存* 在一个下面的一个偏移量,所以还需要将仿射变换后的位置再进行旋转或平移一下偏移才是最终的位置。
DistRect1CenterRow := Rect1Row - CenterROIRow
DistRect1CenterCol := Rect1Col - CenterROIColumn
DistRect2CenterRow := Rect2Row - CenterROIRow
DistRect2CenterCol := Rect2Col - CenterROIColumn
* 生成测量1D对象
gen_measure_rectangle2 (Rect1Row, Rect1Col, RectPhi, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle1)
gen_measure_rectangle2 (Rect2Row, Rect2Col, RectPhi, RectLength1, RectLength2, Width, Height, 'bilinear', MeasureHandle2)
* step6: 加载待测量图像
read_image(SearchImage,'razors2')
* step7:进行模板搜索
find_shape_model(SearchImage,ModelID,0,0,0.8,0,0.5,'least_squares',0,0.7,RowCheck,ColumnCheck,AngleCheck,Score)
* step8: 遍历所有匹配到的位置,并将模板区域和1D测量区域仿射变换到检测的新的位置。
if(|Score| > 0)
for i:=0 to |Score|-1 by 1
* STEP8.1: 使用点和角度获取原点到模板匹配点之间的仿射变换矩阵,并将模板轮廓转移到当前匹配的位置
vector_angle_to_rigid(0,0,0,RowCheck[i],ColumnCheck[i],AngleCheck[i],MovementOfObject)
affine_trans_contour_xld(ShapeModel,ModelAtNewPosition,MovementOfObject)
* 显示模板到匹配位置
dev_display(ModelAtNewPosition)
*Step8.2: 将测量矩形region仿射变换到匹配的位置,用于显示当前的测量位置
affine_trans_region(MeasureROI1Ref,MeasureROIO1AtNewPosition,MovementOfObject)
affine_trans_region(MeasureROI2Ref,MeasureROIO2AtNewPosition,MovementOfObject)
dev_display(MeasureROIO1AtNewPosition)
dev_display(MeasureROIO2AtNewPosition)
*step8.3: 将之前生成的测量对象应用于当前的匹配测量区域或者重新生成1D测量对象
affine_trans_pixel (MovementOfObject, DistRect1CenterRow, DistRect1CenterCol, Rect1RowCheck, Rect1ColCheck)
affine_trans_pixel (MovementOfObject, DistRect2CenterRow, DistRect2CenterCol, Rect2RowCheck, Rect2ColCheck)
* 执行测量,检测出边缘对
translate_measure (MeasureHandle1, Rect1RowCheck, Rect1ColCheck)
translate_measure (MeasureHandle2, Rect2RowCheck, Rect2ColCheck)
measure_pairs (SearchImage, MeasureHandle1, 2, 25, 'negative', 'all', RowEdge11, ColEdge11, Amp11, RowEdge21, ColEdge21, Amp21, Width1, Distance1)
measure_pairs (SearchImage, MeasureHandle2, 2, 25, 'negative', 'all', RowEdge12, ColEdge12, Amp12, RowEdge22, ColEdge22, Amp22, Width2, Distance2)
* step8.4: 根据测量的结果进行判断
...............................................
endfor
endif
* step9: 释放测量对象
close_measure(MeasureHandle1)
close_measure()MeasureHandle2
* step10: 释放模板对象
clear_shape_model(ModelID)
通常1D测量的结果为一个边缘点,为了实现直线和圆的检测可以通过结合gen_contour_polygon_xld与fit_line_contour_xld()或fit_circle_contour_xld()实现。
基本逻辑:
step1: 沿着要检测的边缘绘制一条直线区域;
step2: 设定需要检测多少个边缘点用于直线拟合;
step3: 生成指定个数的边缘检测矩形;
step4: 生成1D测量对象;
step5: 执行检测;
step6: 使用gen_contour_polygon_xld将检测的边缘点转换为轮廓类型数据
step7: 使用fit_line_contour_xld()执行拟合。
实现代码:
read_image (Realep92, 'C:/Users/Administrator/Desktop/image4.jpg')
* step1:根据指定的检测目标直线生成指定条测量直线
dev_get_window (WindowHandle)
draw_rectangle1 (WindowHandle, Row11, Column11, Row21, Column21)
gen_rectangle1 (Rectangle, Row11, Column11, Row21, Column21)
reduce_domain (Realep92, Rectangle, ImageReduced)
crop_domain (ImageReduced, ImagePart)
dev_display (ImagePart)
draw_line (WindowHandle, Row1, Column1, Row2, Column2)
line_orientation (Row1, Column1, Row2, Column2, AngleLX)
* 根据指定的测量直线数量划分直线
tuple_abs (Column2 - Column1, X_dis)
tuple_abs (Row2 - Row1, Y_dis)
splitePoint:=10
if((splitePoint-1) > 0)
per_disx := X_dis / (splitePoint-1)
per_disy := Y_dis / (splitePoint-1)
else
per_disx := X_dis / 2
per_disy := Y_dis / 2
endif
MeasureLineStart_row := []
MeasureLineStart_column := []
MeasureLineEnd_row := []
MeasureLineEnd_column := []
* 检测矩形的中心点
MeasureRectangleCenter_row:=[]
MeasureRectangleCenter_column:=[]
dev_set_draw ('margin')
dev_set_color ('red')
dev_set_line_width (1)
for index:=0 to splitePoint-1 by 1
if(Row1<=Row2)
temRow := Row1 + per_disy*index
else
temRow := Row1 - per_disy*index
endif
if(Column1<=Column2)
temColumn := Column1 + per_disx*index
else
temColumn := Column1 - per_disx*index
endif
* 计算过划分点的垂直直线的起点
tuple_cos (AngleLX, Cos)
MeasureLineStart_row[index] := (temRow -Cos * 100)
tuple_sin (AngleLX, Sin)
MeasureLineStart_column[index] := (temColumn -Sin * 100)
* 计算过划分点的垂直直线的终点
MeasureLineEnd_row[index] := (temRow + Cos * 100)
MeasureLineEnd_column[index] := (temColumn + Sin * 100)
MeasureRectangleCenter_row[index] := temRow
MeasureRectangleCenter_column[index] := temColumn
endfor
* 显示所有的检测直线区域
* gen_region_line (RegionLines, MeasureLineStart_row, MeasureLineStart_column, \
MeasureLineEnd_row, MeasureLineEnd_column)
* dev_display (RegionLines)
* 将检测直线转换为检测矩形
temDr := MeasureLineStart_row - MeasureLineEnd_row
temDc := MeasureLineEnd_column - MeasureLineStart_column
tuple_atan2 (temDr, temDc, TemPhi)
tuple_sqrt (temDr*temDr + temDc*temDc, Sqrt)
TemLen1 := 0.5 * Sqrt
tuple_length (MeasureRectangleCenter_row, Length)
tuple_gen_const (Length, 30, TemLen2)
dev_set_color ('green')
gen_rectangle2 (Rectangle1, MeasureRectangleCenter_row, MeasureRectangleCenter_column, TemPhi, TemLen1, TemLen2)
dev_display (Rectangle1)
* step2: 开始边缘点的检测
get_image_size (ImagePart, Width, Height)
EdgePoint_row := []
EdgePoint_column := []
for index1:=0 to Length-1 by 1
gen_measure_rectangle2 (MeasureRectangleCenter_row[index1], MeasureRectangleCenter_column[index1], TemPhi[index1], TemLen1[index1], \
TemLen2[index1], Width, Height, 'nearest_neighbor', MeasureHandle)
measure_pos (ImagePart, MeasureHandle, 1, 10, 'all', 'first', RowEdge, ColumnEdge, Amplitude, Distance)
tuple_length (RowEdge, Length2)
if(Length2 > 0)
EdgePoint_row[index1] := RowEdge
EdgePoint_column[index1] := ColumnEdge
endif
close_measure (MeasureHandle)
endfor
* step3: 实现直线拟合
tuple_length (EdgePoint_row, Length1)
if(Length1 > 2)
dev_set_color ('red')
gen_region_points (Region, EdgePoint_row, EdgePoint_column)
gen_cross_contour_xld (Cross, EdgePoint_row, EdgePoint_column, 76, 0.7)
dev_display (Region)
gen_contour_polygon_xld (Contour, EdgePoint_row, EdgePoint_column)
fit_line_contour_xld (Contour, 'tukey', -1, 0, 5, 2, RowBegin, ColBegin, RowEnd, ColEnd, Nr, Nc, Dist)
gen_region_line (RegionLines, RowBegin, ColBegin, RowEnd, ColEnd)
count_obj (RegionLines, Number)
endif
基本检测逻辑:
step1: 沿着要检测的边缘绘制一条圆弧区域;
step2: 设定需要检测多少个边缘点用于直线拟合;
step3: 生成指定个数的边缘检测矩形;
step4: 生成1D测量对象;
step5: 执行检测;
step6: 使用gen_contour_polygon_xld将检测的边缘点转换为轮廓类型数据
step7: 使用fit_circle_contour_xld执行拟合。
实现代码:
read_image (Realep92, 'C:/Users/Administrator/Desktop/0.jpg.bmp')
* step1:根据指定的检测目标直线生成指定条测量直线
dev_get_window (WindowHandle)
draw_rectangle1 (WindowHandle, Row11, Column11, Row21, Column21)
gen_rectangle1 (Rectangle, Row11, Column11, Row21, Column21)
reduce_domain (Realep92, Rectangle, ImageReduced)
crop_domain (ImageReduced, ImagePart)
dev_display (ImagePart)
draw_circle (WindowHandle, Row, Column, Radius)
* 根据指定测量圆弧去划分测量圆弧段,直接用圆的周长除以测量矩形的宽度就是需要的测量矩阵数
pi:=acos(0.0)*2
circumference:=2*pi*Radius
* 设定测量矩形的宽度为20
splitCircle := circumference / 20
tuple_int (splitCircle, splitCircleInt)
* 获取测量矩形的中心点的直线的起点(园内点)和终点(圆外点)坐标
SmallRadius := Radius - 10
LargeRadius := Radius + 10
MeasureCircleStart_row := []
MeasureCircleStart_column := []
MeasureCircleEnd_row := []
MeasureCircleEnd_column := []
perAngle := 360 / splitCircle
StartAngle := perAngle / 2
for index:=0 to splitCircle by 1
SmallDr := SmallRadius * sin(rad(StartAngle))
SmallDc := SmallRadius * cos(rad(StartAngle))
LargeDr := LargeRadius * sin(rad(StartAngle))
LargeDc := LargeRadius * cos(rad(StartAngle))
StartAngle := StartAngle + perAngle
MeasureCircleStart_row[index] := Row - SmallDr
MeasureCircleStart_column[index] := Column + SmallDc
MeasureCircleEnd_row[index] := Row - LargeDr
MeasureCircleEnd_column[index] := Column + LargeDc
endfor
gen_cross_contour_xld (Cross, MeasureCircleStart_row, MeasureCircleStart_column, 10, 0.7)
gen_cross_contour_xld (Cross1, MeasureCircleEnd_row, MeasureCircleEnd_column, 10, 0.7)
* 将检测直线转换为检测矩形
MeasureRectangleCenter_row := 0.5*(MeasureCircleStart_row + MeasureCircleEnd_row)
MeasureRectangleCenter_column := 0.5*(MeasureCircleStart_column + MeasureCircleEnd_column)
temDr := MeasureCircleStart_row - MeasureCircleEnd_row
temDc := MeasureCircleEnd_column - MeasureCircleStart_column
tuple_atan2 (temDr, temDc, TemPhi)
tuple_sqrt (temDr*temDr + temDc*temDc, Sqrt)
TemLen1 := 0.5 * Sqrt
tuple_length (MeasureCircleStart_row, Length)
tuple_gen_const (Length, 10, TemLen2)
dev_set_draw ('margin')
dev_set_color ('green')
gen_rectangle2 (Rectangle1, MeasureRectangleCenter_row, MeasureRectangleCenter_column, TemPhi, TemLen1, TemLen2)
dev_display (Rectangle1)
* step2: 开始边缘点的检测,这里也可以进行优化
get_image_size (ImagePart, Width, Height)
EdgePoint_row := []
EdgePoint_column := []
for index1:=0 to Length-1 by 1
gen_measure_rectangle2 (MeasureRectangleCenter_row[index1], MeasureRectangleCenter_column[index1], TemPhi[index1], TemLen1[index1], \
TemLen2[index1], Width, Height, 'nearest_neighbor', MeasureHandle)
measure_pos (ImagePart, MeasureHandle, 1, 10, 'all', 'first', RowEdge, ColumnEdge, Amplitude, Distance)
tuple_length (RowEdge, Length1)
if(Length1 > 0)
EdgePoint_row[index1] := RowEdge
EdgePoint_column[index1] := ColumnEdge
endif
close_measure (MeasureHandle)
endfor
* step3: 实现直线拟合,当然这里的拟合过程可以进行更多优化处理
dev_set_color ('red')
gen_region_points (Region, EdgePoint_row, EdgePoint_column)
gen_cross_contour_xld (Cross, EdgePoint_row, EdgePoint_column, 10, 0.7)
dev_display (Region)
gen_contour_polygon_xld (Contour, EdgePoint_row, EdgePoint_column)
fit_circle_contour_xld (Contour, 'algebraic', -1, 0, 0, 3, 2, Row1, Column1, Radius1, \
StartPhi, EndPhi, PointOrder)
gen_circle (Circle, Row1, Column1, Radius1)
count_obj (Circle, Number)