当前位置: 首页 > news >正文

智能光电检测:YOLO+OpenCV联合算法工程实践

前言 最近,我独立开发了一套面向光电设备的上位机系统,用于实时拍摄与目标跟踪。起初,我对 AI 可谓一窍不通,但项目需求逼人,只能“硬核”补课。几番调研后,我锁定了当下最火的目标检测框架——YOLO。然而,YOLO 在大目标上表现惊艳,面对小目标却力不从心。为此,我又引入 OpenCV 的轮廓识别算法,将两种方案融合:大目标交给 YOLO,小目标交给 OpenCV,互补短板,整体精度显著提升。

为了把算法落地,我啃完了 YOLO 标注、训练、推理的整条链路,并自研了一套配套软件,集成两大核心功能:

  1. 智能标注:
    针对工业场景反复打磨,支持一键框选、快捷键批量操作、自动保存与回滚;相比市面工具,真正做到了“打开就会用,十分钟出活”。

  2. 目标检测:
    图片或视频直接拖拽进软件,即可实时完成目标识别与跟踪,结果可视化、可导出,全流程无缝衔接。

本文将完整记录从零搭建这套系统的思路、踩坑与优化细节,并公开软件的核心功能设计,希望能给同样奋战在上位机与 AI 结合一线的开发者一点参考。

1 图片搜集与标注

为训练“鸟 vs 无人机”二分类模型,每类需准备上千张样本。数据源三路并进:

  1. 自采:无人机实拍+长焦拍鸟,确保场景真实;
  2. 开源:COCO 中抽取含鸟/无人机的切片;
  3. 补充:淘宝购买高清图包、CSDN 资源帖批量下载。

下载完成后,按类别归档:dataset/bird/ ,dataset/drone/ 目录就绪,双击启动自研标注工具,开始高效标注。

2 环境搭建

 虚拟环境使用conda,ide使用PyCharm,官网下载ultralytics。具体配置参见文章《基于YOLOv11的无人机目标检测实战(Windows环境)》

3 图片整理与训练

  图片按照训练集、验证集、测试集分类,比例为8:1:1 ,实现分类的代码如下

# 将图片和标注数据按比例切分为 训练集和测试集
import shutil
import random
import os# 原始路径
image_original_path = "data/images/"
label_original_path = "data/labels/"cur_path = os.getcwd()
# 训练集路径
train_image_path = os.path.join(cur_path, "datasets/images/train/")
train_label_path = os.path.join(cur_path, "datasets/labels/train/")# 验证集路径
val_image_path = os.path.join(cur_path, "datasets/images/val/")
val_label_path = os.path.join(cur_path, "datasets/labels/val/")# 测试集路径
test_image_path = os.path.join(cur_path, "datasets/images/test/")
test_label_path = os.path.join(cur_path, "datasets/labels/test/")# 训练集目录
list_train = os.path.join(cur_path, "datasets/train.txt")
list_val = os.path.join(cur_path, "datasets/val.txt")
list_test = os.path.join(cur_path, "datasets/test.txt")train_percent = 0.8
val_percent = 0.1
test_percent = 0.1def del_file(path):for i in os.listdir(path):file_data = path + "\\" + ios.remove(file_data)def mkdir():if not os.path.exists(train_image_path):os.makedirs(train_image_path)else:del_file(train_image_path)if not os.path.exists(train_label_path):os.makedirs(train_label_path)else:del_file(train_label_path)if not os.path.exists(val_image_path):os.makedirs(val_image_path)else:del_file(val_image_path)if not os.path.exists(val_label_path):os.makedirs(val_label_path)else:del_file(val_label_path)if not os.path.exists(test_image_path):os.makedirs(test_image_path)else:del_file(test_image_path)if not os.path.exists(test_label_path):os.makedirs(test_label_path)else:del_file(test_label_path)def clearfile():if os.path.exists(list_train):os.remove(list_train)if os.path.exists(list_val):os.remove(list_val)if os.path.exists(list_test):os.remove(list_test)def main():mkdir()clearfile()file_train = open(list_train, 'w')file_val = open(list_val, 'w')file_test = open(list_test, 'w')total_txt = os.listdir(label_original_path)num_txt = len(total_txt)list_all_txt = range(num_txt)num_train = int(num_txt * train_percent)num_val = int(num_txt * val_percent)num_test = num_txt - num_train - num_valtrain = random.sample(list_all_txt, num_train)# train从list_all_txt取出num_train个元素# 所以list_all_txt列表只剩下了这些元素val_test = [i for i in list_all_txt if not i in train]# 再从val_test取出num_val个元素,val_test剩下的元素就是testval = random.sample(val_test, num_val)print("训练集数目:{}, 验证集数目:{}, 测试集数目:{}".format(len(train), len(val), len(val_test) - len(val)))for i in list_all_txt:name = total_txt[i][:-4]srcImage = image_original_path + name + '.jpg'if os.path.isfile(srcImage):suffix = '.jpg'else:suffix = '.png'srcImage = image_original_path + name + '.png'srcLabel = label_original_path + name + ".txt"if i in train:dst_train_Image = train_image_path + name + suffixdst_train_Label = train_label_path + name + '.txt'shutil.copyfile(srcImage, dst_train_Image)shutil.copyfile(srcLabel, dst_train_Label)file_train.write(dst_train_Image + '\n')elif i in val:dst_val_Image = val_image_path + name + '.jpg'dst_val_Label = val_label_path + name + '.txt'shutil.copyfile(srcImage, dst_val_Image)shutil.copyfile(srcLabel, dst_val_Label)file_val.write(dst_val_Image + '\n')else:dst_test_Image = test_image_path + name + suffixdst_test_Label = test_label_path + name + '.txt'shutil.copyfile(srcImage, dst_test_Image)shutil.copyfile(srcLabel, dst_test_Label)file_test.write(dst_test_Image + '\n')file_train.close()file_val.close()file_test.close()if __name__ == "__main__":main()

