halcon写微信跳一跳辅助
执行之后的结果:
利用halcon的算子检测程序:
dev_set_draw ('margin') read_image (Image, 'C:/Users/6013_1.jpeg') stop () rgb1_to_gray(Image, GrayImage) threshold (Image, Regions, 0, 135) opening_rectangle1 (Regions, RegionOpening, 15, 15) connection(RegionOpening, ConnectedRegions) select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 20045.9, 30137.6) opening_rectangle1 (SelectedRegions, RegionOpening1, 35, 35) count_obj (RegionOpening1, Number) for Index := 1 to Number by 1 select_obj (RegionOpening1, ObjectSelected, Index) smallest_rectangle2 (ObjectSelected, Row, Column, Phi, Length1, Length2) area_center (ObjectSelected, Area, Row1, Column1) gen_circle (Circle, Row1, Column1, 5) gen_rectangle2 (ObjectSelected, Row, Column, Phi, Length1, Length2) endfor
这个只是检测方形的垫板,而且对颜色深度有要求.后续在测试下其他的方法...
查找小人所在坐标:
read_image (Image, 'C:/Users/Administrator/Desktop/t1t/IMG_2339.PNG') stop () rgb1_to_gray(Image, GrayImage) scale_image (GrayImage, ImageScaled1, 7.72727, -394) threshold (ImageScaled1, Regions, 0, 253) erosion_circle (Regions, RegionErosion, 15) fill_up (RegionErosion, RegionFillUp) area_center (RegionFillUp, Area, Row1, Column1) gen_circle (Circle, Row1, Column1, 5)
转一个查找边缘的代码:
dev_close_window() read_image (Image, 'C:/Users/Administrator/Desktop/t1t/13_3421_3422e3e192ef9bf.bmp') get_image_size(Image, Width, Height) dev_open_window(0, 0, Width, Height, 'black', WindowHandle) dev_display(Image) edges_sub_pix(Image, Edges, 'canny', 1, 20, 40) select_contours_xld(Edges, SelectedContours, 'contour_length',200, 500, -0.5, 0.5) dev_clear_window() dev_display(SelectedContours) union_adjacent_contours_xld(SelectedContours, UnionContours, 10, 1, 'attr_keep') shape_trans_xld(UnionContours, XLDTrans,'rectangle2') dev_display(Image) dev_display(XLDTrans) area_center_xld(XLDTrans, Area, Row, Column, PointOrder) disp_cross(WindowHandle, Row, Column, 20, 0)
第四版:
利用查找边缘 , 滤波之后按照行坐标排序,提取第一个边缘线, 画出这个边缘线的最小外接圆, 获取到外接圆的圆心坐标 即为 下一个跳板的中心坐标.
小人坐标继续利用上面的方法实现.
存在的问题: 可能边缘方法用的不好, 外接圆有时候圆心会靠边缘. 估计实际测试中有可能会跳出跳板导致摔死......
dev_close_window () for Index := 1 to 13 by 1 dev_set_draw ('margin') read_image (Image, 'C:/Users/RD-W/Desktop/跳一跳/tt' + Index) read_image(BGImage1, 'C:/Users/RD-W/Desktop/跳一跳/bg.png') dev_open_window_fit_image (BGImage1, 0, 0, -1, -1, WindowHandle) rgb1_to_gray(BGImage1, BGGrayImage) rgb1_to_gray(Image, ImageGray) *找小人坐标 scale_image (ImageGray, xiaorenImageScaled, 7.72727, -394) *缩放亮度 threshold (xiaorenImageScaled, xiaorenRegions, 0, 253) *腐蚀 erosion_circle (xiaorenRegions, xiaorenRegionErosion, 15) dev_set_color ('green') *填充 fill_up (xiaorenRegionErosion, xiaorenRegionFillUp) *获取小人双脚中心 area_center (xiaorenRegionFillUp, xiaorenArea, xiaorenRow1, xiaorenColumn1) dev_set_color ('magenta') dev_set_line_width (3) *画十字坐标位 gen_cross_contour_xld (xiaorenCross, xiaorenRow1, xiaorenColumn1, 50, 0.785398) *stop() dev_set_color ('green') *找最上方跳板坐标 *设置ROI区域 gen_rectangle1 (Rectangle, 236, 0, 1334, 750) *截图,只留下感兴趣区域 reduce_domain (ImageGray, Rectangle, ImageReduced) reduce_domain (BGGrayImage, Rectangle, BGImageReduced) *前景图减去背景图,并翻倍结果值,使对比更强烈 abs_diff_image (ImageReduced, BGImageReduced, ImageAbsDiff, 7) dev_set_line_width (3) *边缘查找 edges_sub_pix (ImageAbsDiff, Edges, 'mshen', 1, 40, 60) *将临近边缘合并 union_adjacent_contours_xld (Edges, UnionContours1, 35, 2, 'attr_keep') * union_collinear_contours_xld (Edges, UnionContours, 30, 10, 200, 0.7, 'attr_keep') *排序边缘线,按照行坐标大小顺序 sort_contours_xld (UnionContours1, SortedContours, 'upper_left', 'true', 'row') *选择第一个边缘线 select_obj (SortedContours, ObjectSelected1, 1) *多边形填充这个边缘线 gen_region_contour_xld (ObjectSelected1, Region, 'filled') * smallest_rectangle2_xld (ObjectSelected1, Row1, Column1, Phi, Length1, Length2) * gen_rectangle2_contour_xld (Rectangle1, Row1, Column1, Phi, Length1, Length2) *改变填充好的边缘图形外形为外接圆 shape_trans (Region, RegionTrans, 'outer_circle') dev_set_color ('green') *查找外接圆圆心坐标 area_center (RegionTrans, Area, Row, Column) dev_set_color ('magenta') dev_set_line_width (3) *画十字线 gen_cross_contour_xld (Cross, Row, Column, 50, 0.785398) * threshold (ImageAbsDiff, Regions, 238, 255) * erosion_circle (Regions, RegionErosion, 5) * erosion_rectangle1 (RegionErosion, RegionErosion1, 11, 11) * connection (RegionErosion1, ConnectedRegions) * select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 9862.39, 50000) * count_obj (SelectedRegions, Number) * for Index := 1 to Number by 1 * select_obj (SelectedRegions, ObjectSelected, Index) * area_center (ObjectSelected, Area, Row, Column) * dev_set_color ('green') * dev_set_line_width (3) * gen_cross_contour_xld (Cross, Row, Column, 50, 0.785398) * endfor *测量小人中心点和跳板中心点距离 distance_pp (xiaorenRow1, xiaorenColumn1, Row, Column, Distance) *disp_message (WindowHandle, Distance, 'window', 310, 87, 'white', 'true') *显示在窗体上 *dev_disp_text (Distance, 'window', 260, 263, 'white', [], []) *把小人中心点和跳板中心点画线 gen_region_line (RegionLines, xiaorenRow1, xiaorenColumn1, Row, Column) stop() endfor
将上面的halcon代码移植到aardio软件之后如下:
import win.ui; /*DSG{{*/ mainForm = win.form(text="Halcon处理跳一跳演示算法";right=938;bottom=1349) mainForm.add( button={cls="button";text="加载一副测试图";left=9;top=369;right=170;bottom=419;z=2}; picturebox={cls="picturebox";left=182;top=0;right=938;bottom=1350;bgcolor=8421376;z=1}; snumber={cls="static";text="0";left=9;top=307;right=171;bottom=343;align="center";center=1;font=LOGFONT(h=-20);transparent=1;z=3}; static={cls="static";text="线段距离:(像素)";left=10;top=255;right=168;bottom=291;font=LOGFONT(h=-21);transparent=1;z=4}; static2={cls="static";text="AAR调用Halcon 处理跳一跳 演示算法";left=8;top=14;right=166;bottom=154;font=LOGFONT(h=-21);transparent=1;z=5} ) /*}}*/ //import console; import halconc; //console.open(); //首先设置默认背景图像 var ret,BGImage = halconc.read_image(0,"res/bg"); var ret,width,height = halconc.get_image_size(BGImage,0,0); var ret,Hwindow = halconc.open_window(0,0,width,height,mainForm.picturebox.hwnd,"visible", "",0); var ret = halconc.disp_obj(BGImage,Hwindow); var pathnum = 0; mainForm.button.oncommand = function(id,event){ if(pathnum >= 13){ pathnum = 1; }else { pathnum ++; } //win.delay(1000) //var ret = halconc.set_draw(Hwindow,"margin"); //var ret = halconc.set_color(Hwindow,"green"); //调用演示图像 var ret,gameImage = halconc.read_image(0,"res/tt" ++ pathnum); //灰度化 var ret,BGGrayImage = halconc.rgb1_to_gray(BGImage, 0); var ret,gameGrayImage = halconc.rgb1_to_gray(gameImage, 0); //找小人坐标 var ret,xiaorenImageScaled = halconc.scale_image (gameGrayImage, 0, 7.72727, -394); var ret,xiaorenRegions = halconc.threshold (xiaorenImageScaled, 0, 0, 253) var ret,xiaorenRegionErosion = halconc.erosion_circle(xiaorenRegions,0,15); var ret,xiaorenRegionFillUp = halconc.fill_up (xiaorenRegionErosion, 0); var ret,xiaorenArea, xiaorenRow1, xiaorenColumn1 = halconc.area_center (xiaorenRegionFillUp, 0,0,0); var ret = halconc.set_color(Hwindow,"magenta"); var ret = halconc.set_line_width(Hwindow,3); var ret,xiaorenCross = halconc.gen_cross_contour_xld (0, xiaorenRow1, xiaorenColumn1, 50, 0.785398); var ret = halconc.disp_obj(gameGrayImage,Hwindow); var ret = halconc.disp_obj(xiaorenCross,Hwindow); //找最上方跳板坐标 var ret,Rectangle = halconc.gen_rectangle1 (0, 236, 0, 1334, 750); var ret,gameImageReduced = halconc.reduce_domain (gameGrayImage, Rectangle, 0); var ret,BGImageReduced = halconc.reduce_domain (BGGrayImage, Rectangle, 0); var ret,ImageAbsDiff = halconc.abs_diff_image (gameImageReduced, BGImageReduced, 0, 7); var ret,Edges = halconc.edges_sub_pix (ImageAbsDiff, 0, "mshen", 1, 40, 60); var ret,UnionContours1 = halconc.union_adjacent_contours_xld (Edges, 0, 35, 2, "attr_keep"); var ret,SortedContours = halconc.sort_contours_xld (UnionContours1, 0, "upper_left", "true", "row"); var ret,ObjectSelected1 = halconc.select_obj (SortedContours, 0, 1); var ret,Region = halconc.gen_region_contour_xld (ObjectSelected1, 0, "filled"); var ret,RegionTrans = halconc.shape_trans (Region, 0, "outer_circle"); //var ret = halconc.set_color(Hwindow,"green"); var ret,gameArea, gameRow, gameColumn = halconc.area_center (RegionTrans, 0,0,0); var ret,gameCross = halconc.gen_cross_contour_xld (0, gameRow, gameColumn, 50, 0.785398) var ret = halconc.disp_obj(gameCross,Hwindow); var ret,RegionLines = halconc.gen_region_line (0, xiaorenRow1, xiaorenColumn1, gameRow, gameColumn); var ret = halconc.disp_obj(RegionLines,Hwindow); //测两点间距离 var ret,Distance = halconc.distance_pp (xiaorenRow1, xiaorenColumn1, gameRow, gameColumn, 0); mainForm.snumber.text = Distance; //console.dump(Distance); } mainForm.enableDpiScaling(); mainForm.show(); return win.loopMessage();
另外一个思路:
观察发现跳一跳的图形都是从小人脚部开始向左或者向右成30度角形成的跳板,而且跳板的中心就是这个跳板最顶部的点的正下方, 于是,我们可以以小人脚部点30度画一条斜线, 跳板的最高顶部点画一条垂直线, 两条线相交的地方就是跳板中心点.
通过简单的三角计算,就可以得到落脚点的中心坐标了.
于是只要找到了小人的脚部坐标和跳板的最高处坐标, 就可以进行操作了.
import win.ui; /*DSG{{*/ mainForm = win.form(text="Halcon处理跳一跳演示算法";right=938;bottom=1349) mainForm.add( button={cls="button";text="加载一副测试图";left=9;top=369;right=170;bottom=419;z=2}; picturebox={cls="picturebox";left=182;top=0;right=938;bottom=1350;bgcolor=8421376;z=1}; snumber={cls="static";text="0";left=9;top=307;right=171;bottom=343;align="center";center=1;font=LOGFONT(h=-20);transparent=1;z=3}; static={cls="static";text="线段距离:(像素)";left=10;top=255;right=168;bottom=291;font=LOGFONT(h=-21);transparent=1;z=4}; static2={cls="static";text="AAR调用Halcon 处理跳一跳 演示算法";left=8;top=14;right=166;bottom=154;font=LOGFONT(h=-21);transparent=1;z=5} ) /*}}*/ import halconc; import console; console.open(); //首先设置默认背景图像 var ret,BGImage = halconc.read_image(0,"res/IMG_2466.PNG"); var ret,width,height = halconc.get_image_size(BGImage,0,0); var ret,Hwindow = halconc.open_window(0,0,width,height,mainForm.picturebox.hwnd,"visible", "",0); //var ret = halconc.disp_obj(BGImage,Hwindow); var pathnum = 2465; mainForm.button.oncommand = function(id,event){ if(pathnum >= 2475){ pathnum = 2466; }else { pathnum ++; } //调用演示图像 var ret,gameImage = halconc.read_image(0,"res/IMG_"++pathnum ); //var ret = halconc.disp_obj(gameImage,Hwindow); var ret,Rectangle = halconc.gen_rectangle1 (0, 218.498, 0.61276, 1223.44, 743.936); var ret,gameImageReduced = halconc.reduce_domain (gameImage, Rectangle, 0); var ret,gameGrayImage = halconc.rgb1_to_gray(gameImageReduced, 0); //获取三通道 var ret,Image1, Image2, Image3 = halconc.decompose3 (gameImage, 0,0,0); //找小人坐标 var ret,xiaorenImageScaled = halconc.scale_image (gameGrayImage, 0, 7.72727, -394); var ret,xiaorenRegions = halconc.threshold (xiaorenImageScaled, 0, 0, 253) var ret,xiaorenRegionErosion = halconc.erosion_circle(xiaorenRegions,0,15); var ret,xiaorenRegionFillUp = halconc.fill_up (xiaorenRegionErosion, 0); var ret,Row11, Column11, Row2, Column2 = halconc.smallest_rectangle1(xiaorenRegionFillUp, 0,0,0,0); var ret = halconc.set_color(Hwindow,"magenta"); var ret = halconc.set_line_width(Hwindow,3); var ret,xiaorenCross = halconc.gen_cross_contour_xld (0, Row2, (Column11+Column2)/2, 50, 0.785398); //var ret = halconc.disp_obj(xiaorenCross,Hwindow); //手动绘制ROI //var ret,ROI_0 = halconc.gen_rectangle1 (0, 218.498, 2.83828, 1223.44, 746.162); //获取图片左边第一个点的灰度值作为基准,连续取后面的灰度值,相减判断 for(y=219;1222;1){ var ret,base_Grayval = halconc.get_grayval (Image3, y, 3, 0) for(x=4;744;1){ var ret,single_Grayval = halconc.get_grayval (Image3, y, x, 0) var dec_val = math.abs(single_Grayval-base_Grayval) //不是背景色 if(dec_val!=0){ var ret = halconc.set_grayval (Image3, y, x, 0) var ret = halconc.set_color(Hwindow,"magenta"); var ret = halconc.set_line_width(Hwindow,3); //var ret,dingdianCross = halconc.gen_cross_contour_xld (0, y, x, 50, 0.785398); var ret = halconc.disp_obj(Image3,Hwindow); var ret = halconc.disp_obj(xiaorenCross,Hwindow); //var ret = halconc.disp_obj(dingdianCross,Hwindow); //如果小人在屏幕中间的左边 //if( (Column11+Column2)/2 <= width/2 ){ var ret,tiaobancenterCross = halconc.gen_cross_contour_xld (0, ( Row2- math.abs(x - (Column11+Column2)/2 )*0.557 ), x, 50, 0.785398); //}else { //} var ret = halconc.disp_obj(tiaobancenterCross,Hwindow); break 2; }else { //是背景色 } } } //var ret = halconc.disp_obj(ImageReduced,Hwindow); } mainForm.enableDpiScaling(); mainForm.show(); return win.loopMessage();
上述代码测试,基本每次都落在中心点了.
实测发现上述代码还是有一点不足,如果图像中有一个类似汉堡店的图形,那么小人的定位就不准,导致跳板定位也不准,于是,重新更改了小人的获取方式
图像进行缩放阈值处理之后,
halcon代码如下:
read_image (Img2506, 'C:/Users/Administrator/Desktop/t1ttest/halcon_T1T/res/tt/IMG_2506.PNG') rgb1_to_gray (Img2506, GrayImage) scale_image (GrayImage, ImageScaled, 7.72727, -394) //缩放阈值之后,选择色值 threshold (ImageScaled, Region, 0, 253) //分隔相连图形 connection (Region, ConnectedRegions) //填充每个分隔区域 fill_up (ConnectedRegions, RegionFillUp1) //选择小人身体所在的区域(通过面积) select_shape (RegionFillUp1, SelectedRegions, 'area', 'and', 3503.13, 4443.57) //最小方框 smallest_rectangle1 (SelectedRegions, Row1, Column1, Row2, Column2) //画出方框 gen_rectangle1 (SelectedRegions, Row1, Column1, Row2, Column2)
这样就可以避免跳板图形的颜色黑度对小人寻找带来的影响了
于是,修改aar的代码如下:
import win.ui; /*DSG{{*/ mainForm = win.form(text="Halcon处理跳一跳演示算法";right=938;bottom=1349) mainForm.add( button={cls="button";text="加载一副测试图";left=9;top=369;right=170;bottom=419;z=2}; picturebox={cls="picturebox";left=182;top=0;right=938;bottom=1350;bgcolor=8421376;z=1}; snumber={cls="static";text="0";left=9;top=307;right=171;bottom=343;align="center";center=1;font=LOGFONT(h=-20);transparent=1;z=3}; static={cls="static";text="线段距离:(像素)";left=10;top=255;right=168;bottom=291;font=LOGFONT(h=-21);transparent=1;z=4}; static2={cls="static";text="AAR调用Halcon 处理跳一跳 演示算法";left=8;top=14;right=166;bottom=154;font=LOGFONT(h=-21);transparent=1;z=5} ) /*}}*/ import halconc; //首先设置默认背景图像 var ret,BGImage = halconc.read_image(0,"res/IMG_2480.PNG"); var ret,width,height = halconc.get_image_size(BGImage,0,0); var ret,Hwindow = halconc.open_window(0,0,width,height,mainForm.picturebox.hwnd,"visible", "",0); //var ret = halconc.disp_obj(BGImage,Hwindow); var pathnum = 2479; mainForm.button.oncommand = function(id,event){ if(pathnum >= 2505){ pathnum = 2480; }else { pathnum ++; } //调用演示图像 var ret,gameImage = halconc.read_image(0,"res/IMG_"++pathnum ); //var ret = halconc.disp_obj(gameImage,Hwindow); var ret,Rectangle = halconc.gen_rectangle1 (0, 218.498, 0.61276, 1223.44, 743.936); var ret,gameImageReduced = halconc.reduce_domain (gameImage, Rectangle, 0); var ret,gameGrayImage = halconc.rgb1_to_gray(gameImageReduced, 0); //获取三通道 var ret,Image1, Image2, Image3 = halconc.decompose3 (gameImage, 0,0,0); //找小人坐标 var ret,xiaorenImageScaled = halconc.scale_image (gameGrayImage, 0, 7.72727, -394); var ret,xiaorenRegions = halconc.threshold (xiaorenImageScaled, 0, 0, 253) var ret,ConnectedRegions = halconc.connection (xiaorenRegions, 0) var ret,xiaorenRegionFillUp = halconc.fill_up (ConnectedRegions, 0); var ret,SelectedRegions = halconc.select_shape (xiaorenRegionFillUp, 0, 'area', 'and', 3503.13, 4443.57) var ret,Row11, Column11, Row2, Column2 = halconc.smallest_rectangle1(SelectedRegions, 0,0,0,0); var ret = halconc.set_color(Hwindow,"magenta"); var ret = halconc.set_line_width(Hwindow,3); Row2 = Row2 -20; var ret,xiaorenCross = halconc.gen_cross_contour_xld (0, Row2, (Column11+Column2)/2, 50, 0.785398); //var ret = halconc.disp_obj(xiaorenCross,Hwindow); //如果小人在左边 var 列起始,列终止 = 0,0; if( (Column11+Column2)/2 <= width/2 ){ 列起始 = Column2 + 10; 列终止 = width-10; }else{ 列起始 = 10; 列终止 = Column11-10; } //获取图片左边第一个点的灰度值作为基准,连续取后面的灰度值,相减判断 for(y=219;Row2;1){ var ret,base_Grayval = halconc.get_grayval (Image3, y, 3, 0) for(x=列起始;列终止;1){ var ret,single_Grayval = halconc.get_grayval (Image3, y, x, 0) var dec_val = math.abs(single_Grayval-base_Grayval) //不是背景色 if(dec_val!=0){ var ret = halconc.set_grayval (Image3, y, x, 0) var ret = halconc.set_color(Hwindow,"magenta"); var ret = halconc.set_line_width(Hwindow,3); //var ret,dingdianCross = halconc.gen_cross_contour_xld (0, y, x, 50, 0.785398); var ret = halconc.disp_obj(Image3,Hwindow); var ret = halconc.disp_obj(xiaorenCross,Hwindow); //var ret = halconc.disp_obj(dingdianCross,Hwindow); var ret,tiaobancenterCross = halconc.gen_cross_contour_xld (0, ( Row2- math.abs(x - (Column11+Column2)/2 )*0.557 ), x, 50, 0.785398); var ret = halconc.disp_obj(tiaobancenterCross,Hwindow); break 2; }else { //是背景色 } } } //var ret = halconc.disp_obj(ImageReduced,Hwindow); } mainForm.enableDpiScaling(); mainForm.show(); return win.loopMessage();
在前面版本的基础上增加了参数外部可调功能:
ios系统手机要想和PC机相连来截图,需要用到airplayer Pro软件,安装之后可以根据获取到的句柄截图,然后进行操作.
import win.ui; /*DSG{{*/ mainForm = win.form(text="跳一跳视觉处理(By Aardio.com.cn)";right=690;bottom=806;border="dialog frame") mainForm.add( button={cls="button";text="获取图像";left=27;top=19;right=199;bottom=77;dl=1;dt=1;z=1}; button2={cls="button";text="等待画ROI";left=27;top=90;right=200;bottom=142;dl=1;dt=1;z=3}; button3={cls="button";text="识别小人";left=27;top=313;right=200;bottom=365;dl=1;dt=1;z=4}; button4={cls="button";text="画出小人身体部分";left=27;top=159;right=200;bottom=211;dl=1;dt=1;z=5}; button5={cls="button";text="开启循环识别模式";left=27;top=540;right=141;bottom=592;db=1;dl=1;z=12}; button6={cls="button";text="停止";left=145;top=541;right=194;bottom=593;db=1;dl=1;z=13}; button7={cls="button";text="识别跳板中心";left=27;top=442;right=200;bottom=494;db=1;dl=1;z=14}; picturebox={cls="picturebox";left=217;top=0;right=674;bottom=784;autosize=1;db=1;dl=1;dr=1;dt=1;z=2}; static={cls="static";text="小人最小面积系数:";left=27;top=224;right=133;bottom=243;dl=1;dt=1;transparent=1;z=8}; static2={cls="static";text="小人最大面积系数:";left=27;top=252;right=133;bottom=271;dl=1;dt=1;transparent=1;z=9}; static3={cls="static";text="小人脚部坐标偏移量:";left=27;top=282;right=147;bottom=301;dl=1;dt=1;transparent=1;z=11}; static4={cls="static";text="最小色差值:";left=27;top=383;right=104;bottom=402;dl=1;dt=1;transparent=1;z=16}; static5={cls="static";text="跳板相对水平角度:";left=27;top=411;right=142;bottom=430;db=1;dl=1;transparent=1;z=18}; static6={cls="static";text="像素距离:";left=27;top=611;right=90;bottom=630;db=1;dl=1;transparent=1;z=20}; static7={cls="static";text="时间系数:";left=27;top=647;right=90;bottom=666;db=1;dl=1;transparent=1;z=22}; static8={cls="static";text="长按时间:";left=27;top=688;right=90;bottom=707;db=1;dl=1;transparent=1;z=24}; 像素距离={cls="edit";text="0";left=107;top=605;right=188;bottom=627;db=1;dl=1;edge=1;multiline=1;z=19}; 时间系数={cls="edit";text="0.135";left=107;top=641;right=188;bottom=663;db=1;dl=1;edge=1;multiline=1;z=21}; 最大面积系数={cls="edit";text="0.85";left=157;top=249;right=198;bottom=268;dl=1;dt=1;edge=1;z=7}; 最小色差值={cls="edit";text="10";left=158;top=383;right=196;bottom=402;dl=1;dt=1;edge=1;z=15}; 最小面积系数={cls="edit";text="0.6";left=157;top=224;right=198;bottom=243;dl=1;dt=1;edge=1;z=6}; 脚部偏移系数={cls="edit";text="0.98";left=157;top=279;right=198;bottom=298;dl=1;dt=1;edge=1;z=10}; 跳板角度值={cls="edit";text="30";left=157;top=411;right=193;bottom=430;db=1;dl=1;edge=1;z=17}; 长按时间={cls="edit";text="0";left=107;top=682;right=188;bottom=704;db=1;dl=1;edge=1;multiline=1;z=23} ) /*}}*/ import halconc; import gdip; import winex import console console.open() var picPath = "pic/1135"/*temp.png";*/ //var tthwnd = winex.waitVisible("",,"CHWindow") //var picc = com.picture.printWindow(tthwnd); //com.picture 转换为GDI+位图 //var bmp = gdip.bitmap(picc); //首先设置默认背景图像 //bmp.save(picPath); var ret,BGImage = halconc.read_image(0,picPath); var ret,width,height = halconc.get_image_size(BGImage,0,0); var ret,Hwindow = halconc.open_window(0,0,width,height,mainForm.picturebox.hwnd,"visible", "",0); var ret = halconc.set_draw(Hwindow,'margin'); var ret = halconc.disp_obj(BGImage,Hwindow); mainForm.button.oncommand = function(id,event){ //var ret; picc = com.picture.printWindow(tthwnd); //com.picture 转换为GDI+位图 bmp = gdip.bitmap(picc); //首先设置默认背景图像 bmp.save(picPath) // win.delay(1000) ret,BGImage = halconc.read_image(0,picPath); ret = halconc.disp_obj(BGImage,Hwindow); //mainForm.picturebox.setBitmap(bmp.copyHandle()) } var ROI_Row1, ROI_Column1, ROI_Row21, ROI_Column21,Rectangle; mainForm.button2.oncommand = function(id,event){ var ret = halconc.set_color(Hwindow,"magenta"); ret = halconc.set_line_width(Hwindow,2); ret,ROI_Row1, ROI_Column1, ROI_Row21, ROI_Column21 = halconc.draw_rectangle1 (Hwindow,0,0,0,0); ret,Rectangle = halconc.gen_rectangle1 (0, ROI_Row1, ROI_Column1, ROI_Row21, ROI_Column21) ret = halconc.disp_obj(Rectangle,Hwindow); } var xxROI_Row1, xxROI_Column1, xxROI_Row21, xxROI_Column21,Area; mainForm.button4.oncommand = function(id,event){ var ret = halconc.set_color(Hwindow,"blue"); ret = halconc.set_line_width(Hwindow,2); ret,xxROI_Row1, xxROI_Column1, xxROI_Row21, xxROI_Column21 = halconc.draw_rectangle1 (Hwindow,0,0,0,0); ret,xxRectangle = halconc.gen_rectangle1 (0, xxROI_Row1, xxROI_Column1, xxROI_Row21, xxROI_Column21) ret,Area, Row, Column = halconc.area_center (xxRectangle, 0,0,0) ret = halconc.disp_obj(xxRectangle,Hwindow); } var Row11, Column11, Row2, Column2; mainForm.button3.oncommand = function(id,event){ var ret,gameImageReduced = halconc.reduce_domain (BGImage, Rectangle, 0); var ret,gameGrayImage = halconc.rgb1_to_gray(gameImageReduced, 0); //找小人坐标 var ret,xiaorenImageScaled = halconc.scale_image (gameGrayImage, 0, 7.72727, -394); var ret,xiaorenRegions = halconc.threshold (xiaorenImageScaled, 0, 0, 253) var ret,ConnectedRegions = halconc.connection (xiaorenRegions, 0) var ret,xiaorenRegionFillUp = halconc.fill_up (ConnectedRegions, 0); var ret,SelectedRegions = halconc.select_shape (xiaorenRegionFillUp, 0, 'area', 'and', Area*tonumber(mainForm.最小面积系数.text), Area*tonumber(mainForm.最大面积系数.text)) halconc.disp_obj(SelectedRegions,Hwindow); ret,Row11, Column11, Row2, Column2 = halconc.smallest_rectangle1(SelectedRegions, 0,0,0,0); var ret = halconc.set_color(Hwindow,"magenta"); var ret = halconc.set_line_width(Hwindow,3); //小人脚部纵左边上移一点点 Row2 = Row2*tonumber(mainForm.脚部偏移系数.text); var ret,xiaorenCross = halconc.gen_cross_contour_xld (0, Row2, (Column11+Column2)/2, 30, 0.785398); var ret = halconc.disp_obj(xiaorenCross,Hwindow); } mainForm.button7.oncommand = function(id,event){ //获取三通道 var ret,Image1, Image2, Image3 = halconc.decompose3 (BGImage, 0,0,0); //如果小人在左边 var 列起始,列终止 = 0,0; if( (Column11+Column2)/2 <= width/2 ){ 列起始 = Column2 + 10; 列终止 = ROI_Column21-10; }else{ 列起始 = ROI_Column1+10; 列终止 = Column11-10; } //获取图片左边第一个点的灰度值作为基准,连续取后面的灰度值,相减判断 for(y=ROI_Row1;Row2;1){ var ret,base_Grayval = halconc.get_grayval (Image3, y, 3, 0) for(x=列起始;列终止;1){ var ret,single_Grayval = halconc.get_grayval (Image3, y, x, 0) var dec_val = math.abs(single_Grayval-base_Grayval) //不是背景色 if(dec_val>=tonumber(mainForm.最小色差值.text)){ var ret = halconc.set_grayval (Image3, y, x, 0) var ret = halconc.set_color(Hwindow,"green"); var ret = halconc.set_line_width(Hwindow,2); //var ret,dingdianCross = halconc.gen_cross_contour_xld (0, y, x, 50, 0.785398); //var ret = halconc.disp_obj(Image3,Hwindow); //var ret = halconc.disp_obj(xiaorenCross,Hwindow); //var ret = halconc.disp_obj(dingdianCross,Hwindow); var ret,tiaobancenterCross = halconc.gen_cross_contour_xld (0, ( Row2- math.abs(x - (Column11+Column2)/2 )*math.tan(math.rad(tonumber(mainForm.跳板角度值.text))) ), x, 30, 0.785398); var ret = halconc.disp_obj(tiaobancenterCross,Hwindow); var ret,Distance = halconc.distance_pp (Row2, (Column11+Column2)/2, ( Row2- math.abs(x - (Column11+Column2)/2 )*math.tan(math.rad(tonumber(mainForm.跳板角度值.text))) ), x, 0); mainForm.像素距离.text = Distance; mainForm.长按时间.text = Distance*tonumber(mainForm.时间系数.text); break 2; }else { //是背景色 } } } } var tmid; mainForm.button5.oncommand = function(id,event){ tmid = mainForm.addtimer( 500/*毫秒*/, function(hwnd,msg,id,tick){//定时执行代码 /* picc = com.picture.printWindow(tthwnd); bmp = gdip.bitmap(picc); //首先设置默认背景图像 bmp.save(picPath,false) */ // win.delay(1000) ret,BGImage = halconc.read_image(0,picPath); ret = halconc.disp_obj(BGImage,Hwindow); var ret,gameImageReduced = halconc.reduce_domain (BGImage, Rectangle, 0); var ret,gameGrayImage = halconc.rgb1_to_gray(gameImageReduced, 0); //找小人坐标 var ret,xiaorenImageScaled = halconc.scale_image (gameGrayImage, 0, 7.72727, -394); var ret,xiaorenRegions = halconc.threshold (xiaorenImageScaled, 0, 0, 253) var ret,ConnectedRegions = halconc.connection (xiaorenRegions, 0) var ret,xiaorenRegionFillUp = halconc.fill_up (ConnectedRegions, 0); var ret,SelectedRegions = halconc.select_shape (xiaorenRegionFillUp, 0, 'area', 'and', Area*tonumber(mainForm.最小面积系数.text), Area*tonumber(mainForm.最大面积系数.text)) var ret,Row11, Column11, Row2, Column2 = halconc.smallest_rectangle1(SelectedRegions, 0,0,0,0); var ret = halconc.set_color(Hwindow,"magenta"); var ret = halconc.set_line_width(Hwindow,3); //小人脚部纵左边上移一点点 Row2 = Row2*tonumber(mainForm.脚部偏移系数.text); var ret,xiaorenCross = halconc.gen_cross_contour_xld (0, Row2, (Column11+Column2)/2, 30, 0.785398); ret = halconc.disp_obj(BGImage,Hwindow); halconc.disp_obj(SelectedRegions,Hwindow); ret = halconc.disp_obj(xiaorenCross,Hwindow); //获取三通道 var ret,Image1, Image2, Image3 = halconc.decompose3 (BGImage, 0,0,0); //如果小人在左边 var 列起始,列终止 = 0,0; if( (Column11+Column2)/2 <= width/2 ){ 列起始 = Column2 + 10; 列终止 = ROI_Column21-10; }else{ 列起始 = ROI_Column1+10; 列终止 = Column11-10; } //获取图片左边第一个点的灰度值作为基准,连续取后面的灰度值,相减判断 for(y=ROI_Row1;Row2;1){ var ret,base_Grayval = halconc.get_grayval (Image3, y, 3, 0) for(x=列起始;列终止;1){ var ret,single_Grayval = halconc.get_grayval (Image3, y, x, 0) var dec_val = math.abs(single_Grayval-base_Grayval) //不是背景色 if(dec_val>=tonumber(mainForm.最小色差值.text)){ var ret = halconc.set_grayval (Image3, y, x, 0) var ret = halconc.set_color(Hwindow,"green"); var ret = halconc.set_line_width(Hwindow,2); //var ret,dingdianCross = halconc.gen_cross_contour_xld (0, y, x, 50, 0.785398); //var ret = halconc.disp_obj(Image3,Hwindow); //var ret = halconc.disp_obj(xiaorenCross,Hwindow); //var ret = halconc.disp_obj(dingdianCross,Hwindow); var ret,tiaobancenterCross = halconc.gen_cross_contour_xld (0, ( Row2- math.abs(x - (Column11+Column2)/2 )*math.tan(math.rad(tonumber(mainForm.跳板角度值.text))) ), x, 30, 0.785398); var ret = halconc.disp_obj(tiaobancenterCross,Hwindow); break 2; }else { //是背景色 } } } } ); } mainForm.button6.oncommand = function(id,event){ mainForm.settimer(tmid,-1); } mainForm.enableDpiScaling(); mainForm.show(); return win.loopMessage();
decompose3 (Image, Image1, Image2, Image3) trans_from_rgb (Image1, Image2, Image3, ImageResult11, ImageResult21, ImageResult31, 'hsv') threshold (ImageResult31, Regions1, 0, 129) opening_circle (Regions1, RegionOpening1, 3) threshold (ImageResult11, Regions, 143, 196) opening_circle (Regions, RegionOpening, 3.5) intersection (RegionOpening1, RegionOpening, RegionIntersection)
转换为hsv来求小人坐标
mainForm.button2.oncommand = function(id,event){ HImageX = com.CreateObject("{6EBD90E7-D219-11D2-ADE5-0000C00F4EF9}") var filepath = com.Variant("res/double_circle.png"); HImageX.ReadImage(filepath); var ww,ll = HImageX.GetImageSize(null,null); console.varDump(ww) console.varDump(ll) } mainForm.button3.oncommand = function(id,event){ HOperatorSetX = com.CreateObject("{6ebd90e2-d219-11d2-ade5-0000c00f4ef9}") Image = HOperatorSetX.ReadImage("res/tt10.png"); Width , Height = HOperatorSetX.GetImageSize( Image ); WindowHandle = HOperatorSetX.OpenWindow( 0 , 0 , Width , Height , mainForm.picturebox.hwnd , "transparent","" ); //HOperatorSetX.DispObj( Image , WindowHandle ); //win.delay(1000) ModelRegion = HOperatorSetX.GenRectangle1( 457.06, 36.5763, 624.989, 110.729 ); TemplateImage = HOperatorSetX.ReduceDomain( Image , ModelRegion ); HOperatorSetX.DispObj( Image , WindowHandle ); win.delay(1000) /* var tt = { "none";"no_pregeneration" } var opt = com.Variant(tt); var num = { 22;27;4 } var con = com.Variant(num); */ ModelID = HOperatorSetX.CreateShapeModel( TemplateImage , 5, math.rad(0), math.rad(360), math.rad(0.9965), "none", "use_polarity", 22, 4 ); ModelContours = HOperatorSetX.GetShapeModelContours( ModelID , 1 ); HOperatorSetX.DispObj( ModelContours , WindowHandle ); //Area , Row , Column = HOperatorSetX.AreaCenter( ModelRegion ); //HomMat2d = HOperatorSetX.VectorAngleToRigid( 0 , 0 , 0 , Row , Column , 0 ); // console.log(Row , Column) // var RowTrans , ColTrans = HOperatorSetX.AffineTransPixel( HomMat2d , Row , Col ); //ContoursAffineTrans = HOperatorSetX.AffineTransContourXld( ModelContours , HomMat2d ); //HomMat2dTranslate = HOperatorSetX.HomMat2dTranslate( HomMat2d , 0.5 , 0.5 ); //HomMat2DAdapted = HOperatorSetX.HomMat2dTranslateLocal( HomMat2dTranslate , -0.5 , -0.5 ); //ContoursAffineTrans = HOperatorSetX.AffineTransContourXld( ModelContours , HomMat2DAdapted ); //HOperatorSetX.DispObj( Image , WindowHandle ); HOperatorSetX.SetColor( WindowHandle , "green" ); //HOperatorSetX.SetDraw( WindowHandle , "margin" ); //HOperatorSetX.DispObj( ModelRegion , WindowHandle ); //HOperatorSetX.DispObj( ContoursAffineTrans , WindowHandle ); //var HomMat2dIdentity = HOperatorSetX.HomMat2dIdentity( ); //var HomMat2dRotate = HOperatorSetX.HomMat2dRotate( HomMat2dIdentity , 0 , 0 , 0 ); //var HomMat2dTranslate = HOperatorSetX.HomMat2dTranslate( HomMat2dRotate , Row , Column ); //var ContoursAffineTrans = HOperatorSetX.AffineTransContourXld( Contours , HomMat2dTranslate ); console.log("开始匹配-------------") var Image = HOperatorSetX.ReadImage( "res/tt1.png" ); console.log("读取结束-------------") HOperatorSetX.DispObj( Image , WindowHandle ); console.log("显示结束--------------") var Row , Column , Angle , Score = HOperatorSetX.FindShapeModel( Image , ModelID , math.rad(0), math.rad(360), 0.7, 1, 0.5, 'least_squares', 5, 0.75 ); console.log("匹配结束--------------") //win.delay(1000) HOperatorSetX.DispCross( WindowHandle , Row+75 , Column , 10 , 0 ); }
var num = 2480; mainForm.button4.oncommand = function(id,event){ if(num >= 2506){ num= 2480; } console.log("开始匹配-------------") var Image = HOperatorSetX.ReadImage( "res/IMG_"++num ); console.log("读取结束-------------") HOperatorSetX.DispObj( Image , WindowHandle ); console.log("显示结束--------------") var Row , Column , Angle , Score = HOperatorSetX.FindShapeModel( Image , ModelID , math.rad(0), math.rad(360), 0.7, 1, 0.5, 'least_squares', 5, 0.75 ); console.log("匹配结束--------------") //win.delay(1000) HOperatorSetX.DispCross( WindowHandle , Row+75 , Column , 30 , 0 ); num++; }
mainForm.button5.oncommand = function(id,event){ HOperatorSetX = com.CreateObject("{6ebd90e2-d219-11d2-ade5-0000c00f4ef9}") Image = HOperatorSetX.ReadImage("res/1135.jpg"); Width , Height = HOperatorSetX.GetImageSize( Image ); WindowHandle = HOperatorSetX.OpenWindow( 0 , 0 , Width , Height , mainForm.picturebox.hwnd , "transparent","" ); HOperatorSetX.DispObj( Image , WindowHandle ); //win.delay(1000) HOperatorSetX.SetColor( WindowHandle , "blue" ); HOperatorSetX.SetLineWidth( WindowHandle , 2 ); Row1 , Column1 , Row2 , Column2 = HOperatorSetX.DrawRectangle1( WindowHandle ); ModelRegion = HOperatorSetX.GenRectangle1( Row1 , Column1 , Row2 , Column2 ); HOperatorSetX.DispObj( ModelRegion , WindowHandle ); win.delay(1000) TemplateImage = HOperatorSetX.ReduceDomain( Image , ModelRegion ); HOperatorSetX.DispObj( Image , WindowHandle ); ModelID = HOperatorSetX.CreateShapeModel( TemplateImage , 5, math.rad(0), math.rad(360), math.rad(0.9965), "none", "use_polarity", 22, 4 ); ModelContours = HOperatorSetX.GetShapeModelContours( ModelID , 1 ); HOperatorSetX.DispObj( ModelContours , WindowHandle ); HOperatorSetX.SetColor( WindowHandle , "green" ); console.log("开始匹配-------------") var Image = HOperatorSetX.ReadImage( "res/1135.jpg"); console.log("读取结束-------------") HOperatorSetX.DispObj( Image , WindowHandle ); console.log("显示结束--------------") var Row , Column , Angle , Score = HOperatorSetX.FindShapeModel( Image , ModelID , math.rad(0), math.rad(360), 0.7, 1, 0.5, 'least_squares', 5, 0.75 ); console.log("匹配结束--------------") //win.delay(1000) HOperatorSetX.DispCross( WindowHandle , Row+(Row2-Row1)/2-20 , Column , 30 , 0 ); }
import win.ui; /*DSG{{*/ var winform = win.form(text="aardio form";right=838;bottom=1133;parent=...) winform.add( button={cls="button";text="读图";left=689;top=0;right=839;bottom=64;z=2}; button2={cls="button";text="画识别区";left=689;top=83;right=839;bottom=147;z=3}; button3={cls="button";text="画小人区";left=689;top=174;right=839;bottom=238;z=4}; button4={cls="button";text="训练小人";left=689;top=268;right=839;bottom=332;z=5}; button5={cls="button";text="识别小人";left=689;top=360;right=839;bottom=424;z=6}; button6={cls="button";text="识别踏板";left=689;top=456;right=839;bottom=520;z=7}; button7={cls="button";text="多次测试";left=688;top=671;right=838;bottom=735;z=10}; picturebox={cls="picturebox";left=0;top=0;right=674;bottom=1134;z=1}; 最小色差值={cls="edit";text="20";left=706;top=567;right=829;bottom=596;edge=1;z=8}; 跳板角度值={cls="edit";text="30";left=705;top=613;right=828;bottom=640;edge=1;z=9} ) /*}}*/ import com; HOperatorSetX = com.CreateObject("{6ebd90e2-d219-11d2-ade5-0000c00f4ef9}"); winform.button.oncommand = function(id,event){ Image = HOperatorSetX.ReadImage("res/IMG_2480"); Width , Height = HOperatorSetX.GetImageSize( Image ); WindowHandle = HOperatorSetX.OpenWindow( 0 , 0 , Width , Height , winform.picturebox.hwnd , "transparent","" ); HOperatorSetX.SetDraw( WindowHandle , "margin" ); HOperatorSetX.DispObj( Image , WindowHandle ); } winform.button2.oncommand = function(id,event){ HOperatorSetX.SetColor( WindowHandle , "blue" ); HOperatorSetX.SetLineWidth( WindowHandle , 2 ); Row1 , Column1 , Row2 , Column2 = HOperatorSetX.DrawRectangle1( WindowHandle ); ModelRegion = HOperatorSetX.GenRectangle1( Row1 , Column1 , Row2 , Column2 ); HOperatorSetX.DispObj( ModelRegion , WindowHandle ); } winform.button3.oncommand = function(id,event){ HOperatorSetX.SetColor( WindowHandle , "red" ); HOperatorSetX.SetLineWidth( WindowHandle , 2 ); xrRow1 , xrColumn1 , xrRow2 , xrColumn2 = HOperatorSetX.DrawRectangle1( WindowHandle ); xrModelRegion = HOperatorSetX.GenRectangle1( xrRow1 , xrColumn1 , xrRow2 , xrColumn2 ); HOperatorSetX.DispObj( xrModelRegion , WindowHandle ); } winform.button4.oncommand = function(id,event){ TemplateImage = HOperatorSetX.ReduceDomain( Image , xrModelRegion ); //HOperatorSetX.DispObj( Image , WindowHandle ); ModelID = HOperatorSetX.CreateShapeModel( TemplateImage , 5, math.rad(0), math.rad(360), math.rad(0.9965), "none", "use_polarity", 22, 4 ); ModelContours = HOperatorSetX.GetShapeModelContours( ModelID , 1 ); } winform.button5.oncommand = function(id,event){ //HOperatorSetX.SetColor( WindowHandle , "green" ); //ggImage = HOperatorSetX.ReadImage( "res/1135.jpg"); ReduceImage = HOperatorSetX.ReduceDomain( Image , ModelRegion ); //HOperatorSetX.DispObj( ReduceImage , WindowHandle ); Row , Column , Angle , Score = HOperatorSetX.FindShapeModel( ReduceImage , ModelID , math.rad(0), math.rad(360), 0.7, 1, 0.5, 'least_squares', 5, 0.75 ); 脚部行坐标 = Row+(xrRow2-xrRow1)/2-15; 脚部列坐标 = Column; 小人宽度 = xrColumn2-xrColumn1; 小人高度 = xrRow2 - xrRow1; HOperatorSetX.DispCross( WindowHandle , 脚部行坐标 , 脚部列坐标 , 30 , 0 ); } winform.button6.oncommand = function(id,event){ var Image1 , Image2 , Image3 = HOperatorSetX.Decompose3( Image ); var 列起始,列终止 = 0,0; if(脚部列坐标 <= Width/2){ 列起始 = 脚部列坐标+ 小人宽度/2 + 10; 列终止 = Column2-10; }else{ 列起始 = Column1 + 10; 列终止 = 脚部列坐标 - 小人宽度/2 -10; } //获取图片左边第一个点的灰度值作为基准,连续取后面的灰度值,相减判断 for(y=Row1;脚部行坐标;1){ var base_Grayval1 = HOperatorSetX.GetGrayval( Image1 , y , 3 ); var base_Grayval2 = HOperatorSetX.GetGrayval( Image2 , y , 3 ); var base_Grayval3 = HOperatorSetX.GetGrayval( Image3 , y , 3 ); var base_Grayval = base_Grayval1+base_Grayval2+base_Grayval3; for(x=列起始;列终止;1){ var single_Grayval1 = HOperatorSetX.GetGrayval( Image1 , y , x ); var single_Grayval2 = HOperatorSetX.GetGrayval( Image2 , y , x ); var single_Grayval3 = HOperatorSetX.GetGrayval( Image3 , y , x ); var single_Grayval = single_Grayval1+single_Grayval2+single_Grayval3; var dec_val = math.abs(single_Grayval-base_Grayval) //不是背景色 if(dec_val>=tonumber(winform.最小色差值.text)){ HOperatorSetX.SetColor( WindowHandle , "green" ); HOperatorSetX.DispCross( WindowHandle , 脚部行坐标- math.abs(x - 脚部列坐标 )*math.tan(math.rad(tonumber(winform.跳板角度值.text))) , x , 30 , 0 ); /* var ret,Distance = halconc.distance_pp (Row+(xxROI_Row21-xxROI_Row1)/2-15, Column, ( Row+(xxROI_Row21-xxROI_Row1)/2-15- math.abs(x - Column )*math.tan(math.rad(tonumber(mainForm.跳板角度值.text))) ), x, 0); mainForm.像素距离.text = Distance; mainForm.长按时间.text = Distance*tonumber(mainForm.时间系数.text); */ break 2; }else { //是背景色 } } } } var gnum = 2480; winform.button7.oncommand = function(id,event){ if(gnum >= 2506){ gnum = 2480; } Image = HOperatorSetX.ReadImage("res/IMG_"++tostring(gnum)); HOperatorSetX.DispObj( Image , WindowHandle ); winform.button5.oncommand() winform.button6.oncommand() gnum++; } winform.enableDpiScaling(); winform.show(); win.loopMessage(); return winform;
登录后方可回帖
第二版,按照区域连同 + 面积选择 来做. 基本实现了简单图形的功能,但是,有一处问题:
上面箭头处的绿色被选中图形总是被检测到,这个问题应该可以利用更精确的面积来删除,或者利用region的角度来删除.
更新:
刚刚试了下面积精确选择,将面积值调大之后,可以了