最近遇到一个问题,如何读取仪表中的指针指向的刻度

解决方法有多种,比如,方案一:模板匹配+边缘检测+霍夫直线检测,方案二:神将网络(CNN)目标定位等,

其中CNN就有点麻烦了,需要一定数量的训练样本,太麻烦,而方案一太普通,最后我采用了方案三,

方案三:模板匹配+k-means+直线拟合

具体做法如下:

首先说一下模板匹配,它是OpenCV自带的一个算法,可以根据一个模板图到目标图上去寻找对应位置,如果模板找的比较好那么效果显著,这里说一下寻找模板的技巧,模板一定要标准、精准且特征明显。

第一次的模板选取如下:

匹配的效果如下:

根据模板选取的原则我们,必须进行两次匹配才能的到精确和更高准确率的结果

第二次的模板如下:

然后在第一次结果的的基础上也就是蓝色矩形框区域进行第二次匹配,结果如下:

下面对上图进行k-means二值化,由于途中的阴影,所以只截取原图的0.6(从中心)作为k-means聚类的样本点,然后将聚类结果应用至上图并重新二值化(聚类结果为2,求中值,根据中值二值化),同时只保留内切圆部分,效果如下:

接下来就是拟合直线,拟合直线我采用旋转虚拟直线法,假设一条直线从右边0度位置顺时针绕中心旋转当它转到指针指向的位置时重合的最多,此时记录下角度,最后根据角度计算刻度值。效果图如下:

最后就读取到了数值:

聚类结果:

[[31.99054054 23.04324324 14.89054054]
 [62.69068323 53.56024845 40.05652174]]
重合数量和对应角度: (1566, 158) 
对应刻度:36.005082940886126

源码如下:

