巡检机器人图像识别:调节阀锈蚀、泄漏与仪表状态检测
“一个调节阀的微小渗漏,人工巡检可能要几天才能发现,但机器人配合视觉算法,30秒内就能精准定位并报警。”
—— 基于哈尔滨工程大学《工业过程控制》第十二章“过程控制系统的故障检测与诊断”与第八章“智能控制基础”
一、实际应用场景描述
在石油化工、天然气、精细化工等流程工业中,巡检机器人正逐步替代人工执行高危区域巡检任务:
┌──────────────────────────────────────────────────────┐
│ 巡检机器人视觉检测系统架构 │
│ │
│ [巡检机器人本体] │
│ • 激光导航/SLAM定位 │
│ • 防爆云台(水平360°/垂直±90°) │
│ • 高清工业相机(200万像素,全局快门) │
│ • 补光灯(自适应亮度调节) │
│ • 边缘计算单元(Jetson Xavier/Intel NUC) │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ 视觉预处理模块(边缘端) │ │
│ │ • 图像去噪(高斯滤波/双边滤波) │ │
│ │ • 亮度均衡(CLAHE自适应直方图均衡) │ │
│ │ • 畸变校正(相机内参标定) │ │
│ │ • 感兴趣区域提取(ROI) │ │
│ └──────────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ 核心检测算法(本工具重点) │ │
│ │ ┌────────────┐ ┌────────────┐ │ │
│ │ │ 锈蚀检测 │ │ 泄漏检测 │ │ │
│ │ │ • 颜色特征 │ │ • 纹理异常 │ │ │
│ │ │ • 纹理分析 │ │ • 光流分析 │ │ │
│ │ │ • 边缘缺陷 │ │ • 气泡检测 │ │ │
│ │ └────────────┘ └────────────┘ │ │
│ │ │ │ │ │
│ │ ▼ ▼ │ │
│ │ ┌────────────────────────────────────┐ │ │
│ │ │ 仪表指示灯状态识别 │ │ │
│ │ │ • HSV颜色分割 │ │ │
│ │ │ • 圆形检测(Hough变换) │ │ │
│ │ │ • 亮度阈值判断 │ │ │
│ │ └────────────────────────────────────┘ │ │
│ └──────────────┬───────────────────────────┘ │
│ │ 检测结果+置信度 │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ 上位机监控与报警系统 │ │
│ │ • 实时视频流显示 │ │
│ │ • 缺陷标注与截图保存 │ │
│ │ • 分级报警(一般/严重/紧急) │ │
│ │ • 生成巡检报告(PDF/Excel) │ │
│ │ • 联动DCS系统(触发维护工单) │ │
│ └──────────────────────────────────────────┘ │
│ │
│ 典型巡检流程: │
│ 1. 机器人导航至预设点位 → 2. 云台对准目标 │
│ 3. 采集高清图像 → 4. 边缘端预处理 │
│ 5. 并行执行三项检测 → 6. 结果融合与置信度计算 │
│ 7. 上传结果至上位机 → 8. 触发报警/生成工单 │
└──────────────────────────────────────────────────────┘
典型应用场景
场景 检测目标 风险等级 检测难点
炼油厂管廊 调节阀法兰、阀杆 极高 油污覆盖、光线昏暗
天然气站场 阀门密封、压力表 极高 防爆要求、振动干扰
化工厂反应区 调节阀、仪表盘 高 腐蚀严重、背景复杂
海上平台 阀门、仪表、管线 高 盐雾腐蚀、高湿环境
制药洁净区 隔膜阀、传感器 中 反光干扰、洁净度要求
二、引入痛点
2.1 现场的真实困境
场景 现场反馈 根因
“看不见” “阀门在管廊深处,手电筒照不到,根本看不清” 人工视野受限,光线不足
“看不准” “以为是锈迹,结果是油污,白跑一趟” 人工主观判断,误报率高
“看不快” “一个阀门要蹲下看半天,巡检一圈要2小时” 人工效率低,覆盖不全
“看不全” “漏检了背面的泄漏点,一周后才发现” 人工视角固定,盲区多
“记不住” “上次巡检啥样记不清了,不知道有没有恶化” 缺乏历史对比,趋势不明
“报不上” “发现泄漏了,打电话上报要10分钟” 信息传递延迟,响应慢
2.2 核心矛盾
巡检机器人视觉检测的核心矛盾是“工业现场复杂环境”与“高精度检测要求”之间的不匹配。
现场存在油污、反光、阴影、振动等干扰,传统图像处理方法鲁棒性不足,而深度学习需要大量标注数据,两者都需要结合工业过程控制知识进行优化。
2.3 三种解决思路
思路 核心思想 优势 劣势
传统图像处理 颜色/纹理/边缘特征 实时性好,无需训练 鲁棒性差,参数敏感
深度学习 CNN目标检测/分割 精度高,适应性强 需要大量标注数据,算力要求高
混合方法 传统+深度学习结合 平衡精度与效率 系统复杂度高
三、核心逻辑讲解
3.1 理论基础:故障检测与诊断
本工具基于哈工程《工业过程控制》第十二章“过程控制系统的故障检测与诊断”:
① 基于解析模型的故障检测
J = \| y - \hat{y} \| > \eta
其中:
- y :实际观测值(图像特征)
- \hat{y} :模型预测值(正常状态模板)
- J :残差(异常程度)
- \eta :阈值(根据历史数据统计确定)
② 调节阀典型故障模式
故障类型 表现形式 图像特征 检测方法
锈蚀 表面红褐色斑点/剥落 颜色(R通道增强)、纹理粗糙化 HSV颜色分割+纹理分析
外泄漏 阀杆/法兰处液滴、湿润 局部反光异常、纹理不连续 光流法+局部二值模式
内泄漏 阀位指示异常、压力波动 需结合仪表读数(间接检测) 仪表识别+过程数据融合
卡涩 阀位反馈与指令不一致 需结合阀位变送器(间接检测) 阀位识别+控制回路分析
③ 仪表指示灯状态识别
仪表指示灯识别流程:
1. 定位仪表盘区域(模板匹配/边缘检测)
2. 检测圆形指示灯(Hough圆变换)
3. 提取HSV颜色特征:
• 红色: H∈[0,10]∪[170,180], S>50, V>50
• 绿色: H∈[40,80], S>50, V>50
• 黄色: H∈[20,40], S>50, V>50
4. 计算区域平均亮度
5. 状态判断:
• 亮红灯: 报警状态
• 亮绿灯: 正常运行
• 亮黄灯: 预警状态
• 不亮: 电源故障/灯泡损坏
3.2 图像处理算法核心逻辑
锈蚀检测算法流程:
输入: 调节阀RGB图像 I(x,y)
Step 1: 预处理
I_gray = RGB2Gray(I)
I_denoised = GaussianBlur(I_gray, σ=1.5)
I_clahe = CLAHE(I_denoised, clipLimit=2.0)
Step 2: 颜色特征提取(锈蚀关键特征)
I_hsv = RGB2HSV(I)
R_enhanced = I[:,:,0] * 1.5 # 增强红色通道
Rust_mask = (H∈[0,30] ∪ [150,180]) ∩ (S>50) ∩ (V>30)
Step 3: 纹理特征提取
Gabor_filter_bank = 多尺度多方向Gabor滤波器组
Texture_features = Gabor_filter_bank * I_gray
粗糙度 = var(Texture_features)
Step 4: 边缘缺陷检测
Edges = Canny(I_clahe, low_thresh=50, high_thresh=150)
边缘密度 = sum(Edges) / area
Step 5: 特征融合与分类
Rust_score = w1*R_enhanced + w2*粗糙度 + w3*边缘密度
if Rust_score > threshold:
判定为锈蚀
计算锈蚀面积占比
Step 6: 结果输出
返回: 锈蚀位置、面积、严重程度等级
泄漏检测算法流程:
输入: 连续两帧图像 I1(x,y), I2(x,y)
Step 1: 光流场计算
Flow = FarnebackOpticalFlow(I1, I2)
Magnitude = √(Flow_x² + Flow_y²)
Angle = arctan2(Flow_y, Flow_x)
Step 2: 异常区域检测
# 泄漏点通常表现为局部纹理变化
Gradient_x = Sobel(I1, dx=1)
Gradient_y = Sobel(I1, dy=1)
Gradient_mag = √(Gradient_x² + Gradient_y²)
# 寻找局部极值(泄漏点特征)
Local_max = dilate(Gradient_mag) - Gradient_mag
Leak_candidates = Local_max > threshold
Step 3: 气泡/液滴检测(针对明显泄漏)
# 使用LoG(Laplacian of Gaussian)检测圆形斑点
LoG_filter = ∇²G_σ * I1
Blob_centers = find_zero_crossings(LoG_filter)
# 验证圆形度
for center in Blob_centers:
circularity = 4π*area/perimeter²
if 0.7 < circularity < 1.2:
确认为液滴/气泡
Step 4: 时序验证(减少误报)
连续N帧均检测到异常 → 确认为泄漏
单帧异常 → 判定为噪声/误报
Step 5: 结果输出
返回: 泄漏位置、泄漏程度、置信度
3.3 置信度计算与决策融合
多算法融合决策:
1. 单算法置信度计算:
• 锈蚀检测置信度 = f(颜色纯度, 纹理复杂度, 边缘密度)
• 泄漏检测置信度 = f(光流强度, 纹理异常度, 时序一致性)
• 仪表识别置信度 = f(圆形度, 颜色纯度, 亮度均匀性)
2. 加权融合:
Final_confidence = Σ(w_i * Confidence_i)
其中: Σw_i = 1
权重分配(基于历史准确率):
• 锈蚀检测: w1 = 0.4
• 泄漏检测: w2 = 0.4
• 仪表识别: w3 = 0.2
3. 决策阈值:
• Confidence > 0.8: 确认故障,紧急报警
• 0.6 < Confidence < 0.8: 疑似故障,人工复核
• Confidence < 0.6: 正常,记录存档
4. 故障严重程度分级:
• 一级(紧急): 泄漏面积>5cm² 或 锈蚀面积>30%
• 二级(严重): 泄漏面积1-5cm² 或 锈蚀面积10-30%
• 三级(一般): 泄漏面积<1cm² 或 锈蚀面积<10%
四、代码讲解(面向对象设计)
4.1 类结构总览
类名 职责 设计模式
"DetectionConfig" 检测算法配置(dataclass) 值对象
"DefectType" 缺陷类型枚举 枚举类型
"SeverityLevel" 严重程度枚举 枚举类型
"DetectionResult" 检测结果(dataclass) 值对象
"ImagePreprocessor" 图像预处理 策略模式
"RustDetector" 锈蚀检测算法 单一职责
"LeakDetector" 泄漏检测算法 单一职责
"IndicatorDetector" 仪表指示灯检测 单一职责
"DecisionFusion" 多算法决策融合 策略模式
"InspectionRobot" 巡检机器人(聚合根) 聚合根
4.2 核心代码(精简版,CSDN友好)
完整源码约 450 行,单文件,包含 9 个核心类 + 完整检测逻辑。
以下为关键类摘录,完整代码见附件。
"""
巡检机器人视觉检测:调节阀锈蚀、泄漏与仪表状态识别
参考哈尔滨工程大学《工业过程控制》第十二章"故障检测与诊断"
"""
from dataclasses import dataclass, field
from typing import List, Tuple, Optional, Dict, Any
from enum import Enum, auto
import numpy as np
import cv2
import logging
from abc import ABC, abstractmethod
from collections import deque
import time
# ============================================================
# 1. 基础数据结构(枚举与值对象)
# ============================================================
class DefectType(Enum):
"""缺陷类型"""
RUST = "锈蚀"
LEAK = "泄漏"
INDICATOR_FAULT = "指示灯异常"
NORMAL = "正常"
class SeverityLevel(Enum):
"""严重程度"""
EMERGENCY = 1 # 紧急(红色)
CRITICAL = 2 # 严重(橙色)
WARNING = 3 # 警告(黄色)
NORMAL = 4 # 正常(绿色)
@dataclass
class DetectionConfig:
"""检测算法配置"""
# 锈蚀检测参数
rust_hsv_lower1: Tuple[int, int, int] = (0, 50, 50)
rust_hsv_upper1: Tuple[int, int, int] = (10, 255, 255)
rust_hsv_lower2: Tuple[int, int, int] = (170, 50, 50)
rust_hsv_upper2: Tuple[int, int, int] = (180, 255, 255)
rust_min_area: int = 100
rust_texture_threshold: float = 0.3
# 泄漏检测参数
leak_flow_threshold: float = 1.5
leak_blob_min_area: int = 50
leak_blob_max_area: int = 5000
leak_circularity_min: float = 0.6
leak_temporal_frames: int = 3
# 仪表检测参数
indicator_hough_dp: float = 1.2
indicator_hough_min_dist: float = 20
indicator_hough_param1: int = 50
indicator_hough_param2: int = 30
indicator_min_radius: int = 10
indicator_max_radius: int = 50
# 决策融合参数
rust_weight: float = 0.4
leak_weight: float = 0.4
indicator_weight: float = 0.2
confidence_threshold: float = 0.6
@dataclass
class DetectionResult:
"""检测结果"""
defect_type: DefectType
severity: SeverityLevel
confidence: float
bbox: Optional[Tuple[int, int, int, int]] = None # (x, y, w, h)
area: float = 0.0
center: Optional[Tuple[int, int]] = None
details: Dict[str, Any] = field(default_factory=dict)
timestamp: float = field(default_factory=time.time)
def to_dict(self) -> Dict:
"""转换为字典(便于序列化)"""
return {
'defect_type': self.defect_type.value,
'severity': self.severity.name,
'confidence': round(self.confidence, 3),
'bbox': self.bbox,
'area': round(self.area, 2),
'center': self.center,
'details': self.details,
'timestamp': self.timestamp
}
# ============================================================
# 2. 图像预处理(策略模式)
# ============================================================
class ImagePreprocessor:
"""图像预处理类"""
def __init__(self, config: DetectionConfig):
self.config = config
logging.info("[Preprocessor] 图像预处理器初始化")
def preprocess(self, image: np.ndarray) -> np.ndarray:
"""完整预处理流程"""
# 1. 转换为灰度图
if len(image.shape) == 3:
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
else:
gray = image.copy()
# 2. 高斯滤波去噪
denoised = cv2.GaussianBlur(gray, (5, 5), 1.5)
# 3. CLAHE自适应直方图均衡
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
enhanced = clahe.apply(denoised)
# 4. 边缘增强
kernel = np.array([[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]])
sharpened = cv2.filter2D(enhanced, -1, kernel)
return sharpened
def extract_hsv(self, image: np.ndarray) -> np.ndarray:
"""提取HSV特征"""
if len(image.shape) == 3:
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
else:
# 灰度图转伪HSV
hsv = cv2.cvtColor(cv2.cvtColor(image, cv2.COLOR_GRAY2BGR),
cv2.COLOR_BGR2HSV)
return hsv
# ============================================================
# 3. 锈蚀检测算法(单一职责)
# ============================================================
class RustDetector:
"""
锈蚀检测算法
基于哈工程《工业过程控制》第十二章"故障检测与诊断"
核心思想: 锈蚀表现为红褐色颜色特征 + 粗糙纹理特征
"""
def __init__(self, config: DetectionConfig):
self.config = config
self.preprocessor = ImagePreprocessor(config)
logging.info("[RustDetector] 锈蚀检测器初始化")
def detect(self, image: np.ndarray) -> DetectionResult:
"""执行锈蚀检测"""
# 1. 预处理
hsv = self.preprocessor.extract_hsv(image)
# 2. HSV颜色分割(锈蚀特征:红褐色)
mask1 = cv2.inRange(hsv,
self.config.rust_hsv_lower1,
self.config.rust_hsv_upper1)
mask2 = cv2.inRange(hsv,
self.config.rust_hsv_lower2,
self.config.rust_hsv_upper2)
rust_mask = cv2.bitwise_or(mask1, mask2)
# 3. 形态学操作去噪
kernel = np.ones((5, 5), np.uint8)
rust_mask = cv2.morphologyEx(rust_mask, cv2.MORPH_CLOSE, kernel)
rust_mask = cv2.morphologyEx(rust_mask, cv2.MORPH_OPEN, kernel)
# 4. 查找轮廓
contours, _ = cv2.findContours(rust_mask,
cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
# 5. 筛选有效锈蚀区域
rust_areas = []
total_area = 0
largest_bbox = None
largest_area = 0
for contour in contours:
area = cv2.contourArea(contour)
if area > self.config.rust_min_area:
rust_areas.append(area)
total_area += area
# 获取边界框
x, y, w, h = cv2.boundingRect(contour)
if area > largest_area:
largest_area = area
largest_bbox = (x, y, w, h)
# 6. 计算置信度
if total_area > 0:
# 基于面积、颜色纯度、纹理复杂度计算置信度
color_purity = np.sum(rust_mask > 0) / rust_mask.size
texture_score = self._calculate_texture_score(image)
confidence = (0.5 * color_purity +
0.3 * min(1.0, total_area / 5000) +
0.2 * texture_score)
# 确定严重程度
if total_area > 5000: # >5% 图像面积
severity = SeverityLevel.EMERGENCY
elif total_area > 2000:
severity = SeverityLevel.CRITICAL
elif total_area > 500:
severity = SeverityLevel.WARNING
else:
severity = SeverityLevel.NORMAL
center = None
if largest_bbox:
x, y, w, h = largest_bbox
center = (x + w//2, y + h//2)
result = DetectionResult(
defect_type=DefectType.RUST,
severity=severity,
confidence=confidence,
bbox=largest_bbox,
area=total_area,
center=center,
details={
'rust_areas': len(rust_areas),
'color_purity': round(color_purity, 3),
'texture_score': round(texture_score, 3)
}
)
else:
result = DetectionResult(
defect_type=DefectType.NORMAL,
severity=SeverityLevel.NORMAL,
confidence=0.9,
details={'message': '未检测到锈蚀'}
)
logging.info(f"[RustDetector] 检测完成: {result.defect_type.value}, "
f"置信度: {result.confidence:.3f}")
return result
def _calculate_texture_score(self, image: np.ndarray) -> float:
"""计算纹理复杂度(锈蚀区域纹理粗糙)"""
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) if len(image.shape) == 3 else image
# 使用Sobel算子计算梯度
grad_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
grad_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
grad_mag = np.sqrt(grad_x**2 + grad_y**2)
# 纹理复杂度 = 梯度幅值的标准差
texture_complexity = np.std(grad_mag) / 255.0
return min(1.0, texture_complexity * 2) # 归一化
# ============================================================
# 4. 泄漏检测算法(单一职责)
# ============================================================
class LeakDetector:
"""
泄漏检测算法
基于光流法 + 局部纹理异常检测
"""
def __init__(self, config: DetectionConfig):
self.config = config
self.preprocessor = ImagePreprocessor(config)
self.frame_buffer = deque(maxlen=config.leak_temporal_frames)
logging.info("[LeakDetector] 泄漏检测器初始化")
def detect(self, image: np.ndarray, prev_image: Optional[np.ndarray] = None) -> DetectionResult:
"""执行泄漏检测"""
# 1. 添加到帧缓冲区
self.frame_buffer.append(image.copy())
if len(self.frame_buffer) < 2:
return DetectionResult(
defect_type=DefectType.NORMAL,
severity=SeverityLevel.NORMAL,
confidence=0.0,
details={'message': '需要更多帧进行时序分析'}
)
# 2. 光流分析
prev_gray = cv2.cvtColor(self.frame_buffer[-2], cv2.COLOR_BGR2GRAY)
curr_gray = cv2.cvtColor(self.frame_buffer[-1], cv2.COLOR_BGR2GRAY)
# 使用Farneback光流法
flow = cv2.calcOpticalFlowFarneback(
prev_gray, curr_gray, None,
0.5, 3, 15, 3, 5, 1.2, 0
)
# 计算光流幅值
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
# 3. 寻找异常光流区域(泄漏点特征)
flow_mask = mag > self.config.leak_flow_threshold * 255
flow_mask = flow_mask.astype(np.uint8) * 255
# 4. 形态学操作
kernel = np.ones((3, 3), np.uint8)
flow_mask = cv2.morphologyEx(flow_mask, cv2.MORPH_CLOSE, kernel)
# 5. 检测圆形斑点(气泡/液滴特征)
blob_detector = cv2.SimpleBlobDetector_create(
cv2.SimpleBlobDetector_Params(
filterByArea=True,
minArea=self.config.leak_blob_min_area,
maxArea=self.config.leak_blob_max_area,
filterByCircularity=True,
minCircularity=self.config.leak_circularity_min,
filterByConvexity=True,
minConvexity=0.8
)
)
keypoints = blob_detector.detect(flow_mask)
# 6. 评估检测结果
if keypoints:
total_area = sum([kp.size for kp in keypoints])
avg_confidence = min(1.0, total_area / 1000)
# 时序一致性检查
if len(self.frame_buffer) >= self.config.leak_temporal_frames:
temporal_consistency = self._check_temporal_consistency()
avg_confidence *= (0.7 + 0.3 * temporal_consistency)
# 确定严重程度
if total_area > 1000:
severity = SeverityLevel.EMERGENCY
elif total_area > 300:
severity = SeverityLevel.CRITICAL
else:
severity = SeverityLevel.WARNING
# 获取最大泄漏点
largest_kp = max(keypoints, key=lambda kp: kp.size)
bbox = (int(largest_kp.pt[0] - largest_kp.size/2),
int(largest_kp.pt[1] - largest_kp.size/2),
int(largest_kp.size), int(largest_kp.size))
center = (int(largest_kp.pt[0]), int(largest_kp.pt[1]))
result = DetectionResult(
defect_type=DefectType.LEAK,
severity=severity,
confidence=avg_confidence,
bbox=bbox,
area=total_area,
center=center,
details={
'leak_points': len(keypoints),
'avg_flow_magnitude': float(np.mean(mag[flow_mask > 0])) if np.any(flow_mask) else 0,
'temporal_consistency': round(self._check_temporal_consistency(), 3)
}
)
else:
result = DetectionResult(
defect_type=DefectType.NORMAL,
severity=SeverityLevel.NORMAL,
confidence=0.9,
details={'message': '未检测到泄漏'}
)
logging.info(f"[LeakDetector] 检测完成: {result.defect_type.value}, "
f"置信度: {result.confidence:.3f}")
return result
def _check_temporal_consistency(self) -> float:
"""检查时序一致性(减少误报)"""
if len(self.frame_buffer) < self.config.leak_temporal_frames:
return 0.0
# 简化实现:检查连续帧中是否有相似异常
consistency = 0.8 # 模拟值
return consistency
# ============================================================
# 5. 仪表指示灯检测(单一职责)
# ============================================================
class IndicatorDetector:
"""
仪表指示灯状态检测
基于HSV颜色分割 + Hough圆变换
"""
def __init__(self, config: DetectionConfig):
self.config = config
self.preprocessor = ImagePreprocessor(config)
logging.info("[IndicatorDetector] 仪表指示灯检测器初始化")
def detect(self, image: np.ndarray) -> DetectionResult:
"""执行指示灯检测"""
利用AI解决实际问题,如果你觉得这个工具好用,欢迎关注长安牧笛!