mmdetection 类别出错问题+训练+测试

mmdetection 是时下比较常用的目标检测工具箱,集成了faster ,cascade,yolo 等性能比较好的检测算法,熟练使用mmdetection进行自定义数据的目标检测就成为了很多AIer的必经之路。

项目仓库地址:https://github.com/open-mmlab/mmdetection

安装,装环境就略过了。

装完之后,想要训练自己的数据集,首先要将自己的数据整理成COCO的格式:

--------data

---------------coco

-----------------------annotations

---------------------------------------train.json,val.json

------------------------images

---------------------------------------......jpg

annotations文件夹下包含了train.json和val.json,images文件夹下则为全部图像数据。

自己的数据标签格式需要整理为json才行,具体的转换方法可以直接去搜程序,也可以自己写。这里给出一部分,可能不适应直接用。

1.xml转coco

import os.path as osp
import xml.etree.ElementTree as ET

import mmcv

from mmdet.core import sea_classes

from glob import glob
from tqdm import tqdm
from PIL import Image

label_ids = {name: i + 1 for i, name in enumerate(sea_classes())}


def get_segmentation(points):
    return [points[0], points[1], points[2] + points[0], points[1],
            points[2] + points[0], points[3] + points[1], points[0], points[3] + points[1]]


def parse_xml(xml_path, img_id, anno_id):
    tree = ET.parse(xml_path)
    # print(str(xml_path))
    root = tree.getroot()
    annotation = []
    for obj in root.findall('object'):
        try:
            name = obj.find('name').text
            # if name in ['lighter','powerbank','zippooil','firecrackers','handcuffs','pressure','slingshot','nailpolish']:
            #    continue

            category_id = label_ids[name]
            bnd_box = obj.find('bndbox')
            xmin = int(bnd_box.find('xmin').text)
            ymin = int(bnd_box.find('ymin').text)
            xmax = int(bnd_box.find('xmax').text)
            ymax = int(bnd_box.find('ymax').text)
            if xmin >= xmax or ymin >= ymax:
                continue
            w = xmax - xmin + 1
            h = ymax - ymin + 1
            area = w * h
            segmentation = get_segmentation([xmin, ymin, w, h])
            annotation.append({
                "segmentation": segmentation,
                "area": area,
                "iscrowd": 0,
                "image_id": img_id,
                "bbox": [xmin, ymin, w, h],
                "category_id": category_id,
                "id": anno_id,
                "ignore": 0})
            anno_id += 1
        except:
            continue
    return annotation, anno_id


def cvt_annotations(img_path, xml_path, out_file):
    images = []
    annotations = []

    # xml_paths = glob(xml_path + '/*.xml')
    img_id = 1
    anno_id = 1
    for img_path in tqdm(glob(img_path + '/*.jpg')):
        w, h = Image.open(img_path).size
        img_name = osp.basename(img_path)
        img = {"file_name": img_name, "height": int(h), "width": int(w), "id": img_id}
        images.append(img)

        xml_file_name = img_name.split('.')[0] + '.xml'
        xml_file_path = osp.join(xml_path, xml_file_name)
        annos, anno_id = parse_xml(xml_file_path, img_id, anno_id)
        annotations.extend(annos)
        img_id += 1

    categories = []
    for k, v in label_ids.items():
        categories.append({"name": k, "id": v})
    final_result = {"images": images, "annotations": annotations, "categories": categories}
    mmcv.dump(final_result, out_file)
    return annotations


def main():
    xml_path = "/.../mmdetection-master/data/coco/xmlannotations/"####xml文件文件夹
    img_path = "/.../mmdetection-master/data/coco/images/"####所有图像
    print('processing {} ...'.format("xml format annotations"))
    cvt_annotations(img_path, xml_path, '/.../mmdetection-master/data/coco/annotations/train.json')#####train.json文件保存地址
    print('Done!')


if __name__ == '__main__':
    main()

2. train.json文件分成训练集和验证集

import os
import os.path as pt
import json
import funcy
from pycocotools.coco import COCO
from pycocotools.cocoeval import COCOeval
from sklearn.model_selection import train_test_split


def split_train_val(annotations, trainpath, valpath, splitrate=0.99):
    with open(annotations, 'rt', encoding='UTF-8') as annotations:
        coco = json.load(annotations)
        images = coco['images']
        annotations = coco['annotations']
        categories = coco['categories']

        # number_of_images = len(images)
        train, val = train_test_split(images, train_size=splitrate)

        save_coco(trainpath, train, filter_annotations(annotations, train),
                  categories)
        save_coco(valpath, val, filter_annotations(annotations, val),
                  categories)

        print("Saved {} entries in {} and {} in {}".format(
            len(train), trainpath, len(val), valpath))


def save_coco(file, images, annotations, categories):
    with open(file, 'wt', encoding='UTF-8') as coco:
        json.dump(
            {
                'images': images,
                'annotations': annotations,
                'categories': categories
            },
            coco,
            indent=4,
            sort_keys=True)


def filter_annotations(annotations, images):
    image_ids = funcy.lmap(lambda i: int(i['id']), images)
    return funcy.lfilter(lambda a: int(a['image_id']) in image_ids,
                         annotations)


def main():
    COCO_FORMAT_JSON_PATH = '/.../mmdetection-master/data/coco/annotations/'###json文件保存文件夹

    annotations = pt.join(COCO_FORMAT_JSON_PATH, 'train.json')###待分割json
    trainpath = pt.join(COCO_FORMAT_JSON_PATH, 'train_.json')###分割后
    valpath = pt.join(COCO_FORMAT_JSON_PATH, 'val.json')
    split_train_val(annotations, trainpath, valpath)


if __name__ == '__main__':
    main()

训练

数据准备完毕后,就要修改配置文件,使mmdetection中的分类类别,类别数与自己的数据集一样,需要修改的地方如下:

    1./mmdetection-master/mmdet/datasets/coco.py

将class CocoDataset(CustomDataset):

    CLASSES = (
        'holothurian','echinus','scallop','starfish'
    )

中的CLASSES元组列表中80类替换为自己的。如上我的为4类,注意:只有一个类别是需要改成这样:CLASSES=('pig',)      必须要有一个逗号才行。

  2 . /mmdetection-master/mmdet/core/evaluation/classes_name.py中


def coco_classes():
    return [
        'holothurian','echinus','scallop','starfish'
    ]

中的80类也替换为自己的,此处类别为一类的话就不需要加逗号了。

 3. 修改你要跑的模型的配置文件,比如faster_rpn_50

/mmdetection-master/configs/faster_rcnn/faster_rcnn_r50_fpn_1x_coco.py

打开可以看到_base_ = [
    '../_base_/models/faster_rcnn_r50_fpn.py',
    '../_base_/datasets/coco_detection.py',
    '../_base_/schedules/schedule_1x.py', '../_base_/default_runtime.py'
]

说明其网络配置在_base_/models/faster_rcnn_r50_fpn.py中,训练数据加载在_base_/datasets/coco_detection.py中,可以到_base_/datasets/coco_detection.py中直接修改训练文件路径:

dataset_type = 'CocoDataset'
data_root = '/home1/dzzHD/mmdetection-master/data/coco/'

data = dict(
    samples_per_gpu=2,
    workers_per_gpu=2,
    train=dict(
        type=dataset_type,
        ann_file=data_root + 'annotations/train.json',
        img_prefix=data_root + 'train/',
        pipeline=train_pipeline),
    val=dict(
        type=dataset_type,
        ann_file=data_root + 'annotations/val.json',
        img_prefix=data_root + 'val/',
        pipeline=test_pipeline),
    test=dict(
        type=dataset_type,
        ann_file=data_root + 'annotations/val.json',
        img_prefix=data_root + 'test/',
        pipeline=test_pipeline))
evaluation = dict(interval=1, metric='bbox')

然后就可以运行训练

python tools/train.py configs/faster_rcnn/.....py  --work-dir  +自己建立的结果保存路径即可

我用的2.0的,这样直接运行会报错,说类别数还是没有改成功,只能通过重新编译才行,但是我没有重新编译的权限,所以想了一个曲线救国的办法:

运行出错后,仍然会才输出文件路径保存一个你自己的配置文件,这个配置文件中有你选择的网络、数据、训练方式等,可以直接在该配置文件中设定自己的类别数:

###################################################### 
           max_per_img=200)))
