机器视觉(仪表篇)

机器视觉(仪表篇)
Xxcy欢迎阅读机器视觉(仪表篇)笔记
1. 根据 0 刻度线计算仪表盘角度
基本工具类
```python
import numpy as np
import cv2
import os
import random
class Functions:
@staticmethod
def GetClockAngle(v1, v2):
# 向量模长
TheNorm = np.linalg.norm(v1) * np.linalg.norm(v2)
# 叉乘判断方向
rho = np.rad2deg(np.arcsin(np.cross(v1, v2) / TheNorm))
# 点乘计算角度
theta = np.rad2deg(np.arccos(np.dot(v1, v2) / TheNorm))
if rho > 0:
return 360 - theta
else:
return theta
@staticmethod
def Disttances(a, b):
x1, y1 = a
x2, y2 = b
return int(((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5)
@staticmethod
def couputeMean(deg):
mean = np.mean(deg)
percentile = np.percentile(deg, (25, 50, 75))
Q1 = percentile[0]
Q3 = percentile[2]
IQR = Q3 - Q1
ulim = Q3 + 2.5 * IQR
llim = Q1 - 1.5 * IQR
new_deg = [d for d in deg if llim < d < ulim]
return np.mean(new_deg)
class MeterDetection:
def init(self, path):
self.imageName = path.split(‘/‘)[-1].split(‘.’)[0]
self.outputPath = ‘outputs/‘
self.image = cv2.imread(path)
self.circleData = None
self.panMask = None
self.pointerMask = None
self.numLineMask = None
self.centerPoint = None
self.farPoint = None
self.zeroPoint = None
self.r = None
self.divisionValue = 100 / 360
self.makeFiledir()
self.markZeroPoint()
# 创建文件夹
def makeFiledir(self):
if not os.path.exists(self.outputPath):
os.makedirs(self.outputPath)
# 手动标记0刻度
def markZeroPoint(self):
img = self.image
def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
self.zeroPoint = [x, y]
cv2.circle(img, (x, y), 2, (120, 0, 255), -1)
cv2.imshow("image", img)
cv2.imshow("image", img)
cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN)
cv2.waitKey()
# 圆形检测
def ImgCutCircle(self):
img = self.image
dst = cv2.pyrMeanShiftFiltering(img, 10, 100)
gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
circles = cv2.HoughCircles(
gray,
cv2.HOUGH_GRADIENT,
1,
80,
param1=100,
param2=20,
minRadius=80,
maxRadius=0
)
if circles is None:
raise ValueError("未检测到表盘圆")
circles = np.uint16(np.around(circles))
r_1 = circles[0, 0, 2]
c_x = circles[0, 0, 0]
c_y = circles[0, 0, 1]
circle = np.ones(img.shape, dtype="uint8") * 255
cv2.circle(circle, (c_x, c_y), int(r_1), 0, -1)
bitwiseOr = cv2.bitwise_or(img, circle)
self.circleData = [r_1, c_x, c_y]
self.panMask = bitwiseOr
return bitwiseOr
# 轮廓筛选
def ContoursFilter(self):
r_1, c_x, c_y = self.circleData
img = self.panMask.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
binary = cv2.adaptiveThreshold(
~gray,
255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY,
15,
-10
)
contours, _ = cv2.findContours(
binary,
cv2.RETR_LIST,
cv2.CHAIN_APPROX_SIMPLE
)
cntset = []
needlecnt = []
radiusLength = [r_1 * 0.6, r_1 * 1]
localtion = []
for cnt in contours:
rect = cv2.minAreaRect(cnt)
(cx, cy), (w, h), angle = rect
if w == 0 or h == 0:
continue
dis = Functions.Disttances((c_x, c_y), (cx, cy))
if radiusLength[0] < dis < radiusLength[1]:
if h / w > 4 or w / h > 4:
cntset.append(cnt)
localtion.append(dis)
else:
needlecnt.append(cnt)
self.r = np.mean(localtion)
mask = np.zeros(img.shape[:2], np.uint8)
self.pointerMask = cv2.drawContours(mask.copy(), needlecnt, -1, 255, -1)
self.numLineMask = cv2.drawContours(mask.copy(), cntset, -1, 255, -1)
return cntset
# 计算最终值
def Readvalue(self):
try:
self.ImgCutCircle()
self.ContoursFilter()
# 示例:这里只保留核心流程
v1 = [
self.zeroPoint[0] - self.circleData[1],
self.circleData[2] - self.zeroPoint[1]
]
v2 = [0, -1] # 示例指针向量(简化)
theta = Functions.GetClockAngle(v1, v2)
readValue = self.divisionValue * theta
print("角度:", theta)
print("读数:", readValue)
return readValue
except Exception as e:
print("程序错误:", e)
评论
匿名评论隐私政策
Twikoo Valine
✅ 你无需删除空行,直接评论以获取最佳展示效果


