移动paddle_detection
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
# add python path of PaddleDetection to sys.path
|
||||
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
|
||||
sys.path.insert(0, parent_path)
|
||||
|
||||
from ppdet.utils.logger import setup_logger
|
||||
logger = setup_logger('ppdet.anchor_cluster')
|
||||
|
||||
from scipy.cluster.vq import kmeans
|
||||
import numpy as np
|
||||
from tqdm import tqdm
|
||||
|
||||
from ppdet.utils.cli import ArgsParser
|
||||
from ppdet.utils.check import check_gpu, check_version, check_config
|
||||
from ppdet.core.workspace import load_config, merge_config
|
||||
|
||||
|
||||
class BaseAnchorCluster(object):
|
||||
def __init__(self, n, cache_path, cache, verbose=True):
|
||||
"""
|
||||
Base Anchor Cluster
|
||||
|
||||
Args:
|
||||
n (int): number of clusters
|
||||
cache_path (str): cache directory path
|
||||
cache (bool): whether using cache
|
||||
verbose (bool): whether print results
|
||||
"""
|
||||
super(BaseAnchorCluster, self).__init__()
|
||||
self.n = n
|
||||
self.cache_path = cache_path
|
||||
self.cache = cache
|
||||
self.verbose = verbose
|
||||
|
||||
def print_result(self, centers):
|
||||
raise NotImplementedError('%s.print_result is not available' %
|
||||
self.__class__.__name__)
|
||||
|
||||
def get_whs(self):
|
||||
whs_cache_path = os.path.join(self.cache_path, 'whs.npy')
|
||||
shapes_cache_path = os.path.join(self.cache_path, 'shapes.npy')
|
||||
if self.cache and os.path.exists(whs_cache_path) and os.path.exists(
|
||||
shapes_cache_path):
|
||||
self.whs = np.load(whs_cache_path)
|
||||
self.shapes = np.load(shapes_cache_path)
|
||||
return self.whs, self.shapes
|
||||
whs = np.zeros((0, 2))
|
||||
shapes = np.zeros((0, 2))
|
||||
self.dataset.parse_dataset()
|
||||
roidbs = self.dataset.roidbs
|
||||
for rec in tqdm(roidbs):
|
||||
h, w = rec['h'], rec['w']
|
||||
bbox = rec['gt_bbox']
|
||||
wh = bbox[:, 2:4] - bbox[:, 0:2] + 1
|
||||
wh = wh / np.array([[w, h]])
|
||||
shape = np.ones_like(wh) * np.array([[w, h]])
|
||||
whs = np.vstack((whs, wh))
|
||||
shapes = np.vstack((shapes, shape))
|
||||
|
||||
if self.cache:
|
||||
os.makedirs(self.cache_path, exist_ok=True)
|
||||
np.save(whs_cache_path, whs)
|
||||
np.save(shapes_cache_path, shapes)
|
||||
|
||||
self.whs = whs
|
||||
self.shapes = shapes
|
||||
return self.whs, self.shapes
|
||||
|
||||
def calc_anchors(self):
|
||||
raise NotImplementedError('%s.calc_anchors is not available' %
|
||||
self.__class__.__name__)
|
||||
|
||||
def __call__(self):
|
||||
self.get_whs()
|
||||
centers = self.calc_anchors()
|
||||
if self.verbose:
|
||||
self.print_result(centers)
|
||||
return centers
|
||||
|
||||
|
||||
class YOLOv2AnchorCluster(BaseAnchorCluster):
|
||||
def __init__(self,
|
||||
n,
|
||||
dataset,
|
||||
size,
|
||||
cache_path,
|
||||
cache,
|
||||
iters=1000,
|
||||
verbose=True):
|
||||
super(YOLOv2AnchorCluster, self).__init__(
|
||||
n, cache_path, cache, verbose=verbose)
|
||||
"""
|
||||
YOLOv2 Anchor Cluster
|
||||
|
||||
The code is based on https://github.com/AlexeyAB/darknet/blob/master/scripts/gen_anchors.py
|
||||
|
||||
Args:
|
||||
n (int): number of clusters
|
||||
dataset (DataSet): DataSet instance, VOC or COCO
|
||||
size (list): [w, h]
|
||||
cache_path (str): cache directory path
|
||||
cache (bool): whether using cache
|
||||
iters (int): kmeans algorithm iters
|
||||
verbose (bool): whether print results
|
||||
"""
|
||||
self.dataset = dataset
|
||||
self.size = size
|
||||
self.iters = iters
|
||||
|
||||
def print_result(self, centers):
|
||||
logger.info('%d anchor cluster result: [w, h]' % self.n)
|
||||
for w, h in centers:
|
||||
logger.info('[%d, %d]' % (round(w), round(h)))
|
||||
|
||||
def metric(self, whs, centers):
|
||||
wh1 = whs[:, None]
|
||||
wh2 = centers[None]
|
||||
inter = np.minimum(wh1, wh2).prod(2)
|
||||
return inter / (wh1.prod(2) + wh2.prod(2) - inter)
|
||||
|
||||
def kmeans_expectation(self, whs, centers, assignments):
|
||||
dist = self.metric(whs, centers)
|
||||
new_assignments = dist.argmax(1)
|
||||
converged = (new_assignments == assignments).all()
|
||||
return converged, new_assignments
|
||||
|
||||
def kmeans_maximizations(self, whs, centers, assignments):
|
||||
new_centers = np.zeros_like(centers)
|
||||
for i in range(centers.shape[0]):
|
||||
mask = (assignments == i)
|
||||
if mask.sum():
|
||||
new_centers[i, :] = whs[mask].mean(0)
|
||||
return new_centers
|
||||
|
||||
def calc_anchors(self):
|
||||
self.whs = self.whs * np.array([self.size])
|
||||
# random select k centers
|
||||
whs, n, iters = self.whs, self.n, self.iters
|
||||
logger.info('Running kmeans for %d anchors on %d points...' %
|
||||
(n, len(whs)))
|
||||
idx = np.random.choice(whs.shape[0], size=n, replace=False)
|
||||
centers = whs[idx]
|
||||
assignments = np.zeros(whs.shape[0:1]) * -1
|
||||
# kmeans
|
||||
if n == 1:
|
||||
return self.kmeans_maximizations(whs, centers, assignments)
|
||||
|
||||
pbar = tqdm(range(iters), desc='Cluster anchors with k-means algorithm')
|
||||
for _ in pbar:
|
||||
# E step
|
||||
converged, assignments = self.kmeans_expectation(whs, centers,
|
||||
assignments)
|
||||
if converged:
|
||||
logger.info('kmeans algorithm has converged')
|
||||
break
|
||||
# M step
|
||||
centers = self.kmeans_maximizations(whs, centers, assignments)
|
||||
ious = self.metric(whs, centers)
|
||||
pbar.desc = 'avg_iou: %.4f' % (ious.max(1).mean())
|
||||
|
||||
centers = sorted(centers, key=lambda x: x[0] * x[1])
|
||||
return centers
|
||||
|
||||
|
||||
def main():
|
||||
parser = ArgsParser()
|
||||
parser.add_argument(
|
||||
'--n', '-n', default=9, type=int, help='num of clusters')
|
||||
parser.add_argument(
|
||||
'--iters',
|
||||
'-i',
|
||||
default=1000,
|
||||
type=int,
|
||||
help='num of iterations for kmeans')
|
||||
parser.add_argument(
|
||||
'--verbose', '-v', default=True, type=bool, help='whether print result')
|
||||
parser.add_argument(
|
||||
'--size',
|
||||
'-s',
|
||||
default=None,
|
||||
type=str,
|
||||
help='image size: w,h, using comma as delimiter')
|
||||
parser.add_argument(
|
||||
'--method',
|
||||
'-m',
|
||||
default='v2',
|
||||
type=str,
|
||||
help='cluster method, v2 is only supported now')
|
||||
parser.add_argument(
|
||||
'--cache_path', default='cache', type=str, help='cache path')
|
||||
parser.add_argument(
|
||||
'--cache', action='store_true', help='whether use cache')
|
||||
FLAGS = parser.parse_args()
|
||||
|
||||
cfg = load_config(FLAGS.config)
|
||||
merge_config(FLAGS.opt)
|
||||
check_config(cfg)
|
||||
# check if set use_gpu=True in paddlepaddle cpu version
|
||||
if 'use_gpu' not in cfg:
|
||||
cfg.use_gpu = False
|
||||
check_gpu(cfg.use_gpu)
|
||||
# check if paddlepaddle version is satisfied
|
||||
check_version('develop')
|
||||
|
||||
# get dataset
|
||||
dataset = cfg['TrainDataset']
|
||||
if FLAGS.size:
|
||||
if ',' in FLAGS.size:
|
||||
size = list(map(int, FLAGS.size.split(',')))
|
||||
assert len(size) == 2, "the format of size is incorrect"
|
||||
else:
|
||||
size = int(FLAGS.size)
|
||||
size = [size, size]
|
||||
elif 'inputs_def' in cfg['TestReader'] and 'image_shape' in cfg[
|
||||
'TestReader']['inputs_def']:
|
||||
size = cfg['TestReader']['inputs_def']['image_shape'][1:]
|
||||
else:
|
||||
raise ValueError('size is not specified')
|
||||
|
||||
if FLAGS.method == 'v2':
|
||||
cluster = YOLOv2AnchorCluster(FLAGS.n, dataset, size, FLAGS.cache_path,
|
||||
FLAGS.cache, FLAGS.iters, FLAGS.verbose)
|
||||
else:
|
||||
raise ValueError('cluster method: %s is not supported' % FLAGS.method)
|
||||
|
||||
anchors = cluster()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,141 @@
|
||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import json
|
||||
import numpy as np
|
||||
import argparse
|
||||
from pycocotools.coco import COCO
|
||||
from tqdm import tqdm
|
||||
|
||||
|
||||
def median(data):
|
||||
data.sort()
|
||||
mid = len(data) // 2
|
||||
median = (data[mid] + data[~mid]) / 2
|
||||
return median
|
||||
|
||||
|
||||
def draw_distribution(width, height, out_path):
|
||||
w_bins = int((max(width) - min(width)) // 10)
|
||||
h_bins = int((max(height) - min(height)) // 10)
|
||||
plt.figure()
|
||||
plt.subplot(221)
|
||||
plt.hist(width, bins=w_bins, color='green')
|
||||
plt.xlabel('Width rate *1000')
|
||||
plt.ylabel('number')
|
||||
plt.title('Distribution of Width')
|
||||
plt.subplot(222)
|
||||
plt.hist(height, bins=h_bins, color='blue')
|
||||
plt.xlabel('Height rate *1000')
|
||||
plt.title('Distribution of Height')
|
||||
plt.savefig(out_path)
|
||||
print(f'Distribution saved as {out_path}')
|
||||
plt.show()
|
||||
|
||||
|
||||
def get_ratio_infos(jsonfile, out_img, eval_size, small_stride):
|
||||
coco = COCO(annotation_file=jsonfile)
|
||||
allannjson = json.load(open(jsonfile, 'r'))
|
||||
be_im_id = allannjson['annotations'][0]['image_id']
|
||||
be_im_w = []
|
||||
be_im_h = []
|
||||
ratio_w = []
|
||||
ratio_h = []
|
||||
im_wid,im_hei=[],[]
|
||||
for ann in tqdm(allannjson['annotations']):
|
||||
if ann['iscrowd']:
|
||||
continue
|
||||
x0, y0, w, h = ann['bbox'][:]
|
||||
if be_im_id == ann['image_id']:
|
||||
be_im_w.append(w)
|
||||
be_im_h.append(h)
|
||||
else:
|
||||
im_w = coco.imgs[be_im_id]['width']
|
||||
im_h = coco.imgs[be_im_id]['height']
|
||||
im_wid.append(im_w)
|
||||
im_hei.append(im_h)
|
||||
im_m_w = np.mean(be_im_w)
|
||||
im_m_h = np.mean(be_im_h)
|
||||
dis_w = im_m_w / im_w
|
||||
dis_h = im_m_h / im_h
|
||||
ratio_w.append(dis_w)
|
||||
ratio_h.append(dis_h)
|
||||
be_im_id = ann['image_id']
|
||||
be_im_w = [w]
|
||||
be_im_h = [h]
|
||||
|
||||
|
||||
im_w = coco.imgs[be_im_id]['width']
|
||||
im_h = coco.imgs[be_im_id]['height']
|
||||
im_wid.append(im_w)
|
||||
im_hei.append(im_h)
|
||||
all_im_m_w = np.mean(im_wid)
|
||||
all_im_m_h = np.mean(im_hei)
|
||||
|
||||
|
||||
im_m_w = np.mean(be_im_w)
|
||||
im_m_h = np.mean(be_im_h)
|
||||
dis_w = im_m_w / im_w
|
||||
dis_h = im_m_h / im_h
|
||||
ratio_w.append(dis_w)
|
||||
ratio_h.append(dis_h)
|
||||
mid_w = median(ratio_w)
|
||||
mid_h = median(ratio_h)
|
||||
|
||||
reg_ratio = []
|
||||
ratio_all = ratio_h + ratio_w
|
||||
for r in ratio_all:
|
||||
if r < 0.2:
|
||||
reg_ratio.append(r)
|
||||
elif r < 0.4:
|
||||
reg_ratio.append(r/2)
|
||||
else:
|
||||
reg_ratio.append(r/4)
|
||||
reg_ratio = sorted(reg_ratio)
|
||||
max_ratio = reg_ratio[int(0.95*len(reg_ratio))]
|
||||
reg_max = round(max_ratio*eval_size/small_stride)
|
||||
|
||||
ratio_w = [i * 1000 for i in ratio_w]
|
||||
ratio_h = [i * 1000 for i in ratio_h]
|
||||
print(f'Suggested reg_range[1] is {reg_max+1}' )
|
||||
print(f'Mean of all img_w is {all_im_m_w}')
|
||||
print(f'Mean of all img_h is {all_im_m_h}')
|
||||
print(f'Median of ratio_w is {mid_w}')
|
||||
print(f'Median of ratio_h is {mid_h}')
|
||||
print('all_img with box: ', len(ratio_h))
|
||||
print('all_ann: ', len(allannjson['annotations']))
|
||||
draw_distribution(ratio_w, ratio_h, out_img)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'--json_path', type=str, default=None, help="Dataset json path.")
|
||||
parser.add_argument(
|
||||
'--eval_size', type=int, default=640, help="eval size.")
|
||||
parser.add_argument(
|
||||
'--small_stride', type=int, default=8, help="smallest stride.")
|
||||
parser.add_argument(
|
||||
'--out_img',
|
||||
type=str,
|
||||
default='box_distribution.jpg',
|
||||
help="Name of distibution img.")
|
||||
args = parser.parse_args()
|
||||
|
||||
get_ratio_infos(args.json_path, args.out_img, args.eval_size, args.small_stride)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
115
services/paddle_services/paddle_detection/tools/cam_ppdet.py
Normal file
115
services/paddle_services/paddle_detection/tools/cam_ppdet.py
Normal file
@@ -0,0 +1,115 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
# add python path of PaddleDetection to sys.path
|
||||
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
|
||||
sys.path.insert(0, parent_path)
|
||||
|
||||
# ignore warning log
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
from ppdet.utils.cli import ArgsParser, merge_args
|
||||
from ppdet.core.workspace import load_config, merge_config
|
||||
from ppdet.utils.check import check_gpu, check_npu, check_xpu, check_version, check_config
|
||||
from ppdet.utils.cam_utils import BBoxCAM
|
||||
import paddle
|
||||
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgsParser()
|
||||
parser.add_argument(
|
||||
"--infer_img",
|
||||
type=str,
|
||||
default='demo/000000014439.jpg', # hxw: 404x640
|
||||
help="Image path, has higher priority over --infer_dir")
|
||||
parser.add_argument("--weights",
|
||||
type=str,
|
||||
default='output/faster_rcnn_r50_vd_fpn_2x_coco_paddlejob/best_model.pdparams'
|
||||
)
|
||||
parser.add_argument("--cam_out",
|
||||
type=str,
|
||||
default='cam_faster_rcnn'
|
||||
)
|
||||
parser.add_argument("--use_gpu",
|
||||
type=bool,
|
||||
default=True)
|
||||
parser.add_argument(
|
||||
"--infer_dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Directory for images to perform inference on.")
|
||||
parser.add_argument(
|
||||
"--output_dir",
|
||||
type=str,
|
||||
default="output",
|
||||
help="Directory for storing the output visualization files.")
|
||||
parser.add_argument(
|
||||
"--draw_threshold",
|
||||
type=float,
|
||||
default=0.8,
|
||||
help="Threshold to reserve the result for visualization.")
|
||||
parser.add_argument(
|
||||
"--save_results",
|
||||
type=bool,
|
||||
default=False,
|
||||
help="Whether to save inference results to output_dir.")
|
||||
parser.add_argument(
|
||||
"--target_feature_layer_name",
|
||||
type=str,
|
||||
default='model.backbone', # define the featuremap to show grad cam, such as model.backbone, model.bbox_head.roi_extractor
|
||||
help="Whether to save inference results to output_dir.")
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
def run(FLAGS, cfg):
|
||||
assert cfg.architecture in ['FasterRCNN', 'MaskRCNN', 'YOLOv3', 'PPYOLOE',
|
||||
'PPYOLOEWithAuxHead', 'BlazeFace', 'SSD', 'RetinaNet'], \
|
||||
'Only supported cam for faster_rcnn based and yolov3 based architecture for now, ' \
|
||||
'the others are not supported temporarily!'
|
||||
|
||||
bbox_cam = BBoxCAM(FLAGS, cfg)
|
||||
bbox_cam.get_bboxes_cams()
|
||||
|
||||
print('finish')
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
FLAGS = parse_args()
|
||||
cfg = load_config(FLAGS.config)
|
||||
merge_args(cfg, FLAGS)
|
||||
merge_config(FLAGS.opt)
|
||||
|
||||
# disable npu in config by default
|
||||
if 'use_npu' not in cfg:
|
||||
cfg.use_npu = False
|
||||
|
||||
# disable xpu in config by default
|
||||
if 'use_xpu' not in cfg:
|
||||
cfg.use_xpu = False
|
||||
|
||||
if cfg.use_gpu:
|
||||
place = paddle.set_device('gpu')
|
||||
elif cfg.use_npu:
|
||||
place = paddle.set_device('npu')
|
||||
elif cfg.use_xpu:
|
||||
place = paddle.set_device('xpu')
|
||||
else:
|
||||
place = paddle.set_device('cpu')
|
||||
|
||||
check_config(cfg)
|
||||
check_gpu(cfg.use_gpu)
|
||||
check_npu(cfg.use_npu)
|
||||
check_xpu(cfg.use_xpu)
|
||||
check_version()
|
||||
|
||||
run(FLAGS, cfg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
208
services/paddle_services/paddle_detection/tools/eval.py
Normal file
208
services/paddle_services/paddle_detection/tools/eval.py
Normal file
@@ -0,0 +1,208 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# add python path of PaddleDetection to sys.path
|
||||
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
|
||||
sys.path.insert(0, parent_path)
|
||||
|
||||
# ignore warning log
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
import paddle
|
||||
|
||||
from ppdet.core.workspace import create, load_config, merge_config
|
||||
from ppdet.utils.check import check_gpu, check_npu, check_xpu, check_mlu, check_version, check_config
|
||||
from ppdet.utils.cli import ArgsParser, merge_args
|
||||
from ppdet.engine import Trainer, Trainer_ARSL, init_parallel_env
|
||||
from ppdet.metrics.coco_utils import json_eval_results
|
||||
from ppdet.slim import build_slim_model
|
||||
|
||||
from ppdet.utils.logger import setup_logger
|
||||
logger = setup_logger('eval')
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgsParser()
|
||||
parser.add_argument(
|
||||
"--output_eval",
|
||||
default=None,
|
||||
type=str,
|
||||
help="Evaluation directory, default is current directory.")
|
||||
|
||||
parser.add_argument(
|
||||
'--json_eval',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Whether to re eval with already exists bbox.json or mask.json')
|
||||
|
||||
parser.add_argument(
|
||||
"--slim_config",
|
||||
default=None,
|
||||
type=str,
|
||||
help="Configuration file of slim method.")
|
||||
|
||||
# TODO: bias should be unified
|
||||
parser.add_argument(
|
||||
"--bias",
|
||||
action="store_true",
|
||||
help="whether add bias or not while getting w and h")
|
||||
|
||||
parser.add_argument(
|
||||
"--classwise",
|
||||
action="store_true",
|
||||
help="whether per-category AP and draw P-R Curve or not.")
|
||||
|
||||
parser.add_argument(
|
||||
'--save_prediction_only',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Whether to save the evaluation results only')
|
||||
|
||||
parser.add_argument(
|
||||
"--amp",
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Enable auto mixed precision eval.")
|
||||
|
||||
# for smalldet slice_infer
|
||||
parser.add_argument(
|
||||
"--slice_infer",
|
||||
action='store_true',
|
||||
help="Whether to slice the image and merge the inference results for small object detection."
|
||||
)
|
||||
parser.add_argument(
|
||||
'--slice_size',
|
||||
nargs='+',
|
||||
type=int,
|
||||
default=[640, 640],
|
||||
help="Height of the sliced image.")
|
||||
parser.add_argument(
|
||||
"--overlap_ratio",
|
||||
nargs='+',
|
||||
type=float,
|
||||
default=[0.25, 0.25],
|
||||
help="Overlap height ratio of the sliced image.")
|
||||
parser.add_argument(
|
||||
"--combine_method",
|
||||
type=str,
|
||||
default='nms',
|
||||
help="Combine method of the sliced images' detection results, choose in ['nms', 'nmm', 'concat']."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--match_threshold",
|
||||
type=float,
|
||||
default=0.6,
|
||||
help="Combine method matching threshold.")
|
||||
parser.add_argument(
|
||||
"--match_metric",
|
||||
type=str,
|
||||
default='ios',
|
||||
help="Combine method matching metric, choose in ['iou', 'ios'].")
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def run(FLAGS, cfg):
|
||||
if FLAGS.json_eval:
|
||||
logger.info(
|
||||
"In json_eval mode, PaddleDetection will evaluate json files in "
|
||||
"output_eval directly. And proposal.json, bbox.json and mask.json "
|
||||
"will be detected by default.")
|
||||
json_eval_results(
|
||||
cfg.metric,
|
||||
json_directory=FLAGS.output_eval,
|
||||
dataset=create('EvalDataset')())
|
||||
return
|
||||
|
||||
# init parallel environment if nranks > 1
|
||||
init_parallel_env()
|
||||
ssod_method = cfg.get('ssod_method', None)
|
||||
if ssod_method == 'ARSL':
|
||||
# build ARSL_trainer
|
||||
trainer = Trainer_ARSL(cfg, mode='eval')
|
||||
# load ARSL_weights
|
||||
trainer.load_weights(cfg.weights, ARSL_eval=True)
|
||||
else:
|
||||
# build trainer
|
||||
trainer = Trainer(cfg, mode='eval')
|
||||
#load weights
|
||||
trainer.load_weights(cfg.weights)
|
||||
|
||||
# training
|
||||
if FLAGS.slice_infer:
|
||||
trainer.evaluate_slice(
|
||||
slice_size=FLAGS.slice_size,
|
||||
overlap_ratio=FLAGS.overlap_ratio,
|
||||
combine_method=FLAGS.combine_method,
|
||||
match_threshold=FLAGS.match_threshold,
|
||||
match_metric=FLAGS.match_metric)
|
||||
else:
|
||||
trainer.evaluate()
|
||||
|
||||
|
||||
def main():
|
||||
FLAGS = parse_args()
|
||||
cfg = load_config(FLAGS.config)
|
||||
merge_args(cfg, FLAGS)
|
||||
merge_config(FLAGS.opt)
|
||||
|
||||
# disable npu in config by default
|
||||
if 'use_npu' not in cfg:
|
||||
cfg.use_npu = False
|
||||
|
||||
# disable xpu in config by default
|
||||
if 'use_xpu' not in cfg:
|
||||
cfg.use_xpu = False
|
||||
|
||||
if 'use_gpu' not in cfg:
|
||||
cfg.use_gpu = False
|
||||
|
||||
# disable mlu in config by default
|
||||
if 'use_mlu' not in cfg:
|
||||
cfg.use_mlu = False
|
||||
|
||||
if cfg.use_gpu:
|
||||
place = paddle.set_device('gpu')
|
||||
elif cfg.use_npu:
|
||||
place = paddle.set_device('npu')
|
||||
elif cfg.use_xpu:
|
||||
place = paddle.set_device('xpu')
|
||||
elif cfg.use_mlu:
|
||||
place = paddle.set_device('mlu')
|
||||
else:
|
||||
place = paddle.set_device('cpu')
|
||||
|
||||
if FLAGS.slim_config:
|
||||
cfg = build_slim_model(cfg, FLAGS.slim_config, mode='eval')
|
||||
|
||||
check_config(cfg)
|
||||
check_gpu(cfg.use_gpu)
|
||||
check_npu(cfg.use_npu)
|
||||
check_xpu(cfg.use_xpu)
|
||||
check_mlu(cfg.use_mlu)
|
||||
check_version()
|
||||
|
||||
run(FLAGS, cfg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
144
services/paddle_services/paddle_detection/tools/eval_mot.py
Normal file
144
services/paddle_services/paddle_detection/tools/eval_mot.py
Normal file
@@ -0,0 +1,144 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# add python path of PaddleDetection to sys.path
|
||||
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
|
||||
sys.path.insert(0, parent_path)
|
||||
|
||||
# ignore warning log
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
import paddle
|
||||
|
||||
from ppdet.core.workspace import load_config, merge_config
|
||||
from ppdet.utils.check import check_gpu, check_npu, check_xpu, check_mlu, check_version, check_config
|
||||
from ppdet.utils.cli import ArgsParser
|
||||
from ppdet.engine import Tracker
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgsParser()
|
||||
parser.add_argument(
|
||||
"--det_results_dir",
|
||||
type=str,
|
||||
default='',
|
||||
help="Directory name for detection results.")
|
||||
parser.add_argument(
|
||||
'--output_dir',
|
||||
type=str,
|
||||
default='output',
|
||||
help='Directory name for output tracking results.')
|
||||
parser.add_argument(
|
||||
'--save_images',
|
||||
action='store_true',
|
||||
help='Save tracking results (image).')
|
||||
parser.add_argument(
|
||||
'--save_videos',
|
||||
action='store_true',
|
||||
help='Save tracking results (video).')
|
||||
parser.add_argument(
|
||||
'--show_image',
|
||||
action='store_true',
|
||||
help='Show tracking results (image).')
|
||||
parser.add_argument(
|
||||
'--scaled',
|
||||
type=bool,
|
||||
default=False,
|
||||
help="Whether coords after detector outputs are scaled, False in JDE YOLOv3 "
|
||||
"True in general detector.")
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def run(FLAGS, cfg):
|
||||
dataset_dir = cfg['EvalMOTDataset'].dataset_dir
|
||||
data_root = cfg['EvalMOTDataset'].data_root
|
||||
data_root = '{}/{}'.format(dataset_dir, data_root)
|
||||
seqs = os.listdir(data_root)
|
||||
seqs.sort()
|
||||
|
||||
# build Tracker
|
||||
tracker = Tracker(cfg, mode='eval')
|
||||
|
||||
# load weights
|
||||
if cfg.architecture in ['DeepSORT', 'ByteTrack']:
|
||||
tracker.load_weights_sde(cfg.det_weights, cfg.reid_weights)
|
||||
else:
|
||||
tracker.load_weights_jde(cfg.weights)
|
||||
|
||||
# inference
|
||||
tracker.mot_evaluate(
|
||||
data_root=data_root,
|
||||
seqs=seqs,
|
||||
data_type=cfg.metric.lower(),
|
||||
model_type=cfg.architecture,
|
||||
output_dir=FLAGS.output_dir,
|
||||
save_images=FLAGS.save_images,
|
||||
save_videos=FLAGS.save_videos,
|
||||
show_image=FLAGS.show_image,
|
||||
scaled=FLAGS.scaled,
|
||||
det_results_dir=FLAGS.det_results_dir)
|
||||
|
||||
|
||||
def main():
|
||||
FLAGS = parse_args()
|
||||
cfg = load_config(FLAGS.config)
|
||||
merge_config(FLAGS.opt)
|
||||
|
||||
# disable npu in config by default
|
||||
if 'use_npu' not in cfg:
|
||||
cfg.use_npu = False
|
||||
|
||||
# disable xpu in config by default
|
||||
if 'use_xpu' not in cfg:
|
||||
cfg.use_xpu = False
|
||||
|
||||
if 'use_gpu' not in cfg:
|
||||
cfg.use_gpu = False
|
||||
|
||||
# disable mlu in config by default
|
||||
if 'use_mlu' not in cfg:
|
||||
cfg.use_mlu = False
|
||||
|
||||
if cfg.use_gpu:
|
||||
place = paddle.set_device('gpu')
|
||||
elif cfg.use_npu:
|
||||
place = paddle.set_device('npu')
|
||||
elif cfg.use_xpu:
|
||||
place = paddle.set_device('xpu')
|
||||
elif cfg.use_mlu:
|
||||
place = paddle.set_device('mlu')
|
||||
else:
|
||||
place = paddle.set_device('cpu')
|
||||
|
||||
check_config(cfg)
|
||||
check_gpu(cfg.use_gpu)
|
||||
check_npu(cfg.use_npu)
|
||||
check_xpu(cfg.use_xpu)
|
||||
check_mlu(cfg.use_mlu)
|
||||
check_version()
|
||||
|
||||
run(FLAGS, cfg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
118
services/paddle_services/paddle_detection/tools/export_model.py
Normal file
118
services/paddle_services/paddle_detection/tools/export_model.py
Normal file
@@ -0,0 +1,118 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# add python path of PaddleDetection to sys.path
|
||||
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
|
||||
sys.path.insert(0, parent_path)
|
||||
|
||||
# ignore warning log
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
import paddle
|
||||
from ppdet.core.workspace import load_config, merge_config
|
||||
from ppdet.utils.check import check_gpu, check_version, check_config
|
||||
from ppdet.utils.cli import ArgsParser
|
||||
from ppdet.engine import Trainer
|
||||
from ppdet.engine.trainer_ssod import Trainer_ARSL
|
||||
from ppdet.slim import build_slim_model
|
||||
|
||||
from ppdet.utils.logger import setup_logger
|
||||
logger = setup_logger('export_model')
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgsParser()
|
||||
parser.add_argument(
|
||||
"--output_dir",
|
||||
type=str,
|
||||
default="output_inference",
|
||||
help="Directory for storing the output model files.")
|
||||
parser.add_argument(
|
||||
"--export_serving_model",
|
||||
type=bool,
|
||||
default=False,
|
||||
help="Whether to export serving model or not.")
|
||||
parser.add_argument(
|
||||
"--slim_config",
|
||||
default=None,
|
||||
type=str,
|
||||
help="Configuration file of slim method.")
|
||||
parser.add_argument("--for_fd", action='store_true')
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def run(FLAGS, cfg):
|
||||
ssod_method = cfg.get('ssod_method', None)
|
||||
if ssod_method is not None and ssod_method == 'ARSL':
|
||||
trainer = Trainer_ARSL(cfg, mode='test')
|
||||
trainer.load_weights(cfg.weights, ARSL_eval=True)
|
||||
# build detector
|
||||
else:
|
||||
trainer = Trainer(cfg, mode='test')
|
||||
|
||||
# load weights
|
||||
if cfg.architecture in ['DeepSORT', 'ByteTrack']:
|
||||
trainer.load_weights_sde(cfg.det_weights, cfg.reid_weights)
|
||||
else:
|
||||
trainer.load_weights(cfg.weights)
|
||||
|
||||
# export model
|
||||
trainer.export(FLAGS.output_dir, for_fd=FLAGS.for_fd)
|
||||
|
||||
if FLAGS.export_serving_model:
|
||||
assert not FLAGS.for_fd
|
||||
from paddle_serving_client.io import inference_model_to_serving
|
||||
model_name = os.path.splitext(os.path.split(cfg.filename)[-1])[0]
|
||||
|
||||
inference_model_to_serving(
|
||||
dirname="{}/{}".format(FLAGS.output_dir, model_name),
|
||||
serving_server="{}/{}/serving_server".format(FLAGS.output_dir,
|
||||
model_name),
|
||||
serving_client="{}/{}/serving_client".format(FLAGS.output_dir,
|
||||
model_name),
|
||||
model_filename="model.pdmodel",
|
||||
params_filename="model.pdiparams")
|
||||
|
||||
|
||||
def main():
|
||||
paddle.set_device("cpu")
|
||||
FLAGS = parse_args()
|
||||
cfg = load_config(FLAGS.config)
|
||||
merge_config(FLAGS.opt)
|
||||
|
||||
if FLAGS.slim_config:
|
||||
cfg = build_slim_model(cfg, FLAGS.slim_config, mode='test')
|
||||
|
||||
# FIXME: Temporarily solve the priority problem of FLAGS.opt
|
||||
merge_config(FLAGS.opt)
|
||||
check_config(cfg)
|
||||
if 'use_gpu' not in cfg:
|
||||
cfg.use_gpu = False
|
||||
check_gpu(cfg.use_gpu)
|
||||
check_version()
|
||||
|
||||
run(FLAGS, cfg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
102
services/paddle_services/paddle_detection/tools/gen_semi_coco.py
Normal file
102
services/paddle_services/paddle_detection/tools/gen_semi_coco.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import json
|
||||
import argparse
|
||||
import numpy as np
|
||||
|
||||
|
||||
def save_json(path, images, annotations, categories):
|
||||
new_json = {
|
||||
'images': images,
|
||||
'annotations': annotations,
|
||||
'categories': categories,
|
||||
}
|
||||
with open(path, 'w') as f:
|
||||
json.dump(new_json, f)
|
||||
print('{} saved, with {} images and {} annotations.'.format(
|
||||
path, len(images), len(annotations)))
|
||||
|
||||
|
||||
def gen_semi_data(data_dir,
|
||||
json_file,
|
||||
percent=10.0,
|
||||
seed=1,
|
||||
seed_offset=0,
|
||||
txt_file=None):
|
||||
json_name = json_file.split('/')[-1].split('.')[0]
|
||||
json_file = os.path.join(data_dir, json_file)
|
||||
anno = json.load(open(json_file, 'r'))
|
||||
categories = anno['categories']
|
||||
all_images = anno['images']
|
||||
all_anns = anno['annotations']
|
||||
print(
|
||||
'Totally {} images and {} annotations, about {} gts per image.'.format(
|
||||
len(all_images), len(all_anns), len(all_anns) / len(all_images)))
|
||||
|
||||
if txt_file:
|
||||
print('Using percent {} and seed {}.'.format(percent, seed))
|
||||
txt_file = os.path.join(data_dir, txt_file)
|
||||
sup_idx = json.load(open(txt_file, 'r'))[str(percent)][str(seed)]
|
||||
# max(sup_idx) = 117262 # 10%, sup_idx is not image_id
|
||||
else:
|
||||
np.random.seed(seed + seed_offset)
|
||||
sup_len = int(percent / 100.0 * len(all_images))
|
||||
sup_idx = np.random.choice(
|
||||
range(len(all_images)), size=sup_len, replace=False)
|
||||
labeled_images, labeled_anns = [], []
|
||||
labeled_im_ids = []
|
||||
unlabeled_images, unlabeled_anns = [], []
|
||||
|
||||
for i in range(len(all_images)):
|
||||
if i in sup_idx:
|
||||
labeled_im_ids.append(all_images[i]['id'])
|
||||
labeled_images.append(all_images[i])
|
||||
else:
|
||||
unlabeled_images.append(all_images[i])
|
||||
|
||||
for an in all_anns:
|
||||
im_id = an['image_id']
|
||||
if im_id in labeled_im_ids:
|
||||
labeled_anns.append(an)
|
||||
else:
|
||||
continue
|
||||
|
||||
save_path = '{}/{}'.format(data_dir, 'semi_annotations')
|
||||
if not os.path.exists(save_path):
|
||||
os.mkdir(save_path)
|
||||
|
||||
sup_name = '{}.{}@{}.json'.format(json_name, seed, int(percent))
|
||||
sup_path = os.path.join(save_path, sup_name)
|
||||
save_json(sup_path, labeled_images, labeled_anns, categories)
|
||||
|
||||
unsup_name = '{}.{}@{}-unlabeled.json'.format(json_name, seed, int(percent))
|
||||
unsup_path = os.path.join(save_path, unsup_name)
|
||||
save_json(unsup_path, unlabeled_images, unlabeled_anns, categories)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--data_dir', type=str, default='./dataset/coco')
|
||||
parser.add_argument(
|
||||
'--json_file', type=str, default='annotations/instances_train2017.json')
|
||||
parser.add_argument('--percent', type=float, default=10.0)
|
||||
parser.add_argument('--seed', type=int, default=1)
|
||||
parser.add_argument('--seed_offset', type=int, default=0)
|
||||
parser.add_argument('--txt_file', type=str, default='COCO_supervision.txt')
|
||||
args = parser.parse_args()
|
||||
print(args)
|
||||
gen_semi_data(args.data_dir, args.json_file, args.percent, args.seed,
|
||||
args.seed_offset, args.txt_file)
|
||||
237
services/paddle_services/paddle_detection/tools/infer.py
Normal file
237
services/paddle_services/paddle_detection/tools/infer.py
Normal file
@@ -0,0 +1,237 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# add python path of PaddleDetection to sys.path
|
||||
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
|
||||
sys.path.insert(0, parent_path)
|
||||
|
||||
# ignore warning log
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
import glob
|
||||
import ast
|
||||
|
||||
import paddle
|
||||
from ppdet.core.workspace import load_config, merge_config
|
||||
from ppdet.engine import Trainer, Trainer_ARSL
|
||||
from ppdet.utils.check import check_gpu, check_npu, check_xpu, check_mlu, check_version, check_config
|
||||
from ppdet.utils.cli import ArgsParser, merge_args
|
||||
from ppdet.slim import build_slim_model
|
||||
|
||||
from ppdet.utils.logger import setup_logger
|
||||
logger = setup_logger('train')
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgsParser()
|
||||
parser.add_argument(
|
||||
"--infer_dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Directory for images to perform inference on.")
|
||||
parser.add_argument(
|
||||
"--infer_img",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Image path, has higher priority over --infer_dir")
|
||||
parser.add_argument(
|
||||
"--output_dir",
|
||||
type=str,
|
||||
default="output",
|
||||
help="Directory for storing the output visualization files.")
|
||||
parser.add_argument(
|
||||
"--draw_threshold",
|
||||
type=float,
|
||||
default=0.5,
|
||||
help="Threshold to reserve the result for visualization.")
|
||||
parser.add_argument(
|
||||
"--slim_config",
|
||||
default=None,
|
||||
type=str,
|
||||
help="Configuration file of slim method.")
|
||||
parser.add_argument(
|
||||
"--use_vdl",
|
||||
type=bool,
|
||||
default=False,
|
||||
help="Whether to record the data to VisualDL.")
|
||||
parser.add_argument(
|
||||
'--vdl_log_dir',
|
||||
type=str,
|
||||
default="vdl_log_dir/image",
|
||||
help='VisualDL logging directory for image.')
|
||||
parser.add_argument(
|
||||
"--save_results",
|
||||
type=bool,
|
||||
default=False,
|
||||
help="Whether to save inference results to output_dir.")
|
||||
parser.add_argument(
|
||||
"--slice_infer",
|
||||
action='store_true',
|
||||
help="Whether to slice the image and merge the inference results for small object detection."
|
||||
)
|
||||
parser.add_argument(
|
||||
'--slice_size',
|
||||
nargs='+',
|
||||
type=int,
|
||||
default=[640, 640],
|
||||
help="Height of the sliced image.")
|
||||
parser.add_argument(
|
||||
"--overlap_ratio",
|
||||
nargs='+',
|
||||
type=float,
|
||||
default=[0.25, 0.25],
|
||||
help="Overlap height ratio of the sliced image.")
|
||||
parser.add_argument(
|
||||
"--combine_method",
|
||||
type=str,
|
||||
default='nms',
|
||||
help="Combine method of the sliced images' detection results, choose in ['nms', 'nmm', 'concat']."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--match_threshold",
|
||||
type=float,
|
||||
default=0.6,
|
||||
help="Combine method matching threshold.")
|
||||
parser.add_argument(
|
||||
"--match_metric",
|
||||
type=str,
|
||||
default='ios',
|
||||
help="Combine method matching metric, choose in ['iou', 'ios'].")
|
||||
parser.add_argument(
|
||||
"--visualize",
|
||||
type=ast.literal_eval,
|
||||
default=True,
|
||||
help="Whether to save visualize results to output_dir.")
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def get_test_images(infer_dir, infer_img):
|
||||
"""
|
||||
Get image path list in TEST mode
|
||||
"""
|
||||
assert infer_img is not None or infer_dir is not None, \
|
||||
"--infer_img or --infer_dir should be set"
|
||||
assert infer_img is None or os.path.isfile(infer_img), \
|
||||
"{} is not a file".format(infer_img)
|
||||
assert infer_dir is None or os.path.isdir(infer_dir), \
|
||||
"{} is not a directory".format(infer_dir)
|
||||
|
||||
# infer_img has a higher priority
|
||||
if infer_img and os.path.isfile(infer_img):
|
||||
return [infer_img]
|
||||
|
||||
images = set()
|
||||
infer_dir = os.path.abspath(infer_dir)
|
||||
assert os.path.isdir(infer_dir), \
|
||||
"infer_dir {} is not a directory".format(infer_dir)
|
||||
exts = ['jpg', 'jpeg', 'png', 'bmp']
|
||||
exts += [ext.upper() for ext in exts]
|
||||
for ext in exts:
|
||||
images.update(glob.glob('{}/*.{}'.format(infer_dir, ext)))
|
||||
images = list(images)
|
||||
|
||||
assert len(images) > 0, "no image found in {}".format(infer_dir)
|
||||
logger.info("Found {} inference images in total.".format(len(images)))
|
||||
|
||||
return images
|
||||
|
||||
|
||||
def run(FLAGS, cfg):
|
||||
ssod_method = cfg.get('ssod_method', None)
|
||||
if ssod_method == 'ARSL':
|
||||
trainer = Trainer_ARSL(cfg, mode='test')
|
||||
trainer.load_weights(cfg.weights, ARSL_eval=True)
|
||||
else:
|
||||
trainer = Trainer(cfg, mode='test')
|
||||
trainer.load_weights(cfg.weights)
|
||||
# get inference images
|
||||
images = get_test_images(FLAGS.infer_dir, FLAGS.infer_img)
|
||||
|
||||
# inference
|
||||
if FLAGS.slice_infer:
|
||||
trainer.slice_predict(
|
||||
images,
|
||||
slice_size=FLAGS.slice_size,
|
||||
overlap_ratio=FLAGS.overlap_ratio,
|
||||
combine_method=FLAGS.combine_method,
|
||||
match_threshold=FLAGS.match_threshold,
|
||||
match_metric=FLAGS.match_metric,
|
||||
draw_threshold=FLAGS.draw_threshold,
|
||||
output_dir=FLAGS.output_dir,
|
||||
save_results=FLAGS.save_results,
|
||||
visualize=FLAGS.visualize)
|
||||
else:
|
||||
trainer.predict(
|
||||
images,
|
||||
draw_threshold=FLAGS.draw_threshold,
|
||||
output_dir=FLAGS.output_dir,
|
||||
save_results=FLAGS.save_results,
|
||||
visualize=FLAGS.visualize)
|
||||
|
||||
|
||||
def main():
|
||||
FLAGS = parse_args()
|
||||
cfg = load_config(FLAGS.config)
|
||||
merge_args(cfg, FLAGS)
|
||||
merge_config(FLAGS.opt)
|
||||
|
||||
# disable npu in config by default
|
||||
if 'use_npu' not in cfg:
|
||||
cfg.use_npu = False
|
||||
|
||||
# disable xpu in config by default
|
||||
if 'use_xpu' not in cfg:
|
||||
cfg.use_xpu = False
|
||||
|
||||
if 'use_gpu' not in cfg:
|
||||
cfg.use_gpu = False
|
||||
|
||||
# disable mlu in config by default
|
||||
if 'use_mlu' not in cfg:
|
||||
cfg.use_mlu = False
|
||||
|
||||
if cfg.use_gpu:
|
||||
place = paddle.set_device('gpu')
|
||||
elif cfg.use_npu:
|
||||
place = paddle.set_device('npu')
|
||||
elif cfg.use_xpu:
|
||||
place = paddle.set_device('xpu')
|
||||
elif cfg.use_mlu:
|
||||
place = paddle.set_device('mlu')
|
||||
else:
|
||||
place = paddle.set_device('cpu')
|
||||
|
||||
if FLAGS.slim_config:
|
||||
cfg = build_slim_model(cfg, FLAGS.slim_config, mode='test')
|
||||
|
||||
check_config(cfg)
|
||||
check_gpu(cfg.use_gpu)
|
||||
check_npu(cfg.use_npu)
|
||||
check_xpu(cfg.use_xpu)
|
||||
check_mlu(cfg.use_mlu)
|
||||
check_version()
|
||||
|
||||
run(FLAGS, cfg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
165
services/paddle_services/paddle_detection/tools/infer_culane.py
Normal file
165
services/paddle_services/paddle_detection/tools/infer_culane.py
Normal file
@@ -0,0 +1,165 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# add python path of PaddleDetection to sys.path
|
||||
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
|
||||
sys.path.insert(0, parent_path)
|
||||
|
||||
# ignore warning log
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
import glob
|
||||
import ast
|
||||
|
||||
import paddle
|
||||
from ppdet.core.workspace import load_config, merge_config
|
||||
from ppdet.engine import Trainer
|
||||
from ppdet.utils.check import check_gpu, check_npu, check_xpu, check_mlu, check_version, check_config
|
||||
from ppdet.utils.cli import ArgsParser, merge_args
|
||||
from ppdet.slim import build_slim_model
|
||||
|
||||
from ppdet.utils.logger import setup_logger
|
||||
logger = setup_logger('train')
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgsParser()
|
||||
parser.add_argument(
|
||||
"--infer_dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Directory for images to perform inference on.")
|
||||
parser.add_argument(
|
||||
"--infer_img",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Image path, has higher priority over --infer_dir")
|
||||
parser.add_argument(
|
||||
"--output_dir",
|
||||
type=str,
|
||||
default="output",
|
||||
help="Directory for storing the output visualization files.")
|
||||
parser.add_argument(
|
||||
"--save_results",
|
||||
type=bool,
|
||||
default=False,
|
||||
help="Whether to save inference results to output_dir.")
|
||||
parser.add_argument(
|
||||
"--visualize",
|
||||
type=ast.literal_eval,
|
||||
default=True,
|
||||
help="Whether to save visualize results to output_dir.")
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def get_test_images(infer_dir, infer_img):
|
||||
"""
|
||||
Get image path list in TEST mode
|
||||
"""
|
||||
assert infer_img is not None or infer_dir is not None, \
|
||||
"--infer_img or --infer_dir should be set"
|
||||
assert infer_img is None or os.path.isfile(infer_img), \
|
||||
"{} is not a file".format(infer_img)
|
||||
assert infer_dir is None or os.path.isdir(infer_dir), \
|
||||
"{} is not a directory".format(infer_dir)
|
||||
|
||||
# infer_img has a higher priority
|
||||
if infer_img and os.path.isfile(infer_img):
|
||||
return [infer_img]
|
||||
|
||||
images = set()
|
||||
infer_dir = os.path.abspath(infer_dir)
|
||||
assert os.path.isdir(infer_dir), \
|
||||
"infer_dir {} is not a directory".format(infer_dir)
|
||||
exts = ['jpg', 'jpeg', 'png', 'bmp']
|
||||
exts += [ext.upper() for ext in exts]
|
||||
for ext in exts:
|
||||
images.update(glob.glob('{}/*.{}'.format(infer_dir, ext)))
|
||||
images = list(images)
|
||||
|
||||
assert len(images) > 0, "no image found in {}".format(infer_dir)
|
||||
logger.info("Found {} inference images in total.".format(len(images)))
|
||||
|
||||
return images
|
||||
|
||||
|
||||
def run(FLAGS, cfg):
|
||||
# build trainer
|
||||
trainer = Trainer(cfg, mode='test')
|
||||
|
||||
# load weights
|
||||
trainer.load_weights(cfg.weights)
|
||||
|
||||
# get inference images
|
||||
images = get_test_images(FLAGS.infer_dir, FLAGS.infer_img)
|
||||
|
||||
trainer.predict_culane(
|
||||
images,
|
||||
output_dir=FLAGS.output_dir,
|
||||
save_results=FLAGS.save_results,
|
||||
visualize=FLAGS.visualize)
|
||||
|
||||
|
||||
def main():
|
||||
FLAGS = parse_args()
|
||||
cfg = load_config(FLAGS.config)
|
||||
merge_args(cfg, FLAGS)
|
||||
merge_config(FLAGS.opt)
|
||||
|
||||
# disable npu in config by default
|
||||
if 'use_npu' not in cfg:
|
||||
cfg.use_npu = False
|
||||
|
||||
# disable xpu in config by default
|
||||
if 'use_xpu' not in cfg:
|
||||
cfg.use_xpu = False
|
||||
|
||||
if 'use_gpu' not in cfg:
|
||||
cfg.use_gpu = False
|
||||
|
||||
# disable mlu in config by default
|
||||
if 'use_mlu' not in cfg:
|
||||
cfg.use_mlu = False
|
||||
|
||||
if cfg.use_gpu:
|
||||
place = paddle.set_device('gpu')
|
||||
elif cfg.use_npu:
|
||||
place = paddle.set_device('npu')
|
||||
elif cfg.use_xpu:
|
||||
place = paddle.set_device('xpu')
|
||||
elif cfg.use_mlu:
|
||||
place = paddle.set_device('mlu')
|
||||
else:
|
||||
place = paddle.set_device('cpu')
|
||||
|
||||
check_config(cfg)
|
||||
check_gpu(cfg.use_gpu)
|
||||
check_npu(cfg.use_npu)
|
||||
check_xpu(cfg.use_xpu)
|
||||
check_mlu(cfg.use_mlu)
|
||||
check_version()
|
||||
|
||||
run(FLAGS, cfg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
156
services/paddle_services/paddle_detection/tools/infer_mot.py
Normal file
156
services/paddle_services/paddle_detection/tools/infer_mot.py
Normal file
@@ -0,0 +1,156 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# add python path of PaddleDetection to sys.path
|
||||
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
|
||||
sys.path.insert(0, parent_path)
|
||||
|
||||
# ignore warning log
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
import paddle
|
||||
from ppdet.core.workspace import load_config, merge_config
|
||||
from ppdet.engine import Tracker
|
||||
from ppdet.utils.check import check_gpu, check_npu, check_xpu, check_mlu, check_version, check_config
|
||||
from ppdet.utils.cli import ArgsParser
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgsParser()
|
||||
parser.add_argument(
|
||||
'--video_file', type=str, default=None, help='Video name for tracking.')
|
||||
parser.add_argument(
|
||||
'--frame_rate',
|
||||
type=int,
|
||||
default=-1,
|
||||
help='Video frame rate for tracking.')
|
||||
parser.add_argument(
|
||||
"--image_dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Directory for images to perform inference on.")
|
||||
parser.add_argument(
|
||||
"--det_results_dir",
|
||||
type=str,
|
||||
default='',
|
||||
help="Directory name for detection results.")
|
||||
parser.add_argument(
|
||||
'--output_dir',
|
||||
type=str,
|
||||
default='output',
|
||||
help='Directory name for output tracking results.')
|
||||
parser.add_argument(
|
||||
'--save_images',
|
||||
action='store_true',
|
||||
help='Save tracking results (image).')
|
||||
parser.add_argument(
|
||||
'--save_videos',
|
||||
action='store_true',
|
||||
help='Save tracking results (video).')
|
||||
parser.add_argument(
|
||||
'--show_image',
|
||||
action='store_true',
|
||||
help='Show tracking results (image).')
|
||||
parser.add_argument(
|
||||
'--scaled',
|
||||
type=bool,
|
||||
default=False,
|
||||
help="Whether coords after detector outputs are scaled, False in JDE YOLOv3 "
|
||||
"True in general detector.")
|
||||
parser.add_argument(
|
||||
"--draw_threshold",
|
||||
type=float,
|
||||
default=0.5,
|
||||
help="Threshold to reserve the result for visualization.")
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def run(FLAGS, cfg):
|
||||
# build Tracker
|
||||
tracker = Tracker(cfg, mode='test')
|
||||
|
||||
# load weights
|
||||
if cfg.architecture in ['DeepSORT', 'ByteTrack']:
|
||||
tracker.load_weights_sde(cfg.det_weights, cfg.reid_weights)
|
||||
else:
|
||||
tracker.load_weights_jde(cfg.weights)
|
||||
|
||||
# inference
|
||||
tracker.mot_predict_seq(
|
||||
video_file=FLAGS.video_file,
|
||||
frame_rate=FLAGS.frame_rate,
|
||||
image_dir=FLAGS.image_dir,
|
||||
data_type=cfg.metric.lower(),
|
||||
model_type=cfg.architecture,
|
||||
output_dir=FLAGS.output_dir,
|
||||
save_images=FLAGS.save_images,
|
||||
save_videos=FLAGS.save_videos,
|
||||
show_image=FLAGS.show_image,
|
||||
scaled=FLAGS.scaled,
|
||||
det_results_dir=FLAGS.det_results_dir,
|
||||
draw_threshold=FLAGS.draw_threshold)
|
||||
|
||||
|
||||
def main():
|
||||
FLAGS = parse_args()
|
||||
cfg = load_config(FLAGS.config)
|
||||
merge_config(FLAGS.opt)
|
||||
|
||||
# disable npu in config by default
|
||||
if 'use_npu' not in cfg:
|
||||
cfg.use_npu = False
|
||||
|
||||
# disable xpu in config by default
|
||||
if 'use_xpu' not in cfg:
|
||||
cfg.use_xpu = False
|
||||
|
||||
if 'use_gpu' not in cfg:
|
||||
cfg.use_gpu = False
|
||||
|
||||
# disable mlu in config by default
|
||||
if 'use_mlu' not in cfg:
|
||||
cfg.use_mlu = False
|
||||
|
||||
if cfg.use_gpu:
|
||||
place = paddle.set_device('gpu')
|
||||
elif cfg.use_npu:
|
||||
place = paddle.set_device('npu')
|
||||
elif cfg.use_xpu:
|
||||
place = paddle.set_device('xpu')
|
||||
elif cfg.use_mlu:
|
||||
place = paddle.set_device('mlu')
|
||||
else:
|
||||
place = paddle.set_device('cpu')
|
||||
|
||||
check_config(cfg)
|
||||
check_gpu(cfg.use_gpu)
|
||||
check_npu(cfg.use_npu)
|
||||
check_xpu(cfg.use_xpu)
|
||||
check_mlu(cfg.use_mlu)
|
||||
check_version()
|
||||
|
||||
run(FLAGS, cfg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,98 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# add python path of PaddleDetection to sys.path
|
||||
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
|
||||
sys.path.insert(0, parent_path)
|
||||
|
||||
# ignore warning log
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
import paddle
|
||||
|
||||
from ppdet.core.workspace import load_config, merge_config
|
||||
from ppdet.utils.check import check_gpu, check_version, check_config
|
||||
from ppdet.utils.cli import ArgsParser
|
||||
from ppdet.engine import Trainer
|
||||
from ppdet.slim import build_slim_model
|
||||
|
||||
from ppdet.utils.logger import setup_logger
|
||||
logger = setup_logger('post_quant')
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgsParser()
|
||||
parser.add_argument(
|
||||
"--output_dir",
|
||||
type=str,
|
||||
default="output_inference",
|
||||
help="Directory for storing the output model files.")
|
||||
parser.add_argument(
|
||||
"--slim_config",
|
||||
default=None,
|
||||
type=str,
|
||||
help="Configuration file of slim method.")
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def run(FLAGS, cfg):
|
||||
# build detector
|
||||
trainer = Trainer(cfg, mode='eval')
|
||||
|
||||
# load weights
|
||||
if cfg.architecture in ['DeepSORT']:
|
||||
if cfg.det_weights != 'None':
|
||||
trainer.load_weights_sde(cfg.det_weights, cfg.reid_weights)
|
||||
else:
|
||||
trainer.load_weights_sde(None, cfg.reid_weights)
|
||||
else:
|
||||
trainer.load_weights(cfg.weights)
|
||||
|
||||
# post quant model
|
||||
trainer.post_quant(FLAGS.output_dir)
|
||||
|
||||
|
||||
def main():
|
||||
FLAGS = parse_args()
|
||||
cfg = load_config(FLAGS.config)
|
||||
# TODO: to be refined in the future
|
||||
if 'norm_type' in cfg and cfg['norm_type'] == 'sync_bn':
|
||||
FLAGS.opt['norm_type'] = 'bn'
|
||||
merge_config(FLAGS.opt)
|
||||
|
||||
if FLAGS.slim_config:
|
||||
cfg = build_slim_model(cfg, FLAGS.slim_config, mode='test')
|
||||
|
||||
# FIXME: Temporarily solve the priority problem of FLAGS.opt
|
||||
merge_config(FLAGS.opt)
|
||||
check_config(cfg)
|
||||
if 'use_gpu' not in cfg:
|
||||
cfg.use_gpu = False
|
||||
check_gpu(cfg.use_gpu)
|
||||
check_version()
|
||||
|
||||
run(FLAGS, cfg)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,56 @@
|
||||
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
from tqdm import tqdm
|
||||
|
||||
|
||||
def slice_data(image_dir, dataset_json_path, output_dir, slice_size,
|
||||
overlap_ratio):
|
||||
try:
|
||||
from sahi.scripts.slice_coco import slice
|
||||
except Exception as e:
|
||||
raise RuntimeError(
|
||||
'Unable to use sahi to slice images, please install sahi, for example: `pip install sahi`, see https://github.com/obss/sahi'
|
||||
)
|
||||
tqdm.write(
|
||||
f" slicing for slice_size={slice_size}, overlap_ratio={overlap_ratio}")
|
||||
slice(
|
||||
image_dir=image_dir,
|
||||
dataset_json_path=dataset_json_path,
|
||||
output_dir=output_dir,
|
||||
slice_size=slice_size,
|
||||
overlap_ratio=overlap_ratio, )
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
'--image_dir', type=str, default=None, help="The image folder path.")
|
||||
parser.add_argument(
|
||||
'--json_path', type=str, default=None, help="Dataset json path.")
|
||||
parser.add_argument(
|
||||
'--output_dir', type=str, default=None, help="Output dir.")
|
||||
parser.add_argument(
|
||||
'--slice_size', type=int, default=500, help="slice_size")
|
||||
parser.add_argument(
|
||||
'--overlap_ratio', type=float, default=0.25, help="overlap_ratio")
|
||||
args = parser.parse_args()
|
||||
|
||||
slice_data(args.image_dir, args.json_path, args.output_dir, args.slice_size,
|
||||
args.overlap_ratio)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,178 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import sys
|
||||
import json
|
||||
import logging
|
||||
import numpy as np
|
||||
|
||||
from ppdet.utils.logger import setup_logger
|
||||
logger = setup_logger('sniper_params_stats')
|
||||
|
||||
def get_default_params(architecture):
|
||||
"""get_default_params"""
|
||||
if architecture == "FasterRCNN":
|
||||
anchor_range = np.array([64., 512.]) # for frcnn-fpn
|
||||
# anchor_range = np.array([16., 373.]) # for yolov3
|
||||
# anchor_range = np.array([32., 373.]) # for yolov3
|
||||
default_crop_size = 1536 # mod 32 for frcnn-fpn
|
||||
default_max_bbox_size = 352
|
||||
elif architecture == "YOLOv3":
|
||||
anchor_range = np.array([32., 373.]) # for yolov3
|
||||
default_crop_size = 800 # mod 32 for yolov3
|
||||
default_max_bbox_size = 352
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
return anchor_range, default_crop_size, default_max_bbox_size
|
||||
|
||||
|
||||
def get_box_ratios(anno_file):
|
||||
"""
|
||||
get_size_ratios
|
||||
:param anno_file: coco anno flile
|
||||
:return: size_ratio: (box_long_size / pic_long_size)
|
||||
"""
|
||||
coco_dict = json.load(open(anno_file))
|
||||
image_list = coco_dict['images']
|
||||
anno_list = coco_dict['annotations']
|
||||
|
||||
image_id2hw = {}
|
||||
for im_dict in image_list:
|
||||
im_id = im_dict['id']
|
||||
h, w = im_dict['height'], im_dict['width']
|
||||
image_id2hw[im_id] = (h, w)
|
||||
|
||||
box_ratios = []
|
||||
for a_dict in anno_list:
|
||||
im_id = a_dict['image_id']
|
||||
im_h, im_w = image_id2hw[im_id]
|
||||
bbox = a_dict['bbox']
|
||||
x1, y1, w, h = bbox
|
||||
pic_long = max(im_h, im_w)
|
||||
box_long = max(w, h)
|
||||
box_ratios.append(box_long / pic_long)
|
||||
|
||||
return np.array(box_ratios)
|
||||
|
||||
|
||||
def get_target_size_and_valid_box_ratios(anchor_range, box_ratio_p2, box_ratio_p98):
|
||||
"""get_scale_and_ratios"""
|
||||
anchor_better_low, anchor_better_high = anchor_range # (60., 512.)
|
||||
anchor_center = np.sqrt(anchor_better_high * anchor_better_low)
|
||||
|
||||
anchor_log_range = np.log10(anchor_better_high) - np.log10(anchor_better_low)
|
||||
box_ratio_log_range = np.log10(box_ratio_p98) - np.log10(box_ratio_p2)
|
||||
logger.info("anchor_log_range:{}, box_ratio_log_range:{}".format(anchor_log_range, box_ratio_log_range))
|
||||
|
||||
box_cut_num = int(np.ceil(box_ratio_log_range / anchor_log_range))
|
||||
box_ratio_log_window = box_ratio_log_range / box_cut_num
|
||||
logger.info("box_cut_num:{}, box_ratio_log_window:{}".format(box_cut_num, box_ratio_log_window))
|
||||
|
||||
image_target_sizes = []
|
||||
valid_ratios = []
|
||||
for i in range(box_cut_num):
|
||||
# # method1: align center
|
||||
# box_ratio_log_center = np.log10(p2) + 0.5 * box_ratio_log_window + i * box_ratio_log_window
|
||||
# box_ratio_center = np.power(10, box_ratio_log_center)
|
||||
# scale = anchor_center / box_ratio_center
|
||||
# method2: align left low
|
||||
box_ratio_low = np.power(10, np.log10(box_ratio_p2) + i * box_ratio_log_window)
|
||||
image_target_size = anchor_better_low / box_ratio_low
|
||||
|
||||
image_target_sizes.append(int(image_target_size))
|
||||
valid_ratio = anchor_range / image_target_size
|
||||
valid_ratios.append(valid_ratio.tolist())
|
||||
|
||||
logger.info("Box cut {}".format(i))
|
||||
logger.info("box_ratio_low: {}".format(box_ratio_low))
|
||||
logger.info("image_target_size: {}".format(image_target_size))
|
||||
logger.info("valid_ratio: {}".format(valid_ratio))
|
||||
|
||||
return image_target_sizes, valid_ratios
|
||||
|
||||
|
||||
def get_valid_ranges(valid_ratios):
|
||||
"""
|
||||
get_valid_box_ratios_range
|
||||
:param valid_ratios:
|
||||
:return:
|
||||
"""
|
||||
valid_ranges = []
|
||||
if len(valid_ratios) == 1:
|
||||
valid_ranges.append([-1, -1])
|
||||
else:
|
||||
for i, vratio in enumerate(valid_ratios):
|
||||
if i == 0:
|
||||
valid_ranges.append([-1, vratio[1]])
|
||||
elif i == len(valid_ratios) - 1:
|
||||
valid_ranges.append([vratio[0], -1])
|
||||
else:
|
||||
valid_ranges.append(vratio)
|
||||
return valid_ranges
|
||||
|
||||
|
||||
def get_percentile(a_array, low_percent, high_percent):
|
||||
"""
|
||||
get_percentile
|
||||
:param low_percent:
|
||||
:param high_percent:
|
||||
:return:
|
||||
"""
|
||||
array_p0 = min(a_array)
|
||||
array_p100 = max(a_array)
|
||||
array_plow = np.percentile(a_array, low_percent)
|
||||
array_phigh = np.percentile(a_array, high_percent)
|
||||
logger.info(
|
||||
"array_percentile(0): {},array_percentile low({}): {}, "
|
||||
"array_percentile high({}): {}, array_percentile 100: {}".format(
|
||||
array_p0, low_percent, array_plow, high_percent, array_phigh, array_p100))
|
||||
return array_plow, array_phigh
|
||||
|
||||
|
||||
def sniper_anno_stats(architecture, anno_file):
|
||||
"""
|
||||
sniper_anno_stats
|
||||
:param anno_file:
|
||||
:return:
|
||||
"""
|
||||
|
||||
anchor_range, default_crop_size, default_max_bbox_size = get_default_params(architecture)
|
||||
|
||||
box_ratios = get_box_ratios(anno_file)
|
||||
|
||||
box_ratio_p8, box_ratio_p92 = get_percentile(box_ratios, 8, 92)
|
||||
|
||||
image_target_sizes, valid_box_ratios = get_target_size_and_valid_box_ratios(anchor_range, box_ratio_p8, box_ratio_p92)
|
||||
|
||||
valid_ranges = get_valid_ranges(valid_box_ratios)
|
||||
|
||||
crop_size = min(default_crop_size, min([item for item in image_target_sizes]))
|
||||
crop_size = int(np.ceil(crop_size / 32.) * 32.)
|
||||
crop_stride = max(min(default_max_bbox_size, crop_size), crop_size - default_max_bbox_size)
|
||||
logger.info("Result".center(100, '-'))
|
||||
logger.info("image_target_sizes: {}".format(image_target_sizes))
|
||||
logger.info("valid_box_ratio_ranges: {}".format(valid_ranges))
|
||||
logger.info("chip_target_size: {}, chip_target_stride: {}".format(crop_size, crop_stride))
|
||||
|
||||
return {
|
||||
"image_target_sizes": image_target_sizes,
|
||||
"valid_box_ratio_ranges": valid_ranges,
|
||||
"chip_target_size": crop_size,
|
||||
"chip_target_stride": crop_stride
|
||||
}
|
||||
|
||||
if __name__=="__main__":
|
||||
architecture, anno_file = sys.argv[1], sys.argv[2]
|
||||
sniper_anno_stats(architecture, anno_file)
|
||||
209
services/paddle_services/paddle_detection/tools/train.py
Normal file
209
services/paddle_services/paddle_detection/tools/train.py
Normal file
@@ -0,0 +1,209 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# add python path of PaddleDetection to sys.path
|
||||
parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2)))
|
||||
sys.path.insert(0, parent_path)
|
||||
|
||||
# ignore warning log
|
||||
import warnings
|
||||
warnings.filterwarnings('ignore')
|
||||
|
||||
import paddle
|
||||
|
||||
from ppdet.core.workspace import load_config, merge_config
|
||||
|
||||
from ppdet.engine import Trainer, TrainerCot, init_parallel_env, set_random_seed, init_fleet_env
|
||||
from ppdet.engine.trainer_ssod import Trainer_DenseTeacher, Trainer_ARSL, Trainer_Semi_RTDETR
|
||||
|
||||
from ppdet.slim import build_slim_model
|
||||
|
||||
from ppdet.utils.cli import ArgsParser, merge_args
|
||||
import ppdet.utils.check as check
|
||||
from ppdet.utils.logger import setup_logger
|
||||
logger = setup_logger('train')
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = ArgsParser()
|
||||
parser.add_argument(
|
||||
"--eval",
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Whether to perform evaluation in train")
|
||||
parser.add_argument(
|
||||
"-r", "--resume", default=None, help="weights path for resume")
|
||||
parser.add_argument(
|
||||
"--slim_config",
|
||||
default=None,
|
||||
type=str,
|
||||
help="Configuration file of slim method.")
|
||||
parser.add_argument(
|
||||
"--enable_ce",
|
||||
type=bool,
|
||||
default=False,
|
||||
help="If set True, enable continuous evaluation job."
|
||||
"This flag is only used for internal test.")
|
||||
parser.add_argument(
|
||||
"--amp",
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Enable auto mixed precision training.")
|
||||
parser.add_argument(
|
||||
"--fleet", action='store_true', default=False, help="Use fleet or not")
|
||||
parser.add_argument(
|
||||
"--use_vdl",
|
||||
type=bool,
|
||||
default=False,
|
||||
help="whether to record the data to VisualDL.")
|
||||
parser.add_argument(
|
||||
'--vdl_log_dir',
|
||||
type=str,
|
||||
default="vdl_log_dir/scalar",
|
||||
help='VisualDL logging directory for scalar.')
|
||||
parser.add_argument(
|
||||
"--use_wandb",
|
||||
type=bool,
|
||||
default=False,
|
||||
help="whether to record the data to wandb.")
|
||||
parser.add_argument(
|
||||
'--save_prediction_only',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Whether to save the evaluation results only')
|
||||
parser.add_argument(
|
||||
'--profiler_options',
|
||||
type=str,
|
||||
default=None,
|
||||
help="The option of profiler, which should be in "
|
||||
"format \"key1=value1;key2=value2;key3=value3\"."
|
||||
"please see ppdet/utils/profiler.py for detail.")
|
||||
parser.add_argument(
|
||||
'--save_proposals',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Whether to save the train proposals')
|
||||
parser.add_argument(
|
||||
'--proposals_path',
|
||||
type=str,
|
||||
default="sniper/proposals.json",
|
||||
help='Train proposals directory')
|
||||
parser.add_argument(
|
||||
"--to_static",
|
||||
action='store_true',
|
||||
default=False,
|
||||
help="Enable dy2st to train.")
|
||||
|
||||
args = parser.parse_args()
|
||||
return args
|
||||
|
||||
|
||||
def run(FLAGS, cfg):
|
||||
# init fleet environment
|
||||
if cfg.fleet:
|
||||
init_fleet_env(cfg.get('find_unused_parameters', False))
|
||||
else:
|
||||
# init parallel environment if nranks > 1
|
||||
init_parallel_env()
|
||||
|
||||
if FLAGS.enable_ce:
|
||||
set_random_seed(0)
|
||||
|
||||
# build trainer
|
||||
ssod_method = cfg.get('ssod_method', None)
|
||||
if ssod_method is not None:
|
||||
if ssod_method == 'DenseTeacher':
|
||||
trainer = Trainer_DenseTeacher(cfg, mode='train')
|
||||
elif ssod_method == 'ARSL':
|
||||
trainer = Trainer_ARSL(cfg, mode='train')
|
||||
elif ssod_method == 'Semi_RTDETR':
|
||||
trainer = Trainer_Semi_RTDETR(cfg, mode='train')
|
||||
else:
|
||||
raise ValueError(
|
||||
"Semi-Supervised Object Detection only no support this method.")
|
||||
elif cfg.get('use_cot', False):
|
||||
trainer = TrainerCot(cfg, mode='train')
|
||||
else:
|
||||
trainer = Trainer(cfg, mode='train')
|
||||
|
||||
# load weights
|
||||
if FLAGS.resume is not None:
|
||||
trainer.resume_weights(FLAGS.resume)
|
||||
elif 'pretrain_student_weights' in cfg and 'pretrain_teacher_weights' in cfg \
|
||||
and cfg.pretrain_teacher_weights and cfg.pretrain_student_weights:
|
||||
trainer.load_semi_weights(cfg.pretrain_teacher_weights,
|
||||
cfg.pretrain_student_weights)
|
||||
elif 'pretrain_weights' in cfg and cfg.pretrain_weights:
|
||||
trainer.load_weights(cfg.pretrain_weights)
|
||||
|
||||
# training
|
||||
trainer.train(FLAGS.eval)
|
||||
|
||||
|
||||
def main():
|
||||
FLAGS = parse_args()
|
||||
cfg = load_config(FLAGS.config)
|
||||
merge_args(cfg, FLAGS)
|
||||
merge_config(FLAGS.opt)
|
||||
|
||||
# disable npu in config by default
|
||||
if 'use_npu' not in cfg:
|
||||
cfg.use_npu = False
|
||||
|
||||
# disable xpu in config by default
|
||||
if 'use_xpu' not in cfg:
|
||||
cfg.use_xpu = False
|
||||
|
||||
if 'use_gpu' not in cfg:
|
||||
cfg.use_gpu = False
|
||||
|
||||
# disable mlu in config by default
|
||||
if 'use_mlu' not in cfg:
|
||||
cfg.use_mlu = False
|
||||
|
||||
if cfg.use_gpu:
|
||||
place = paddle.set_device('gpu')
|
||||
elif cfg.use_npu:
|
||||
place = paddle.set_device('npu')
|
||||
elif cfg.use_xpu:
|
||||
place = paddle.set_device('xpu')
|
||||
elif cfg.use_mlu:
|
||||
place = paddle.set_device('mlu')
|
||||
else:
|
||||
place = paddle.set_device('cpu')
|
||||
|
||||
if FLAGS.slim_config:
|
||||
cfg = build_slim_model(cfg, FLAGS.slim_config)
|
||||
|
||||
# FIXME: Temporarily solve the priority problem of FLAGS.opt
|
||||
merge_config(FLAGS.opt)
|
||||
check.check_config(cfg)
|
||||
check.check_gpu(cfg.use_gpu)
|
||||
check.check_npu(cfg.use_npu)
|
||||
check.check_xpu(cfg.use_xpu)
|
||||
check.check_mlu(cfg.use_mlu)
|
||||
check.check_version()
|
||||
|
||||
run(FLAGS, cfg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
542
services/paddle_services/paddle_detection/tools/x2coco.py
Normal file
542
services/paddle_services/paddle_detection/tools/x2coco.py
Normal file
@@ -0,0 +1,542 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import os.path as osp
|
||||
import shutil
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import numpy as np
|
||||
import PIL.ImageDraw
|
||||
from tqdm import tqdm
|
||||
import cv2
|
||||
|
||||
label_to_num = {}
|
||||
categories_list = []
|
||||
labels_list = []
|
||||
|
||||
|
||||
class MyEncoder(json.JSONEncoder):
|
||||
def default(self, obj):
|
||||
if isinstance(obj, np.integer):
|
||||
return int(obj)
|
||||
elif isinstance(obj, np.floating):
|
||||
return float(obj)
|
||||
elif isinstance(obj, np.ndarray):
|
||||
return obj.tolist()
|
||||
else:
|
||||
return super(MyEncoder, self).default(obj)
|
||||
|
||||
|
||||
def images_labelme(data, num):
|
||||
image = {}
|
||||
image['height'] = data['imageHeight']
|
||||
image['width'] = data['imageWidth']
|
||||
image['id'] = num + 1
|
||||
if '\\' in data['imagePath']:
|
||||
image['file_name'] = data['imagePath'].split('\\')[-1]
|
||||
else:
|
||||
image['file_name'] = data['imagePath'].split('/')[-1]
|
||||
return image
|
||||
|
||||
|
||||
def images_cityscape(data, num, img_file):
|
||||
image = {}
|
||||
image['height'] = data['imgHeight']
|
||||
image['width'] = data['imgWidth']
|
||||
image['id'] = num + 1
|
||||
image['file_name'] = img_file
|
||||
return image
|
||||
|
||||
|
||||
def categories(label, labels_list):
|
||||
category = {}
|
||||
category['supercategory'] = 'component'
|
||||
category['id'] = len(labels_list) + 1
|
||||
category['name'] = label
|
||||
return category
|
||||
|
||||
|
||||
def annotations_rectangle(points, label, image_num, object_num, label_to_num):
|
||||
annotation = {}
|
||||
seg_points = np.asarray(points).copy()
|
||||
seg_points[1, :] = np.asarray(points)[2, :]
|
||||
seg_points[2, :] = np.asarray(points)[1, :]
|
||||
annotation['segmentation'] = [list(seg_points.flatten())]
|
||||
annotation['iscrowd'] = 0
|
||||
annotation['image_id'] = image_num + 1
|
||||
annotation['bbox'] = list(
|
||||
map(float, [
|
||||
points[0][0], points[0][1], points[1][0] - points[0][0], points[1][
|
||||
1] - points[0][1]
|
||||
]))
|
||||
annotation['area'] = annotation['bbox'][2] * annotation['bbox'][3]
|
||||
annotation['category_id'] = label_to_num[label]
|
||||
annotation['id'] = object_num + 1
|
||||
return annotation
|
||||
|
||||
|
||||
def annotations_polygon(height, width, points, label, image_num, object_num,
|
||||
label_to_num):
|
||||
annotation = {}
|
||||
annotation['segmentation'] = [list(np.asarray(points).flatten())]
|
||||
annotation['iscrowd'] = 0
|
||||
annotation['image_id'] = image_num + 1
|
||||
annotation['bbox'] = list(map(float, get_bbox(height, width, points)))
|
||||
annotation['area'] = annotation['bbox'][2] * annotation['bbox'][3]
|
||||
annotation['category_id'] = label_to_num[label]
|
||||
annotation['id'] = object_num + 1
|
||||
return annotation
|
||||
|
||||
|
||||
def get_bbox(height, width, points):
|
||||
polygons = points
|
||||
mask = np.zeros([height, width], dtype=np.uint8)
|
||||
mask = PIL.Image.fromarray(mask)
|
||||
xy = list(map(tuple, polygons))
|
||||
PIL.ImageDraw.Draw(mask).polygon(xy=xy, outline=1, fill=1)
|
||||
mask = np.array(mask, dtype=bool)
|
||||
index = np.argwhere(mask == 1)
|
||||
rows = index[:, 0]
|
||||
clos = index[:, 1]
|
||||
left_top_r = np.min(rows)
|
||||
left_top_c = np.min(clos)
|
||||
right_bottom_r = np.max(rows)
|
||||
right_bottom_c = np.max(clos)
|
||||
return [
|
||||
left_top_c, left_top_r, right_bottom_c - left_top_c,
|
||||
right_bottom_r - left_top_r
|
||||
]
|
||||
|
||||
|
||||
def deal_json(ds_type, img_path, json_path):
|
||||
data_coco = {}
|
||||
images_list = []
|
||||
annotations_list = []
|
||||
image_num = -1
|
||||
object_num = -1
|
||||
for img_file in os.listdir(img_path):
|
||||
img_label = os.path.splitext(img_file)[0]
|
||||
if img_file.split('.')[
|
||||
-1] not in ['bmp', 'jpg', 'jpeg', 'png', 'JPEG', 'JPG', 'PNG']:
|
||||
continue
|
||||
label_file = osp.join(json_path, img_label + '.json')
|
||||
print('Generating dataset from:', label_file)
|
||||
image_num = image_num + 1
|
||||
with open(label_file) as f:
|
||||
data = json.load(f)
|
||||
if ds_type == 'labelme':
|
||||
images_list.append(images_labelme(data, image_num))
|
||||
elif ds_type == 'cityscape':
|
||||
images_list.append(images_cityscape(data, image_num, img_file))
|
||||
if ds_type == 'labelme':
|
||||
for shapes in data['shapes']:
|
||||
object_num = object_num + 1
|
||||
label = shapes['label']
|
||||
if label not in labels_list:
|
||||
categories_list.append(categories(label, labels_list))
|
||||
labels_list.append(label)
|
||||
label_to_num[label] = len(labels_list)
|
||||
p_type = shapes['shape_type']
|
||||
if p_type == 'polygon':
|
||||
points = shapes['points']
|
||||
annotations_list.append(
|
||||
annotations_polygon(data['imageHeight'], data[
|
||||
'imageWidth'], points, label, image_num,
|
||||
object_num, label_to_num))
|
||||
|
||||
if p_type == 'rectangle':
|
||||
(x1, y1), (x2, y2) = shapes['points']
|
||||
x1, x2 = sorted([x1, x2])
|
||||
y1, y2 = sorted([y1, y2])
|
||||
points = [[x1, y1], [x2, y2], [x1, y2], [x2, y1]]
|
||||
annotations_list.append(
|
||||
annotations_rectangle(points, label, image_num,
|
||||
object_num, label_to_num))
|
||||
elif ds_type == 'cityscape':
|
||||
for shapes in data['objects']:
|
||||
object_num = object_num + 1
|
||||
label = shapes['label']
|
||||
if label not in labels_list:
|
||||
categories_list.append(categories(label, labels_list))
|
||||
labels_list.append(label)
|
||||
label_to_num[label] = len(labels_list)
|
||||
points = shapes['polygon']
|
||||
annotations_list.append(
|
||||
annotations_polygon(data['imgHeight'], data[
|
||||
'imgWidth'], points, label, image_num, object_num,
|
||||
label_to_num))
|
||||
data_coco['images'] = images_list
|
||||
data_coco['categories'] = categories_list
|
||||
data_coco['annotations'] = annotations_list
|
||||
return data_coco
|
||||
|
||||
|
||||
def voc_get_label_anno(ann_dir_path, ann_ids_path, labels_path):
|
||||
with open(labels_path, 'r') as f:
|
||||
labels_str = f.read().split()
|
||||
labels_ids = list(range(1, len(labels_str) + 1))
|
||||
|
||||
with open(ann_ids_path, 'r') as f:
|
||||
ann_ids = [lin.strip().split(' ')[-1] for lin in f.readlines()]
|
||||
|
||||
ann_paths = []
|
||||
for aid in ann_ids:
|
||||
if aid.endswith('xml'):
|
||||
ann_path = os.path.join(ann_dir_path, aid)
|
||||
else:
|
||||
ann_path = os.path.join(ann_dir_path, aid + '.xml')
|
||||
ann_paths.append(ann_path)
|
||||
|
||||
return dict(zip(labels_str, labels_ids)), ann_paths
|
||||
|
||||
|
||||
def voc_get_image_info(annotation_root, im_id):
|
||||
filename = annotation_root.findtext('filename')
|
||||
assert filename is not None
|
||||
img_name = os.path.basename(filename)
|
||||
|
||||
size = annotation_root.find('size')
|
||||
width = float(size.findtext('width'))
|
||||
height = float(size.findtext('height'))
|
||||
|
||||
image_info = {
|
||||
'file_name': filename,
|
||||
'height': height,
|
||||
'width': width,
|
||||
'id': im_id
|
||||
}
|
||||
return image_info
|
||||
|
||||
|
||||
def voc_get_coco_annotation(obj, label2id):
|
||||
label = obj.findtext('name')
|
||||
assert label in label2id, "label is not in label2id."
|
||||
category_id = label2id[label]
|
||||
bndbox = obj.find('bndbox')
|
||||
xmin = float(bndbox.findtext('xmin'))
|
||||
ymin = float(bndbox.findtext('ymin'))
|
||||
xmax = float(bndbox.findtext('xmax'))
|
||||
ymax = float(bndbox.findtext('ymax'))
|
||||
assert xmax > xmin and ymax > ymin, "Box size error."
|
||||
o_width = xmax - xmin
|
||||
o_height = ymax - ymin
|
||||
anno = {
|
||||
'area': o_width * o_height,
|
||||
'iscrowd': 0,
|
||||
'bbox': [xmin, ymin, o_width, o_height],
|
||||
'category_id': category_id,
|
||||
'ignore': 0,
|
||||
}
|
||||
return anno
|
||||
|
||||
|
||||
def voc_xmls_to_cocojson(annotation_paths, label2id, output_dir, output_file):
|
||||
output_json_dict = {
|
||||
"images": [],
|
||||
"type": "instances",
|
||||
"annotations": [],
|
||||
"categories": []
|
||||
}
|
||||
bnd_id = 1 # bounding box start id
|
||||
im_id = 0
|
||||
print('Start converting !')
|
||||
for a_path in tqdm(annotation_paths):
|
||||
# Read annotation xml
|
||||
ann_tree = ET.parse(a_path)
|
||||
ann_root = ann_tree.getroot()
|
||||
|
||||
img_info = voc_get_image_info(ann_root, im_id)
|
||||
output_json_dict['images'].append(img_info)
|
||||
|
||||
for obj in ann_root.findall('object'):
|
||||
ann = voc_get_coco_annotation(obj=obj, label2id=label2id)
|
||||
ann.update({'image_id': im_id, 'id': bnd_id})
|
||||
output_json_dict['annotations'].append(ann)
|
||||
bnd_id = bnd_id + 1
|
||||
im_id += 1
|
||||
|
||||
for label, label_id in label2id.items():
|
||||
category_info = {'supercategory': 'none', 'id': label_id, 'name': label}
|
||||
output_json_dict['categories'].append(category_info)
|
||||
output_file = os.path.join(output_dir, output_file)
|
||||
with open(output_file, 'w') as f:
|
||||
output_json = json.dumps(output_json_dict)
|
||||
f.write(output_json)
|
||||
|
||||
|
||||
def widerface_to_cocojson(root_path):
|
||||
train_gt_txt = os.path.join(root_path, "wider_face_split", "wider_face_train_bbx_gt.txt")
|
||||
val_gt_txt = os.path.join(root_path, "wider_face_split", "wider_face_val_bbx_gt.txt")
|
||||
train_img_dir = os.path.join(root_path, "WIDER_train", "images")
|
||||
val_img_dir = os.path.join(root_path, "WIDER_val", "images")
|
||||
assert train_gt_txt
|
||||
assert val_gt_txt
|
||||
assert train_img_dir
|
||||
assert val_img_dir
|
||||
save_path = os.path.join(root_path, "widerface_train.json")
|
||||
widerface_convert(train_gt_txt, train_img_dir, save_path)
|
||||
print("Wider Face train dataset converts sucess, the json path: {}".format(save_path))
|
||||
save_path = os.path.join(root_path, "widerface_val.json")
|
||||
widerface_convert(val_gt_txt, val_img_dir, save_path)
|
||||
print("Wider Face val dataset converts sucess, the json path: {}".format(save_path))
|
||||
|
||||
|
||||
def widerface_convert(gt_txt, img_dir, save_path):
|
||||
output_json_dict = {
|
||||
"images": [],
|
||||
"type": "instances",
|
||||
"annotations": [],
|
||||
"categories": [{'supercategory': 'none', 'id': 0, 'name': "human_face"}]
|
||||
}
|
||||
bnd_id = 1 # bounding box start id
|
||||
im_id = 0
|
||||
print('Start converting !')
|
||||
with open(gt_txt) as fd:
|
||||
lines = fd.readlines()
|
||||
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
image_name = lines[i].strip()
|
||||
bbox_num = int(lines[i + 1].strip())
|
||||
i += 2
|
||||
img_info = get_widerface_image_info(img_dir, image_name, im_id)
|
||||
if img_info:
|
||||
output_json_dict["images"].append(img_info)
|
||||
for j in range(i, i + bbox_num):
|
||||
anno = get_widerface_ann_info(lines[j])
|
||||
anno.update({'image_id': im_id, 'id': bnd_id})
|
||||
output_json_dict['annotations'].append(anno)
|
||||
bnd_id += 1
|
||||
else:
|
||||
print("The image dose not exist: {}".format(os.path.join(img_dir, image_name)))
|
||||
bbox_num = 1 if bbox_num == 0 else bbox_num
|
||||
i += bbox_num
|
||||
im_id += 1
|
||||
with open(save_path, 'w') as f:
|
||||
output_json = json.dumps(output_json_dict)
|
||||
f.write(output_json)
|
||||
|
||||
|
||||
def get_widerface_image_info(img_root, img_relative_path, img_id):
|
||||
image_info = {}
|
||||
save_path = os.path.join(img_root, img_relative_path)
|
||||
if os.path.exists(save_path):
|
||||
img = cv2.imread(save_path)
|
||||
image_info["file_name"] = os.path.join(os.path.basename(
|
||||
os.path.dirname(img_root)), os.path.basename(img_root),
|
||||
img_relative_path)
|
||||
image_info["height"] = img.shape[0]
|
||||
image_info["width"] = img.shape[1]
|
||||
image_info["id"] = img_id
|
||||
return image_info
|
||||
|
||||
|
||||
def get_widerface_ann_info(info):
|
||||
info = [int(x) for x in info.strip().split()]
|
||||
anno = {
|
||||
'area': info[2] * info[3],
|
||||
'iscrowd': 0,
|
||||
'bbox': [info[0], info[1], info[2], info[3]],
|
||||
'category_id': 0,
|
||||
'ignore': 0,
|
||||
'blur': info[4],
|
||||
'expression': info[5],
|
||||
'illumination': info[6],
|
||||
'invalid': info[7],
|
||||
'occlusion': info[8],
|
||||
'pose': info[9]
|
||||
}
|
||||
return anno
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument(
|
||||
'--dataset_type',
|
||||
help='the type of dataset, can be `voc`, `widerface`, `labelme` or `cityscape`')
|
||||
parser.add_argument('--json_input_dir', help='input annotated directory')
|
||||
parser.add_argument('--image_input_dir', help='image directory')
|
||||
parser.add_argument(
|
||||
'--output_dir', help='output dataset directory', default='./')
|
||||
parser.add_argument(
|
||||
'--train_proportion',
|
||||
help='the proportion of train dataset',
|
||||
type=float,
|
||||
default=1.0)
|
||||
parser.add_argument(
|
||||
'--val_proportion',
|
||||
help='the proportion of validation dataset',
|
||||
type=float,
|
||||
default=0.0)
|
||||
parser.add_argument(
|
||||
'--test_proportion',
|
||||
help='the proportion of test dataset',
|
||||
type=float,
|
||||
default=0.0)
|
||||
parser.add_argument(
|
||||
'--voc_anno_dir',
|
||||
help='In Voc format dataset, path to annotation files directory.',
|
||||
type=str,
|
||||
default=None)
|
||||
parser.add_argument(
|
||||
'--voc_anno_list',
|
||||
help='In Voc format dataset, path to annotation files ids list.',
|
||||
type=str,
|
||||
default=None)
|
||||
parser.add_argument(
|
||||
'--voc_label_list',
|
||||
help='In Voc format dataset, path to label list. The content of each line is a category.',
|
||||
type=str,
|
||||
default=None)
|
||||
parser.add_argument(
|
||||
'--voc_out_name',
|
||||
type=str,
|
||||
default='voc.json',
|
||||
help='In Voc format dataset, path to output json file')
|
||||
parser.add_argument(
|
||||
'--widerface_root_dir',
|
||||
help='The root_path for wider face dataset, which contains `wider_face_split`, `WIDER_train` and `WIDER_val`.And the json file will save in this path',
|
||||
type=str,
|
||||
default=None)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
assert args.dataset_type in ['voc', 'labelme', 'cityscape', 'widerface']
|
||||
except AssertionError as e:
|
||||
print(
|
||||
'Now only support the voc, cityscape dataset and labelme dataset!!')
|
||||
os._exit(0)
|
||||
|
||||
if args.dataset_type == 'voc':
|
||||
assert args.voc_anno_dir and args.voc_anno_list and args.voc_label_list
|
||||
label2id, ann_paths = voc_get_label_anno(
|
||||
args.voc_anno_dir, args.voc_anno_list, args.voc_label_list)
|
||||
voc_xmls_to_cocojson(
|
||||
annotation_paths=ann_paths,
|
||||
label2id=label2id,
|
||||
output_dir=args.output_dir,
|
||||
output_file=args.voc_out_name)
|
||||
elif args.dataset_type == "widerface":
|
||||
assert args.widerface_root_dir
|
||||
widerface_to_cocojson(args.widerface_root_dir)
|
||||
else:
|
||||
try:
|
||||
assert os.path.exists(args.json_input_dir)
|
||||
except AssertionError as e:
|
||||
print('The json folder does not exist!')
|
||||
os._exit(0)
|
||||
try:
|
||||
assert os.path.exists(args.image_input_dir)
|
||||
except AssertionError as e:
|
||||
print('The image folder does not exist!')
|
||||
os._exit(0)
|
||||
try:
|
||||
assert abs(args.train_proportion + args.val_proportion \
|
||||
+ args.test_proportion - 1.0) < 1e-5
|
||||
except AssertionError as e:
|
||||
print(
|
||||
'The sum of pqoportion of training, validation and test datase must be 1!'
|
||||
)
|
||||
os._exit(0)
|
||||
|
||||
# Allocate the dataset.
|
||||
total_num = len(glob.glob(osp.join(args.json_input_dir, '*.json')))
|
||||
if args.train_proportion != 0:
|
||||
train_num = int(total_num * args.train_proportion)
|
||||
out_dir = args.output_dir + '/train'
|
||||
if not os.path.exists(out_dir):
|
||||
os.makedirs(out_dir)
|
||||
else:
|
||||
train_num = 0
|
||||
if args.val_proportion == 0.0:
|
||||
val_num = 0
|
||||
test_num = total_num - train_num
|
||||
out_dir = args.output_dir + '/test'
|
||||
if args.test_proportion != 0.0 and not os.path.exists(out_dir):
|
||||
os.makedirs(out_dir)
|
||||
else:
|
||||
val_num = int(total_num * args.val_proportion)
|
||||
test_num = total_num - train_num - val_num
|
||||
val_out_dir = args.output_dir + '/val'
|
||||
if not os.path.exists(val_out_dir):
|
||||
os.makedirs(val_out_dir)
|
||||
test_out_dir = args.output_dir + '/test'
|
||||
if args.test_proportion != 0.0 and not os.path.exists(test_out_dir):
|
||||
os.makedirs(test_out_dir)
|
||||
count = 1
|
||||
for img_name in os.listdir(args.image_input_dir):
|
||||
if count <= train_num:
|
||||
if osp.exists(args.output_dir + '/train/'):
|
||||
shutil.copyfile(
|
||||
osp.join(args.image_input_dir, img_name),
|
||||
osp.join(args.output_dir + '/train/', img_name))
|
||||
else:
|
||||
if count <= train_num + val_num:
|
||||
if osp.exists(args.output_dir + '/val/'):
|
||||
shutil.copyfile(
|
||||
osp.join(args.image_input_dir, img_name),
|
||||
osp.join(args.output_dir + '/val/', img_name))
|
||||
else:
|
||||
if osp.exists(args.output_dir + '/test/'):
|
||||
shutil.copyfile(
|
||||
osp.join(args.image_input_dir, img_name),
|
||||
osp.join(args.output_dir + '/test/', img_name))
|
||||
count = count + 1
|
||||
|
||||
# Deal with the json files.
|
||||
if not os.path.exists(args.output_dir + '/annotations'):
|
||||
os.makedirs(args.output_dir + '/annotations')
|
||||
if args.train_proportion != 0:
|
||||
train_data_coco = deal_json(args.dataset_type,
|
||||
args.output_dir + '/train',
|
||||
args.json_input_dir)
|
||||
train_json_path = osp.join(args.output_dir + '/annotations',
|
||||
'instance_train.json')
|
||||
json.dump(
|
||||
train_data_coco,
|
||||
open(train_json_path, 'w'),
|
||||
indent=4,
|
||||
cls=MyEncoder)
|
||||
if args.val_proportion != 0:
|
||||
val_data_coco = deal_json(args.dataset_type,
|
||||
args.output_dir + '/val',
|
||||
args.json_input_dir)
|
||||
val_json_path = osp.join(args.output_dir + '/annotations',
|
||||
'instance_val.json')
|
||||
json.dump(
|
||||
val_data_coco,
|
||||
open(val_json_path, 'w'),
|
||||
indent=4,
|
||||
cls=MyEncoder)
|
||||
if args.test_proportion != 0:
|
||||
test_data_coco = deal_json(args.dataset_type,
|
||||
args.output_dir + '/test',
|
||||
args.json_input_dir)
|
||||
test_json_path = osp.join(args.output_dir + '/annotations',
|
||||
'instance_test.json')
|
||||
json.dump(
|
||||
test_data_coco,
|
||||
open(test_json_path, 'w'),
|
||||
indent=4,
|
||||
cls=MyEncoder)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user