diff --git a/model-optimizer/extensions/front/tf/ObjectDetectionAPI.py b/model-optimizer/extensions/front/tf/ObjectDetectionAPI.py index 4711e3474e5..c33e36fc0e6 100644 --- a/model-optimizer/extensions/front/tf/ObjectDetectionAPI.py +++ b/model-optimizer/extensions/front/tf/ObjectDetectionAPI.py @@ -363,7 +363,8 @@ def skip_nodes_by_condition(current_node: Node, condition: callable): return current_node -def calculate_shape_keeping_aspect_ratio(height: int, width: int, min_size: int, max_size: int): +def calculate_shape_keeping_aspect_ratio(height: int, width: int, min_size: int, max_size: int, + pad_to_max_dimension: bool = False): """ The function scales spatial sizes of the image keeping aspect ratio to satisfy provided requirements. The behavior of this function is equivalent to the output shape calculation of the Preprocessor block of TensorFlow @@ -372,8 +373,11 @@ def calculate_shape_keeping_aspect_ratio(height: int, width: int, min_size: int, :param width: input width. :param min_size: size limit. :param max_size: size limit. + :param pad_to_max_dimension: scale the input image size to the maximum value specified :return: the tuple with scaled image height, width. """ + if pad_to_max_dimension: + return max_size, max_size ratio_min = min_size / min(height, width) ratio_max = max_size / max(height, width) ratio = min(ratio_min, ratio_max) @@ -441,6 +445,7 @@ def calculate_placeholder_spatial_shape(graph: Graph, match: SubgraphMatch, pipe # if the model is created with an input image resizer keeping aspect ratio if resizer_min_dimension and resizer_max_dimension: + pad_to_max_dimension = pipeline_config.get_param('pad_to_max_dimension') print('[ WARNING ] Model Optimizer removes pre-processing block of the model which resizes image keeping ' 'aspect ratio. The Inference Engine does not support dynamic image size so the Intermediate ' 'Representation file is generated with the input image size of a fixed size.') @@ -448,7 +453,8 @@ def calculate_placeholder_spatial_shape(graph: Graph, match: SubgraphMatch, pipe scaled_height, scaled_width = calculate_shape_keeping_aspect_ratio(user_defined_height, user_defined_width, resizer_min_dimension, - resizer_max_dimension) + resizer_max_dimension, + pad_to_max_dimension) if scaled_height != user_defined_height or scaled_width != user_defined_width: log.error('The model resizes the input image keeping aspect ratio with min dimension {}, max ' 'dimension {}. The provided input height {}, width {} is transformed to height {}, width ' @@ -457,7 +463,10 @@ def calculate_placeholder_spatial_shape(graph: Graph, match: SubgraphMatch, pipe height = scaled_height width = scaled_width else: - height = width = resizer_min_dimension + if pad_to_max_dimension: + height = width = resizer_max_dimension + else: + height = width = resizer_min_dimension print('Specify the "--input_shape" command line parameter to override the default shape which is equal to ' '({}, {}).'.format(height, width)) diff --git a/model-optimizer/extensions/front/tf/ObjectDetectionAPI_test.py b/model-optimizer/extensions/front/tf/ObjectDetectionAPI_test.py index 8fcc2609a10..c610a0ed9e4 100644 --- a/model-optimizer/extensions/front/tf/ObjectDetectionAPI_test.py +++ b/model-optimizer/extensions/front/tf/ObjectDetectionAPI_test.py @@ -16,6 +16,8 @@ import unittest +from generator import generator, generate + from extensions.front.tf.ObjectDetectionAPI import calculate_shape_keeping_aspect_ratio, \ calculate_placeholder_spatial_shape from mo.front.subgraph_matcher import SubgraphMatch @@ -34,58 +36,33 @@ class FakePipelineConfig: return self._model_params[param] +@generator class TestCalculateShape(unittest.TestCase): min_size = 600 max_size = 1024 - def test_calculate_shape_1(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(100, 300, self.min_size, self.max_size), (341, 1024)) - - def test_calculate_shape_2(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(100, 600, self.min_size, self.max_size), (171, 1024)) - - def test_calculate_shape_3(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(100, 3000, self.min_size, self.max_size), (34, 1024)) - - def test_calculate_shape_4(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(300, 300, self.min_size, self.max_size), (600, 600)) - - def test_calculate_shape_5(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(300, 400, self.min_size, self.max_size), (600, 800)) - - def test_calculate_shape_6(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(300, 600, self.min_size, self.max_size), (512, 1024)) - - def test_calculate_shape_7(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(1000, 2500, self.min_size, self.max_size), - (410, 1024)) - - def test_calculate_shape_8(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(1800, 2000, self.min_size, self.max_size), - (600, 667)) - - def test_calculate_shape_11(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(300, 100, self.min_size, self.max_size), (1024, 341)) - - def test_calculate_shape_12(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(600, 100, self.min_size, self.max_size), (1024, 171)) - - def test_calculate_shape_13(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(3000, 100, self.min_size, self.max_size), (1024, 34)) - - def test_calculate_shape_15(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(400, 300, self.min_size, self.max_size), (800, 600)) - - def test_calculate_shape_16(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(600, 300, self.min_size, self.max_size), (1024, 512)) - - def test_calculate_shape_17(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(2500, 1000, self.min_size, self.max_size), - (1024, 410)) - - def test_calculate_shape_18(self): - self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(2000, 1800, self.min_size, self.max_size), - (667, 600)) + @generate(*[(100, 300, 341, 1024, False), + (100, 600, 171, 1024, False), + (100, 3000, 34, 1024, False), + (300, 300, 600, 600, False), + (300, 400, 600, 800, False), + (300, 600, 512, 1024, False), + (1000, 2500, 410, 1024, False), + (1800, 2000, 600, 667, False), + (300, 100, 1024, 341, False), + (600, 100, 1024, 171, False), + (3000, 100, 1024, 34, False), + (400, 300, 800, 600, False), + (600, 300, 1024, 512, False), + (2500, 1000, 1024, 410, False), + (2000, 1800, 667, 600, False), + (300, 300, 1024, 1024, True), + (900, 300, 1024, 1024, True), + (1300, 900, 1024, 1024, True), + (1025, 1025, 1024, 1024, True), + ]) + def test_calculate_shape(self, h, w, th, tw, pad): + self.assertTupleEqual(calculate_shape_keeping_aspect_ratio(h, w, self.min_size, self.max_size, pad), (th, tw)) class TestCalculatePlaceholderSpatialShape(unittest.TestCase): @@ -122,5 +99,13 @@ class TestCalculatePlaceholderSpatialShape(unittest.TestCase): self.assertTupleEqual((800, 600), calculate_placeholder_spatial_shape(self.graph, self.match, self.pipeline_config)) + def test_keep_aspect_ratio_resizer_overrided_by_user_pad(self): + self.pipeline_config._model_params['resizer_min_dimension'] = 600 + self.pipeline_config._model_params['resizer_max_dimension'] = 1024 + self.pipeline_config._model_params['pad_to_max_dimension'] = True + self.graph.graph['user_shapes'] = {'image_tensor': [{'shape': [1, 400, 300, 3]}]} + self.assertTupleEqual((1024, 1024), + calculate_placeholder_spatial_shape(self.graph, self.match, self.pipeline_config)) + def test_missing_input_shape_information(self): self.assertRaises(Error, calculate_placeholder_spatial_shape, self.graph, self.match, self.pipeline_config) diff --git a/model-optimizer/mo/utils/pipeline_config.py b/model-optimizer/mo/utils/pipeline_config.py index 1606d539438..7954cddf64a 100644 --- a/model-optimizer/mo/utils/pipeline_config.py +++ b/model-optimizer/mo/utils/pipeline_config.py @@ -32,6 +32,7 @@ mapping_rules = [ ('resizer_image_width', 'image_resizer/fixed_shape_resizer/width'), ('resizer_min_dimension', 'image_resizer/keep_aspect_ratio_resizer/min_dimension'), ('resizer_max_dimension', 'image_resizer/keep_aspect_ratio_resizer/max_dimension'), + ('pad_to_max_dimension', 'image_resizer/keep_aspect_ratio_resizer/pad_to_max_dimension', False), # anchor generator attributes ('anchor_generator_height', 'first_stage_anchor_generator/grid_anchor_generator/height$', 256), ('anchor_generator_width', 'first_stage_anchor_generator/grid_anchor_generator/width$', 256), diff --git a/model-optimizer/mo/utils/pipeline_config_test.py b/model-optimizer/mo/utils/pipeline_config_test.py index 6b63dc91d83..8b642fb1e80 100644 --- a/model-optimizer/mo/utils/pipeline_config_test.py +++ b/model-optimizer/mo/utils/pipeline_config_test.py @@ -151,6 +151,7 @@ class TestingSimpleProtoParser(unittest.TestCase): 'use_matmul_crop_and_resize': False, 'add_background_class': True, 'share_box_across_classes': False, + 'pad_to_max_dimension': False, } os.unlink(file_name) self.assertDictEqual(pipeline_config._model_params, expected_result)