Yolo opencv刻度尺识别 刻度读数识别 水尺识别 水位识别源码

刻度识别项目

    • 简介
    • 实现效果
    • 实现流程
    • 实现原理
      • 刻度尺的标定
        • 指针位置标定
        • 读数位置标定
        • 刻度线标定
      • 数字检测
      • 数字分割
      • 数字识别
    • web部署
    • 附录


简介

好久不见了,我看了一下我最近的博客到现在已经3个月时间没更新了。这是因为我最近都在忙毕业设计,所以一直没有时间更新。我这三个月的收获还是丰富的,最近会慢慢通过博客和大家分享。现在马上水上一篇吧。如果大家有看过我的EAST文本检测器应用这一篇博客的话,可能会好奇我最后的gif demo是怎么完成的。那个其实是我大三的一个srp项目。现在我就介绍一下它。


实现效果

需求不用啰嗦,直接看看效果即可,其实我也是做得比较简单,还有很多可以改进的地方。

1. demo1

在这里插入图片描述

2. demo2

在这里插入图片描述


实现流程

我完成上述的基本功能主要包含以下即可步骤。

  • 刻度尺的标定
  • 数字位置的检测和分割
  • 数字识别
  • 结果可视化
  • 部署到web

其中,✔的是必须的,而其余的是个性化的可选项。


实现原理


刻度尺的标定

刻度尺的标定是非常重要的一环。考虑到刻度尺位置是相对固定的,因此通过简单的人工标定过程就可以知道指针、刻度和数字的相对位置。当然也可以用如今非常厉害的基于深度学习的目标检测技术,大家可以自行发挥。

下面是标定的示意图:
在这里插入图片描述
从demo中可以看到整个读数系统可以象形地作成上图。需要关注的是:1)指针的位置;2)刻度尺读数的位置,我们不妨假定我们可以框出数字,那么框框的中心坐标就是读数的位置;3)读数到指针所指位置的距离;首先数字的起始位置都是有一条粗黑实线,然后得到的实线到指针的像素距离需要转换成实际的刻度距离。


指针位置标定

指针位置标定非常简单,因为其一般呈现等腰三角形,我们把它的边缘绘制出来,然后求其角平分线,就得到指针的指向。

在这里插入图片描述
我的标定程序需要从上往下按顺序指定三个红点,指定后自动连接绿线(指针边缘),然后自动生成其角平分线(蓝线),整个程序是交互式的,执行过程有提示信息,最终标定文件会自动保存,下次使用时加载标定文件即可。


读数位置标定

假定我们得到离指针位置最近的数字的中心像素坐标,但我们还需要知道这个像素坐标离它低下那条粗黑实线有多远。在这里,我假定这个中心坐标的y坐标y c y_c yc​和粗实线所在的y坐标y b y_b yb​存在二次函数的关系,这其实并不严格,只是感觉。所以有:
y b = a y c 2 + b y c + c y_b = ay_c^2 + by_c + c yb​=ayc2​+byc​+c
这样,我们对多张图片的多个位置标定出( y c , y b ) (y_c, y_b) (yc​,yb​),我们就可以拟合出系数。

在这里插入图片描述
程序需要人工框出所有数字,会自动返回红色中心点;然后人工点出黑色实线(蓝点),程序采集足够多组样本之后就可以拟合,生成拟合曲线:

在这里插入图片描述
这个拟合关系还是不错的。


刻度线标定

我们现在可以推出起始的粗实线的坐标,我们还需要知道:1)指针指向和刻度尺的交点(结束坐标);2)像素距离到刻度尺距离的转换。首先,我们先标定刻度,如下所示:
在这里插入图片描述
按从下到上或相反的顺序点出刻度,而且尽量使点排成大致的直线,这是因为在采集多张图以后,程序会把这个直线拟合出来。拟合出的刻度直线,和最开始标定出来的指针的角平分线求交点,得到的y轴方向坐标就是结束坐标。

有开始坐标和结束坐标,就还剩下距离转换的问题了。在这里我也是在此假设,任一y轴坐标y 0 y_0 y0​,它的上一个刻度和下一个刻度的像素增量δ y ↑ , δ y ↓ \delta y_{\uparrow}, \delta y_{\downarrow} δy↑​,δy↓​也存在二次函数的关系,即:
δ y ↑ = a ↑ y 0 2 + b ↑ y 0 + c ↑ δ y ↓ = a ↓ y 0 2 + b ↓ y 0 + c ↓ \delta y_{\uparrow} = a_{\uparrow}y_0^2 + b_{\uparrow}y_0 + c_{\uparrow} \\ \delta y_{\downarrow} = a_{\downarrow}y_0^2 + b_{\downarrow}y_0 + c_{\downarrow} \\ δy↑​=a↑​y02​+b↑​y0​+c↑​δy↓​=a↓​y02​+b↓​y0​+c↓​
和上面一样,采集足够的样本之后拟合,拟合效果如下:
在这里插入图片描述
可见效果还是可以的。拟合之后,假定我们起始坐标和结束坐标为y s , y e y_s,y_e ys​,ye​。那么我们可以求出y s y_s ys​下一个刻度的像素坐标:
y s , 1 = y s + δ y s = a ↓ y s 2 + ( b ↓ + 1 ) y s + c ↓ y_{s,1} = y_s + \delta y_s = a_{\downarrow}y_s^2 + (b_{\downarrow}+1)y_s + c_{\downarrow} ys,1​=ys​+δys​=a↓​ys2​+(b↓​+1)ys​+c↓​
不断重复上述过程,我们可以求出毫米级读数y s , k ≤ y e ≤ y s , k + 1 y_{s,k} \le y_e \le y_{s,k+1} ys,k​≤ye​≤ys,k+1​。如果需要取两位小数,那么在这个区间等比例取就可以了。


数字检测

数字检测使用我之前的博客提到的EAST模型,里面详细介绍了如何配置和使用,模型输入原图片,返回数字的中心坐标。


数字分割

本人数字分割使用的同样是比较传统的方法。首先,将图像转化为灰度图,然后使用OTSU方法对图片进行二值化。最后,对二值化的图片使用MSER算法,这个算法可以有效地抠出连通域。这样的话我们就得到单个分割的数字了。

mser = cv2.MSER_create(_min_area=min_area, _max_area=max_area)
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)		# 转为灰度图
_, img = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)	# 二值化
_, boxes = self.mser.detectRegions(img)		# MSER分割


数字识别

容易发现,我们需要识别的数字都是印刷体的。所以,数据集只需要印刷体数字0~9即可,你可能会觉得找数据集是件麻烦事,但印刷体数据集是可以用opencv生成的。这一部分我参考了开源项目digitx,它非常详细地给出了生成数据集和数据增强的方案,并且训练了一个简单的CNN实现了高效的数字识别。


web部署

本人使用flask实现,但使用本地电脑作为服务器部署后只能供局域网访问,如果需要让国内的朋友都能访问的话,可以申请一个公网的服务器,比如阿里云等,然后把代码放到上面运行,别人就可以访问了。


附录

完整代码见:github

如有问题,可以加下面二维码咨询

Yolo opencv刻度尺识别 刻度读数识别 水尺识别 水位识别源码_第1张图片

 

你可能感兴趣的:(java,python,golang)