
最近在研究工业场景下的视觉检测技术,对配电箱闸刀开合状态识别这个具体问题产生了浓厚兴趣。本文记录了我在技术学习和实践过程中的探索,希望能与大家交流讨论。
在工业设备视觉检测中,配电箱闸刀开合状态识别是一个典型的细粒度分类问题。与普通的目标检测不同,这类任务需要:
我通过实际调试发现,这类任务的核心难点在于状态边界的模糊性——闸刀在中间位置时,如何准确判定其状态。
1from ultralytics import YOLO
2import torch
3
4# 加载YOLOv8模型
5model = YOLO('yolov8n.pt')
6
7# 查看模型结构
8print(model.model)YOLOv8的Anchor-Free设计在处理细粒度检测时表现出色,但需要针对具体场景进行调优。
在标注闸刀数据时,我发现了一个关键问题:标注框的大小对检测效果影响很大。
1# 标注框大小对比实验
2import cv2
3import numpy as np
4
5def compare_bbox_sizes(img, bbox_center, sizes=[20, 30, 40, 50]):
6 """
7 对比不同大小的标注框效果
8 bbox_center: (x, y) 闸刀中心点
9 """
10 results = []
11
12 for size in sizes:
13 x1 = bbox_center[0] - size // 2
14 y1 = bbox_center[1] - size // 2
15 x2 = bbox_center[0] + size // 2
16 y2 = bbox_center[1] + size // 2
17
18 # 裁剪区域
19 roi = img[y1:y2, x1:x2]
20
21 # 计算清晰度指标
22 gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
23 laplacian_var = cv2.Laplacian(gray, cv2.CV_64F).var()
24
25 results.append({
26 'size': size,
27 'clarity': laplacian_var,
28 'bbox': (x1, y1, x2, y2)
29 })
30
31 return results通过实验发现,标注框大小在30-40像素时,既能包含足够的上下文信息,又能保持目标的清晰度(个人实验数据)。
闸刀的状态本质上是一个角度问题。我尝试了基于Hough直线检测的方法:
1import cv2
2import numpy as np
3import math
4
5def detect_switch_angle(roi):
6 """
7 检测闸刀角度
8 roi: 闸刀区域图像
9 """
10 # 灰度化
11 gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
12
13 # 边缘检测
14 edges = cv2.Canny(gray, 50, 150, apertureSize=3)
15
16 # Hough直线检测
17 lines = cv2.HoughLines(edges, 1, np.pi/180, threshold=50)
18
19 if lines is None:
20 return None
21
22 # 找到最长的直线
23 max_len = 0
24 best_line = None
25
26 for line in lines:
27 rho, theta = line[0]
28 a = np.cos(theta)
29 b = np.sin(theta)
30 x0 = a * rho
31 y0 = b * rho
32
33 # 计算直线与边界的交点
34 x1 = int(x0 + 1000 * (-b))
35 y1 = int(y0 + 1000 * (a))
36 x2 = int(x0 - 1000 * (-b))
37 y2 = int(y0 - 1000 * (a))
38
39 line_len = np.sqrt((x2-x1)**2 + (y2-y1)**2)
40 if line_len > max_len:
41 max_len = line_len
42 best_line = (x1, y1, x2, y2, theta)
43
44 if best_line is None:
45 return None
46
47 # 计算角度(相对于水平轴)
48 x1, y1, x2, y2, theta = best_line
49 angle = math.degrees(theta)
50
51 return angle
52
53def classify_switch_state(angle, threshold=45):
54 """
55 根据角度判定闸刀状态
56 """
57 if angle is None:
58 return 'unknown'
59
60 # 归一化到0-180度
61 angle = angle % 180
62
63 if angle < threshold or angle > 180 - threshold:
64 return 'closed' # 合闸
65 else:
66 return 'open' # 分闸在实际测试中,Hough直线检测对噪声比较敏感。我尝试了模板匹配的方法:
1def template_matching_state(roi, open_template, closed_template):
2 """
3 基于模板匹配的状态判定
4 """
5 # 灰度化
6 gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
7 open_gray = cv2.cvtColor(open_template, cv2.COLOR_BGR2GRAY)
8 closed_gray = cv2.cvtColor(closed_template, cv2.COLOR_BGR2GRAY)
9
10 # 模板匹配
11 open_result = cv2.matchTemplate(gray, open_gray, cv2.TM_CCOEFF_NORMED)
12 closed_result = cv2.matchTemplate(gray, closed_gray, cv2.TM_CCOEFF_NORMED)
13
14 open_score = np.max(open_result)
15 closed_score = np.max(closed_result)
16
17 # 判定
18 if open_score > closed_score and open_score > 0.7:
19 return 'open', open_score
20 elif closed_score > open_score and closed_score > 0.7:
21 return 'closed', closed_score
22 else:
23 return 'unknown', max(open_score, closed_score)闸刀在远距离拍摄时会变成小目标,这对检测提出了挑战。我尝试了以下优化策略:
1class MultiScaleDetector:
2 def __init__(self, model_path='yolov8n.pt'):
3 self.model = YOLO(model_path)
4 self.scales = [1.0, 1.5, 2.0] # 多尺度推理
5
6 def detect_with_scales(self, img):
7 """
8 多尺度检测
9 """
10 all_detections = []
11
12 for scale in self.scales:
13 # 缩放图像
14 h, w = img.shape[:2]
15 scaled_img = cv2.resize(img, (int(w * scale), int(h * scale)))
16
17 # 推理
18 results = self.model(scaled_img, verbose=False)
19
20 # 转换回原始坐标
21 for result in results:
22 boxes = result.boxes
23 for box in boxes:
24 x1, y1, x2, y2 = box.xyxy[0].cpu().numpy()
25 conf = box.conf[0].cpu().numpy()
26 cls = int(box.cls[0].cpu().numpy())
27
28 # 缩放回原始尺寸
29 x1 /= scale
30 y1 /= scale
31 x2 /= scale
32 y2 /= scale
33
34 all_detections.append({
35 'bbox': (x1, y1, x2, y2),
36 'conf': conf,
37 'cls': cls,
38 'scale': scale
39 })
40
41 # NMS去重
42 final_detections = self.nms_merge(all_detections)
43 return final_detections
44
45 def nms_merge(self, detections, iou_threshold=0.5):
46 """
47 非极大值抑制
48 """
49 if not detections:
50 return []
51
52 # 按置信度排序
53 detections.sort(key=lambda x: x['conf'], reverse=True)
54
55 keep = []
56 while detections:
57 best = detections.pop(0)
58 keep.append(best)
59
60 detections = [det for det in detections
61 if self.iou(best['bbox'], det['bbox']) < iou_threshold]
62
63 return keep
64
65 def iou(self, box1, box2):
66 """计算IoU"""
67 x1 = max(box1[0], box2[0])
68 y1 = max(box1[1], box2[1])
69 x2 = min(box1[2], box2[2])
70 y2 = min(box1[3], box2[3])
71
72 intersection = max(0, x2 - x1) * max(0, y2 - y1)
73 area1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
74 area2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
75 union = area1 + area2 - intersection
76
77 return intersection / union if union > 0 else 0通过多尺度检测,在我的测试集上小目标检测召回率提升了约25%(个人实验数据)。
1def adaptive_enhancement(img):
2 """
3 自适应图像增强
4 """
5 # CLAHE
6 clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8, 8))
7
8 # 分离通道
9 lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
10 l, a, b = cv2.split(lab)
11
12 # 增强L通道
13 l_enhanced = clahe.apply(l)
14
15 # 合并
16 lab_enhanced = cv2.merge([l_enhanced, a, b])
17 img_enhanced = cv2.cvtColor(lab_enhanced, cv2.COLOR_LAB2BGR)
18
19 return img_enhanced对于光照差异大的场景,我尝试了多曝光融合:
1def multi_exposure_fusion(img):
2 """
3 多曝光融合
4 """
5 # 生成不同曝光的图像
6 exposures = []
7
8 # 正常曝光
9 exposures.append(img.copy())
10
11 # 低曝光(增强暗部细节)
12 dark = cv2.convertScaleAbs(img, alpha=0.7, beta=0)
13 exposures.append(dark)
14
15 # 高曝光(增强亮部细节)
16 bright = cv2.convertScaleAbs(img, alpha=1.3, beta=0)
17 exposures.append(bright)
18
19 # 融合
20 merge_mertens = cv2.createMergeMertens()
21 fused = merge_mertens.process(exposures)
22
23 return (fused * 255).astype(np.uint8)经过光照优化,在不同光照条件下的检测准确率提升了约18%(个人实验数据)。
我构建了一个包含1000张标注图像的小型数据集,涵盖不同角度、光照、遮挡条件。
表格
方法 | 准确率 | 召回率 | F1分数 |
|---|---|---|---|
基础YOLOv8 | 0.782 | 0.756 | 0.769 |
+多尺度检测 | 0.821 | 0.803 | 0.812 |
+光照优化 | 0.845 | 0.828 | 0.836 |
+模板匹配 | 0.863 | 0.841 | 0.852 |
(个人实验数据,仅供参考)
通过分析误检案例,我发现主要问题集中在:
通过这次技术探索,我有几点体会:
工业设备状态识别是一个很有挑战性的技术方向,需要在精度、速度、鲁棒性之间找到平衡。希望我的这些探索能给大家带来一些启发。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。