智能光电检测:YOLO+OpenCV联合算法工程实践
前言 最近,我独立开发了一套面向光电设备的上位机系统,用于实时拍摄与目标跟踪。起初,我对 AI 可谓一窍不通,但项目需求逼人,只能“硬核”补课。几番调研后,我锁定了当下最火的目标检测框架——YOLO。然而,YOLO 在大目标上表现惊艳,面对小目标却力不从心。为此,我又引入 OpenCV 的轮廓识别算法,将两种方案融合:大目标交给 YOLO,小目标交给 OpenCV,互补短板,整体精度显著提升。为了把算法落地,我啃完了 YOLO 标注、训练、推理的整条链路,并自研了一套配套软件,集成两大核心功能:[*]智能标注:
针对工业场景反复打磨,支持一键框选、快捷键批量操作、自动保存与回滚;相比市面工具,真正做到了“打开就会用,十分钟出活”。
[*]目标检测:
图片或视频直接拖拽进软件,即可实时完成目标识别与跟踪,结果可视化、可导出,全流程无缝衔接。
本文将完整记录从零搭建这套系统的思路、踩坑与优化细节,并公开软件的核心功能设计,希望能给同样奋战在上位机与 AI 结合一线的开发者一点参考。1 图片搜集与标注为训练“鸟 vs 无人机”二分类模型,每类需准备上千张样本。数据源三路并进:
[*]自采:无人机实拍+长焦拍鸟,确保场景真实;
[*]开源:COCO 中抽取含鸟/无人机的切片;
[*]补充:淘宝购买高清图包、CSDN 资源帖批量下载。
下载完成后,按类别归档:dataset/bird/ ,dataset/drone/ 目录就绪,双击启动自研标注工具,开始高效标注。
2 环境搭建
虚拟环境使用conda,ide使用PyCharm,官网下载ultralytics。具体配置参见文章《基于YOLOv11的无人机目标检测实战(Windows环境)》
3 图片整理与训练
图片按照训练集、验证集、测试集分类,比例为8:1:1 ,实现分类的代码如下
1 # 将图片和标注数据按比例切分为 训练集和测试集
2 import shutil
3 import random
4 import os
5
6 # 原始路径
7 image_original_path = "data/images/"
8 label_original_path = "data/labels/"
9
10 cur_path = os.getcwd()
11 # 训练集路径
12 train_image_path = os.path.join(cur_path, "datasets/images/train/")
13 train_label_path = os.path.join(cur_path, "datasets/labels/train/")
14
15 # 验证集路径
16 val_image_path = os.path.join(cur_path, "datasets/images/val/")
17 val_label_path = os.path.join(cur_path, "datasets/labels/val/")
18
19 # 测试集路径
20 test_image_path = os.path.join(cur_path, "datasets/images/test/")
21 test_label_path = os.path.join(cur_path, "datasets/labels/test/")
22
23 # 训练集目录
24 list_train = os.path.join(cur_path, "datasets/train.txt")
25 list_val = os.path.join(cur_path, "datasets/val.txt")
26 list_test = os.path.join(cur_path, "datasets/test.txt")
27
28 train_percent = 0.8
29 val_percent = 0.1
30 test_percent = 0.1
31
32
33 def del_file(path):
34 for i in os.listdir(path):
35 file_data = path + "\\" + i
36 os.remove(file_data)
37
38
39 def mkdir():
40 if not os.path.exists(train_image_path):
41 os.makedirs(train_image_path)
42 else:
43 del_file(train_image_path)
44 if not os.path.exists(train_label_path):
45 os.makedirs(train_label_path)
46 else:
47 del_file(train_label_path)
48
49 if not os.path.exists(val_image_path):
50 os.makedirs(val_image_path)
51 else:
52 del_file(val_image_path)
53 if not os.path.exists(val_label_path):
54 os.makedirs(val_label_path)
55 else:
56 del_file(val_label_path)
57
58 if not os.path.exists(test_image_path):
59 os.makedirs(test_image_path)
60 else:
61 del_file(test_image_path)
62 if not os.path.exists(test_label_path):
63 os.makedirs(test_label_path)
64 else:
65 del_file(test_label_path)
66
67
68 def clearfile():
69 if os.path.exists(list_train):
70 os.remove(list_train)
71 if os.path.exists(list_val):
72 os.remove(list_val)
73 if os.path.exists(list_test):
74 os.remove(list_test)
75
76
77 def main():
78 mkdir()
79 clearfile()
80
81 file_train = open(list_train, 'w')
82 file_val = open(list_val, 'w')
83 file_test = open(list_test, 'w')
84
85 total_txt = os.listdir(label_original_path)
86 num_txt = len(total_txt)
87 list_all_txt = range(num_txt)
88
89 num_train = int(num_txt * train_percent)
90 num_val = int(num_txt * val_percent)
91 num_test = num_txt - num_train - num_val
92
93 train = random.sample(list_all_txt, num_train)
94 # train从list_all_txt取出num_train个元素
95 # 所以list_all_txt列表只剩下了这些元素
96 val_test =
97 # 再从val_test取出num_val个元素,val_test剩下的元素就是test
98 val = random.sample(val_test, num_val)
99
100 print("训练集数目:{}, 验证集数目:{}, 测试集数目:{}".format(len(train), len(val), len(val_test) - len(val)))
101 for i in list_all_txt:
102 name = total_txt[:-4]
103
104 srcImage = image_original_path + name + '.jpg'
105 if os.path.isfile(srcImage):
106 suffix = '.jpg'
107 else:
108 suffix = '.png'
109 srcImage = image_original_path + name + '.png'
110
111 srcLabel = label_original_path + name + ".txt"
112
113 if i in train:
114 dst_train_Image = train_image_path + name + suffix
115 dst_train_Label = train_label_path + name + '.txt'
116 shutil.copyfile(srcImage, dst_train_Image)
117 shutil.copyfile(srcLabel, dst_train_Label)
118 file_train.write(dst_train_Image + '\n')
119 elif i in val:
120 dst_val_Image = val_image_path + name + '.jpg'
121 dst_val_Label = val_label_path + name + '.txt'
122 shutil.copyfile(srcImage, dst_val_Image)
123 shutil.copyfile(srcLabel, dst_val_Label)
124 file_val.write(dst_val_Image + '\n')
125 else:
126 dst_test_Image = test_image_path + name + suffix
127 dst_test_Label = test_label_path + name + '.txt'
128 shutil.copyfile(srcImage, dst_test_Image)
129 shutil.copyfile(srcLabel, dst_test_Label)
130 file_test.write(dst_test_Image + '\n')
131
132 file_train.close()
133 file_val.close()
134 file_test.close()
135
136
137 if __name__ == "__main__":
138 main()训练代码如下
1 import warnings
2 warnings.filterwarnings('ignore')
3 from ultralytics import YOLO
4 if __name__ == '__main__':
5 model = YOLO('ultralytics/cfg/models/12/yolo12n.yaml')
6 model.load('yolo12n.pt')#注释则不加载
7 results = model.train(
8 data='data.yaml',#数据集配置文件的路径
9 epochs=180,#训练轮次总数
10 batch=4,#批量大小,即单次输入多少图片训练
11 imgsz=640,#训练图像尺寸
12 workers=2,#加载数据的工作线程数
13 device= 0,#指定训练的计算设备,无nvidia显卡则改为 'cpu'
14 optimizer='SGD',#训练使用优化器,可选 auto,SGD,Adam,AdamW 等
15 amp= True,#True 或者 False, 解释为:自动混合精度(AMP) 训练
16 patience = 50,
17 cache=False,# True 在内存中缓存数据集图像,服务器推荐开启
18 augment=True,
19 lr0 = 0.001,
20 lrf = 0.01,
21 cos_lr=True,
22 weight_decay=0.05
23 )训练结果,mAP精度达到9提上,分数非常高。
4 图片视频目标识别
视频文件目标识别
后记 本文详细介绍了基于YOLO与OpenCV的光电上位机目标检测系统的开发过程。针对YOLO框架在小目标检测上的局限性,创新性地结合OpenCV轮廓识别算法,提升了系统的检测精度和适应性。通过数月的技术研究与实践,完成了以下工作:
[*]技术研究:深入掌握YOLO模型的标注、训练及推理流程,并结合OpenCV优化小目标识别效果。
[*]软件开发:自主设计并实现了一套功能完善的软件系统,包括图像标注工具和目标检测模块,显著提升了易用性和效率。
[*]创新优化:针对实际需求优化标注功能,使软件操作更便捷,性能优于市面同类产品。
本系统的开发不仅验证了YOLO与OpenCV结合的技术可行性,也为类似场景下的目标检测任务提供了可借鉴的解决方案。未来,可进一步优化模型性能,拓展多目标跟踪、实时检测等高级功能,以满足更广泛的应用需求。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]