keras-hub-nightly 0.19.0.dev202502060348__py3-none-any.whl → 0.19.0.dev202502080344__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.
Files changed (28) hide show
  1. keras_hub/api/__init__.py +0 -1
  2. keras_hub/api/layers/__init__.py +3 -1
  3. keras_hub/api/models/__init__.py +10 -4
  4. keras_hub/src/{models/retinanet → layers/modeling}/anchor_generator.py +11 -18
  5. keras_hub/src/{models/retinanet → layers/modeling}/box_matcher.py +17 -4
  6. keras_hub/src/{models/retinanet → layers/modeling}/non_max_supression.py +84 -32
  7. keras_hub/src/layers/preprocessing/image_converter.py +25 -3
  8. keras_hub/src/models/{image_object_detector.py → object_detector.py} +12 -7
  9. keras_hub/src/models/{image_object_detector_preprocessor.py → object_detector_preprocessor.py} +29 -13
  10. keras_hub/src/models/retinanet/retinanet_image_converter.py +8 -40
  11. keras_hub/src/models/retinanet/retinanet_label_encoder.py +18 -16
  12. keras_hub/src/models/retinanet/retinanet_object_detector.py +28 -28
  13. keras_hub/src/models/retinanet/retinanet_object_detector_preprocessor.py +3 -3
  14. keras_hub/src/utils/tensor_utils.py +13 -0
  15. keras_hub/src/version_utils.py +1 -1
  16. {keras_hub_nightly-0.19.0.dev202502060348.dist-info → keras_hub_nightly-0.19.0.dev202502080344.dist-info}/METADATA +1 -1
  17. {keras_hub_nightly-0.19.0.dev202502060348.dist-info → keras_hub_nightly-0.19.0.dev202502080344.dist-info}/RECORD +19 -28
  18. keras_hub/api/bounding_box/__init__.py +0 -23
  19. keras_hub/src/bounding_box/__init__.py +0 -2
  20. keras_hub/src/bounding_box/converters.py +0 -606
  21. keras_hub/src/bounding_box/formats.py +0 -149
  22. keras_hub/src/bounding_box/iou.py +0 -251
  23. keras_hub/src/bounding_box/to_dense.py +0 -81
  24. keras_hub/src/bounding_box/to_ragged.py +0 -86
  25. keras_hub/src/bounding_box/utils.py +0 -181
  26. keras_hub/src/bounding_box/validate_format.py +0 -85
  27. {keras_hub_nightly-0.19.0.dev202502060348.dist-info → keras_hub_nightly-0.19.0.dev202502080344.dist-info}/WHEEL +0 -0
  28. {keras_hub_nightly-0.19.0.dev202502060348.dist-info → keras_hub_nightly-0.19.0.dev202502080344.dist-info}/top_level.txt +0 -0
