• DMNet复现(二)之模型篇:Density map guided object detection in aerial image


    以前用Swin Transformer Tiny训练了40epoch的,官方用的Faster RCNN,这里先用Swin Transformer Tiny进行测试。

    模型训练

    采用基于MMDetection的框架Swin Transformer Tiny进行训练,训练方法可参考官方教程。

    融合检测

    Global Image 检测

    这是我的配置文件及目录

    需要用训练好的权重进行全局图像检测,将结果保存为.bbox.json文件。

    环境信息:

    1. sys.platform: linux
    2. Python: 3.8.10 (default, Jun 4 2021, 15:09:15) [GCC 7.5.0]
    3. CUDA available: True
    4. numpy_random_seed: 2147483648
    5. GPU 0: NVIDIA GeForce RTX 3090
    6. CUDA_HOME: /usr/local/cuda
    7. NVCC: Cuda compilation tools, release 11.3, V11.3.109
    8. GCC: gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
    9. PyTorch: 1.10.0+cu113
    10. PyTorch compiling details: PyTorch built with:
    11. - GCC 7.3
    12. - C++ Version: 201402
    13. - Intel(R) Math Kernel Library Version 2020.0.0 Product Build 20191122 for Intel(R) 64 architecture applications
    14. - Intel(R) MKL-DNN v2.2.3 (Git Hash 7336ca9f055cf1bfa13efb658fe15dc9b41f0740)
    15. - OpenMP 201511 (a.k.a. OpenMP 4.5)
    16. - LAPACK is enabled (usually provided by MKL)
    17. - NNPACK is enabled
    18. - CPU capability usage: AVX512
    19. - CUDA Runtime 11.3
    20. - NVCC architecture flags: -gencode;arch=compute_37,code=sm_37;-gencode;arch=compute_50,code=sm_50;-gencode;arch=compute_60,code=sm_60;-gencode;arch=compute_70,code=sm_70;-gencode;arch=compute_75,code=sm_75;-gencode;arch=compute_80,code=sm_80;-gencode;arch=compute_86,code=sm_86
    21. - CuDNN 8.2
    22. - Magma 2.5.2
    23. - Build settings: BLAS_INFO=mkl, BUILD_TYPE=Release, CUDA_VERSION=11.3, CUDNN_VERSION=8.2.0, CXX_COMPILER=/opt/rh/devtoolset-7/root/usr/bin/c++, CXX_FLAGS= -Wno-deprecated -fvisibility-inlines-hidden -DUSE_PTHREADPOOL -fopenmp -DNDEBUG -DUSE_KINETO -DUSE_FBGEMM -DUSE_QNNPACK -DUSE_PYTORCH_QNNPACK -DUSE_XNNPACK -DSYMBOLICATE_MOBILE_DEBUG_HANDLE -DEDGE_PROFILER_USE_KINETO -O2 -fPIC -Wno-narrowing -Wall -Wextra -Werror=return-type -Wno-missing-field-initializers -Wno-type-limits -Wno-array-bounds -Wno-unknown-pragmas -Wno-sign-compare -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-unused-result -Wno-unused-local-typedefs -Wno-strict-overflow -Wno-strict-aliasing -Wno-error=deprecated-declarations -Wno-stringop-overflow -Wno-psabi -Wno-error=pedantic -Wno-error=redundant-decls -Wno-error=old-style-cast -fdiagnostics-color=always -faligned-new -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-math-errno -fno-trapping-math -Werror=format -Wno-stringop-overflow, LAPACK_INFO=mkl, PERF_WITH_AVX=1, PERF_WITH_AVX2=1, PERF_WITH_AVX512=1, TORCH_VERSION=1.10.0, USE_CUDA=ON, USE_CUDNN=ON, USE_EXCEPTION_PTR=1, USE_GFLAGS=OFF, USE_GLOG=OFF, USE_MKL=ON, USE_MKLDNN=ON, USE_MPI=OFF, USE_NCCL=ON, USE_NNPACK=ON, USE_OPENMP=ON,
    24. TorchVision: 0.11.1+cu113
    25. OpenCV: 4.6.0
    26. MMEngine: 0.8.4
    27. mmdetection: 2.11.0+461e003

    采用以下配置文件

    python tools/test.py  work_dirs/swin_s/swin_tiny_global_detection.py /root/autodl-tmp/result/swin_s/epoch_40.pth --eval bbox
    1. # 继承之前的配置文件
    2. _base_ = ["./mask_rcnn_swin_tiny_patch4_window7_mstrain_480-800_adamw_1x_coco.py"]
    3. # 修改数据路径
    4. dataset_type = 'CocoDataset'
    5. data_root = '/root/autodl-tmp/VisDrone2019/'
    6. data = dict(
    7. samples_per_gpu=1,
    8. workers_per_gpu=0,
    9. train=dict(
    10. type=dataset_type,
    11. ann_file=data_root + 'VisDrone2019-DET-train/Global/train.json',
    12. img_prefix=data_root + 'VisDrone2019-DET-train/Global/images/',),
    13. val=dict(
    14. type=dataset_type,
    15. ann_file=data_root + 'VisDrone2019-DET-val/Global/val.json',
    16. img_prefix=data_root + 'VisDrone2019-DET-val/Global/images/',),
    17. test=dict(
    18. type=dataset_type,
    19. ann_file=data_root + 'VisDrone2019-DET-test-dev/Global/test.json',
    20. img_prefix=data_root + 'VisDrone2019-DET-test-dev/Global/images/',))

    这个mmdetect版本有点老了,生成json文件得靠以下命令:

    python tools/test.py  work_dirs/swin_s/swin_tiny_global_detection.py /root/autodl-tmp/result/swin_s/epoch_40.pth --format-only     --options "jsonfile_prefix=./work_dirs/Global/Global_swin_tiny_test-dev_results"

    Local Image 检测

    配置文件

    1. # 继承之前的配置文件
    2. _base_ = ["./mask_rcnn_swin_tiny_patch4_window7_mstrain_480-800_adamw_1x_coco.py"]
    3. # 修改数据路径
    4. dataset_type = 'CocoDataset'
    5. data_root = '/root/autodl-tmp/VisDrone2019/'
    6. data = dict(
    7. samples_per_gpu=1,
    8. workers_per_gpu=0,
    9. train=dict(
    10. type=dataset_type,
    11. ann_file=data_root + 'VisDrone2019-DET-train/Global/train.json',
    12. img_prefix=data_root + 'VisDrone2019-DET-train/Global/images/',),
    13. val=dict(
    14. type=dataset_type,
    15. ann_file=data_root + 'VisDrone2019-DET-val/Global/val.json',
    16. img_prefix=data_root + 'VisDrone2019-DET-val/Global/images/',),
    17. test=dict(
    18. type=dataset_type,
    19. ann_file=data_root + 'VisDrone2019-DET-test-dev/Density/VisDrone2019-DET-test-dev.json',
    20. img_prefix=data_root + 'VisDrone2019-DET-test-dev/Density/images/',))

    命令

    python tools/test.py  work_dirs/swin_s/swin_tiny_global_detection.py /root/autodl-tmp/result/swin_s/epoch_40.pth --format-only     --options "jsonfile_prefix=./work_dirs/Density/Density_swin_tiny_test-dev_results"

    由于原论文采用的Faster RCNN对验证集进行测试,这里想对比一下精度,就再对验证集生成一下json文件

    Global图像检测命令

    python tools/test.py  work_dirs/swin_s/swin_tiny_global_detection.py /root/autodl-tmp/result/swin_s/epoch_40.pth --format-only     --options "jsonfile_prefix=./work_dirs/Global/swin_tiny_val_results"

    Local图像检测命令

     python tools/test.py  work_dirs/swin_s/swin_tiny_global_detection.py /root/autodl-tmp/result/swin_s/epoch_40.pth --format-only     --options "jsonfile_prefix=./work_dirs/Density/swin_tiny_val_results"

    检测结果融合

    代码:

    1. import os
    2. import glob
    3. import copy, cv2
    4. import numpy as np
    5. from tqdm import tqdm
    6. from plot_utils import overlay_func, overlay_bbox_img
    7. from eval_utils import resize_bbox_to_original, wrap_initial_result, results2json, coco_eval, nms, class_wise_nms
    8. import argparse
    9. from pycocotools.coco import COCO
    10. """
    11. Code for DMnet, Global-local fusion detection
    12. The fusion result of annotations will be saved to output json files
    13. Author: Changlin Li
    14. Code revised on : 7/18/2020
    15. The data should be arranged in following structure before you call any function within this script:
    16. dataset(Train/val/test)
    17. -----mode(Train/val/test)
    18. ------Global
    19. --------images
    20. --------Annotations (Optional, not available only when you conduct inference steps)
    21. ------Density
    22. --------images
    23. --------Annotations (Optional, not available only when you conduct inference steps)
    24. Sample command line to run:
    25. python fusion_detection_result_official.py crop_data_fusion_mcnn --mode val
    26. """
    27. def parse_args():
    28. parser = argparse.ArgumentParser(
    29. description='DMNet -- Global-local fusion detection')
    30. parser.add_argument('root_dir', default=".",
    31. help='the path for source data')
    32. parser.add_argument('--mode', default="train", help='Indicate if you are working on train/val/test set')
    33. parser.add_argument('--truncate_threshold', type=float, default=0,
    34. help='Threshold defined to select the cropped region')
    35. parser.add_argument('--iou_threshold', type=float, default=0.7,
    36. help='Iou Threshold defined to filter out bbox, recommend val by mmdetection: 0.7')
    37. parser.add_argument('--TopN', type=int, default=500,
    38. help='Only keep TopN bboxes with highest score, default value 500, '
    39. 'enforced by visiondrone competition')
    40. parser.add_argument('--show', action='store_true', help='Need to keep original image?')
    41. args = parser.parse_args()
    42. return args
    43. if __name__ == "__main__":
    44. # start by providing inference result based on your file path
    45. # if you perform fusion in val phase, then your img_path belongs to val folder
    46. # pay attention to id and image_id in ann, same val but different name
    47. print("PLEASE CHANGE ALL PATHS BEFORE U GO!!!")
    48. args = parse_args()
    49. mode = args.mode
    50. show = args.show
    51. root = "."
    52. truncate_threshold = args.truncate_threshold
    53. folder_name = args.root_dir
    54. classList = ["pedestrian", "people", "bicycle", "car", "van", "truck", "tricycle", "awning-tricycle",
    55. "bus", "motor","0","1"]
    56. #-------------------------------------------------------------------#
    57. #-----------------------写死验证集路径-------------------------------#
    58. img_path = os.path.join(root, folder_name, mode, "Global", "images")
    59. dens_path = os.path.join(root, folder_name, mode, "Density", "images")
    60. img_gt_file = os.path.join(root, folder_name, mode, "Global", "val.json")
    61. img_detection_file = os.path.join(root, folder_name, mode, "Global_swin_tiny_val_results.bbox.json")
    62. dens_gt_file = os.path.join(root, folder_name, mode, "Density", mode + ".json")
    63. dens_detection_file = os.path.join(root, folder_name, mode, "Density_swin_tiny_val_results.bbox.json")
    64. output_file = os.path.join(root, folder_name, mode, "Global", "final_fusion_result")
    65. # use coco api to retrieve detection result.
    66. # global == all_image dens == density map
    67. cocoGt_global = COCO(img_gt_file)
    68. cocoDt_global = cocoGt_global.loadRes(img_detection_file)
    69. cocoGt_density = COCO(dens_gt_file)
    70. print(len(cocoDt_global.dataset['categories']))
    71. assert len(cocoDt_global.dataset['categories']) == len(
    72. classList), "Not enough classes in global detection json file"
    73. cocoDt_density = cocoGt_density.loadRes(dens_detection_file)
    74. # load image_path and dens_path
    75. # Here we only load part of the data but both separate dataset are required
    76. # for fusion
    77. img_list = glob.glob(f'{img_path}/*.jpg')
    78. # dens means the way to generate data. Not "npy" type.
    79. dens_list = glob.glob(f'{dens_path}/*.jpg')
    80. assert len(img_list) > 0, "Failed to find any images!"
    81. assert len(dens_list) > 0, "Failed to find any inference!"
    82. valider = set()
    83. # initialize image detection result
    84. final_detection_result = []
    85. img_fusion_result_collecter = []
    86. # We have to match the idx for both density crops and original images, otherwise
    87. # we will have issues when merging them
    88. crop_img_matcher = {cocoDt_density.loadImgs(idx)[0]["file_name"]: cocoDt_density.loadImgs(idx)[0]["id"]
    89. for idx in range(len(dens_list))}
    90. assert len(crop_img_matcher) > 0, "Failed to match images"
    91. for img_id in tqdm(cocoGt_global.getImgIds(), total=len(img_list)):
    92. # DO NOT use img/dens name to load data, there is a filepath error
    93. # start by dealing with global detection result
    94. # target 1: pick up all idx that belongs to original detection in the same pic
    95. # find img_id >> load img >>visual img+bbox
    96. img_density_detection_result = []
    97. img_initial_fusion_result = []
    98. global_img = cocoDt_global.loadImgs(img_id)
    99. img_name = global_img[0]["file_name"]
    100. global_detection_not_in_crop = None
    101. # matched_dens_file: Match 1 original image with its multiple crops
    102. matched_dens_file = {filename for filename in dens_list if img_name in filename}
    103. # 'id' from image json
    104. global_annIds = cocoDt_global.getAnnIds(imgIds=global_img[0]['id'],
    105. catIds=[i + 1 for i in range(len(classList))], iscrowd=None)
    106. # global_annIds might be empty, if you use subset to train expert model. So we do not check
    107. # the length here.
    108. current_global_img_bbox = cocoDt_global.loadAnns(global_annIds)
    109. current_global_img_bbox_cp = current_global_img_bbox.copy()
    110. current_global_img_bbox_total = len(current_global_img_bbox)
    111. # Firstly overlay result on global detection
    112. print("filename: ", os.path.join(img_path, img_name))
    113. # You may want to visualize it, for debugging purpose
    114. overlay_func(os.path.join(img_path, img_name), current_global_img_bbox,
    115. classList, truncate_threshold, exclude_region=None, show=show)
    116. exclude_region = []
    117. for dens_img_id, dens_fullname in enumerate(matched_dens_file):
    118. # example of name path: 323_0_648_4160000117_02708_d_0000090
    119. dens_name = dens_fullname.split(r"/")[-1]
    120. # if you use density map crop, by default the first two coord are top and left.
    121. start_y, start_x = dens_name.split("_")[0:2]
    122. start_y, start_x = int(start_y), int(start_x)
    123. # get crop image bbox from detection result
    124. crop_img_id = crop_img_matcher[dens_name]
    125. # get annotation of current crop image
    126. crop_img_annotation = \
    127. overlay_bbox_img(cocoDt_density, dens_path, crop_img_id,
    128. truncate_threshold=truncate_threshold, show=show)
    129. # get bounding box detection for all boxes in crop one. Resized to original scale
    130. crop_bbox_to_original = resize_bbox_to_original(crop_img_annotation, start_x, start_y)
    131. img_density_detection_result.extend(crop_bbox_to_original)
    132. # Afterwards, scan global detection result and get out those detection that not in
    133. # cropped region
    134. # dens_fullname (example below)
    135. # './crop_data/val/density/images/566_1169_729_13260000117_02708_d_0000090.jpg'
    136. crop_img = cv2.imread(os.path.join(dens_fullname))
    137. crop_img_h, crop_img_w = crop_img.shape[:-1]
    138. global_detection_not_in_crop = []
    139. current_global_count, removal = len(current_global_img_bbox), 0
    140. for global_ann in current_global_img_bbox:
    141. bbox_left, bbox_top, bbox_width, bbox_height = global_ann['bbox']
    142. if start_x + truncate_threshold <= int(bbox_left) < int(
    143. bbox_left + bbox_width) <= start_x + crop_img_w - truncate_threshold and \
    144. start_y + truncate_threshold <= int(bbox_top) < int(
    145. bbox_top + bbox_height) <= start_y + crop_img_h - truncate_threshold:
    146. removal += 1
    147. continue
    148. global_detection_not_in_crop.append(global_ann)
    149. del current_global_img_bbox[:]
    150. current_global_img_bbox = global_detection_not_in_crop
    151. exclude_region.append([start_x, start_y, crop_img_w, crop_img_h])
    152. # To verify result, show overlay on global image, after processed all of images
    153. # print out original image with bbox in crop region
    154. if global_detection_not_in_crop is None:
    155. # In this case, there is no density crop generate, we directly use original detection result.
    156. global_detection_not_in_crop = current_global_img_bbox
    157. assert len(img_density_detection_result) == 0, "for the case there is no crop, there should be no " \
    158. "density detection result"
    159. else:
    160. assert len(matched_dens_file) > 0, "Density file should be 0"
    161. overlay_func(os.path.join(img_path, img_name), img_density_detection_result, classList, truncate_threshold,
    162. exclude_region=exclude_region, show=show)
    163. # print out original image with bbox in Non-crop region
    164. overlay_func(os.path.join(img_path, img_name), global_detection_not_in_crop, classList, truncate_threshold,
    165. exclude_region=exclude_region, show=show)
    166. # modify density crop id to align with updated result
    167. global_image_id = None
    168. if len(global_detection_not_in_crop) > 0:
    169. global_image_id = global_detection_not_in_crop[0]['image_id']
    170. for i in range(len(img_density_detection_result)):
    171. if global_image_id:
    172. img_density_detection_result[i]['image_id'] = global_image_id
    173. else:
    174. img_density_detection_result[i]['image_id'] = img_id
    175. img_initial_fusion_result = current_global_img_bbox_cp + img_density_detection_result
    176. img_fusion_result_collecter.append(img_initial_fusion_result)
    177. overlay_func(os.path.join(img_path, img_name), img_initial_fusion_result,
    178. classList, truncate_threshold, exclude_region=None, show=show)
    179. print("collected box: ", len(img_initial_fusion_result))
    180. overlay_func(os.path.join(img_path, img_name), img_initial_fusion_result,
    181. classList, truncate_threshold, exclude_region=None, show=show)
    182. # After we collect global/local bbox result, we then perform class-wise NMS to fuse bbox.
    183. iou_threshold = args.iou_threshold
    184. TopN = args.TopN
    185. for i in tqdm(cocoGt_global.getImgIds(), total=len(img_list)):
    186. current_nms_target = img_fusion_result_collecter[i - 1]
    187. global_img = cocoDt_global.loadImgs(i)
    188. img_name = global_img[0]["file_name"]
    189. nms_preprocess = wrap_initial_result(current_nms_target)
    190. length_pre, length_after = len(current_nms_target), 0
    191. keep = class_wise_nms(nms_preprocess, iou_threshold, TopN)
    192. class_wise_nms_result = [current_nms_target[i] for i in keep]
    193. final_detection_result.extend(class_wise_nms_result)
    194. final_nms_result = class_wise_nms_result
    195. overlay_func(os.path.join(img_path, img_name), final_nms_result,
    196. classList, truncate_threshold, exclude_region=None, show=False)
    197. # Finally, we export fusion detection result to indicated json files, then evaluate it (if not inference)
    198. results2json(final_detection_result, out_file=output_file)
    199. if mode != "test-challenge":
    200. coco_eval(result_files=output_file + ".bbox.json",
    201. result_types=['bbox'],
    202. coco=cocoGt_global,
    203. max_dets=(100, 300, 1000),
    204. classwise=True)

    主要需要改一下路径

    DMNet库采用了很古老的mmcv库,需要重新装个mmcv库,但是这会覆盖原来的库,建议使用新环境装一下,隔离以下之前的mmdetection环境。

    pip install mmcv==0.6.2

    验证集命令
     

    python fusion_detection/fusion_detection_result_official.py /root/autodl-tmp/VisDrone2019 --mode VisDrone2019-DET-val

     我去 这还没论文效果好。

    看下图像效果:

     有些目标的框滤不掉,参数选择是个问题

  • 相关阅读:
    电话状态权限及IMEI获取流程源码分析
    D. Make Them Equal(dp + 范围优化 )
    UE4 扩展详细信息面板
    vertx hello gradle 打包jar
    docker出现Cannot connect to the Docker daemon at unix:///var/run/docker.sock....
    Android自动化测试工具调研
    深入 Starknet 去中心化世界,探秘实用开发利器
    单链表基本练习-初始化、插入和输出
    Acwing 287. 积蓄程度
    jdk8更新到333了,你确定不更新你的Java吗
  • 原文地址:https://blog.csdn.net/qq_41964545/article/details/133025170