import cv2
import numpy as np
from sklearn.cluster import KMeans
from sklearn.utils import shuffle
from math import cos, pi, sin
from 计算刻度值 import get_rad_valmethods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR','cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
method = cv2.TM_CCOEFFdef get_match_rect(template,img,method):'''获取模板匹配的矩形的左上角和右下角的坐标'''w, h = template.shape[1],template.shape[0]res = cv2.matchTemplate(img, template, method)mn_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)# 使用不同的方法,对结果的解释不同if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:top_left = min_locelse:top_left = max_locbottom_right = (top_left[0] + w, top_left[1] + h)return top_left,bottom_rightdef get_center_point(top_left,bottom_right):'''传入左上角和右下角坐标,获取中心点'''c_x, c_y = ((np.array(top_left) + np.array(bottom_right)) / 2).astype(np.int)return c_x,c_ydef get_circle_field_color(img,center,r,thickness):'''获取中心圆形区域的色值集'''temp=img.copy().astype(np.int)cv2.circle(temp,center,r,-100,thickness=thickness)return img[temp == -100]def v2_by_center_circle(img,colors):'''二值化通过中心圆的颜色集合'''for i in range(img.shape[0]):for j in range(img.shape[1]):a = img[i, j]if a in colors:img[i, j] = 0else:img[i, j] = 255def v2_by_k_means(img):'''使用k-means二值化'''original_img = np.array(img, dtype=np.float64)src = original_img.copy()delta_y = int(original_img.shape[0] * (0.4))delta_x = int(original_img.shape[1] * (0.4))original_img = original_img[delta_y:-delta_y, delta_x:-delta_x]h, w, d = src.shapeprint(w, h, d)dts = min([w, h])print(dts)r2 = (dts / 2) ** 2c_x, c_y = w / 2, h / 2a: np.ndarray = original_img[:, :, 0:3].astype(np.uint8)# 获取尺寸(宽度、长度、深度)height, width = original_img.shape[0], original_img.shape[1]depth = 3print(depth)image_flattened = np.reshape(original_img, (width * height, depth))'''用K-Means算法在颜色样本中建立2个类。'''image_array_sample = shuffle(image_flattened, random_state=0)estimator = KMeans(n_clusters=2, random_state=0)estimator.fit(image_array_sample)'''我们为原始图片的每个像素进行类的分配。'''src_shape = src.shapenew_img_flattened = np.reshape(src, (src_shape[0] * src_shape[1], depth))cluster_assignments = estimator.predict(new_img_flattened)compressed_palette = estimator.cluster_centers_print(compressed_palette)a = np.apply_along_axis(func1d=lambda x: np.uint8(compressed_palette[x]), arr=cluster_assignments, axis=0)img = a.reshape(src_shape[0], src_shape[1], depth)print(compressed_palette[0, 0])threshold = (compressed_palette[0, 0] + compressed_palette[1, 0]) / 2img[img[:, :, 0] > threshold] = 255img[img[:, :, 0] < threshold] = 0cv2.imshow('sd0', img)for x in range(w):for y in range(h):distance = ((x - c_x) ** 2 + (y - c_y) ** 2)if distance > r2:passimg[y, x] = (255, 255, 255)cv2.imshow('sd', img)cv2.waitKey(0)cv2.destroyAllWindows()return imgdef get_pointer_rad(img):'''获取角度'''shape = img.shapec_y, c_x, depth = int(shape[0] / 2), int(shape[1] / 2), shape[2]x1=c_x+c_x*0.8src = img.copy()freq_list = []for i in range(361):x = (x1 - c_x) * cos(i * pi / 180) + c_xy = (x1 - c_x) * sin(i * pi / 180) + c_ytemp = src.copy()cv2.line(temp, (c_x, c_y), (int(x), int(y)), (0, 0, 255), thickness=3)t1 = img.copy()t1[temp[:, :, 2] == 255] = 255c = img[temp[:, :, 2] == 255]points = c[c == 0]freq_list.append((len(points), i))cv2.imshow('d', temp)cv2.imshow('d1', t1)cv2.waitKey(1)print('当前角度:',max(freq_list, key=lambda x: x[0]),'度')cv2.destroyAllWindows()return max(freq_list, key=lambda x: x[0])if __name__ == '__main__':for x in range(1,32):#获取测试图像img_s = cv2.imread('test/ (%s).jpg'%x)img=cv2.cvtColor(img_s,cv2.COLOR_BGR2GRAY)template = cv2.imread('template1.png')template=cv2.cvtColor(template,cv2.COLOR_BGR2GRAY)#匹配并返回矩形坐标top_left,bottom_right=get_match_rect(template,img,method)c_x,c_y=get_center_point(top_left,bottom_right)print(c_x,c_y)#绘制矩形cv2.rectangle(img_s, top_left, bottom_right, 255, 2)cv2.imshow('img',cv2.resize(img_s,(int(img.shape[1]*0.5),int(img.shape[0]*0.5))))cv2.waitKey(0)cv2.destroyAllWindows()#################################################################new = img_s[top_left[1]:bottom_right[1] + 1, top_left[0]:bottom_right[0] + 1]template = cv2.imread('template.png')top_left, bottom_right = get_match_rect(template, new, method=method)new_ = new[top_left[1]:bottom_right[1] + 1, top_left[0]:bottom_right[0] + 1]# 二值化图像cv2.imshow('ererss',new_)img=v2_by_k_means(new_)rad=get_pointer_rad(img)#################################################################print(get_rad_val(rad[1]),'对应刻度')

完整源码下载地址 :https://download.csdn.net/download/a1053904672/11052037

