import os
import os.path as osp
import numpy as np
from mmcv import Config
from mmdet.models import build_detector
import math
import argparse
import pickle
def save_cplus_h(multi_level_anchors, savefilepath):
"""
multi_level_anchors.shape: [[box1,box2, ...], [], ...]
"""
_template = '''
#ifndef _ANCHOR_H
#define _ANCHOR_H
#include "stdlib.h"
#include <vector>
/*
* 目标检测的anchor框 头文件
* */
static std::vector<std::vector<std::vector<float>>> ssd_anchor_all_levels = {
// // stride 8
// {
// {-10., 0, -10., 20.}, // x1 y1 x2 y2
// {-10., 0, -10., 20.},
// {-10., 0, -10., 20.},
// },
//
// // stride 16
// {
// {-10., 0, -10., 20.}, // x1 y1 x2 y2
// {-10., 0, -10., 20.},
// {-10., 0, -10., 20.},
// },
//
// // stride 32
// {
// {-10., 0, -10., 20.}, // x1 y1 x2 y2
// {-10., 0, -10., 20.},
// {-10., 0, -10., 20.},
// },
//
// //...
@here
};
#endif //_ANCHOR_H
'''
with open(savefilepath, 'w', encoding='utf-8') as f:
m = ''
for anchors in multi_level_anchors:
# [N,4]
a = '{\n'
for x1, y1, x2, y2 in anchors:
line = '{' + f'{x1}, {y1}, {x2}, {y2}' + '},\n'
a += line
a += '},\n'
m += a
_template = _template.replace('@here', m)
f.write(_template)
return
def parse_args():
parser = argparse.ArgumentParser(
description='Convert MMDetection models to ONNX')
parser.add_argument('config', help='test config file path')
parser.add_argument('--output-file', type=str, default='anchor.npy')
parser.add_argument(
'--shape',
type=int,
nargs='+',
default=[3, 224, 320],
help='input image size (CHW)')
args = parser.parse_args()
return args
if __name__ == '__main__':
args = parse_args()
CONFIG = args.config
assert args.output_file is not None
INPUT_C, INPUT_H, INPUT_W = tuple(args.shape)
cfg = Config.fromfile(CONFIG)
model = build_detector(cfg.model)
model.eval()
assert hasattr(model, 'bbox_head')
strides_tuple_list = model.bbox_head.anchor_generator.strides
featmap_sizes = []
c, h, w = INPUT_C, INPUT_H, INPUT_W
for sh, sw in strides_tuple_list:
featmap_sizes.append((math.ceil(h / sh + 0.5), math.ceil(w / sw + 0.5)))
print([sh, sw], featmap_sizes)
multi_level_anchors = model.bbox_head.anchor_generator.grid_anchors(featmap_sizes, 'cpu')
total_anchors = np.concatenate(multi_level_anchors, axis=0)
print(total_anchors.shape)
print(total_anchors[:10])
wh = np.array([[w, h] * 2])
total_anchors_norm = total_anchors / wh
###################### 转bin #######################################################
anchor_num = total_anchors.shape[0]
total_anchors_bin_file = total_anchors_norm.reshape((1, 1, -1))
# todo: bbox_coder
target_stds = cfg.model.bbox_head.bbox_coder.target_stds
target_stds = np.array(target_stds * anchor_num).reshape((1, 1, -1))
# [1,2,anchor_nums * 4]
total_anchors_bin_file_res = np.concatenate((total_anchors_bin_file, target_stds), axis=1)
_savefilepath_bin = f'{args.output_file[:-4]}.bin'
total_anchors_bin_file_res.astype('float32').tofile(_savefilepath_bin)
# .npy for python caffe
_savefilepath_npy = f'{args.output_file[:-4]}.npy'
np.save(_savefilepath_npy, total_anchors_norm)
print(_savefilepath_bin)
print(_savefilepath_npy)
# 单独保存每个尺度的anchor
# [[box1,box2, ...], [], ...]
_savefilepath_pkl_per_levels = f'{args.output_file[:-4]}_per_level.pkl'
f = open(_savefilepath_pkl_per_levels, 'wb')
multi_level_anchors = [i.cpu().numpy() for i in multi_level_anchors]
pickle.dump(multi_level_anchors, f)
f.close()
print(_savefilepath_pkl_per_levels)
# 保存c++ 的头文件
_savefilepath_h_per_levels = f'{args.output_file[:-4]}_per_level.h'
save_cplus_h(multi_level_anchors, _savefilepath_h_per_levels)
print(_savefilepath_h_per_levels)
print('done.')