python 仪表盘图片读数_OpenCV 表盘指针自动读数的示例代码

本文介绍了如何使用Python和OpenCV库来处理仪表盘图片,通过提取红色区域、找到表盘中心、图像裁剪和极坐标转换,实现指针读数。方法包括径向灰度求和和Hough直线检测,能够有效识别表盘的长指针和短指针角度。但这种方法在指针重合和直线检测不完整时存在挑战,且角度计算较为复杂。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前段时间参加了一个表盘指针读数的比赛,今天来总结一下

数据集一共有一千张图片:

2020041010333632.jpg

方法一:径向灰度求和

基本原理:

将图像以表盘圆心转换成极坐标,然后通过矩阵按行求和找到二值图最大值即为指针尖端

导入需要用到的包

import cv2 as cv

import numpy as np

import math

from matplotlib import pyplot as plt

import os

图像预处理

去除背景:利用提取红色实现

def extract_red(image):

"""

通过红色过滤提取出指针

"""

red_lower1 = np.array([0, 43, 46])

red_upper1 = np.array([10, 255, 255])

red_lower2 = np.array([156, 43, 46])

red_upper2 = np.array([180, 255, 255])

dst = cv.cvtColor(image, cv.COLOR_BGR2HSV)

mask1 = cv.inRange(dst, lowerb=red_lower1, upperb=red_upper1)

mask2 = cv.inRange(dst, lowerb=red_lower2, upperb=red_upper2)

mask = cv.add(mask1, mask2)

return mask

2020041010333633.jpg

获得钟表中心:轮廓查找,取出轮廓的外接矩形,根据矩形面积找出圆心

def get_center(image):

"""

获取钟表中心

"""

edg_output = cv.Canny(image, 100, 150, 2) # canny算子提取边缘

cv.imshow('dsd', edg_output)

# 获取图片轮廓

contours, hireachy = cv.findContours(edg_output, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

center = []

cut=[0, 0]

for i, contour in enumerate(contours):

x, y, w, h = cv.boundingRect(contour) # 外接矩形

area = w * h # 面积

if area < 100 or area > 4000:

continue

cv.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 1)

cx = w / 2

cy = h / 2

cv.circle(image, (np.int(x + cx), np.int(y + cy)), 1, (255, 0, 0)) ## 在图上标出圆心

center = [np.int(x + cx), np.int(y + cy)]

break

return center[::-1]

2020041010333734.jpg

由上面的图像可以看出,圆心定位还是非常准确的

图片裁剪

def ChangeImage(image):

"""

图像裁剪

"""

# 指针提取

mask = extract_red(image)

mask = cv.medianBlur(mask,ksize=5)#去噪

# 获取中心

center = get_center(mask)

# 去除多余黑色边框

[y, x] = center

cut = mask[y-300:y+300, x-300:x+300]

# 因为mask处理后已经是二值图像,故不用转化为灰度图像

return cut

剪裁后的图像如下图所示:

### 使用OpenCV实现指针仪表盘读数识别 为了利用OpenCV进行指针仪表盘读数识别,整个过程可以分为几个主要阶段:像预处理、表盘提取、刻度线检测、指针定位以及最终数值计算。 #### 1. 像预处理 在开始任何复杂的像分析之前,通常需要先对原始像做一些基本的调整来改善后续步骤的效果。这可能涉及到灰度化转换、噪声去除(如高斯模糊)、边缘增强等操作[^2]。 ```python import cv2 import numpy as np def preprocess_image(image_path): img = cv2.imread(image_path) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0) # Canny Edge Detection edges = cv2.Canny(blurred, threshold1=30, threshold2=150) return edges ``` #### 2. 提取表盘 接下来是从背景中分离出实际的表盘区域。可以通过霍夫变换圆检测算法找到圆形边界,并据此裁剪出感兴趣的区域[^1]。 ```python def extract_dial(edges_img): circles = cv2.HoughCircles( edges_img, method=cv2.HOUGH_GRADIENT, dp=1, minDist=80, param1=100, param2=30, minRadius=70, maxRadius=140 ) if circles is not None: circle = circles[0][0] center_x, center_y, radius = map(int, circle) mask = np.zeros_like(edges_img) cv2.circle(mask, (center_x, center_y), radius, color=(255, 255, 255), thickness=-1) dial_region = cv2.bitwise_and(edges_img, mask) return dial_region, (center_x, center_y) else: raise ValueError("Failed to detect the dial.") ``` #### 3. 刻度线轮廓拟合直线 一旦获得了清晰的表盘像,则需进一步寻找其上的刻度标记。这些通常是沿着圆周分布的小短线或点。通过形态学运算和Hough Line Transform可以从二值化的边缘中提取到这些特征。 ```python def find_tick_marks(dial_region): lines = cv2.HoughLinesP( dial_region, rho=1, theta=np.pi / 180, threshold=50, minLineLength=10, maxLineGap=5 ) tick_points = [] for line in lines: x1, y1, x2, y2 = line[0] angle = np.arctan2(y2-y1, x2-x1)*180/np.pi # Filter out non-tick marks based on angles and lengths. if abs(angle) >= 60 or abs(angle) <= 120: continue mid_point = ((x1+x2)/2, (y1+y2)/2) tick_points.append(mid_point) return tick_points ``` #### 4. 指针定位 对于指针本身来说,由于它往往具有较长且连续的特点,在经过适当阈值分割后的二值里应该很容易被发现。同样采用霍夫变换中的直线检测功能可以帮助精确定位指针的位置。 ```python def locate_needle(dial_region): needle_lines = cv2.HoughLinesP( dial_region, rho=1, theta=np.pi / 180, threshold=30, minLineLength=50, maxLineGap=10 ) longest_line_length = 0 best_fit_line = None for line in needle_lines: x1, y1, x2, y2 = line[0] length = np.sqrt((x2 - x1)**2 + (y2 - y1)**2) if length > longest_line_length: longest_line_length = length best_fit_line = [(x1,y1),(x2,y2)] return best_fit_line ``` #### 5. 数值计算 最后一步就是根据已知条件——比如零刻度位置、最大量程范围以及当前指针指向的角度——来进行相应的数学运算得出具体的测量结果。 ```python from math import atan2, degrees def calculate_reading(ticks_positions, needle_endpoints, zero_degree_position, full_scale_degrees): cx, cy = ticks_positions.mean(axis=0).astype('int') start_angle = degrees(atan2(*reversed(np.subtract(zero_degree_position, (cx,cy))))) end_angle = degrees(atan2(*reversed(np.subtract(needle_endpoints[-1], (cx,cy))))) reading_percentage = (end_angle-start_angle)%full_scale_degrees/full_scale_degrees*100 return round(reading_percentage, 2) ``` 上述代码片段展示了如何一步步构建起一套完整的指针式仪表板自动读数系统。当然,具体应用时还需要针对不同类型的仪器做些微调适配工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值