deepdoctection 0.31__py3-none-any.whl → 0.33__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of deepdoctection might be problematic. Click here for more details.
- deepdoctection/__init__.py +16 -29
- deepdoctection/analyzer/dd.py +70 -59
- deepdoctection/configs/conf_dd_one.yaml +34 -31
- deepdoctection/dataflow/common.py +9 -5
- deepdoctection/dataflow/custom.py +5 -5
- deepdoctection/dataflow/custom_serialize.py +75 -18
- deepdoctection/dataflow/parallel_map.py +3 -3
- deepdoctection/dataflow/serialize.py +4 -4
- deepdoctection/dataflow/stats.py +3 -3
- deepdoctection/datapoint/annotation.py +41 -56
- deepdoctection/datapoint/box.py +9 -8
- deepdoctection/datapoint/convert.py +6 -6
- deepdoctection/datapoint/image.py +56 -44
- deepdoctection/datapoint/view.py +245 -150
- deepdoctection/datasets/__init__.py +1 -4
- deepdoctection/datasets/adapter.py +35 -26
- deepdoctection/datasets/base.py +14 -12
- deepdoctection/datasets/dataflow_builder.py +3 -3
- deepdoctection/datasets/info.py +24 -26
- deepdoctection/datasets/instances/doclaynet.py +51 -51
- deepdoctection/datasets/instances/fintabnet.py +46 -46
- deepdoctection/datasets/instances/funsd.py +25 -24
- deepdoctection/datasets/instances/iiitar13k.py +13 -10
- deepdoctection/datasets/instances/layouttest.py +4 -3
- deepdoctection/datasets/instances/publaynet.py +5 -5
- deepdoctection/datasets/instances/pubtables1m.py +24 -21
- deepdoctection/datasets/instances/pubtabnet.py +32 -30
- deepdoctection/datasets/instances/rvlcdip.py +30 -30
- deepdoctection/datasets/instances/xfund.py +26 -26
- deepdoctection/datasets/save.py +6 -6
- deepdoctection/eval/__init__.py +1 -4
- deepdoctection/eval/accmetric.py +32 -33
- deepdoctection/eval/base.py +8 -9
- deepdoctection/eval/cocometric.py +15 -13
- deepdoctection/eval/eval.py +41 -37
- deepdoctection/eval/tedsmetric.py +30 -23
- deepdoctection/eval/tp_eval_callback.py +16 -19
- deepdoctection/extern/__init__.py +2 -7
- deepdoctection/extern/base.py +339 -134
- deepdoctection/extern/d2detect.py +85 -113
- deepdoctection/extern/deskew.py +14 -11
- deepdoctection/extern/doctrocr.py +141 -130
- deepdoctection/extern/fastlang.py +27 -18
- deepdoctection/extern/hfdetr.py +71 -62
- deepdoctection/extern/hflayoutlm.py +504 -211
- deepdoctection/extern/hflm.py +230 -0
- deepdoctection/extern/model.py +488 -302
- deepdoctection/extern/pdftext.py +23 -19
- deepdoctection/extern/pt/__init__.py +1 -3
- deepdoctection/extern/pt/nms.py +6 -2
- deepdoctection/extern/pt/ptutils.py +29 -19
- deepdoctection/extern/tessocr.py +39 -38
- deepdoctection/extern/texocr.py +18 -18
- deepdoctection/extern/tp/tfutils.py +57 -9
- deepdoctection/extern/tp/tpcompat.py +21 -14
- deepdoctection/extern/tp/tpfrcnn/__init__.py +20 -0
- deepdoctection/extern/tp/tpfrcnn/common.py +7 -3
- deepdoctection/extern/tp/tpfrcnn/config/__init__.py +20 -0
- deepdoctection/extern/tp/tpfrcnn/config/config.py +13 -10
- deepdoctection/extern/tp/tpfrcnn/modeling/__init__.py +20 -0
- deepdoctection/extern/tp/tpfrcnn/modeling/backbone.py +18 -8
- deepdoctection/extern/tp/tpfrcnn/modeling/generalized_rcnn.py +12 -6
- deepdoctection/extern/tp/tpfrcnn/modeling/model_box.py +14 -9
- deepdoctection/extern/tp/tpfrcnn/modeling/model_cascade.py +8 -5
- deepdoctection/extern/tp/tpfrcnn/modeling/model_fpn.py +22 -17
- deepdoctection/extern/tp/tpfrcnn/modeling/model_frcnn.py +21 -14
- deepdoctection/extern/tp/tpfrcnn/modeling/model_mrcnn.py +19 -11
- deepdoctection/extern/tp/tpfrcnn/modeling/model_rpn.py +15 -10
- deepdoctection/extern/tp/tpfrcnn/predict.py +9 -4
- deepdoctection/extern/tp/tpfrcnn/preproc.py +12 -8
- deepdoctection/extern/tp/tpfrcnn/utils/__init__.py +20 -0
- deepdoctection/extern/tp/tpfrcnn/utils/box_ops.py +10 -2
- deepdoctection/extern/tpdetect.py +45 -53
- deepdoctection/mapper/__init__.py +3 -8
- deepdoctection/mapper/cats.py +27 -29
- deepdoctection/mapper/cocostruct.py +10 -10
- deepdoctection/mapper/d2struct.py +27 -26
- deepdoctection/mapper/hfstruct.py +13 -8
- deepdoctection/mapper/laylmstruct.py +178 -37
- deepdoctection/mapper/maputils.py +12 -11
- deepdoctection/mapper/match.py +2 -2
- deepdoctection/mapper/misc.py +11 -9
- deepdoctection/mapper/pascalstruct.py +4 -4
- deepdoctection/mapper/prodigystruct.py +5 -5
- deepdoctection/mapper/pubstruct.py +84 -92
- deepdoctection/mapper/tpstruct.py +5 -5
- deepdoctection/mapper/xfundstruct.py +33 -33
- deepdoctection/pipe/__init__.py +1 -1
- deepdoctection/pipe/anngen.py +12 -14
- deepdoctection/pipe/base.py +52 -106
- deepdoctection/pipe/common.py +72 -59
- deepdoctection/pipe/concurrency.py +16 -11
- deepdoctection/pipe/doctectionpipe.py +24 -21
- deepdoctection/pipe/language.py +20 -25
- deepdoctection/pipe/layout.py +20 -16
- deepdoctection/pipe/lm.py +75 -105
- deepdoctection/pipe/order.py +194 -89
- deepdoctection/pipe/refine.py +111 -124
- deepdoctection/pipe/segment.py +156 -161
- deepdoctection/pipe/{cell.py → sub_layout.py} +50 -40
- deepdoctection/pipe/text.py +37 -36
- deepdoctection/pipe/transform.py +19 -16
- deepdoctection/train/__init__.py +6 -12
- deepdoctection/train/d2_frcnn_train.py +48 -41
- deepdoctection/train/hf_detr_train.py +41 -30
- deepdoctection/train/hf_layoutlm_train.py +153 -135
- deepdoctection/train/tp_frcnn_train.py +32 -31
- deepdoctection/utils/concurrency.py +1 -1
- deepdoctection/utils/context.py +13 -6
- deepdoctection/utils/develop.py +4 -4
- deepdoctection/utils/env_info.py +87 -125
- deepdoctection/utils/file_utils.py +6 -11
- deepdoctection/utils/fs.py +22 -18
- deepdoctection/utils/identifier.py +2 -2
- deepdoctection/utils/logger.py +16 -15
- deepdoctection/utils/metacfg.py +7 -7
- deepdoctection/utils/mocks.py +93 -0
- deepdoctection/utils/pdf_utils.py +11 -11
- deepdoctection/utils/settings.py +185 -181
- deepdoctection/utils/tqdm.py +1 -1
- deepdoctection/utils/transform.py +14 -9
- deepdoctection/utils/types.py +104 -0
- deepdoctection/utils/utils.py +7 -7
- deepdoctection/utils/viz.py +74 -72
- {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/METADATA +30 -21
- deepdoctection-0.33.dist-info/RECORD +146 -0
- {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/WHEEL +1 -1
- deepdoctection/utils/detection_types.py +0 -68
- deepdoctection-0.31.dist-info/RECORD +0 -144
- {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/LICENSE +0 -0
- {deepdoctection-0.31.dist-info → deepdoctection-0.33.dist-info}/top_level.txt +0 -0
|
@@ -18,21 +18,27 @@
|
|
|
18
18
|
"""
|
|
19
19
|
Compatibility classes and methods related to Tensorpack package
|
|
20
20
|
"""
|
|
21
|
+
from __future__ import annotations
|
|
21
22
|
|
|
23
|
+
import os
|
|
22
24
|
from abc import ABC, abstractmethod
|
|
23
|
-
from
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import Any, Mapping, Union
|
|
24
27
|
|
|
25
|
-
from
|
|
26
|
-
from tensorpack.tfutils import SmartInit # pylint: disable=E0401
|
|
27
|
-
|
|
28
|
-
# pylint: disable=import-error
|
|
29
|
-
from tensorpack.train.model_desc import ModelDesc
|
|
30
|
-
from tensorpack.utils.gpu import get_num_gpu
|
|
28
|
+
from lazy_imports import try_import
|
|
31
29
|
|
|
32
30
|
from ...utils.metacfg import AttrDict
|
|
33
31
|
from ...utils.settings import ObjectTypes
|
|
32
|
+
from ...utils.types import PathLikeOrStr, PixelValues
|
|
33
|
+
|
|
34
|
+
with try_import() as import_guard:
|
|
35
|
+
from tensorpack.predict import OfflinePredictor, PredictConfig # pylint: disable=E0401
|
|
36
|
+
from tensorpack.tfutils import SmartInit # pylint: disable=E0401
|
|
37
|
+
from tensorpack.train.model_desc import ModelDesc # pylint: disable=E0401
|
|
38
|
+
from tensorpack.utils.gpu import get_num_gpu # pylint: disable=E0401
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
if not import_guard.is_successful():
|
|
41
|
+
from ...utils.mocks import ModelDesc
|
|
36
42
|
|
|
37
43
|
|
|
38
44
|
class ModelDescWithConfig(ModelDesc, ABC): # type: ignore
|
|
@@ -48,7 +54,7 @@ class ModelDescWithConfig(ModelDesc, ABC): # type: ignore
|
|
|
48
54
|
super().__init__()
|
|
49
55
|
self.cfg = config
|
|
50
56
|
|
|
51
|
-
def get_inference_tensor_names(self) ->
|
|
57
|
+
def get_inference_tensor_names(self) -> tuple[list[str], list[str]]:
|
|
52
58
|
"""
|
|
53
59
|
Returns lists of tensor names to be used to create an inference callable. "build_graph" must create tensors
|
|
54
60
|
of these names when called under inference context.
|
|
@@ -74,7 +80,7 @@ class TensorpackPredictor(ABC):
|
|
|
74
80
|
as there is an explicit class available for this.
|
|
75
81
|
"""
|
|
76
82
|
|
|
77
|
-
def __init__(self, model: ModelDescWithConfig, path_weights:
|
|
83
|
+
def __init__(self, model: ModelDescWithConfig, path_weights: PathLikeOrStr, ignore_mismatch: bool) -> None:
|
|
78
84
|
"""
|
|
79
85
|
:param model: Model, either as ModelDescWithConfig or derived from that class.
|
|
80
86
|
:param path_weights: Model weights of the prediction config.
|
|
@@ -82,7 +88,7 @@ class TensorpackPredictor(ABC):
|
|
|
82
88
|
if a pre-trained model is to be fine-tuned on a custom dataset.
|
|
83
89
|
"""
|
|
84
90
|
self._model = model
|
|
85
|
-
self.path_weights = path_weights
|
|
91
|
+
self.path_weights = Path(path_weights)
|
|
86
92
|
self.ignore_mismatch = ignore_mismatch
|
|
87
93
|
self._number_gpus = get_num_gpu()
|
|
88
94
|
self.predict_config = self._build_config()
|
|
@@ -95,9 +101,10 @@ class TensorpackPredictor(ABC):
|
|
|
95
101
|
return OfflinePredictor(self.predict_config)
|
|
96
102
|
|
|
97
103
|
def _build_config(self) -> PredictConfig:
|
|
104
|
+
path_weights = os.fspath(self.path_weights) if os.fspath(self.path_weights) != "." else ""
|
|
98
105
|
predict_config = PredictConfig(
|
|
99
106
|
model=self._model,
|
|
100
|
-
session_init=SmartInit(
|
|
107
|
+
session_init=SmartInit(path_weights, ignore_mismatch=self.ignore_mismatch),
|
|
101
108
|
input_names=self._model.get_inference_tensor_names()[0],
|
|
102
109
|
output_names=self._model.get_inference_tensor_names()[1],
|
|
103
110
|
)
|
|
@@ -107,7 +114,7 @@ class TensorpackPredictor(ABC):
|
|
|
107
114
|
@staticmethod
|
|
108
115
|
@abstractmethod
|
|
109
116
|
def get_wrapped_model(
|
|
110
|
-
path_yaml:
|
|
117
|
+
path_yaml: PathLikeOrStr, categories: Mapping[int, ObjectTypes], config_overwrite: Union[list[str], None]
|
|
111
118
|
) -> ModelDescWithConfig:
|
|
112
119
|
"""
|
|
113
120
|
Implement the config generation, its modification and instantiate a version of the model. See
|
|
@@ -116,7 +123,7 @@ class TensorpackPredictor(ABC):
|
|
|
116
123
|
raise NotImplementedError()
|
|
117
124
|
|
|
118
125
|
@abstractmethod
|
|
119
|
-
def predict(self, np_img:
|
|
126
|
+
def predict(self, np_img: PixelValues) -> Any:
|
|
120
127
|
"""
|
|
121
128
|
Implement, how `self.tp_predictor` is invoked and raw prediction results are generated. Do use only raw
|
|
122
129
|
objects and nothing, which is related to the DD API.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# File: __init__.py
|
|
3
|
+
|
|
4
|
+
# Copyright 2021 Dr. Janis Meyer. All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
Init file for code for Tensorpack FRCNN example
|
|
20
|
+
"""
|
|
@@ -11,13 +11,17 @@ This file is modified from
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
import numpy as np
|
|
14
|
-
from
|
|
14
|
+
from lazy_imports import try_import
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
with try_import() as import_guard:
|
|
17
|
+
from tensorpack.dataflow.imgaug import ImageAugmentor, ResizeTransform # pylint: disable=E0401
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
with try_import() as cc_import_guard:
|
|
19
20
|
import pycocotools.mask as coco_mask
|
|
20
21
|
|
|
22
|
+
if not import_guard.is_successful():
|
|
23
|
+
from ....utils.mocks import ImageAugmentor
|
|
24
|
+
|
|
21
25
|
|
|
22
26
|
class CustomResize(ImageAugmentor):
|
|
23
27
|
"""
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# File: __init__.py
|
|
3
|
+
|
|
4
|
+
# Copyright 2021 Dr. Janis Meyer. All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
Init file for code for Tensorpack's FRCNN configs
|
|
20
|
+
"""
|
|
@@ -191,22 +191,25 @@ import os
|
|
|
191
191
|
from typing import List, Mapping, Tuple
|
|
192
192
|
|
|
193
193
|
import numpy as np
|
|
194
|
-
from
|
|
195
|
-
from tensorpack.utils import logger # pylint: disable=E0401
|
|
196
|
-
|
|
197
|
-
# pylint: disable=import-error
|
|
198
|
-
from tensorpack.utils.gpu import get_num_gpu
|
|
194
|
+
from lazy_imports import try_import
|
|
199
195
|
|
|
200
196
|
from .....utils.metacfg import AttrDict
|
|
201
|
-
from .....utils.settings import
|
|
197
|
+
from .....utils.settings import TypeOrStr, get_type
|
|
198
|
+
|
|
199
|
+
with try_import() as import_guard:
|
|
200
|
+
from tensorpack.tfutils import collect_env_info # pylint: disable=E0401
|
|
201
|
+
from tensorpack.utils import logger # pylint: disable=E0401
|
|
202
|
+
|
|
203
|
+
# pylint: disable=import-error
|
|
204
|
+
from tensorpack.utils.gpu import get_num_gpu
|
|
202
205
|
|
|
203
|
-
# pylint: enable=import-error
|
|
206
|
+
# pylint: enable=import-error
|
|
204
207
|
|
|
205
208
|
|
|
206
209
|
__all__ = ["train_frcnn_config", "model_frcnn_config"]
|
|
207
210
|
|
|
208
211
|
|
|
209
|
-
def model_frcnn_config(config: AttrDict, categories: Mapping[
|
|
212
|
+
def model_frcnn_config(config: AttrDict, categories: Mapping[int, TypeOrStr], print_summary: bool = True) -> None:
|
|
210
213
|
"""
|
|
211
214
|
Sanity checks for Tensorpack Faster-RCNN config settings, where the focus lies on the model for predicting.
|
|
212
215
|
It will update the config instance.
|
|
@@ -218,8 +221,8 @@ def model_frcnn_config(config: AttrDict, categories: Mapping[str, ObjectTypes],
|
|
|
218
221
|
|
|
219
222
|
config.freeze(False)
|
|
220
223
|
|
|
221
|
-
categories = {
|
|
222
|
-
categories[0] = "
|
|
224
|
+
categories = {key: get_type(categories[val]) for key, val in enumerate(categories, 1)}
|
|
225
|
+
categories[0] = get_type("background")
|
|
223
226
|
config.DATA.CLASS_NAMES = list(categories.values())
|
|
224
227
|
config.DATA.CLASS_DICT = categories
|
|
225
228
|
config.DATA.NUM_CATEGORY = len(config.DATA.CLASS_NAMES) - 1
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# File: __init__.py
|
|
3
|
+
|
|
4
|
+
# Copyright 2021 Dr. Janis Meyer. All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
Init file for code for Tensorpack's FRCNN configs
|
|
20
|
+
"""
|
|
@@ -12,22 +12,30 @@ This file is modified from
|
|
|
12
12
|
from contextlib import ExitStack, contextmanager
|
|
13
13
|
|
|
14
14
|
import numpy as np
|
|
15
|
+
from lazy_imports import try_import
|
|
15
16
|
|
|
16
17
|
# pylint: disable=import-error
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
from tensorpack
|
|
21
|
-
from tensorpack.
|
|
18
|
+
|
|
19
|
+
with try_import() as import_guard:
|
|
20
|
+
import tensorflow as tf
|
|
21
|
+
from tensorpack import tfv1
|
|
22
|
+
from tensorpack.models import BatchNorm, Conv2D, MaxPooling, layer_register
|
|
23
|
+
from tensorpack.tfutils import argscope
|
|
24
|
+
from tensorpack.tfutils.varreplace import custom_getter_scope, freeze_variables
|
|
22
25
|
|
|
23
26
|
# pylint: enable=import-error
|
|
24
27
|
|
|
28
|
+
if not import_guard.is_successful():
|
|
29
|
+
from .....utils.mocks import layer_register
|
|
30
|
+
|
|
25
31
|
|
|
26
32
|
@layer_register(log_shape=True)
|
|
27
|
-
def GroupNorm(x, group=32, gamma_initializer=
|
|
33
|
+
def GroupNorm(x, group=32, gamma_initializer=None):
|
|
28
34
|
"""
|
|
29
35
|
More code that reproduces the paper can be found at <https://github.com/ppwwyyxx/GroupNorm-reproduce/>.
|
|
30
36
|
"""
|
|
37
|
+
if gamma_initializer is None:
|
|
38
|
+
gamma_initializer = tf.constant_initializer(1.0)
|
|
31
39
|
shape = x.get_shape().as_list()
|
|
32
40
|
ndims = len(shape)
|
|
33
41
|
assert ndims == 4, shape
|
|
@@ -63,7 +71,7 @@ def freeze_affine_getter(getter, *args, **kwargs):
|
|
|
63
71
|
if name.endswith("/gamma") or name.endswith("/beta"):
|
|
64
72
|
kwargs["trainable"] = False
|
|
65
73
|
ret = getter(*args, **kwargs)
|
|
66
|
-
tf.add_to_collection(tf.GraphKeys.MODEL_VARIABLES, ret)
|
|
74
|
+
tf.add_to_collection(tf.GraphKeys.MODEL_VARIABLES, ret) # pylint: disable=E1101
|
|
67
75
|
else:
|
|
68
76
|
ret = getter(*args, **kwargs)
|
|
69
77
|
return ret
|
|
@@ -153,7 +161,7 @@ def get_norm(cfg, zero_init=False):
|
|
|
153
161
|
return lambda x: norm(layer_name, x, gamma_initializer=tf.zeros_initializer() if zero_init else None)
|
|
154
162
|
|
|
155
163
|
|
|
156
|
-
def resnet_shortcut(l, n_out, stride, activation=
|
|
164
|
+
def resnet_shortcut(l, n_out, stride, activation=None):
|
|
157
165
|
"""
|
|
158
166
|
Defining the skip connection in bottleneck
|
|
159
167
|
|
|
@@ -163,6 +171,8 @@ def resnet_shortcut(l, n_out, stride, activation=tf.identity):
|
|
|
163
171
|
:param activation: An activation function
|
|
164
172
|
:return: tf.Tensor
|
|
165
173
|
"""
|
|
174
|
+
if activation is None:
|
|
175
|
+
activation = tf.identity
|
|
166
176
|
n_in = l.shape[1]
|
|
167
177
|
if n_in != n_out: # change dimension when channel is not the same
|
|
168
178
|
return Conv2D("convshortcut", l, n_out, 1, strides=stride, activation=activation) # pylint: disable=E1124
|
|
@@ -9,12 +9,8 @@ This file is modified from
|
|
|
9
9
|
<https://github.com/tensorpack/tensorpack/blob/master/examples/FasterRCNN/modeling/generalized_rcnn.py>
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
from tensorpack import tfv1
|
|
15
|
-
from tensorpack.models import l2_regularizer, regularize_cost
|
|
16
|
-
from tensorpack.tfutils import optimizer
|
|
17
|
-
from tensorpack.tfutils.summary import add_moving_summary
|
|
12
|
+
|
|
13
|
+
from lazy_imports import try_import
|
|
18
14
|
|
|
19
15
|
from ...tpcompat import ModelDescWithConfig
|
|
20
16
|
from ..utils.box_ops import area as tf_area
|
|
@@ -40,6 +36,16 @@ from .model_frcnn import (
|
|
|
40
36
|
from .model_mrcnn import maskrcnn_loss, unpackbits_masks
|
|
41
37
|
from .model_rpn import rpn_head
|
|
42
38
|
|
|
39
|
+
with try_import() as import_guard:
|
|
40
|
+
# pylint: disable=import-error
|
|
41
|
+
import tensorflow as tf
|
|
42
|
+
from tensorpack import tfv1
|
|
43
|
+
from tensorpack.models import l2_regularizer, regularize_cost
|
|
44
|
+
from tensorpack.tfutils import optimizer
|
|
45
|
+
from tensorpack.tfutils.summary import add_moving_summary
|
|
46
|
+
|
|
47
|
+
# pylint: enable=import-error
|
|
48
|
+
|
|
43
49
|
|
|
44
50
|
class GeneralizedRCNN(ModelDescWithConfig):
|
|
45
51
|
"""
|
|
@@ -11,12 +11,17 @@ This file is modified from
|
|
|
11
11
|
from collections import namedtuple
|
|
12
12
|
|
|
13
13
|
import numpy as np
|
|
14
|
+
from lazy_imports import try_import
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
with try_import() as import_guard:
|
|
17
|
+
# pylint: disable=import-error
|
|
18
|
+
import tensorflow as tf
|
|
19
|
+
from tensorpack.tfutils.scope_utils import under_name_scope
|
|
18
20
|
|
|
19
|
-
# pylint: enable=import-error
|
|
21
|
+
# pylint: enable=import-error
|
|
22
|
+
|
|
23
|
+
if not import_guard.is_successful():
|
|
24
|
+
from .....utils.mocks import under_name_scope
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
@under_name_scope()
|
|
@@ -61,7 +66,7 @@ def decode_bbox_target(box_predictions, anchors, preproc_max_size):
|
|
|
61
66
|
xbyb = box_pred_txty * waha + xaya
|
|
62
67
|
x1y1 = xbyb - wbhb * 0.5
|
|
63
68
|
x2y2 = xbyb + wbhb * 0.5 # (...)x1x2
|
|
64
|
-
out = tf.concat([x1y1, x2y2], axis=-2)
|
|
69
|
+
out = tf.concat([x1y1, x2y2], axis=-2) # pylint: disable=E1123
|
|
65
70
|
return tf.reshape(out, orig_shape)
|
|
66
71
|
|
|
67
72
|
|
|
@@ -88,7 +93,7 @@ def encode_bbox_target(boxes, anchors):
|
|
|
88
93
|
# Note that here not all boxes are valid. Some may be zero
|
|
89
94
|
txty = (xbyb - xaya) / waha
|
|
90
95
|
twth = tf.math.log(wbhb / waha) # may contain -inf for invalid boxes
|
|
91
|
-
encoded = tf.concat([txty, twth], axis=1) # (-1x2x2)
|
|
96
|
+
encoded = tf.concat([txty, twth], axis=1) # (-1x2x2) # pylint: disable=E1123
|
|
92
97
|
return tf.reshape(encoded, tf.shape(boxes))
|
|
93
98
|
|
|
94
99
|
|
|
@@ -148,7 +153,7 @@ def crop_and_resize(image, boxes, box_ind, crop_size, pad_border=True):
|
|
|
148
153
|
n_w = spacing_w * tf.cast(crop_shape[1] - 1, tf.float32) / imshape[1]
|
|
149
154
|
n_h = spacing_h * tf.cast(crop_shape[0] - 1, tf.float32) / imshape[0]
|
|
150
155
|
|
|
151
|
-
return tf.concat([ny0, nx0, ny0 + n_h, nx0 + n_w], axis=1)
|
|
156
|
+
return tf.concat([ny0, nx0, ny0 + n_h, nx0 + n_w], axis=1) # pylint: disable=E1123
|
|
152
157
|
|
|
153
158
|
image_shape = tf.shape(image)[2:]
|
|
154
159
|
|
|
@@ -208,8 +213,8 @@ class RPNAnchors(namedtuple("_RPNAnchors", ["boxes", "gt_labels", "gt_boxes"])):
|
|
|
208
213
|
Slice anchors to the spatial size of this feature map.
|
|
209
214
|
"""
|
|
210
215
|
shape2d = tf.shape(featuremap)[2:] # h,w
|
|
211
|
-
slice3d = tf.concat([shape2d, [-1]], axis=0)
|
|
212
|
-
slice4d = tf.concat([shape2d, [-1, -1]], axis=0)
|
|
216
|
+
slice3d = tf.concat([shape2d, [-1]], axis=0) # pylint: disable=E1123
|
|
217
|
+
slice4d = tf.concat([shape2d, [-1, -1]], axis=0) # pylint: disable=E1123
|
|
213
218
|
boxes = tf.slice(self.boxes, [0, 0, 0, 0], slice4d)
|
|
214
219
|
gt_labels = tf.slice(self.gt_labels, [0, 0, 0], slice3d)
|
|
215
220
|
gt_boxes = tf.slice(self.gt_boxes, [0, 0, 0, 0], slice4d)
|
|
@@ -9,17 +9,20 @@ This file is modified from
|
|
|
9
9
|
<https://github.com/tensorpack/tensorpack/blob/master/examples/FasterRCNN/modeling/model_cascade.py>
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
import tensorflow as tf
|
|
14
|
-
from tensorpack import tfv1
|
|
15
|
-
from tensorpack.tfutils import get_current_tower_context
|
|
12
|
+
from lazy_imports import try_import
|
|
16
13
|
|
|
17
14
|
from ..utils.box_ops import area as tf_area
|
|
18
15
|
from ..utils.box_ops import pairwise_iou
|
|
19
16
|
from .model_box import clip_boxes
|
|
20
17
|
from .model_frcnn import BoxProposals, FastRCNNHead, fastrcnn_outputs
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
with try_import() as import_guard:
|
|
20
|
+
# pylint: disable=import-error
|
|
21
|
+
import tensorflow as tf
|
|
22
|
+
from tensorpack import tfv1
|
|
23
|
+
from tensorpack.tfutils import get_current_tower_context
|
|
24
|
+
|
|
25
|
+
# pylint: enable=import-error
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
class CascadeRCNNHead:
|
|
@@ -12,23 +12,28 @@ This file is modified from
|
|
|
12
12
|
import itertools
|
|
13
13
|
|
|
14
14
|
import numpy as np
|
|
15
|
-
|
|
16
|
-
# pylint: disable=import-error
|
|
17
|
-
import tensorflow as tf
|
|
18
|
-
from tensorpack import tfv1
|
|
19
|
-
from tensorpack.models import Conv2D, FixedUnPooling, MaxPooling, layer_register
|
|
20
|
-
from tensorpack.tfutils.argscope import argscope
|
|
21
|
-
from tensorpack.tfutils.scope_utils import under_name_scope
|
|
22
|
-
from tensorpack.tfutils.summary import add_moving_summary
|
|
23
|
-
from tensorpack.tfutils.tower import get_current_tower_context
|
|
24
|
-
from tensorpack.utils.argtools import memoized
|
|
15
|
+
from lazy_imports import try_import
|
|
25
16
|
|
|
26
17
|
from ..utils.box_ops import area as tf_area
|
|
27
18
|
from .backbone import GroupNorm
|
|
28
19
|
from .model_box import roi_align
|
|
29
20
|
from .model_rpn import generate_rpn_proposals, get_all_anchors, rpn_losses
|
|
30
21
|
|
|
31
|
-
|
|
22
|
+
with try_import() as import_guard:
|
|
23
|
+
# pylint: disable=import-error
|
|
24
|
+
import tensorflow as tf
|
|
25
|
+
from tensorpack import tfv1
|
|
26
|
+
from tensorpack.models import Conv2D, FixedUnPooling, MaxPooling, layer_register
|
|
27
|
+
from tensorpack.tfutils.argscope import argscope
|
|
28
|
+
from tensorpack.tfutils.scope_utils import under_name_scope
|
|
29
|
+
from tensorpack.tfutils.summary import add_moving_summary
|
|
30
|
+
from tensorpack.tfutils.tower import get_current_tower_context
|
|
31
|
+
from tensorpack.utils.argtools import memoized
|
|
32
|
+
|
|
33
|
+
# pylint: enable=import-error
|
|
34
|
+
|
|
35
|
+
if not import_guard.is_successful():
|
|
36
|
+
from .....utils.mocks import layer_register, memoized, under_name_scope
|
|
32
37
|
|
|
33
38
|
|
|
34
39
|
@layer_register(log_shape=True)
|
|
@@ -146,9 +151,9 @@ def multilevel_roi_align(features, rcnn_boxes, resolution, fpn_anchor_strides):
|
|
|
146
151
|
all_rois.append(roi_align(featuremap, boxes_on_featuremap, resolution))
|
|
147
152
|
|
|
148
153
|
# this can fail if using TF<=1.8 with MKL build
|
|
149
|
-
all_rois = tf.concat(all_rois, axis=0) # NCHW
|
|
154
|
+
all_rois = tf.concat(all_rois, axis=0) # NCHW # pylint: disable=E1123
|
|
150
155
|
# Unshuffle to the original order, to match the original samples
|
|
151
|
-
level_id_perm = tf.concat(level_ids, axis=0) # A permutation of 1~N
|
|
156
|
+
level_id_perm = tf.concat(level_ids, axis=0) # A permutation of 1~N # pylint: disable=E1123
|
|
152
157
|
level_id_invert_perm = tf.math.invert_permutation(level_id_perm)
|
|
153
158
|
all_rois = tf.gather(all_rois, level_id_invert_perm, name="output")
|
|
154
159
|
return all_rois
|
|
@@ -253,8 +258,8 @@ def generate_fpn_proposals(
|
|
|
253
258
|
all_boxes.append(proposal_boxes)
|
|
254
259
|
all_scores.append(proposal_scores)
|
|
255
260
|
|
|
256
|
-
proposal_boxes = tf.concat(all_boxes, axis=0) # nx4
|
|
257
|
-
proposal_scores = tf.concat(all_scores, axis=0) # n
|
|
261
|
+
proposal_boxes = tf.concat(all_boxes, axis=0) # nx4 # pylint: disable=E1123
|
|
262
|
+
proposal_scores = tf.concat(all_scores, axis=0) # n # pylint: disable=E1123
|
|
258
263
|
# Here we are different from Detectron.
|
|
259
264
|
# Detectron picks top-k within the batch, rather than within an image, however we do not have a batch.
|
|
260
265
|
proposal_topk = tf.minimum(tf.size(proposal_scores), fpn_nms_top_k)
|
|
@@ -266,8 +271,8 @@ def generate_fpn_proposals(
|
|
|
266
271
|
pred_boxes_decoded = multilevel_pred_boxes[lvl]
|
|
267
272
|
all_boxes.append(tf.reshape(pred_boxes_decoded, [-1, 4]))
|
|
268
273
|
all_scores.append(tf.reshape(multilevel_label_logits[lvl], [-1]))
|
|
269
|
-
all_boxes = tf.concat(all_boxes, axis=0)
|
|
270
|
-
all_scores = tf.concat(all_scores, axis=0)
|
|
274
|
+
all_boxes = tf.concat(all_boxes, axis=0) # pylint: disable=E1123
|
|
275
|
+
all_scores = tf.concat(all_scores, axis=0) # pylint: disable=E1123
|
|
271
276
|
proposal_boxes, proposal_scores = generate_rpn_proposals(
|
|
272
277
|
all_boxes,
|
|
273
278
|
all_scores,
|
|
@@ -8,21 +8,28 @@
|
|
|
8
8
|
This file is modified from
|
|
9
9
|
<https://github.com/tensorpack/tensorpack/blob/master/examples/FasterRCNN/modeling/model_frcnn.py>
|
|
10
10
|
"""
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
from tensorpack import tfv1
|
|
14
|
-
from tensorpack.models import Conv2D, FullyConnected, layer_register
|
|
15
|
-
from tensorpack.tfutils.argscope import argscope
|
|
16
|
-
from tensorpack.tfutils.common import get_tf_version_tuple
|
|
17
|
-
from tensorpack.tfutils.scope_utils import under_name_scope
|
|
18
|
-
from tensorpack.tfutils.summary import add_moving_summary
|
|
19
|
-
from tensorpack.utils.argtools import memoized_method
|
|
11
|
+
|
|
12
|
+
from lazy_imports import try_import
|
|
20
13
|
|
|
21
14
|
from ..utils.box_ops import pairwise_iou
|
|
22
15
|
from .backbone import GroupNorm
|
|
23
16
|
from .model_box import decode_bbox_target, encode_bbox_target
|
|
24
17
|
|
|
25
|
-
|
|
18
|
+
with try_import() as import_guard:
|
|
19
|
+
# pylint: disable=import-error
|
|
20
|
+
import tensorflow as tf
|
|
21
|
+
from tensorpack import tfv1
|
|
22
|
+
from tensorpack.models import Conv2D, FullyConnected, layer_register
|
|
23
|
+
from tensorpack.tfutils.argscope import argscope
|
|
24
|
+
from tensorpack.tfutils.common import get_tf_version_tuple
|
|
25
|
+
from tensorpack.tfutils.scope_utils import under_name_scope
|
|
26
|
+
from tensorpack.tfutils.summary import add_moving_summary
|
|
27
|
+
from tensorpack.utils.argtools import memoized_method
|
|
28
|
+
|
|
29
|
+
# pylint: enable=import-error
|
|
30
|
+
|
|
31
|
+
if not import_guard.is_successful():
|
|
32
|
+
from .....utils.mocks import layer_register, memoized_method, under_name_scope
|
|
26
33
|
|
|
27
34
|
|
|
28
35
|
@under_name_scope()
|
|
@@ -72,8 +79,8 @@ def sample_fast_rcnn_targets(boxes, gt_boxes, gt_labels, frcnn_fg_thresh, frcnn_
|
|
|
72
79
|
proposal_metrics(iou)
|
|
73
80
|
|
|
74
81
|
# add ground truth as proposals as well
|
|
75
|
-
boxes = tf.concat([boxes, gt_boxes], axis=0) # (n+m) x 4
|
|
76
|
-
iou = tf.concat([iou, tf.eye(tf.shape(gt_boxes)[0])], axis=0) # (n+m) x m
|
|
82
|
+
boxes = tf.concat([boxes, gt_boxes], axis=0) # (n+m) x 4 # pylint: disable=E1123
|
|
83
|
+
iou = tf.concat([iou, tf.eye(tf.shape(gt_boxes)[0])], axis=0) # (n+m) x m # pylint: disable=E1123
|
|
77
84
|
# #proposal=n+m from now on
|
|
78
85
|
|
|
79
86
|
def sample_fg_bg(iou):
|
|
@@ -107,10 +114,10 @@ def sample_fast_rcnn_targets(boxes, gt_boxes, gt_labels, frcnn_fg_thresh, frcnn_
|
|
|
107
114
|
)
|
|
108
115
|
fg_inds_wrt_gt = tf.gather(best_iou_ind, fg_inds) # num_fg
|
|
109
116
|
|
|
110
|
-
all_indices = tf.concat([fg_inds, bg_inds], axis=0) # indices w.r.t all n+m proposal boxes
|
|
117
|
+
all_indices = tf.concat([fg_inds, bg_inds], axis=0) # indices w.r.t all n+m proposal boxes # pylint: disable=E1123
|
|
111
118
|
ret_boxes = tf.gather(boxes, all_indices)
|
|
112
119
|
|
|
113
|
-
ret_labels = tf.concat(
|
|
120
|
+
ret_labels = tf.concat( # pylint: disable=E1123
|
|
114
121
|
[tf.gather(gt_labels, fg_inds_wrt_gt), tf.zeros_like(bg_inds, dtype=tf.int64)],
|
|
115
122
|
axis=0,
|
|
116
123
|
)
|
|
@@ -9,17 +9,23 @@ This file is modified from
|
|
|
9
9
|
<https://github.com/tensorpack/tensorpack/blob/master/examples/FasterRCNN/modeling/model_mrcnn.py>
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
import tensorflow as tf
|
|
14
|
-
from tensorpack.models import Conv2D, Conv2DTranspose, layer_register
|
|
15
|
-
from tensorpack.tfutils.argscope import argscope
|
|
16
|
-
from tensorpack.tfutils.common import get_tf_version_tuple
|
|
17
|
-
from tensorpack.tfutils.scope_utils import under_name_scope
|
|
18
|
-
from tensorpack.tfutils.summary import add_moving_summary
|
|
12
|
+
from lazy_imports import try_import
|
|
19
13
|
|
|
20
14
|
from .backbone import GroupNorm
|
|
21
15
|
|
|
22
|
-
|
|
16
|
+
with try_import() as import_guard:
|
|
17
|
+
# pylint: disable=import-error
|
|
18
|
+
import tensorflow as tf
|
|
19
|
+
from tensorpack.models import Conv2D, Conv2DTranspose, layer_register
|
|
20
|
+
from tensorpack.tfutils.argscope import argscope
|
|
21
|
+
from tensorpack.tfutils.common import get_tf_version_tuple
|
|
22
|
+
from tensorpack.tfutils.scope_utils import under_name_scope
|
|
23
|
+
from tensorpack.tfutils.summary import add_moving_summary
|
|
24
|
+
|
|
25
|
+
# pylint: enable=import-error
|
|
26
|
+
|
|
27
|
+
if not import_guard.is_successful():
|
|
28
|
+
from .....utils.mocks import layer_register, under_name_scope
|
|
23
29
|
|
|
24
30
|
|
|
25
31
|
@under_name_scope()
|
|
@@ -41,7 +47,7 @@ def maskrcnn_loss(mask_logits, fg_labels, fg_target_masks):
|
|
|
41
47
|
|
|
42
48
|
# add some training visualizations to tensorboard
|
|
43
49
|
with tf.name_scope("mask_viz"):
|
|
44
|
-
viz = tf.concat([fg_target_masks, mask_probs], axis=1)
|
|
50
|
+
viz = tf.concat([fg_target_masks, mask_probs], axis=1) # pylint: disable=E1123
|
|
45
51
|
viz = tf.expand_dims(viz, 3)
|
|
46
52
|
viz = tf.cast(viz * 255, tf.uint8, name="viz")
|
|
47
53
|
tf.summary.image("mask_truth|pred", viz, max_outputs=10)
|
|
@@ -77,7 +83,7 @@ def maskrcnn_upXconv_head(feature, num_category, num_convs, norm=None, **kwargs)
|
|
|
77
83
|
with argscope(
|
|
78
84
|
[Conv2D, Conv2DTranspose],
|
|
79
85
|
data_format="channels_first",
|
|
80
|
-
kernel_initializer=tf.variance_scaling_initializer(
|
|
86
|
+
kernel_initializer=tf.variance_scaling_initializer( # pylint: disable=E1101
|
|
81
87
|
scale=2.0,
|
|
82
88
|
mode="fan_out",
|
|
83
89
|
distribution="untruncated_normal" if get_tf_version_tuple() >= (1, 12) else "normal",
|
|
@@ -121,5 +127,7 @@ def unpackbits_masks(masks):
|
|
|
121
127
|
assert masks.dtype == tf.uint8, masks
|
|
122
128
|
bits = tf.constant((128, 64, 32, 16, 8, 4, 2, 1), dtype=tf.uint8)
|
|
123
129
|
unpacked = tf.bitwise.bitwise_and(tf.expand_dims(masks, -1), bits) > 0
|
|
124
|
-
unpacked = tf.reshape(
|
|
130
|
+
unpacked = tf.reshape(
|
|
131
|
+
unpacked, tf.concat([tf.shape(masks)[:-1], [8 * tf.shape(masks)[-1]]], axis=0) # pylint: disable=E1123
|
|
132
|
+
) # pylint: disable=E1123
|
|
125
133
|
return unpacked
|
|
@@ -10,19 +10,24 @@ This file is modified from
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
import numpy as np
|
|
13
|
-
|
|
14
|
-
# pylint: disable=import-error
|
|
15
|
-
import tensorflow as tf
|
|
16
|
-
from tensorpack import tfv1
|
|
17
|
-
from tensorpack.models import Conv2D, layer_register
|
|
18
|
-
from tensorpack.tfutils.argscope import argscope
|
|
19
|
-
from tensorpack.tfutils.scope_utils import auto_reuse_variable_scope, under_name_scope
|
|
20
|
-
from tensorpack.tfutils.summary import add_moving_summary
|
|
21
|
-
from tensorpack.utils.argtools import memoized
|
|
13
|
+
from lazy_imports import try_import
|
|
22
14
|
|
|
23
15
|
from .model_box import clip_boxes
|
|
24
16
|
|
|
25
|
-
|
|
17
|
+
with try_import() as import_guard:
|
|
18
|
+
# pylint: disable=import-error
|
|
19
|
+
import tensorflow as tf
|
|
20
|
+
from tensorpack import tfv1
|
|
21
|
+
from tensorpack.models import Conv2D, layer_register
|
|
22
|
+
from tensorpack.tfutils.argscope import argscope
|
|
23
|
+
from tensorpack.tfutils.scope_utils import auto_reuse_variable_scope, under_name_scope
|
|
24
|
+
from tensorpack.tfutils.summary import add_moving_summary
|
|
25
|
+
from tensorpack.utils.argtools import memoized
|
|
26
|
+
|
|
27
|
+
# pylint: enable=import-error
|
|
28
|
+
|
|
29
|
+
if not import_guard.is_successful():
|
|
30
|
+
from .....utils.mocks import auto_reuse_variable_scope, layer_register, memoized, under_name_scope
|
|
26
31
|
|
|
27
32
|
|
|
28
33
|
@layer_register(log_shape=True)
|
|
@@ -8,21 +8,26 @@
|
|
|
8
8
|
This file is modified from
|
|
9
9
|
<https://github.com/tensorpack/tensorpack/blob/master/examples/FasterRCNN/predict.py>
|
|
10
10
|
"""
|
|
11
|
+
from __future__ import annotations
|
|
11
12
|
|
|
12
13
|
from typing import List
|
|
13
14
|
|
|
14
|
-
import cv2
|
|
15
15
|
import numpy as np
|
|
16
|
-
from
|
|
16
|
+
from lazy_imports import try_import
|
|
17
17
|
|
|
18
|
-
from ....utils.file_utils import scipy_available
|
|
19
18
|
from ....utils.transform import InferenceResize
|
|
20
19
|
from ...base import DetectionResult
|
|
21
20
|
from .common import clip_boxes
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
with try_import() as import_guard:
|
|
23
|
+
from tensorpack.predict.base import OfflinePredictor # pylint: disable=E0401
|
|
24
|
+
|
|
25
|
+
with try_import() as sp_import_guard:
|
|
24
26
|
from scipy import interpolate
|
|
25
27
|
|
|
28
|
+
with try_import() as cv2_import_guard:
|
|
29
|
+
import cv2
|
|
30
|
+
|
|
26
31
|
|
|
27
32
|
def _scale_box(box, scale):
|
|
28
33
|
w_half = (box[2] - box[0]) * 0.5
|