鉴于上次数学建模由于审题错误失利,报了亚太赛来为美赛增加参赛经验。但是由于之前一点没准备以及临近月底事情较多比赛进行的比较匆忙。选择的A题,最开始审题时以为跟国赛一样,用matlab可以全部解决,但是读完题之后发现需要借助其他的工具,后来发现Python由于anaconda环境不知道出了什么问题,运行不了,需要卸了重新安装,附带的jupyter、pytorch,panda等一系列全部无法使用。熟悉anaconda的伙伴肯定知道安装卸载它有多么痛苦。无奈只好安装C++版的opencv和halcon。并且感觉亚太赛此次的A题是必须借助外界函数和软件的,不然以其理论的复杂程度,很难在四天内完成,这也是感觉亚太赛与国赛最大的区别。
其中第一问要求对图像进行亚像素分割,画出图像的边缘轮廓。最开始审题时被论文里面五颜六色的图片迷惑住了,以为第一问就要对图像进行轮廓识别。所以最开始由于想复杂了在第一问耽误了很多时间。第一问整体的思路是先对图像进行二值化分割,将图像主体分割出来,并且去除图像表面由于过曝和光线不均的影响,然后绘出二值化后图像的轮廓线。
在对图像像进行二值化分割上,由于第三张图像光线极其复杂,一共尝试三种方法:
1.区域分割算法
根据不同区域的灰度设置不同的阈值进行分割,但是由于第二张图像整体的背景较为混杂,分割出来的效果并不好,因此我们放弃了这种方案。
2.迭代式阈值选择进行阈值分割
3.基于PSO优化的otsu分割
对图像进行了中值滤波去除椒盐噪声并进行了高斯滤波
进行了中值滤波
未进行中值滤波
从图片对比中可以看出中值滤波对图像椒盐噪声的去除有很好的效果
对第三张图像我们进行了直方图均衡化,因为图像背景是空,所以较为讨巧,如下图显示可以看出我们取得了很好的效果。
但是由于该图像高光部位是完全没有值的,跟背景属于同一性质,因此除非进行图像识别,暂时没有相处更好的分割对策,来去除中间高光带来的孔洞,因此最后对中心高光部位进行了填洞操作。
根据比对,我们最后选择了第三种算法作为实验结果。
在绘制图像轮廓方面,我们选择了Canny算子进行亚像素边缘检测。
最后结果如下图所示:
第二问相机标定,由于matlab的相机标定是基于棋盘格标定板的,halcon的标定文件也是应用halcon特定标定板。所以最后选则使用opencv对圆点标定板进行标定,先对图像标定点进行识别,然后根据世界坐标系对其进行矫正。将校正后的标定板图片进行计算像素距离与真实距离的比值。再通过第一问测量出图像轮廓数据,从而得出图像轮廓的真实长度。
第三问使用halcon轮廓分割算子进行计算,最烦燥的是要注意题目的坐标系及角度要求。跟halcon默认顺序是相反的!需要进行修正。对第一个轮廓进行了圆弧和直线的分割,对第二条轮廓进行了椭圆弧和直线的分割,注意分割顺序要求顺时针。
halcon代码如下:
open_file('EdgeContour2.csv','input', FileHandle)
x1:=[]
y1:=[]
x2:=[]
y2:=[]
IsEOF1:=0
while(IsEOF1==0)
fread_line(FileHandle, OutLine, IsEOF1)
tuple_split(OutLine, ', \n', Substrings)
tuple_length(Substrings, Length)
if(Length!=0)
x1:=[x1,Substrings[0]]
y1:=[y1,Substrings[1]]
endif
endwhile
dev_set_color('red')
dev_set_draw('margin')
tuple_number(x1,col1)
tuple_number(y1,row1)
dev_update_window('off')
dev_close_window()
dev_open_window(0,0,1000,1000,'black',WindowID)
dev_set_color('white')
gen_contour_polygon_xld(Contours,row1,col1)
segment_contours_xld (Contours, ContoursSplit, 'lines_ellipses', 20, 7, 3)
dev_display(Contours)
count_obj(ContoursSplit,NumSegments)
NumCirCles :=0
NumLines :=0
open_file ('test2.txt', 'append', FileHandle)
for i :=NumSegments to 1 by -1
select_obj(ContoursSplit,SingleSegment,i)
* Attrib = -1 线段 0 椭圆 1圆
get_contour_global_attrib_xld(SingleSegment,'cont_approx',Attrib)
length_xld(SingleSegment, len)
*获取轮廓点的个数
contour_point_num_xld(SingleSegment, num_1)
*获取轮廓点坐标
get_contour_xld(SingleSegment, Row1, Col1)
if(Attrib = 1)
*对单个轮廓做 圆逼近
fit_circle_contour_xld (SingleSegment, 'atukey', -1, 0, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)
*根据逼近结果生成一个圆轮廓
gen_ellipse_contour_xld (ContEllipse, Row, Column, 0, Radius, Radius, 0, 6.28318, 'positive', 1.5)
dev_set_color('blue')
dev_display(ContEllipse)
set_tposition(WindowID,Row,Column)
tuple_sub(StartPhi*57.3,EndPhi*57.3,Phi_sub)
tuple_length(Col1,LC)
tuple_length(Row1,LR)
fwrite_string (FileHandle, 'S'+i+' CircularArc '+'('+Column+','+Row+')'+' ('+Col1[LC-1]+','+Row1[LR-1]+')'+' ('+Col1[0]+','+Row1[0]+') '+Phi_sub+'\n')
*fwrite_string (FileHandle, Row1+','+Col1+'\n')
elseif(Attrib = -1)
fit_line_contour_xld (SingleSegment, 'tukey', -1, 0, 5, 2, RowBegin, ColBegin, RowEnd, ColEnd, Nr, Nc, Dist)
gen_contour_polygon_xld (Line, [RowBegin,RowEnd], [ColBegin,ColEnd])
distance_pp(RowBegin,ColBegin,RowEnd,ColEnd,Length)
dev_set_color('yellow')
dev_display(Line)
set_tposition(WindowID,(RowBegin + RowEnd)/2,(ColBegin +ColEnd)/2)
fwrite_string (FileHandle, 'S'+i+' Line'+' ('+ColEnd+','+RowEnd+')'+' ('+ColBegin+','+RowBegin+') '+Length+'\n')
else
fit_ellipse_contour_xld (SingleSegment, 'fitzgibbon', -1, 2, 0, 200, 3, 2.0, \
Row, Column, Phi, Radius1, Radius2, StartPhi, \
EndPhi, PointOrder)
gen_ellipse_contour_xld (ContEllipse, Row, Column, Phi, Radius1, Radius2, \
StartPhi, EndPhi, PointOrder, 1.5)
dev_set_color('blue')
dev_display(ContEllipse)
set_tposition(WindowID,Row,Column)
tuple_sub(StartPhi*57.3,EndPhi*57.3,Phi_sub)
tuple_length(Col1,LC)
tuple_length(Row1,LR)
fwrite_string (FileHandle, 'S'+i+' EllipticArc '+'('+Column+','+Row+')'+' ['+Radius1+','+Radius2+']'+ \
' ('+Col1[LC-1]+','+Row1[LR-1]+')'+' ('+Col1[0]+','+Row1[0]+') '+Phi_sub+' '+Phi*57.3+'\n')
endif
endfor
close_file (FileHandle)