训练代码如下

import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO
if __name__ == '__main__':model = YOLO('ultralytics/cfg/models/12/yolo12n.yaml')model.load('yolo12n.pt')  #注释则不加载results = model.train(data='data.yaml',  #数据集配置文件的路径epochs=180,  #训练轮次总数batch=4,  #批量大小,即单次输入多少图片训练imgsz=640,  #训练图像尺寸workers=2,  #加载数据的工作线程数device= 0,  #指定训练的计算设备,无nvidia显卡则改为 'cpu'optimizer='SGD',  #训练使用优化器,可选 auto,SGD,Adam,AdamW 等amp= True,  #True 或者 False, 解释为:自动混合精度(AMP) 训练patience = 50,cache=False,  # True 在内存中缓存数据集图像,服务器推荐开启augment=True,lr0 = 0.001,lrf = 0.01,cos_lr=True,weight_decay=0.05
)

训练结果,mAP精度达到9提上,分数非常高。

4 图片视频目标识别

视频文件目标识别

后记  本文详细介绍了基于YOLO与OpenCV的光电上位机目标检测系统的开发过程。针对YOLO框架在小目标检测上的局限性,创新性地结合OpenCV轮廓识别算法,提升了系统的检测精度和适应性。通过数月的技术研究与实践,完成了以下工作:

  1. 技术研究:深入掌握YOLO模型的标注、训练及推理流程,并结合OpenCV优化小目标识别效果。

  2. 软件开发:自主设计并实现了一套功能完善的软件系统,包括图像标注工具和目标检测模块,显著提升了易用性和效率。

  3. 创新优化:针对实际需求优化标注功能,使软件操作更便捷,性能优于市面同类产品。

        本系统的开发不仅验证了YOLO与OpenCV结合的技术可行性,也为类似场景下的目标检测任务提供了可借鉴的解决方案。未来,可进一步优化模型性能,拓展多目标跟踪、实时检测等高级功能,以满足更广泛的应用需求。

http://www.dtcms.com/a/287677.html

相关文章:

  • Spring Boot入门
  • NJU 凸优化导论(9) 对偶(II)KKT条件+变形重构
  • 从Prompt到结构建模:如何以数据驱动重构日本语言学校体系?以国际日本语学院为例
  • Java行为型模式---访问者模式
  • 自动驾驶仿真领域常见开源工具
  • Linux 内存管理(2):了解内存回收机制
  • Linux 技术概述与学习指南
  • 微信小程序——世界天气小助手
  • AWS Partner: Sales Accreditation (Business)
  • [MySQL基础3] 数据控制语言DCL和MySQL中的常用函数
  • LVS(Linux virtual server)-实现四层负载均衡
  • MyBatis动态SQL实战:告别硬编码,拥抱智能SQL生成
  • Python高级数据类型:集合(Set)
  • 【深度学习笔记 Ⅱ】5 梯度消失和梯度爆炸
  • 猎板:在 5G 与 AI 时代,印制线路板如何满足高性能需求
  • GeoPandas 城市规划:Python 空间数据初学者指南
  • gitee 分支切换
  • 【kafka4源码学习系列】kafka4总体架构介绍
  • Gerrit workflow
  • 3-大语言模型—理论基础:生成式预训练语言模型GPT(代码“活起来”)
  • 2、Redis持久化详解
  • 【iOS】编译和链接、动静态库及dyld的简单学习
  • 历史数据分析——国药现代
  • ABP VNext + Kubernetes Istio:微服务网格实战指南
  • 基于Socket来构建无界数据流并通过Flink框架进行处理
  • 读书笔记:最好使用C++转型操作符
  • 【C++】初识C++(2)
  • c#泛型集合(ArrayList和List、Dictionary的对比)
  • 记录我coding印象比较深刻的BUG
  • 支付宝支付