Python基于OpenCV的指针式表盘检测系统

作品简介

视频演示

https://www.bilibili.com/video/BV1qB4y1V7JV/?vd_source=bc9aec86d164b67a7004b996143742dc

技术博客

https://zhuanlan.zhihu.com/p/561088184

1.背景

指针式机械表盘具有安装维护方便、结构简单、防电磁干扰等诸多优点, 目前广泛应用于工矿企业、能源及计量等部门。随着仪表数量的增加及精密仪表技术的发展,人工判读已经不能满足实际应用需求。随着计算机技术和图像处理技术的不断发展,指针式机械表自动读表技术应运而生。该技术提高了表盘识别的自动化程度及实时性,将代替传统工业仪表的读取方式得到广泛应用。


2.国内外研究现状

识别对象的型号:HCDL821-YB 避雷在线监测装置


识别难点:

1.内表盘很深,导致内表盘面阴影严重,给内椭圆的识别增加难度。

2.电表外轮廓反光严重,如果采用点光源照明,会产生亮斑和眩光现象。

3.电表内表盘反光严重,导致不同角度颜色不同,不利于阈值的设置。

4.电表外轮廓经过打磨圆角处理,导致识别的椭圆外轮廓精度下降。


表盘特点:刻度盘和指针具有颜色,而且不同的颜色区间代表不同的刻度值范围。


3.算法的特点

1.可以识别不同光照条件下的表盘:强光、正常光、弱光、点光源、平行光源等。

2.可以识别不同拍摄角度的表盘:正面、左斜侧、右斜侧、前斜侧、后斜侧等。

3.可以识别不同距离的表盘:近距离拍摄、中距离拍摄、远距离拍摄等。

4.可以识别带干扰颜色的场景:红色桌子、白色墙纸、绿色桶、蓝色盆子等。

5.可以识别不同尺寸、像素的表盘照片。

6.识别效率高:整个程序运行时间在10秒以内,而传统的椭圆检测程序就需要一分钟以上。


4.算法流程图

5.算法过程可视化


6.初步处理

preliminary_pretreatment()

该函数进行表盘大致位置的找寻,该函数的亮点是一个参数自调整的cv.HoughCircles()。

其中param2参数会根据找寻圆的结果进行自动调整。(param2是检测阶段圆心的累加阈值,它越小,可以检测到更多的假圆。它越大,能通过检测的圆越少且更加接近完美的圆。)


circles, param, x, y, r = [ ], 50, 0, 0, 0
     while 1:
             circles = cv.HoughCircles(pre, cv.HOUGH_GRADIENT, 1, 20, param1=100, param2=param, minRadius=100, maxRadius=300)
               if  circles  is  None:
                         param = param - 5
                         continue
               circles = np.uint16(np.around(circles))
               for i in circles[0 ,  : ]:
                         if  i[2]  >  r and i[2]  <  width / 2:
                                  r = i[2]
                                  x = i[0]
                                  y = i[1]
               break
      


7.预处理

pretreatment()

该函数是常规的图像预处理步骤,对图像进行灰度化、高斯滤波降噪、卷积模糊、边缘检测、形态学闭变换。

gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
img_thresh = cv.GaussianBlur(gray, (5, 5), 0)
kernel = np.ones((5, 5), np.float32) / 25
img_thresh = cv.filter2D(img_thresh, -1, kernel)
edges = cv.Canny(img_thresh, 50, 150, apertureSize=3)
Matrix = np.ones((2, 2), np.uint8)
img_edge = cv.morphologyEx(edges, cv.MORPH_CLOSE, Matrix)


findEllipse()

该函数主要通过cv.fitEllipse()函数来拟合椭圆,再对拟合出的多条椭圆进行多条件的筛选,其中一个重要的筛选条件就是根据初步预处理center()函数得到的大致范围。

    contours, hierarchy = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
    X, Y, ma, MA,angle = 0, 0, 0, 0, 0
    height, width, channels = img_copy.shape


    for   ind, cont  in  enumerate(contours):
         if (len(cont) > 5):
              (X0, Y0), (MA0, ma0), angle0 = cv.fitEllipse(cont)
              if  ma0 < min(width,height)  and  MA0 < max(width,height)  and  distance(X0, Y0, x, y) < 1 / 2 * r  and  ma0 > ma  and  MA0 > MA(等):
                   X, Y, MA, ma, angle = X0, Y0, MA0, ma0, angle0

8.透视变换纠正拍摄角度

findvertex()

points = []
img1 = np.zeros((img_copy.shape[0], img_copy.shape[1]), dtype=np.uint8)
cv.ellipse(img1, (int(X), int(Y)), (int(MA / 2), int(ma / 2)), angle, 0, 360, (255, 255, 255), 2)
img2 = np.zeros((img_copy.shape[0], img_copy.shape[1]), dtype=np.uint8)
cv.line(img2, (int(X - math.cos(angle) * ma), int(Y + math.sin(angle) * ma)),
        (int(X + math.cos(angle) * ma), int(Y - math.sin(angle) * ma)), (255, 255, 255), 1)
cv.line(img2, (int(X + math.sin(angle) * MA), int(Y + math.cos(angle) * MA)),
        (int(X - math.sin(angle) * MA), int(Y - math.cos(angle) * MA)), (255, 255, 255), 1)
for i in range(img_copy.shape[0]):
    for j in range(img_copy.shape[1]):
        if img1[i, j] > 0 and img2[i, j] > 0:
            points.append((j, i))
point = list([])
n = points[0][0]
for i in range(len(points)):
    if abs(points[i][0] - n) > 2:
        point.append(points[i])
        n = points[i][0]
point.append(points[0])
img3 = np.zeros((img_copy.shape[0], img_copy.shape[1]), dtype=np.uint8)
cv.ellipse(img3, (int(X), int(Y)), (int(MA / 2), int(ma / 2)), angle, 0, 360, (255, 255, 255), -1)
for i in range(img_copy.shape[0]):
    for j in range(img_copy.shape[1]):
        if img3[i, j] == 0:
            img_copy[i,j] = 255
order = []
order.append(point[np.argmin(point, axis=0)[1]])
order.append(point[np.argmax(point, axis=0)[1]])
order.append(point[np.argmin(point, axis=0)[0]])
order.append(point[np.argmax(point, axis=0)[0]])
return img_copy,order


...


创作时间: