当前位置:   article > 正文

手把手教学旋转框目标检测mmrotate v0.3.4_深度学习旋转目标框

深度学习旋转目标框

旋转目标检测mmrotate

干什么:

旋转目标检测框任务

优势:

  • 复现顶会的论文
  • 自定义旋转目标检测模型
  • 基础模型进行对比

实现mmrotate的五个步骤

  • 环境的安装

首先创建虚拟环境,

  1. conda create --n mmrotate python=3.8 -y
  2. conda activate mmrotate

然后需要安装pytorch,这里需要根据自己服务器的显卡,如果是30系列的话,最好使用cuda11,

我这里使用的torch v1.11.0

  1. # CUDA 11.3
  2. conda install pytorch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 cudatoolkit=11.3 -c pytorch

可以conda安装pytorch,也可以使用pip,

紧接着就是安装对应的包

  1. 0步: 使用 MIM 安装 MMCV 和 MMDetection
  2. pip install -U openmim
  3. mim install mmcv-full
  4. mim install mmdet\<3.0.0
  5. 1步: 安装 MMRotate.
  6. git clone https://github.com/open-mmlab/mmrotate.git
  7. cd mmrotate
  8. pip install -v -e .

需要注意的点是,可以使用pip,也可以使用mim,建议使用mim安装,

pip install  -v  -e . 这个.一定不能漏掉,否则会报错。

使用pip show mmrotate,查看对应的库的版本

环境验证

验证是否正确安装了 MMRotate和环境依赖

第1步: 我们需要下载配置文件和检查点文件。

mim download mmrotate --config oriented_rcnn_r50_fpn_1x_dota_le90 --dest .

下载完成之后,当前文件夹下会找到oriented_rcnn_r50_fpn_1x_dota_le90.py 和 oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth 这两个文件。.py为配置文件,.pth为权重文件

第2步: 验证推理演示

  1. 运行以下命令
  2. python demo/image_demo.py demo/demo.jpg oriented_rcnn_r50_fpn_1x_dota_le90.py oriented_rcnn_r50_fpn_1x_dota_le90-6d2b2ce0.pth --out-file result.jpg

当前目录下看到一张名为 result.jpg 的新图片,其中旋转边界框绘制在汽车、公共汽车等目标上

  • 数据集的处理

MMRoteate 支持的数据集

每个格式都有对应的代码图像修改

这是我们最开始的图像文件夹放置格式

这里我使用DOTA V1.0和自己构造的数据集进行训练,首先先介绍DOTA V1.0数据集

DOTA V1.0数据集

下载地址:DOTA(推荐使用google driver下载)

当将文件夹按照上面情况摆放后,对数据集进行裁剪  ,因为dota格式需要满足图片为.png格式且尺寸是 n×n 的(方形)通过./tools/data/dota/split/img_split.py (裁剪脚本),split文件夹里面存放着配置文件split_configs和img_split.py的执行文件。

其他的val和test也是一样类似处理,处理好后,结果是下面的情况。(其中ss_表示单一尺度裁剪,ms_表示多尺度裁剪)

以上是对公共数据集进行裁剪和整理。下面对我自己的数据集进行裁剪处理,

第一,给图像进行标注,

roLabelImg 打标签

roLabelImg工具专门用于旋转框的标注,操作时:可以使用一些快捷键实现快速标注

最后生成的文件目录为:

第二 给自己的数据集进行格式转化,和数据集划分

xml格式转dota格式(txt)

  1. import os
  2. import xml.etree.ElementTree as ET
  3. import math
  4. import cv2 as cv
  5. def voc_to_dota(xml_dir, xml_name, img_dir, savedImg_dir):
  6. txt_name = xml_name[:-4] + '.txt' # txt文件名字:去掉xml 加上.txt
  7. txt_path = xml_dir + '/txt_label' # txt文件目录:在xml目录下创建的txtl_label文件夹
  8. if not os.path.exists(txt_path):
  9. os.makedirs(txt_path)
  10. txt_file = os.path.join(txt_path, txt_name) # txt完整的含名文件路径
  11. img_name = xml_name[:-4] + '.jpg' # 图像名字
  12. img_path = os.path.join(img_dir, img_name) # 图像完整路径
  13. img = cv.imread(img_path) # 读取图像
  14. xml_file = os.path.join(xml_dir, xml_name)
  15. tree = ET.parse(os.path.join(xml_file)) # 解析xml文件 然后转换为DOTA格式文件
  16. root = tree.getroot()
  17. with open(txt_file, "w+", encoding='UTF-8') as out_file:
  18. # out_file.write('imagesource:null' + '\n' + 'gsd:null' + '\n')
  19. for obj in root.findall('object'):
  20. name = obj.find('name').text
  21. difficult = obj.find('difficult').text
  22. # print(name, difficult)
  23. robndbox = obj.find('robndbox')
  24. cx = float(robndbox.find('cx').text)
  25. cy = float(robndbox.find('cy').text)
  26. w = float(robndbox.find('w').text)
  27. h = float(robndbox.find('h').text)
  28. angle = float(robndbox.find('angle').text)
  29. # print(cx, cy, w, h, angle)
  30. p0x, p0y = rotatePoint(cx, cy, cx - w / 2, cy - h / 2, -angle)
  31. p1x, p1y = rotatePoint(cx, cy, cx + w / 2, cy - h / 2, -angle)
  32. p2x, p2y = rotatePoint(cx, cy, cx + w / 2, cy + h / 2, -angle)
  33. p3x, p3y = rotatePoint(cx, cy, cx - w / 2, cy + h / 2, -angle)
  34. # 找最左上角的点
  35. dict = {p0y:p0x, p1y:p1x, p2y:p2x, p3y:p3x }
  36. list = find_topLeftPopint(dict)
  37. #print((list))
  38. if list[0] == p0x:
  39. list_xy = [p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y]
  40. elif list[0] == p1x:
  41. list_xy = [p1x, p1y, p2x, p2y, p3x, p3y, p0x, p0y]
  42. elif list[0] == p2x:
  43. list_xy = [p2x, p2y, p3x, p3y, p0x, p0y, p1x, p1y]
  44. else:
  45. list_xy = [p3x, p3y, p0x, p0y, p1x, p1y, p2x, p2y]
  46. # 在原图上画矩形 看是否转换正确
  47. cv.line(img, (int(list_xy[0]), int(list_xy[1])), (int(list_xy[2]), int(list_xy[3])), color=(255, 0, 0), thickness= 3)
  48. cv.line(img, (int(list_xy[2]), int(list_xy[3])), (int(list_xy[4]), int(list_xy[5])), color=(0, 255, 0), thickness= 3)
  49. cv.line(img, (int(list_xy[4]), int(list_xy[5])), (int(list_xy[6]), int(list_xy[7])), color=(0, 0, 255), thickness= 2)
  50. cv.line(img, (int(list_xy[6]), int(list_xy[7])), (int(list_xy[0]), int(list_xy[1])), color=(255, 255, 0), thickness= 2)
  51. data = str(list_xy[0]) + " " + str(list_xy[1]) + " " + str(list_xy[2]) + " " + str(list_xy[3]) + " " + \
  52. str(list_xy[4]) + " " + str(list_xy[5]) + " " + str(list_xy[6]) + " " + str(list_xy[7]) + " "
  53. data = data + name + " " + difficult + "\n"
  54. out_file.write(data)
  55. if not os.path.exists(savedImg_dir):
  56. os.makedirs(savedImg_dir)
  57. out_img = os.path.join(savedImg_dir, xml_name[:-4]+'.jpg')
  58. cv.imwrite(out_img, img)
  59. def find_topLeftPopint(dict):
  60. dict_keys = sorted(dict.keys()) # y值
  61. temp = [dict[dict_keys[0]], dict[dict_keys[1]]]
  62. minx = min(temp)
  63. if minx == temp[0]:
  64. miny = dict_keys[0]
  65. else:
  66. miny = dict_keys[1]
  67. return [minx, miny]
  68. # 转换成四点坐标
  69. def rotatePoint(xc, yc, xp, yp, theta):
  70. xoff = xp - xc
  71. yoff = yp - yc
  72. cosTheta = math.cos(theta)
  73. sinTheta = math.sin(theta)
  74. pResx = cosTheta * xoff + sinTheta * yoff
  75. pResy = - sinTheta * xoff + cosTheta * yoff
  76. # pRes = (xc + pResx, yc + pResy)
  77. # 保留一位小数点
  78. return float(format(xc + pResx, '.1f')), float(format(yc + pResy, '.1f'))
  79. # return xc + pResx, yc + pResy
  80. import argparse
  81. def parse_args():
  82. parser = argparse.ArgumentParser(description='数据格式转换')
  83. parser.add_argument('--xml-dir', default='./buildings/train/label', help='original xml file dictionary')
  84. parser.add_argument('--img-dir', default='./buildings/train', help='original image dictionary')
  85. parser.add_argument('--outputImg-dir', default='./buildings/train/out', help='saved image dictionary after dealing ')
  86. args = parser.parse_args()
  87. return args
  88. if __name__ == '__main__':
  89. args = parse_args()
  90. xml_path = args.xml_dir
  91. xmlFile_list = os.listdir(xml_path)
  92. print(xmlFile_list)
  93. for i in range(0, len(xmlFile_list)):
  94. if ('.xml' in xmlFile_list[i]) or ('.XML' in xmlFile_list[i]):
  95. voc_to_dota(xml_path, xmlFile_list[i], args.img_dir, args.outputImg_dir)
  96. print('----------------------------------------{}{}----------------------------------------'
  97. .format(xmlFile_list[i], ' has Done!'))
  98. else:
  99. print(xmlFile_list[i] + ' is not xml file')

运行之后得到的文件目录结果如下,txt_label是dota格式下的标签

第三步,将数据集按照训练集,验证集和最后的测试集

可以参考 将标注好的数据集进行划分

可以将数据集打乱,然后随机划分数据集,输入img和lables,outputimg的地址就可以生成了,

划分好后,参照上面DOTA V1.0对数据集进行裁剪。

  • 配置文件的设置

配置文件这里就需要包含两个方面的配置文件,一个就是对数据的配置文件的修改,另外一个就是对模型配置文件的修改。

数据集配置文件

数据集配置文件主要修改     num_classes类别数,类别名称,数据集的位置,samples_per_gpu ,workers_per_gpu,epochs,打印设置等参数

num_classes类别数在   ./configs/r3det/r3det_tiny_r50_fpn_1x_dota_oc.py文件中

类别名称 ./mmrotate/datasets/dota.py

数据集的位置和samples_per_gpu ,workers_per_gpu,   在./configs/_base_/datasets/dotav1.py 文件

samples_per_gpu ,workers_per_gpu这里需要注意的是,# 设置的batch_size是通过samples_per_gpu,如果你只有一张显卡,那batch_size=samples_per_gpu,如果如果你有两张显卡,那么n x samples_per_gpu= batch_size,即

# 总的batch_size就是单个GPU的batch_size*GPU数量

设置的num_worker是通过修改workers_per_gpu,workers_per_gpu=每个GPU的workers

GPU workers 在 PyTorch 中指的是在 GPU 上运行的工作进程。

  • worker 的数量对性能有很大影响。增加 worker 数可以加速训练,但过多也会导致资源竞争。需要根据 GPU 内存大小适当设置。

  • 数据加载也可以通过 worker 进行并行加速。设置 num_workers 参数来启动数据加载线程。

 ./configs/_base_/schedules/schedule_1x.py 中,设置epochs,

  1. # evaluation
  2. evaluation = dict(interval=5, metric='mAP') # 训练多少轮评估一次
  3. # optimizer
  4. optimizer = dict(type='SGD', lr=0.0025, momentum=0.9, weight_decay=0.0001)
  5. optimizer_config = dict(grad_clip=dict(max_norm=35, norm_type=2))
  6. # learning policy
  7. lr_config = dict(
  8. policy='step',
  9. warmup='linear',
  10. warmup_iters=500,
  11. warmup_ratio=1.0 / 3,
  12. step=[8, 11])
  13. runner = dict(type='EpochBasedRunner', max_epochs=100) # 训练的总次数
  14. checkpoint_config = dict(interval=10) # 训练多少次后保存模型

 ./configs/_base_/default_runtime.py  修改log配置和使用tensorboaed

 
以上是数据集配置文件的修改
模型文件的修改

模型文件的修改需要分为两个部分,一个是自己自定义的模型和使用现有的模型

这里先介绍使用现有的模型进行训练

1、下载模型的预训练权重,这里主要看你自己需要用什么算法,我用的是r3dat,

下载权重的链接

2、修改配置文件

在该./configs/r3det/r3det_tiny_r50_fpn_1x_dota_oc.py文件下设置预训练权重的地址,修改为你下载的预训练权重地址。(我这里使用的是绝对路径)

  1. init_cfg=dict(type='Pretrained', checkpoint='/home/lwc/homework/pytorchs_detection_project/mmrotate/checkpoint/r3det_tiny_r50_fpn_1x_dota_oc-c98a616c.pth')),
  2. neck=dict(
  • 模型的训练

模型的训练,这里需要看自己是单gpu训练,还是多gpu训练

单gpu训练

python tools/train.py ${CONFIG_FILE} [optional arguments]
python tools/train.py    configs/r3det/r3det_tiny_r50_fpn_1x_dota_oc.py  --work-dir  ./run/r3dat/dota

多gpu训练

./tools/dist_train.sh ${CONFIG_FILE} ${GPU_NUM} [optional arguments]

例子:

./tools/dist_train.sh configs/r3det/r3det_tiny_r50_fpn_1x_dota_oc.py 4

看到在运行,不报错,就可以呢!

  • 模型的测试

预测的话,修改 test.py 中的路径参数即可。

主要有三个参数: - -config: 使用的模型文件 ; - -checkpoint:训练得到的模型权重文件; --show-dir: 预测结果存放的路径。

可以在里面加default=’xxxxx‘,也可以在命令行里面加,但是请注意的是,应该怎么添加,否则会报错

参考文献

mmrotate官方文档

旋转框目标检测mmrotate v0.3.1 训练DOTA数据集(二)

MMRotate从零开始训练自己的数据集

基于mmdetection 旋转目标检测(OBB detection)+DOTA数据集&自定义数据集+配docker

MMRotate 详细使用教程

【DOTA】目标检测数据集介绍与使用


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/509399
推荐阅读
相关标签
  

闽ICP备14008679号