@@ -1,149 +0,0 @@
1
- """
2
- formats.py contains axis information for each supported format.
3
- """
4
-
5
- from keras_hub.src.api_export import keras_hub_export
6
-
7
-
8
- @keras_hub_export("keras_hub.bounding_box.XYXY")
9
- class XYXY:
10
- """XYXY contains axis indices for the XYXY format.
11
-
12
- All values in the XYXY format should be absolute pixel values.
13
-
14
- The XYXY format consists of the following required indices:
15
-
16
- - LEFT: left of the bounding box
17
- - TOP: top of the bounding box
18
- - RIGHT: right of the bounding box
19
- - BOTTOM: bottom of the bounding box
20
- """
21
-
22
- LEFT = 0
23
- TOP = 1
24
- RIGHT = 2
25
- BOTTOM = 3
26
-
27
-
28
- @keras_hub_export("keras_hub.bounding_box.REL_XYXY")
29
- class REL_XYXY:
30
- """REL_XYXY contains axis indices for the REL_XYXY format.
31
-
32
- REL_XYXY is like XYXY, but each value is relative to the width and height of
33
- the origin image. Values are percentages of the origin images' width and
34
- height respectively.
35
-
36
- The REL_XYXY format consists of the following required indices:
37
-
38
- - LEFT: left of the bounding box
39
- - TOP: top of the bounding box
40
- - RIGHT: right of the bounding box
41
- - BOTTOM: bottom of the bounding box
42
- """
43
-
44
- LEFT = 0
45
- TOP = 1
46
- RIGHT = 2
47
- BOTTOM = 3
48
-
49
-
50
- @keras_hub_export("keras_hub.bounding_box.CENTER_XYWH")
51
- class CENTER_XYWH:
52
- """CENTER_XYWH contains axis indices for the CENTER_XYWH format.
53
-
54
- All values in the CENTER_XYWH format should be absolute pixel values.
55
-
56
- The CENTER_XYWH format consists of the following required indices:
57
-
58
- - X: X coordinate of the center of the bounding box
59
- - Y: Y coordinate of the center of the bounding box
60
- - WIDTH: width of the bounding box
61
- - HEIGHT: height of the bounding box
62
- """
63
-
64
- X = 0
65
- Y = 1
66
- WIDTH = 2
67
- HEIGHT = 3
68
-
69
-
70
- @keras_hub_export("keras_hub.bounding_box.XYWH")
71
- class XYWH:
72
- """XYWH contains axis indices for the XYWH format.
73
-
74
- All values in the XYWH format should be absolute pixel values.
75
-
76
- The XYWH format consists of the following required indices:
77
-
78
- - X: X coordinate of the left of the bounding box
79
- - Y: Y coordinate of the top of the bounding box
80
- - WIDTH: width of the bounding box
81
- - HEIGHT: height of the bounding box
82
- """
83
-
84
- X = 0
85
- Y = 1
86
- WIDTH = 2
87
- HEIGHT = 3
88
-
89
-
90
- @keras_hub_export("keras_hub.bounding_box.REL_XYWH")
91
- class REL_XYWH:
92
- """REL_XYWH contains axis indices for the XYWH format.
93
-
94
- REL_XYXY is like XYWH, but each value is relative to the width and height of
95
- the origin image. Values are percentages of the origin images' width and
96
- height respectively.
97
-
98
- - X: X coordinate of the left of the bounding box
99
- - Y: Y coordinate of the top of the bounding box
100
- - WIDTH: width of the bounding box
101
- - HEIGHT: height of the bounding box
102
- """
103
-
104
- X = 0
105
- Y = 1
106
- WIDTH = 2
107
- HEIGHT = 3
108
-
109
-
110
- @keras_hub_export("keras_hub.bounding_box.YXYX")
111
- class YXYX:
112
- """YXYX contains axis indices for the YXYX format.
113
-
114
- All values in the YXYX format should be absolute pixel values.
115
-
116
- The YXYX format consists of the following required indices:
117
-
118
- - TOP: top of the bounding box
119
- - LEFT: left of the bounding box
120
- - BOTTOM: bottom of the bounding box
121
- - RIGHT: right of the bounding box
122
- """
123
-
124
- TOP = 0
125
- LEFT = 1
126
- BOTTOM = 2
127
- RIGHT = 3
128
-
129
-
130
- @keras_hub_export("keras_hub.bounding_box.REL_YXYX")
131
- class REL_YXYX:
132
- """REL_YXYX contains axis indices for the REL_YXYX format.
133
-
134
- REL_YXYX is like YXYX, but each value is relative to the width and height of
135
- the origin image. Values are percentages of the origin images' width and
136
- height respectively.
137
-
138
- The REL_YXYX format consists of the following required indices:
139
-
140
- - TOP: top of the bounding box
141
- - LEFT: left of the bounding box
142
- - BOTTOM: bottom of the bounding box
143
- - RIGHT: right of the bounding box
144
- """
145
-
146
- TOP = 0
147
- LEFT = 1
148
- BOTTOM = 2
149
- RIGHT = 3
@@ -1,251 +0,0 @@
1
- """Contains functions to compute ious of bounding boxes."""
2
-
3
- import math
4
-
5
- import keras
6
- from keras import ops
7
-
8
- from keras_hub.src.api_export import keras_hub_export
9
- from keras_hub.src.bounding_box.converters import convert_format
10
- from keras_hub.src.bounding_box.utils import as_relative
11
- from keras_hub.src.bounding_box.utils import is_relative
12
-
13
-
14
- def _compute_area(box):
15
- """Computes area for bounding boxes
16
-
17
- Args:
18
- box: [N, 4] or [batch_size, N, 4] float Tensor, either batched
19
- or unbatched boxes.
20
- Returns:
21
- a float Tensor of [N] or [batch_size, N]
22
- """
23
- y_min, x_min, y_max, x_max = ops.split(box[..., :4], 4, axis=-1)
24
- return ops.squeeze((y_max - y_min) * (x_max - x_min), axis=-1)
25
-
26
-
27
- def _compute_intersection(boxes1, boxes2):
28
- """Computes intersection area between two sets of boxes.
29
-
30
- Args:
31
- boxes1: [N, 4] or [batch_size, N, 4] float Tensor boxes.
32
- boxes2: [M, 4] or [batch_size, M, 4] float Tensor boxes.
33
- Returns:
34
- a [N, M] or [batch_size, N, M] float Tensor.
35
- """
36
- y_min1, x_min1, y_max1, x_max1 = ops.split(boxes1[..., :4], 4, axis=-1)
37
- y_min2, x_min2, y_max2, x_max2 = ops.split(boxes2[..., :4], 4, axis=-1)
38
- boxes2_rank = len(boxes2.shape)
39
- perm = [1, 0] if boxes2_rank == 2 else [0, 2, 1]
40
- # [N, M] or [batch_size, N, M]
41
- intersect_ymax = ops.minimum(y_max1, ops.transpose(y_max2, perm))
42
- intersect_ymin = ops.maximum(y_min1, ops.transpose(y_min2, perm))
43
- intersect_xmax = ops.minimum(x_max1, ops.transpose(x_max2, perm))
44
- intersect_xmin = ops.maximum(x_min1, ops.transpose(x_min2, perm))
45
-
46
- intersect_height = intersect_ymax - intersect_ymin
47
- intersect_width = intersect_xmax - intersect_xmin
48
- zeros_t = ops.cast(0, intersect_height.dtype)
49
- intersect_height = ops.maximum(zeros_t, intersect_height)
50
- intersect_width = ops.maximum(zeros_t, intersect_width)
51
-
52
- return intersect_height * intersect_width
53
-
54
-
55
- @keras_hub_export("keras_hub.bounding_box.compute_iou")
56
- def compute_iou(
57
- boxes1,
58
- boxes2,
59
- bounding_box_format,
60
- use_masking=False,
61
- mask_val=-1,
62
- images=None,
63
- image_shape=None,
64
- ):
65
- """Computes a lookup table vector containing the ious for a given set boxes.
66
-
67
- The lookup vector is to be indexed by [`boxes1_index`,`boxes2_index`] if
68
- boxes are unbatched and by [`batch`, `boxes1_index`,`boxes2_index`] if the
69
- boxes are batched.
70
-
71
- The users can pass `boxes1` and `boxes2` to be different ranks. For example:
72
- 1) `boxes1`: [batch_size, M, 4], `boxes2`: [batch_size, N, 4] -> return
73
- [batch_size, M, N].
74
- 2) `boxes1`: [batch_size, M, 4], `boxes2`: [N, 4] -> return
75
- [batch_size, M, N]
76
- 3) `boxes1`: [M, 4], `boxes2`: [batch_size, N, 4] -> return
77
- [batch_size, M, N]
78
- 4) `boxes1`: [M, 4], `boxes2`: [N, 4] -> return [M, N]
79
-
80
- Args:
81
- boxes1: a list of bounding boxes in 'corners' format. Can be batched or
82
- unbatched.
83
- boxes2: a list of bounding boxes in 'corners' format. Can be batched or
84
- unbatched.
85
- bounding_box_format: a case-insensitive string which is one of `"xyxy"`,
86
- `"rel_xyxy"`, `"xyWH"`, `"center_xyWH"`, `"yxyx"`, `"rel_yxyx"`.
87
- For detailed information on the supported format, see the
88
- [KerasCV bounding box documentation](https://keras.io/api/keras_cv/bounding_box/formats/).
89
- use_masking: whether masking will be applied. This will mask all `boxes1`
90
- or `boxes2` that have values less than 0 in all its 4 dimensions.
91
- Default to `False`.
92
- mask_val: int to mask those returned IOUs if the masking is True, defaults
93
- to -1.
94
-
95
- Returns:
96
- iou_lookup_table: a vector containing the pairwise ious of boxes1 and
97
- boxes2.
98
- """ # noqa: E501
99
-
100
- boxes1_rank = len(boxes1.shape)
101
- boxes2_rank = len(boxes2.shape)
102
-
103
- if boxes1_rank not in [2, 3]:
104
- raise ValueError(
105
- "compute_iou() expects boxes1 to be batched, or to be unbatched. "
106
- f"Received len(boxes1.shape)={boxes1_rank}, "
107
- f"len(boxes2.shape)={boxes2_rank}. Expected either "
108
- "len(boxes1.shape)=2 AND or len(boxes1.shape)=3."
109
- )
110
- if boxes2_rank not in [2, 3]:
111
- raise ValueError(
112
- "compute_iou() expects boxes2 to be batched, or to be unbatched. "
113
- f"Received len(boxes1.shape)={boxes1_rank}, "
114
- f"len(boxes2.shape)={boxes2_rank}. Expected either "
115
- "len(boxes2.shape)=2 AND or len(boxes2.shape)=3."
116
- )
117
-
118
- target_format = "yxyx"
119
- if is_relative(bounding_box_format):
120
- target_format = as_relative(target_format)
121
-
122
- boxes1 = convert_format(
123
- boxes1,
124
- source=bounding_box_format,
125
- target=target_format,
126
- images=images,
127
- image_shape=image_shape,
128
- )
129
-
130
- boxes2 = convert_format(
131
- boxes2,
132
- source=bounding_box_format,
133
- target=target_format,
134
- images=images,
135
- image_shape=image_shape,
136
- )
137
-
138
- intersect_area = _compute_intersection(boxes1, boxes2)
139
- boxes1_area = _compute_area(boxes1)
140
- boxes2_area = _compute_area(boxes2)
141
- boxes2_area_rank = len(boxes2_area.shape)
142
- boxes2_axis = 1 if (boxes2_area_rank == 2) else 0
143
- boxes1_area = ops.expand_dims(boxes1_area, axis=-1)
144
- boxes2_area = ops.expand_dims(boxes2_area, axis=boxes2_axis)
145
- union_area = boxes1_area + boxes2_area - intersect_area
146
- res = ops.divide(intersect_area, union_area + keras.backend.epsilon())
147
-
148
- if boxes1_rank == 2:
149
- perm = [1, 0]
150
- else:
151
- perm = [0, 2, 1]
152
-
153
- if not use_masking:
154
- return res
155
-
156
- mask_val_t = ops.cast(mask_val, res.dtype) * ops.ones_like(res)
157
- boxes1_mask = ops.less(ops.max(boxes1, axis=-1, keepdims=True), 0.0)
158
- boxes2_mask = ops.less(ops.max(boxes2, axis=-1, keepdims=True), 0.0)
159
- background_mask = ops.logical_or(
160
- boxes1_mask, ops.transpose(boxes2_mask, perm)
161
- )
162
- iou_lookup_table = ops.where(background_mask, mask_val_t, res)
163
- return iou_lookup_table
164
-
165
-
166
- @keras_hub_export("keras_hub.bounding_box.compute_ciou")
167
- def compute_ciou(boxes1, boxes2, bounding_box_format):
168
- """
169
- Computes the Complete IoU (CIoU) between two bounding boxes or between
170
- two batches of bounding boxes.
171
-
172
- CIoU loss is an extension of GIoU loss, which further improves the IoU
173
- optimization for object detection. CIoU loss not only penalizes the
174
- bounding box coordinates but also considers the aspect ratio and center
175
- distance of the boxes. The length of the last dimension should be 4 to
176
- represent the bounding boxes.
177
-
178
- Args:
179
- box1 (tensor): tensor representing the first bounding box with
180
- shape (..., 4).
181
- box2 (tensor): tensor representing the second bounding box with
182
- shape (..., 4).
183
- bounding_box_format: a case-insensitive string (for example, "xyxy").
184
- Each bounding box is defined by these 4 values. For detailed
185
- information on the supported formats, see the [KerasCV bounding box
186
- documentation](https://keras.io/api/keras_cv/bounding_box/formats/).
187
-
188
- Returns:
189
- tensor: The CIoU distance between the two bounding boxes.
190
- """
191
- target_format = "xyxy"
192
- if is_relative(bounding_box_format):
193
- target_format = as_relative(target_format)
194
-
195
- boxes1 = convert_format(
196
- boxes1, source=bounding_box_format, target=target_format
197
- )
198
-
199
- boxes2 = convert_format(
200
- boxes2, source=bounding_box_format, target=target_format
201
- )
202
-
203
- x_min1, y_min1, x_max1, y_max1 = ops.split(boxes1[..., :4], 4, axis=-1)
204
- x_min2, y_min2, x_max2, y_max2 = ops.split(boxes2[..., :4], 4, axis=-1)
205
-
206
- width_1 = x_max1 - x_min1
207
- height_1 = y_max1 - y_min1 + keras.backend.epsilon()
208
- width_2 = x_max2 - x_min2
209
- height_2 = y_max2 - y_min2 + keras.backend.epsilon()
210
-
211
- intersection_area = ops.maximum(
212
- ops.minimum(x_max1, x_max2) - ops.maximum(x_min1, x_min2), 0
213
- ) * ops.maximum(
214
- ops.minimum(y_max1, y_max2) - ops.maximum(y_min1, y_min2), 0
215
- )
216
- union_area = (
217
- width_1 * height_1
218
- + width_2 * height_2
219
- - intersection_area
220
- + keras.backend.epsilon()
221
- )
222
- iou = ops.squeeze(
223
- ops.divide(intersection_area, union_area + keras.backend.epsilon()),
224
- axis=-1,
225
- )
226
-
227
- convex_width = ops.maximum(x_max1, x_max2) - ops.minimum(x_min1, x_min2)
228
- convex_height = ops.maximum(y_max1, y_max2) - ops.minimum(y_min1, y_min2)
229
- convex_diagonal_squared = ops.squeeze(
230
- convex_width**2 + convex_height**2 + keras.backend.epsilon(),
231
- axis=-1,
232
- )
233
- centers_distance_squared = ops.squeeze(
234
- ((x_min1 + x_max1) / 2 - (x_min2 + x_max2) / 2) ** 2
235
- + ((y_min1 + y_max1) / 2 - (y_min2 + y_max2) / 2) ** 2,
236
- axis=-1,
237
- )
238
-
239
- v = ops.squeeze(
240
- ops.power(
241
- (4 / math.pi**2)
242
- * (ops.arctan(width_2 / height_2) - ops.arctan(width_1 / height_1)),
243
- 2,
244
- ),
245
- axis=-1,
246
- )
247
- alpha = v / (v - iou + (1 + keras.backend.epsilon()))
248
-
249
- return iou - (
250
- centers_distance_squared / convex_diagonal_squared + v * alpha
251
- )
@@ -1,81 +0,0 @@
1
- import keras_hub.src.bounding_box.validate_format as validate_format
2
- from keras_hub.src.api_export import keras_hub_export
3
-
4
- try:
5
- import tensorflow as tf
6
- except ImportError:
7
- tf = None
8
-
9
-
10
- def _box_shape(batched, boxes_shape, max_boxes):
11
- # ensure we dont drop the final axis in RaggedTensor mode
12
- if max_boxes is None:
13
- shape = list(boxes_shape)
14
- shape[-1] = 4
15
- return shape
16
- if batched:
17
- return [None, max_boxes, 4]
18
- return [max_boxes, 4]
19
-
20
-
21
- def _classes_shape(batched, classes_shape, max_boxes):
22
- if max_boxes is None:
23
- return None
24
- if batched:
25
- return [None, max_boxes] + classes_shape[2:]
26
- return [max_boxes] + classes_shape[2:]
27
-
28
-
29
- @keras_hub_export("keras_hub.bounding_box.to_dense")
30
- def to_dense(bounding_boxes, max_boxes=None, default_value=-1):
31
- """to_dense converts bounding boxes to Dense tensors
32
-
33
- Args:
34
- bounding_boxes: bounding boxes in KerasCV dictionary format.
35
- max_boxes: the maximum number of boxes, used to pad tensors to a given
36
- shape. This can be used to make object detection pipelines TPU
37
- compatible.
38
- default_value: the default value to pad bounding boxes with. defaults
39
- to -1.
40
- """
41
- info = validate_format.validate_format(bounding_boxes)
42
-
43
- # guards against errors in metrics regarding modification of inputs.
44
- # also guards against unexpected behavior when modifying downstream
45
- bounding_boxes = bounding_boxes.copy()
46
-
47
- # Already running in masked mode
48
- if not info["ragged"]:
49
- # even if already ragged, still copy the dictionary for API consistency
50
- return bounding_boxes
51
-
52
- if isinstance(bounding_boxes["classes"], tf.RaggedTensor):
53
- bounding_boxes["classes"] = bounding_boxes["classes"].to_tensor(
54
- default_value=default_value,
55
- shape=_classes_shape(
56
- info["is_batched"], bounding_boxes["classes"].shape, max_boxes
57
- ),
58
- )
59
-
60
- if isinstance(bounding_boxes["boxes"], tf.RaggedTensor):
61
- bounding_boxes["boxes"] = bounding_boxes["boxes"].to_tensor(
62
- default_value=default_value,
63
- shape=_box_shape(
64
- info["is_batched"], bounding_boxes["boxes"].shape, max_boxes
65
- ),
66
- )
67
-
68
- if "confidence" in bounding_boxes:
69
- if isinstance(bounding_boxes["confidence"], tf.RaggedTensor):
70
- bounding_boxes["confidence"] = bounding_boxes[
71
- "confidence"
72
- ].to_tensor(
73
- default_value=default_value,
74
- shape=_classes_shape(
75
- info["is_batched"],
76
- bounding_boxes["confidence"].shape,
77
- max_boxes,
78
- ),
79
- )
80
-
81
- return bounding_boxes
@@ -1,86 +0,0 @@
1
- import keras
2
-
3
- import keras_hub.src.bounding_box.validate_format as validate_format
4
- from keras_hub.src.api_export import keras_hub_export
5
-
6
- try:
7
- import tensorflow as tf
8
- except ImportError:
9
- tf = None
10
-
11
-
12
- @keras_hub_export("keras_hub.bounding_box.to_ragged")
13
- def to_ragged(bounding_boxes, sentinel=-1, dtype="float32"):
14
- """converts a Dense padded bounding box `tf.Tensor` to a `tf.RaggedTensor`.
15
-
16
- Bounding boxes are ragged tensors in most use cases. Converting them to a
17
- dense tensor makes it easier to work with Tensorflow ecosystem.
18
- This function can be used to filter out the masked out bounding boxes by
19
- checking for padded sentinel value of the class_id axis of the
20
- bounding_boxes.
21
-
22
- Example:
23
- ```python
24
- bounding_boxes = {
25
- "boxes": tf.constant([[2, 3, 4, 5], [0, 1, 2, 3]]),
26
- "classes": tf.constant([[-1, 1]]),
27
- }
28
- bounding_boxes = bounding_box.to_ragged(bounding_boxes)
29
- print(bounding_boxes)
30
- # {
31
- # "boxes": [[0, 1, 2, 3]],
32
- # "classes": [[1]]
33
- # }
34
- ```
35
-
36
- Args:
37
- bounding_boxes: a Tensor of bounding boxes. May be batched, or
38
- unbatched.
39
- sentinel: The value indicating that a bounding box does not exist at the
40
- current index, and the corresponding box is padding, defaults to -1.
41
- dtype: the data type to use for the underlying Tensors.
42
- Returns:
43
- dictionary of `tf.RaggedTensor` or 'tf.Tensor' containing the filtered
44
- bounding boxes.
45
- """
46
- if keras.config.backend() != "tensorflow":
47
- raise NotImplementedError(
48
- "`bounding_box.to_ragged` was called using a backend which does "
49
- "not support ragged tensors. "
50
- f"Current backend: {keras.backend.backend()}."
51
- )
52
-
53
- info = validate_format.validate_format(bounding_boxes)
54
-
55
- if info["ragged"]:
56
- return bounding_boxes
57
-
58
- boxes = bounding_boxes.get("boxes")
59
- classes = bounding_boxes.get("classes")
60
- confidence = bounding_boxes.get("confidence", None)
61
-
62
- mask = classes != sentinel
63
-
64
- boxes = tf.ragged.boolean_mask(boxes, mask)
65
- classes = tf.ragged.boolean_mask(classes, mask)
66
- if confidence is not None:
67
- confidence = tf.ragged.boolean_mask(confidence, mask)
68
-
69
- if isinstance(boxes, tf.Tensor):
70
- boxes = tf.RaggedTensor.from_tensor(boxes)
71
-
72
- if isinstance(classes, tf.Tensor) and len(classes.shape) > 1:
73
- classes = tf.RaggedTensor.from_tensor(classes)
74
-
75
- if confidence is not None:
76
- if isinstance(confidence, tf.Tensor) and len(confidence.shape) > 1:
77
- confidence = tf.RaggedTensor.from_tensor(confidence)
78
-
79
- result = bounding_boxes.copy()
80
- result["boxes"] = tf.cast(boxes, dtype)
81
- result["classes"] = tf.cast(classes, dtype)
82
-
83
- if confidence is not None:
84
- result["confidence"] = tf.cast(confidence, dtype)
85
-
86
- return result