dataset_type = 'CocoDataset'
data_root = '/home1/dzzHD/mmdetection-master/data/coco/'
CLASSES = ('holothurian', 'echinus', 'scallop', 'starfish')#####直接添加,一类要加逗号
img_norm_cfg = dict(
    mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
####################################################
#######在data中的train,val ,test都添加: 
data = dict(
    samples_per_gpu=2,
    workers_per_gpu=2,
    train=dict(
        type='CocoDataset',
        classes=CLASSES,#############添加该句
        ann_file=
        '/home1/dzzHD/mmdetection-master/data/coco/sea_2021/jsooon/train_.json',
        img_prefix='/home1/dzzHD/mmdetection-master/data/coco/sea_2021/images/',
        pipeline=[
            dict(type='LoadImageFromFile'),
            dict(type='LoadAnnotations', with_bbox=True),
            dict(
                type='Resize',
                img_scale=[(1780, 600), (1780, 1000)],
                multiscale_mode='range',
                keep_ratio=True),

之后再训练,配置文件直接选择改好的:

python tools/train.py 自己的输出路径下的配置文件 --work-dir  +自己建立的结果保存路径即可

测试:

mmdetection中自带的test.py仅仅是个例子,只能跑一张图像,是个demo,可以自己写test文件并输出自己指定格式的文件:下面是我的,输出格式为txt文件:

#自定义test.py mmdetection中test是仅对一张图片进行的,自定义对多张图片进行,并且保存结果随后对结果进行整形,整到可以提交的结果
####每次运行要清空savepath和finaltxt路径下的内容
from mmdet.apis import inference_detector, init_detector,show_result_pyplot
import cv2
import os
def transformation(txtpath,newtxt):####结果整形,整到提交格式

    f=open(txtpath,'r')
    files=f.readlines()
    # print(files[0][7:])
    files[0] = files[0][7:]
    mm = len(files)
    # print(files[mm-1][:-17])
    files[mm - 1] = files[mm - 1][:-17]
    # print(files)
    files1=files[1::2]
    files2=files[::2]
    num=len(files2)####pignumber
    with open (newtxt,'w', encoding="utf-8") as new:
        for i in range(num):
           # print(item)
            item=files2[i]
            item=item.replace('[','')
            item=item.replace(']','')
            item=item.replace('\n','')
            item2=files1[i]
            item2 = item2.replace('[', '')
            item2 = item2.replace(']', '')
            item2 = item2.replace('\n', '')
            item2=item2.replace(',','')
            #print(item.split(','))
            item=['pig',
                  float(item2),
                  int(0.5*float(item.split(',')[0])+0.5*float(item.split(',')[2])),
                  int(0.5*float(item.split(',')[1])+0.5*float(item.split(',')[3])),
                  int(float(item.split(',')[2])-float(item.split(',')[0])),
                  int(float(item.split(',')[3])-float(item.split(',')[1]))]
            item = str(item)
            item = ''.join(item.split())
            item=item.replace(',',' ')
            item=item.replace('\'','')
            new.write(str(item)[1:-1])
            new.write('\r\n')


config_file = 'output/train/faster_rcnn_r50_fpn_1x_coco.py'#####模型配置文件
checkpoint_file = 'output/train/latest.pth'#####训练好的模型
#
model = init_detector(config_file, checkpoint_file)####初始化模型

imgpath = 'data/coco/test/'#####测试集图像路径
savepath='/home1/dzzHD/mmdetection-master/output/result_v1/'####测试结果txt保存路径
finaltxt='/home1/dzzHD/mmdetection-master/output/test/'###最终整形结果保存路径
imgs=os.listdir(imgpath)

for item in imgs:#######逐张检测测试集图像并保存结果
    print(item)
    imgname=item.split('.')[0]

    img=cv2.imread(imgpath+item)

    result = inference_detector(model, img)
    txtpath1=savepath+imgname+'.txt'
    finaltxtpath=finaltxt+imgname+'.txt'

    file=open(txtpath1,'w', encoding="utf-8")
    file.write(str(result))
    file.close()
    transformation(txtpath1,finaltxtpath)
    ###结果文件整形


#print('result saved')
#print(type(result))
#print(img.split('/'))
#show_result_pyplot(model,img, result, score_thr=0.3) #这里将结果图片进行保存,其余参数为默认

OK,thats all mthank you .

  • 13
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DZZ!!!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值