前言
作为一个地区生物多样性与生态环境的重要指标,“鸟类数量及分布”越来越受到自然保护区、湿地公园、动物保护监管部门等机构的重视,实时监测鸟类品种、数量与分布,成为各地区的常态化工作。本文使用YOLOv5目标检测算法,可以为鸟类监测识别提供AI技术支持,提升监测识别效率,解决单纯人工监测造成的低效与误差,为鸟类保护养育提供更好的数据支撑。
鸟类监测识别具有较高复杂性,鸟类飞行路线不定、落点不定、时间不定,监测区域多样(森林、湿地、湖泊、草地等),部分鸟类习性、形体、颜色具有极高相似度,这些因素使得对鸟类监测识别技术的要求极高。传统的机器视觉算法难以实现准确快速识别鸟类的品种和位置,近年来,机器学习和深度学习取得了较大的发展,深度学习方法在检测精度和速度方面与传统方法相比表现出更良好的性能。YOLOv5是单阶段目标检测算法YOLO的第五代,根据实验得出结论,其在速度与准确性能方面都有了明显提升,其论文可参考TPH-YOLOv5: Improved YOLOv5 Based on Transformer Prediction Head for Object Detection on Drone-captured Scenarios,开源的代码可见https://github.com/ultralytics/yolov5(官方源码仓库)。
自动化的鸟类识别能够帮助人们更方便地了解地理区域内特定鸟类的数量和活动情况,目前网上鸟类检测和识别的应用较少,能够参考的例子不多,几乎没有人将其开发成一个可以展示的完整软件,并不方便选择图片、视频文件和实时检测。对此这里博主利用加州理工学院鸟类数据集(The Caltech-UCSD Birds-200-2011 Dataset)训练YOLOv5模型,并给出自行设计的UI界面,保持博主同款的简约风,功能也可以满足图片、视频和摄像头的识别检测,切换模型、保存结果等,希望大家可以喜欢,初始界面如下图:
检测鸟的种类时的界面截图(点击图片可放大)如下图,可识别画面中存在的多个鸟的类别,也可开启摄像头或视频检测:
详细的功能演示效果参见博主的B站视频或下一节的动图演示,觉得不错的朋友敬请点赞、关注加收藏!系统UI界面的设计工作量较大,界面美化更需仔细雕琢,大家有任何建议或意见和可在下方评论交流。
1. 效果演示
鸟类检测识别系统主要用于野外或日常生活场景中鸟类图像的识别,显示鸟类目标在图像中的类别、位置、数目、置信度等;可对图片、视频文件读取的图像,或从摄像头获取的实时画面中的鸟类进行识别,算法模型可选择替换;系统界面包含用户注册、登录功能,方便用户进行管理和使用;识别结果可视化,结果实时显示并能够进行目标逐个标注、显示和数据展示;画面显示窗口可缩放、拖动、自适应,结果可点击按钮保存,方便后续查阅使用。
软件好不好用,颜值很重要,首先我们还是通过动图看一下鸟类识别的效果,系统主要实现的功能是对图片、视频和摄像头画面中的鸟类进行识别,检测的结果可视化显示在界面和图像中,提供模型切换、单个目标选中等功能,其演示效果如下。
(一)用户注册登录界面
这里设计了一个登录界面,可以注册账号和密码,然后进行登录。界面还是参考了当前流行的UI设计,左侧是一个动图,右侧输入账号、密码、验证码等等。
(二)选择鸟类图片识别
系统允许选择图片文件进行识别,点击图片选择按钮图标选择图片后,显示所有鸟类识别的结果,可通过下拉选框查看单个鸟类的结果。本功能的界面展示如下图所示:
(三)视频识别效果展示
很多时候我们需要识别一段视频中的鸟的种类,这里设计了视频选择功能。点击视频按钮可选择待检测的视频,系统会自动解析视频逐帧识别鸟类,并将结果标记在画面中,效果如下图所示:
(四)摄像头检测效果展示
在真实场景中,我们往往利用设备摄像头获取实时画面,同时需要对画面中的鸟类进行识别,因此本文考虑到此项功能。如下图所示,点击摄像头按钮后系统进入准备状态,系统显示实时画面并开始检测画面中的鸟,识别结果展示如下图:
(五)切换鸟类检测模型
可选择训练得到的检测模型,利用调优后的模型进行检测,对于YOLOv5的预训练模型通用适用。这里可以自由切换不同的模型,以比较不同的检测效果。
2. 鸟类数据集及训练
这里我们使用的鸟类识别数据集,是加州理工学院鸟类数据集(The Caltech-UCSD Birds-200-2011 Dataset),CUB 数据集一共 200 个类别,共 11788 张图片,每张图片除包括类别标签外,还有一个标注的物体边框(Bounding Box)、关键点和一些其他属性,属于具有较高细粒度的鸟类图像数据集。
CUB数据集中每个物种都与Wikipedia文章相关联,并按科学分类(顺序、科、属、物种)进行组织,包含200类鸟类子类,其中训练数据集有5994张图像,测试集有5794张图像。每张图像均提供了图像类标记信息,图像中鸟的bounding box,鸟的关键part信息,以及鸟类的属性信息,下载CUB数据并解压后得到如下的文件夹
由于CUB数据集的标注文件和YOLO的格式不一致,这里我们选取CUB数据集中的类别,转换为YOLO格式。标签格式转换的代码可参考博客:CUB_200_2011数据集转Yolo格式,最终我们得到YOLO格式的数据集文件,并进行模型训练。
在训练模型之前,为了让我们的数据能够被YOLO找到,我们需要写一个data.yaml文件存储在案例目录下,在其中记录下数据的路径和模型要识别的标记类别,文件内容如下所示。YOLO通过读取目录下的data.yaml文件,进而找到我们数据集存储的位置才能读取数据进行训练验证。
python train: F:\BlogCode\BirdDet\Bird\train.txt # 训练集 val: F:\BlogCode\BirdDet\Bird\test.txt # 验证集 nc: 36 # 训练的类别 names: ['Acadian_Flycatcher','American_Crow','American_Goldfinch','American_Pipit', 'American_Redstart','American_Three_toed_Woodpecker','Anna_Hummingbird','Artic_Tern','Baird_Sparrow','Baltimore_Oriole', 'Bank_Swallow','Barn_Swallow','Bay_breasted_Warbler','Belted_Kingfisher', 'Bewick_Wren','Black_Tern','Black_and_white_Warbler','Black_billed_Cuckoo','Black_capped_Vireo','Black_footed_Albatross','Black_throated_Blue_Warbler', 'Black_throated_Sparrow','Blue_Grosbeak','Blue_Jay','Blue_headed_Vireo','Blue_winged_Warbler','Boat_tailed_Grackle', 'Bobolink','Bohemian_Waxwing','Brandt_Cormorant','Brewer_Blackbird','Brewer_Sparrow','Bronzed_Cowbird', 'Brown_Creeper','Brown_Pelican','Brown_Thrasher']
训练模型通过调用模型文件夹下的train.py进行,可以通过--batch参数和--epochs参数调整训练批次大小和训练轮数。YOLOv5提供了在COCO数据集上预训练后的参数,我们可以通过参数--weights yolov5s.pt加载预训练参数进行迁移学习,或在训练大数据集(比如COCO)时用一个空的--weights ''参数从零开始训练。然后设定各种参数,代码如下:
python parser = argparse.ArgumentParser() parser.add_argument('--weights', nargs='+', type=str, default='./weights/best.pt', help='model.pt path(s)') # 模型路径仅支持.pt文件 parser.add_argument('--img-size', type=int, default=480, help='inference size (pixels)') # 检测图像大小,仅支持480 parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold') # 置信度阈值 parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS') # NMS阈值 # 选中运行机器的GPU或者cpu,有GPU则GPU,没有则cpu,若想仅使用cpu,可以填cpu即可 parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu') parser.add_argument('--save-dir', type=str, default='inference', help='directory to save results') # 文件保存路径 parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3') # 分开类别 parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS') # 使用NMS opt = parser.parse_args() # opt局部变量,重要 out, weight, imgsz = opt.save_dir, opt.weights, opt.img_size # 得到文件保存路径,文件权重路径,图像尺寸 device = select_device(opt.device) # 检验计算单元,gpu还是cpu half = device.type != 'cpu' # 如果使用gpu则进行半精度推理 model = attempt_load(weight, map_location=device) # 读取模型 我们可以在终端输入如下命令进行训练,当然也可以直接点击train.py运行。 python python train.py --batch 32 --epochs 300 --data data.yaml --weights yolov5s.pt --hyp data/hyps/hyp.scratch-med.yaml --cache
在深度学习中,我们通常通过损失函数下降的曲线来观察模型训练的情况。而YOLOv5训练时主要包含三个方面的损失:矩形框损失(box_loss)、置信度损失(obj_loss)和分类损失(cls_loss),在训练结束后,我们也可以在logs目录下找到生成对若干训练过程统计图。下图为博主训练鸟类识别的模型训练曲线图。
在我们的训练过程中,mAP50作为一种常用的目标检测评估指标很快达到了较高水平,而mAP50:95也在训练的过程中不断提升,说明我们模型从训练-验证的角度表现良好。读入一个测试文件夹进行预测,通过训练得到的选取验证集上效果最好的权重best.pt进行实验,得到PR曲线如下图所示。
3. 鸟类检测识别
在训练完成后得到最佳模型,接下来我们将帧图像输入到这个网络进行预测,从而得到预测结果,预测方法(predict.py)部分的代码如下所示:
python def predict(img): img = torch.from_numpy(img).to(device) img = img.half() if half else img.float() img /= 255.0 if img.ndimension() == 3: img = img.unsqueeze(0) t1 = time_synchronized() pred = model(img, augment=False)[0] pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes, agnostic=opt.agnostic_nms) t2 = time_synchronized() InferNms = round((t2 - t1), 2) return pred, InferNms
得到预测结果我们便可以将帧图像中的鸟类框出,然后在图片上用opencv绘图操作,输出鸟的类别及鸟的预测分数。以下是读取一个鸟类图片并进行检测的脚本,首先将图片数据进行预处理后送predict进行检测,然后计算标记框的位置并在图中标注出来。
python if __name__ == '__main__': img_path = "./UI_rec/test_/Bobolink_0079_10736.jpg" image = cv_imread(img_path) img0 = image.copy() img = letterbox(img0, new_shape=imgsz)[0] img = np.stack(img, 0) img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 img = np.ascontiguousarray(img) pred, useTime = predict(img) det = pred[0] p, s, im0 = None, '', img0 if det is not None and len(det): # 如果有检测信息则进入 det[:, :4] = scale_coords(img.shape[1:], det[:, :4], im0.shape).round() # 把图像缩放至im0的尺寸 number_i = 0 # 类别预编号 detInfo = [] for *xyxy, conf, cls in reversed(det): # 遍历检测信息 c1, c2 = (int(xyxy[0]), int(xyxy[1])), (int(xyxy[2]), int(xyxy[3])) # 将检测信息添加到字典中 detInfo.append([names[int(cls)], [c1[0], c1[1], c2[0], c2[1]], '%.2f' % conf]) number_i += 1 # 编号数+1 label = '%s %.2f' % (names[int(cls)], conf) # 画出检测到的目标物 plot_one_box(image, xyxy, label=label, color=colors[int(cls)]) # 实时显示检测画面 cv2.imshow('Stream', image) # if cv2.waitKey(1) & 0xFF == ord('q'): # break c = cv2.waitKey(0) & 0xff
执行得到的结果如下图所示,图中鸟类的种类和置信度值都标注出来了,预测速度较快。基于此模型我们可以将其设计成一个带有界面的系统,在界面上选择图片、视频或摄像头然后调用模型进行检测。
博主对整个系统进行了详细测试,最终开发出一版流畅得到清新界面,就是博文演示部分的展示,完整的UI界面、测试图片视频、代码文件,以及Python离线依赖包(方便安装运行,也可自行配置环境),均已打包上传,感兴趣的朋友可以通过下载链接获取。