前言
MMYOLO框架是一个基于PyTorch和MMDetection的YOLO系列算法开源工具箱。MMYOLO定位为YOLO系列热门开源库以及工业应用核心库,MMYOLO框架Github项目地址
支持的任务:目标检测、旋转目标检测
支持的算法:YOLOv5、YOLOX、RTMDet、RTMDet-Rotated、YOLOv6、YOLOv7、PPYOLOE、YOLOv8
支持COCO、VOC数据格式的训练
官方有一篇文章标注+训练+测试+部署全流程 写的很详细,基本上纯新手也是可以走完流程的。也可以观看视频自定义数据集从标注到部署保姆级教程 。MMYOLO系列视频 。
本文主要是对上述教程的一点点扩展(Win10系统),记录在使用过程中遇到的一些问题,解决过程以及对配置文件的深入解释。
pycocotools安装问题
首先从MMYOLO项目地址中下载整个项目,接着在命令窗口中输入pip install openmim。然后使用cd mmyolo进入项目文件下,注意这里的mmyolo是一个路径,比如你项目文件在D盘下,那你应该写cd D:\mmyolo。进入项目文件夹后输入mim install -r requirements/mminstall.txt
我在安装过程中只有一个库安装报错,就是pycocotools库,报错Microsoft Visual C++ 14.0 or greater is required,对应Github库 中作者强调了该错误信息是没有安装Visual C++ 2015 build tools,在文档中作者提供了一个下载地址 ,但是下载过程中总是报错。于是我找到了离线版本,下载链接
安装完成后,再次尝试mim install -r requirements/mminstall.txt无报错,问题解决!
xml文件path问题
因为标定的时候是两个人分开标的,导致xml文件中的path路径不一致,但不是每个人都有这样的问题,这里仅是做一点记录。
import xml. etree. ElementTree as ET
import os
def modify_xml_path ( xml_file) :
tree = ET. parse( xml_file)
root = tree. getroot( )
for path_elem in root. iter ( 'path' ) :
path_elem. text = os. path. basename( path_elem. text)
tree. write( xml_file)
folder_path = './data/xml'
for file in os. listdir( folder_path) :
file_path = os. path. join( folder_path, file )
modify_xml_path( file_path)
xml文件转json文件
因为之前做数据标定的时候没看过MMYOLO教程文档,所以使用Labelimg软件标定的,VOC格式,生成xml文件。
但是教程中使用的是Labelme,生成的json文件,并且后续的数据分隔、标注检验、数据集探索等等都是基于json文件,所以需要将xml文件转换为json文件。
先将文件按下列方式组织:
- mmyolo
- data
- images
- 0001 . bmp
- 0002 . bmp
- . . .
- xml
- 0001 . xml
- 0002 . xml
- . . .
- configs
. . .
在mmyolo项目文件夹下新建data文件夹,将图片放入.\data\images中,标定文件放入.\data\xml中。
然后在.\tools\dataset_converters文件夹中新建xml2json.py文件,填入代码:
import xml. etree. ElementTree as ET
import os
import json
coco = dict ( )
coco[ 'images' ] = [ ]
coco[ 'type' ] = 'instances'
coco[ 'annotations' ] = [ ]
coco[ 'categories' ] = [ ]
category_set = dict ( )
image_set = set ( )
category_item_id = - 1
image_id = 0
annotation_id = 0
def addCatItem ( name) :
global category_item_id
category_item = dict ( )
category_item[ 'supercategory' ] = 'none'
category_item_id += 1
category_item[ 'id' ] = category_item_id
category_item[ 'name' ] = name
coco[ 'categories' ] . append( category_item)
category_set[ name] = category_item_id
return category_item_id
def addImgItem ( file_name, size) :
global image_id
if file_name is None :
raise Exception( 'Could not find filename tag in xml file.' )
if size[ 'width' ] is None :
raise Exception( 'Could not find width tag in xml file.' )
if size[ 'height' ] is None :
raise Exception( 'Could not find height tag in xml file.' )
image_id += 1
image_item = dict ( )
image_item[ 'id' ] = image_id
print ( file_name)
image_item[ 'file_name' ] = file_name + ".jpg"
image_item[ 'width' ] = size[ 'width' ]
image_item[ 'height' ] = size[ 'height' ]
coco[ 'images' ] . append( image_item)
image_set. add( file_name)
return image_id
def addAnnoItem ( object_name, image_id, category_id, bbox) :
global annotation_id
annotation_item = dict ( )
annotation_item[ 'segmentation' ] = [ ]
seg = [ ]
seg. append( bbox[ 0 ] )
seg. append( bbox[ 1 ] )
seg. append( bbox[ 0 ] )
seg. append( bbox[ 1 ] + bbox[ 3 ] )
seg. append( bbox[ 0 ] + bbox[ 2 ] )
seg. append( bbox[ 1 ] + bbox[ 3 ] )
seg. append( bbox[ 0 ] + bbox[ 2 ] )
seg. append( bbox[ 1 ] )
annotation_item[ 'segmentation' ] . append( seg)
annotation_item[ 'area' ] = bbox[ 2 ] * bbox[ 3 ]
annotation_item[ 'iscrowd' ] = 0
annotation_item[ 'ignore' ] = 0
annotation_item[ 'image_id' ] = image_id
annotation_item[ 'bbox' ] = bbox
annotation_item[ 'category_id' ] = category_id
annotation_id += 1
annotation_item[ 'id' ] = annotation_id
coco[ 'annotations' ] . append( annotation_item)
def parseXmlFiles ( xml_path) :
for f in os. listdir( xml_path) :
if not f. endswith( '.xml' ) :
continue
xmlname = f. split( '.xml' ) [ 0 ]
bndbox = dict ( )
size = dict ( )
current_image_id = None
current_category_id = None
file_name = None
size[ 'width' ] = None
size[ 'height' ] = None
size[ 'depth' ] = None
xml_file = os. path. join( xml_path, f)
print ( xml_file)
tree = ET. parse( xml_file)
root = tree. getroot( )
if root. tag != 'annotation' :
raise Exception( 'pascal voc xml root element should be annotation, rather than {}' . format ( root. tag) )
for elem in root:
current_parent = elem. tag
current_sub = None
object_name = None
if elem. tag == 'folder' :
continue
if elem. tag == 'filename' :
file_name = xmlname
if file_name in category_set:
raise Exception( 'file_name duplicated' )
elif current_image_id is None and file_name is not None and size[ 'width' ] is not None :
if file_name not in image_set:
current_image_id = addImgItem( file_name, size)
print ( 'add image with {} and {}' . format ( file_name, size) )
else :
raise Exception( 'duplicated image: {}' . format ( file_name) )
for subelem in elem:
bndbox[ 'xmin' ] = None
bndbox[ 'xmax' ] = None
bndbox[ 'ymin' ] = None
bndbox[ 'ymax' ] = None
current_sub = subelem. tag
if current_parent == 'object' and subelem