使用OpenCV进行仪表数值读取相关推荐

  1. 【python opencv 计算机视觉零基础到实战】二、 opencv文件格式与摄像头读取

    一.学习目标 了解图片的结构属性 了解如何捕获视频 了解waitkey的使用方法 目录 [python opencv 计算机视觉零基础到实战] 一.opencv的helloworld [[python ...

  2. OpenCV使用VideoCapture界面读取一系列图像的实例(附完整代码)

    OpenCV使用VideoCapture界面读取一系列图像的实例 OpenCV使用VideoCapture界面读取一系列图像的实例 OpenCV使用VideoCapture界面读取一系列图像的实例 # ...

  3. OpenCV C++入门,读取和显示一张图片

    文章目录 一.OpenCV C++入门,读取和显示一张图片 二.代码如下 三.类和函数介绍 一.OpenCV C++入门,读取和显示一张图片 OpenCV入门程序,简单显示一张图片. 二.代码如下 # ...

  4. 贾志刚-OpenCV下的图片读取,摄像头调用

    贾志刚-OpenCV下的图片读取,摄像头调用 运行环境:Window10 + Python3.6 + PyCharm OpenCV3 import cv2 as cv import numpy as ...

  5. C++ opencv 4.5 imread() 读取图片,显示为空的解决办法

    C++ opencv 4.5 imread() 读取图片,显示为空的解决办法 一.路径问题 先查看下路径问题,如果使用的是相对路径,先查看下当前路径,判断输入的路径是否有错: #include < ...

  6. OpenCV的imread函数读取图片的路径选择相关问题

    OpenCV的imread函数读取图片的路径选择相关问题 本文参考了几位博主的帖子. https://blog.csdn.net/sss_369/article/details/87740843 读取 ...

  7. opencv 修改图像数值_opencv 修改图像数值_Python中使用OpenCV读取像素

    如何在Python中遍历像素呢?请看代码: import numpy as np import cv2 import matplotlib.pyplot as plt src = cv2.imread ...

  8. videocapture 保存图片_RoboMaster视觉教程OpenCV(二)读取视频图像与转换

    RoboMaster视觉教程OpenCV(二)读取视频图像与转换 在Robomaster比赛中,读取视频或者图像是极其重要的.因为我们需要在热身赛的时候用摄像头保存一段视频或者图片.之后根据视频中的光 ...

  9. 3h精通OpenCV(一)- 读取图像视频与网络摄像头

    0.准备工作 右击新建的项目,选择Python File,新建一个Python文件,然后在开头import cv2导入cv2库. 1.读取图像 调用imread()方法获取我们资源文件夹中的图片 使用 ...

最新文章

  1. (0044) iOS 开发之SDWebImage 深度学习其源码和原理
  2. tomcat与jvm的关系分析
  3. python中str和int区别_Python如何比较string和int?
  4. 同方自主可控系统服务器,自主可控 同方超强TR1210服务器!
  5. extjs 表头居中,数据靠左的写法
  6. 关于Tomcat配置虚拟路径保存、访问图片
  7. treeReduce和reduce
  8. 【Java从0到架构师】SpringMVC - 特殊的请求参数
  9. DataTable 去重合并
  10. 包装应由厂家回收利用
  11. 最难游戏2计算机5关,最囧游戏2第5关通关攻略
  12. 音乐API(仅测试使用)
  13. centos官网下载地址
  14. 夜光:Java语言基础学习笔记(三)在校资源
  15. 100层楼,2个鸡蛋,最少要几次才能测试出鸡蛋能承受的最大楼层?
  16. 如何从零基础入门并精通PS?PS如何快速入门?
  17. android studio 两个工程 引用同一个库,一个可以,另一个不可以
  18. Ruby之旅之字符串
  19. 每周一篇 文献阅读—pape9 (用于单图像去雾的特征融合注意网络FFA-Net)
  20. shell小练(二)(图形千变万化)

热门文章

  1. CSP认证题解第一题
  2. ASP.NET学习篇之——与ASP的区别
  3. 如何解决中文字体加载缓慢的问题?
  4. 在linux下使用视频采集卡
  5. mongoTemplate 常见操作
  6. [opencv] 练习题实现 使用轨迹栏创建颜色和画笔半径可调的Paint应用程序。有关绘制的信息,请参阅有关鼠标处理的先前教程。
  7. 给自己一个清晰的目标
  8. Java操作文件Path 和 Paths 及Files类介绍
  9. 3G技术的宠儿CDMA2000 1X
  10. echarts每个柱条设置不同的颜色