Skip to content

Commit 3204664

Browse files
authored
[Bounding Boxes] Add Support for Bounding Box Transformations during Image Resizing (#20368)
* bounding box utils base * add missing args and correct api call * add support for diff formats * function name correction * use common methods * add missing args for existing bounding box transformation methods * use `get_random_transformation` for input height and width. Remove input dict args for default orig_height and orig_width * Correct single bounding box transform input and output format Change layer names Bounding box resizing as per the aspect ratio * handle when pad_to_aspect_ratio is False * use clip for bounding box transformation and correct the dtype while mul op * corrrect key for labels * correct the stacking of boxes * nit * correct box transformations * handle without aspect ratio * only pad to aspect ratio is handled as of now * handle crop to aspect ratio flag for bboxes transformation * Add test cases where and simplify the bbox transform function * fix test cases for torch channels first
1 parent 49df010 commit 3204664

23 files changed

+1240
-431
lines changed

keras/api/_tf_keras/keras/layers/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@
145145
from keras.src.layers.preprocessing.image_preprocessing.center_crop import (
146146
CenterCrop,
147147
)
148+
from keras.src.layers.preprocessing.image_preprocessing.max_num_bounding_box import (
149+
MaxNumBoundingBoxes,
150+
)
148151
from keras.src.layers.preprocessing.image_preprocessing.random_brightness import (
149152
RandomBrightness,
150153
)

keras/api/_tf_keras/keras/utils/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
since your modifications would be overwritten.
55
"""
66

7+
from keras.api.utils import bounding_boxes
78
from keras.api.utils import legacy
89
from keras.src.backend.common.global_state import clear_session
910
from keras.src.backend.common.keras_tensor import is_keras_tensor
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""DO NOT EDIT.
2+
3+
This file was autogenerated. Do not edit it by hand,
4+
since your modifications would be overwritten.
5+
"""
6+
7+
from keras.src.layers.preprocessing.image_preprocessing.bounding_boxes.converters import (
8+
affine_transform,
9+
)
10+
from keras.src.layers.preprocessing.image_preprocessing.bounding_boxes.converters import (
11+
clip_to_image_size,
12+
)
13+
from keras.src.layers.preprocessing.image_preprocessing.bounding_boxes.converters import (
14+
convert_format,
15+
)
16+
from keras.src.layers.preprocessing.image_preprocessing.bounding_boxes.converters import (
17+
crop,
18+
)
19+
from keras.src.layers.preprocessing.image_preprocessing.bounding_boxes.converters import (
20+
pad,
21+
)

keras/api/layers/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@
145145
from keras.src.layers.preprocessing.image_preprocessing.center_crop import (
146146
CenterCrop,
147147
)
148+
from keras.src.layers.preprocessing.image_preprocessing.max_num_bounding_box import (
149+
MaxNumBoundingBoxes,
150+
)
148151
from keras.src.layers.preprocessing.image_preprocessing.random_brightness import (
149152
RandomBrightness,
150153
)

keras/api/utils/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
since your modifications would be overwritten.
55
"""
66

7+
from keras.api.utils import bounding_boxes
78
from keras.api.utils import legacy
89
from keras.src.backend.common.global_state import clear_session
910
from keras.src.backend.common.keras_tensor import is_keras_tensor
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""DO NOT EDIT.
2+
3+
This file was autogenerated. Do not edit it by hand,
4+
since your modifications would be overwritten.
5+
"""
6+
7+
from keras.src.layers.preprocessing.image_preprocessing.bounding_boxes.converters import (
8+
affine_transform,
9+
)
10+
from keras.src.layers.preprocessing.image_preprocessing.bounding_boxes.converters import (
11+
clip_to_image_size,
12+
)
13+
from keras.src.layers.preprocessing.image_preprocessing.bounding_boxes.converters import (
14+
convert_format,
15+
)
16+
from keras.src.layers.preprocessing.image_preprocessing.bounding_boxes.converters import (
17+
crop,
18+
)
19+
from keras.src.layers.preprocessing.image_preprocessing.bounding_boxes.converters import (
20+
pad,
21+
)

keras/src/layers/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@
8888
from keras.src.layers.preprocessing.image_preprocessing.center_crop import (
8989
CenterCrop,
9090
)
91+
from keras.src.layers.preprocessing.image_preprocessing.max_num_bounding_box import (
92+
MaxNumBoundingBoxes,
93+
)
9194
from keras.src.layers.preprocessing.image_preprocessing.random_brightness import (
9295
RandomBrightness,
9396
)

keras/src/layers/preprocessing/image_preprocessing/auto_contrast.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ def transform_labels(self, labels, transformation, training=True):
8888
return labels
8989

9090
def transform_bounding_boxes(
91-
self, bounding_boxes, transformation, training=True
91+
self,
92+
bounding_boxes,
93+
transformation,
94+
training=True,
9295
):
9396
return bounding_boxes
9497

keras/src/layers/preprocessing/image_preprocessing/base_image_preprocessing_layer.py

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ def transform_labels(self, labels, transformation, training=True):
6464
raise NotImplementedError()
6565

6666
def transform_bounding_boxes(
67-
self, bounding_boxes, transformation, training=True
67+
self,
68+
bounding_boxes,
69+
transformation,
70+
training=True,
6871
):
6972
raise NotImplementedError()
7073

@@ -88,13 +91,19 @@ def transform_single_label(self, label, transformation, training=True):
8891
return self.backend.numpy.squeeze(outputs, axis=0)
8992

9093
def transform_single_bounding_box(
91-
self, bounding_box, transformation, training=True
94+
self,
95+
bounding_box,
96+
transformation,
97+
training=True,
9298
):
93-
bounding_boxes = self.backend.numpy.expand_dims(bounding_box, axis=0)
99+
bounding_boxes = self._format_single_input_bounding_box(bounding_box)
94100
outputs = self.transform_bounding_boxes(
95-
bounding_boxes, transformation=transformation, training=training
101+
bounding_boxes,
102+
transformation=transformation,
103+
training=training,
96104
)
97-
return self.backend.numpy.squeeze(outputs, axis=0)
105+
bounding_box = self._format_single_output_bounding_box(outputs)
106+
return bounding_box
98107

99108
def transform_single_segmentation_mask(
100109
self, segmentation_mask, transformation, training=True
@@ -144,8 +153,11 @@ def call(self, data, training=True):
144153
"`bounding_box_format='xyxy'`."
145154
)
146155
bounding_boxes = densify_bounding_boxes(
147-
data["bounding_boxes"], backend=self.backend
156+
data["bounding_boxes"],
157+
is_batched=is_batched,
158+
backend=self.backend,
148159
)
160+
149161
if is_batched:
150162
data["bounding_boxes"] = self.transform_bounding_boxes(
151163
bounding_boxes,
@@ -203,6 +215,32 @@ def call(self, data, training=True):
203215
training=training,
204216
)
205217

218+
def _format_single_input_bounding_box(self, bounding_box):
219+
for key in bounding_box:
220+
if key == "labels":
221+
bounding_box[key] = self.backend.numpy.expand_dims(
222+
bounding_box[key], axis=0
223+
)
224+
if key == "boxes":
225+
bounding_box[key] = self.backend.numpy.expand_dims(
226+
bounding_box[key], axis=0
227+
)
228+
229+
return bounding_box
230+
231+
def _format_single_output_bounding_box(self, bounding_boxes):
232+
for key in bounding_boxes:
233+
if key == "labels":
234+
bounding_boxes[key] = self.backend.numpy.squeeze(
235+
bounding_boxes[key], axis=0
236+
)
237+
if key == "boxes":
238+
bounding_boxes[key] = self.backend.numpy.squeeze(
239+
bounding_boxes[key], axis=0
240+
)
241+
242+
return bounding_boxes
243+
206244
def get_config(self):
207245
config = super().get_config()
208246
if self.bounding_box_format is not None:

0 commit comments

Comments
 (0)