My solution to the problem of Visual Task 1 of the 2022 Intelligent Manufacturing Competition
比赛赛题:
比赛时间为 180 min。
比赛任务及要求
任务一:实现对图片中的齿轮的检测以及测量,检测内容包括齿轮上是否有划痕,测量内容包括齿数、齿顶圆的直径以及齿根圆的直径(像素长度)。 Task1: For the gear in picture, check whether there are scratches on it, measure the number of teeth, the diameter of the addendum circle and the diameter of the root circle (in pixel length).
import cv2 from skimage import morphology from skimage import filters from skimage import feature from skimage import io from skimage import segmentation from skimage import transform
import matplotlib.pyplot as plt import numpy as np import os
_a, _b, w, h = use_rect print("齿顶圆直径:", (w+h)/2) # diameter of addendum circle
裁剪出来,填补中心的空缺,顺便求个质心(没啥用)直接用框出来的区域的宽高的一半位置作为质心是准确的。 Cut out the gear, fill the hole in center (use flood_fill). You don’t have to culculate the center of the mass and just believe in ‘boudingbox’.
用笨方法迭代求齿根圆。在中心画圆,让圆的半径越来越大,看会不会碰到齿轮外部的像素,注意compare是取反的。还可以用其他办法,比如logpolar做坐标变换会比较简洁。 In order to get the root circle diameter, I use a stupid iterative method. I draw a circle in the center of the binary image and check if it covers the pixels outside the gear. If not, increase the radius and try again util it is over. By doing this, I will get the root circle, see below. You can try to use ‘logpolar’ to get the diameter more elegantly.
不要直接提取轮廓来数齿轮,先膨胀一下 Dilate its teeth before finding contours.
1 2 3 4 5 6
img_d = morphology.dilation(img_thin, morphology.star(1)) img_d = morphology.remove_small_objects(img_d) plt.imshow(img_d) plt.savefig("figs/7.jpg") cnts, hier = cv2.findContours(img_d.astype(np.uint8), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) print("齿数:", len(cnts)) # number of teeth
补充另一种数齿轮的方法:根据凸包点数计算齿数。先用多边形拟合轮廓,然后计算凸包,凸包有多少个点就有多少齿数。 这个感觉比较不准确…齿数很多的时候凸包似乎计算不准,approxPolyDP的eps参数没设定好,看下面那张图大概可能猜出原因。 Another method: By getting convex hull length. Use ‘approxPolyDP’ to fit the gear contour, and use ‘convexhull’ to get the number of teeth. However, it’s not that accurate compared to skeletonization. May be the poly points should be filtered.
hullpt = cv2.convexHull(approx) img_copy = img_bin_crop.copy() cv2.polylines(img_copy, [hullpt], True, (128), 10) plt.imshow(img_copy) plt.savefig("figs/9.jpg") # print("齿轮数目:", len(hullpt)) # number of teeth
最后提取划痕。划痕非常不明显,处理起来比较棘手。如果是直方图均衡的话,会引入更多干扰因素。索性暴力上局部OTSU(不要用全局),提取后虽然有很多小点点,但是比直方图均衡更好过滤掉,可以运行代码自己对比看看。 二值化后,用medianBlur可以过滤掉大多数点点,只留下划痕。然后膨胀一下(合并分裂的划痕),就可以提取轮廓了。轮廓也要过滤,因为这里的轮廓是包括了齿轮的边缘、内孔啥的,设置面积阈值来过滤即可,面积最大值和最小值需要手动尝试出来。 The last step is to check scratches. These scratches are not obvious so I took effort to deal with it. Using histogram equalization will create more noises. So I use local OTSU roughly (do not use global OTSU threshold). It does create viele white points (noises) but can be filtered out by median blur. After that, apply dilation to it (in order to merge splited scratches), find contours and filter contours by area. The contours filter operation aims at filtering the edges of gear to get the scratches by area, so the threshold should be set carefully. It’s simple and efficient in competition, but not recommended in project. Try to filter edges in other way.