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,181 +0,0 @@
1
- """Utility functions for working with bounding boxes."""
2
-
3
- from keras import ops
4
-
5
- from keras_hub.src.api_export import keras_hub_export
6
- from keras_hub.src.bounding_box import converters
7
- from keras_hub.src.bounding_box.formats import XYWH
8
-
9
-
10
- @keras_hub_export("keras_hub.bounding_box.is_relative")
11
- def is_relative(bounding_box_format):
12
- """A util to check if a bounding box format uses relative coordinates"""
13
- if bounding_box_format.lower() not in converters.TO_XYXY_CONVERTERS:
14
- raise ValueError(
15
- "`is_relative()` received an unsupported format for the argument "
16
- f"`bounding_box_format`. `bounding_box_format` should be one of "
17
- f"{converters.TO_XYXY_CONVERTERS.keys()}. "
18
- f"Got bounding_box_format={bounding_box_format}"
19
- )
20
-
21
- return bounding_box_format.startswith("rel")
22
-
23
-
24
- @keras_hub_export("keras_hub.bounding_box.as_relative")
25
- def as_relative(bounding_box_format):
26
- """A util to get the relative equivalent of a provided bounding box format.
27
-
28
- If the specified format is already a relative format,
29
- it will be returned unchanged.
30
- """
31
-
32
- if not is_relative(bounding_box_format):
33
- return "rel_" + bounding_box_format
34
-
35
- return bounding_box_format
36
-
37
-
38
- def _relative_area(boxes, bounding_box_format):
39
- boxes = converters.convert_format(
40
- boxes,
41
- source=bounding_box_format,
42
- target="rel_xywh",
43
- )
44
- widths = boxes[..., XYWH.WIDTH]
45
- heights = boxes[..., XYWH.HEIGHT]
46
- # handle corner case where shear performs a full inversion.
47
- return ops.where(
48
- ops.logical_and(widths > 0, heights > 0), widths * heights, 0.0
49
- )
50
-
51
-
52
- @keras_hub_export("keras_hub.bounding_box.clip_to_image")
53
- def clip_to_image(
54
- bounding_boxes, bounding_box_format, images=None, image_shape=None
55
- ):
56
- """clips bounding boxes to image boundaries.
57
-
58
- `clip_to_image()` clips bounding boxes that have coordinates out of bounds
59
- of an image down to the boundaries of the image. This is done by converting
60
- the bounding box to relative formats, then clipping them to the `[0, 1]`
61
- range. Additionally, bounding boxes that end up with a zero area have their
62
- class ID set to -1, indicating that there is no object present in them.
63
-
64
- Args:
65
- bounding_boxes: bounding box tensor to clip.
66
- bounding_box_format: the KerasCV bounding box format the bounding boxes
67
- are in.
68
- images: list of images to clip the bounding boxes to.
69
- image_shape: the shape of the images to clip the bounding boxes to.
70
- """
71
- boxes, classes = bounding_boxes["boxes"], bounding_boxes["classes"]
72
-
73
- boxes = converters.convert_format(
74
- boxes,
75
- source=bounding_box_format,
76
- target="rel_xyxy",
77
- images=images,
78
- image_shape=image_shape,
79
- )
80
- boxes, classes, images, squeeze = _format_inputs(boxes, classes, images)
81
- x1, y1, x2, y2 = ops.split(boxes, 4, axis=-1)
82
- clipped_bounding_boxes = ops.concatenate(
83
- [
84
- ops.clip(x1, 0, 1),
85
- ops.clip(y1, 0, 1),
86
- ops.clip(x2, 0, 1),
87
- ops.clip(y2, 0, 1),
88
- ],
89
- axis=-1,
90
- )
91
- areas = _relative_area(
92
- clipped_bounding_boxes, bounding_box_format="rel_xyxy"
93
- )
94
- clipped_bounding_boxes = converters.convert_format(
95
- clipped_bounding_boxes,
96
- source="rel_xyxy",
97
- target=bounding_box_format,
98
- images=images,
99
- image_shape=image_shape,
100
- )
101
- clipped_bounding_boxes = ops.where(
102
- ops.expand_dims(areas > 0.0, axis=-1), clipped_bounding_boxes, -1.0
103
- )
104
- classes = ops.where(areas > 0.0, classes, -1)
105
- nan_indices = ops.any(ops.isnan(clipped_bounding_boxes), axis=-1)
106
- classes = ops.where(nan_indices, -1, classes)
107
-
108
- # TODO update dict and return
109
- clipped_bounding_boxes, classes = _format_outputs(
110
- clipped_bounding_boxes, classes, squeeze
111
- )
112
-
113
- bounding_boxes.update({"boxes": clipped_bounding_boxes, "classes": classes})
114
-
115
- return bounding_boxes
116
-
117
-
118
- @keras_hub_export("keras_hub.bounding_box.clip_boxes")
119
- def clip_boxes(boxes, image_shape):
120
- """Clip boxes to the boundaries of the image shape"""
121
- if boxes.shape[-1] != 4:
122
- raise ValueError(
123
- "boxes.shape[-1] is {:d}, but must be 4.".format(boxes.shape[-1])
124
- )
125
-
126
- if isinstance(image_shape, list) or isinstance(image_shape, tuple):
127
- height, width, _ = image_shape
128
- max_length = ops.stack([height, width, height, width], axis=-1)
129
- else:
130
- image_shape = ops.cast(image_shape, dtype=boxes.dtype)
131
- height = image_shape[0]
132
- width = image_shape[1]
133
- max_length = ops.stack([height, width, height, width], axis=-1)
134
-
135
- clipped_boxes = ops.maximum(ops.minimum(boxes, max_length), 0.0)
136
- return clipped_boxes
137
-
138
-
139
- def _format_inputs(boxes, classes, images):
140
- boxes_rank = len(boxes.shape)
141
- if boxes_rank > 3:
142
- raise ValueError(
143
- "Expected len(boxes.shape)=2, or len(boxes.shape)=3, got "
144
- f"len(boxes.shape)={boxes_rank}"
145
- )
146
- boxes_includes_batch = boxes_rank == 3
147
- # Determine if images needs an expand_dims() call
148
- if images is not None:
149
- images_rank = len(images.shape)
150
- if images_rank > 4:
151
- raise ValueError(
152
- "Expected len(images.shape)=2, or len(images.shape)=3, got "
153
- f"len(images.shape)={images_rank}"
154
- )
155
- images_include_batch = images_rank == 4
156
- if boxes_includes_batch != images_include_batch:
157
- raise ValueError(
158
- "clip_to_image() expects both boxes and images to be batched, "
159
- "or both boxes and images to be unbatched. Received "
160
- f"len(boxes.shape)={boxes_rank}, "
161
- f"len(images.shape)={images_rank}. Expected either "
162
- "len(boxes.shape)=2 AND len(images.shape)=3, or "
163
- "len(boxes.shape)=3 AND len(images.shape)=4."
164
- )
165
- if not images_include_batch:
166
- images = ops.expand_dims(images, axis=0)
167
-
168
- if not boxes_includes_batch:
169
- return (
170
- ops.expand_dims(boxes, axis=0),
171
- ops.expand_dims(classes, axis=0),
172
- images,
173
- True,
174
- )
175
- return boxes, classes, images, False
176
-
177
-
178
- def _format_outputs(boxes, classes, squeeze):
179
- if squeeze:
180
- return ops.squeeze(boxes, axis=0), ops.squeeze(classes, axis=0)
181
- return boxes, classes
@@ -1,85 +0,0 @@
1
- from keras_hub.src.api_export import keras_hub_export
2
-
3
- try:
4
- import tensorflow as tf
5
- except ImportError:
6
- tf = None
7
-
8
-
9
- @keras_hub_export("keras_hub.bounding_box.validate_format")
10
- def validate_format(bounding_boxes, variable_name="bounding_boxes"):
11
- """validates that a given set of bounding boxes complies with KerasHub
12
- format.
13
-
14
- For a set of bounding boxes to be valid it must satisfy the following
15
- conditions:
16
- - `bounding_boxes` must be a dictionary
17
- - contains keys `"boxes"` and `"classes"`
18
- - each entry must have matching first two dimensions; representing the batch
19
- axis and the number of boxes per image axis.
20
- - either both `"boxes"` and `"classes"` are batched, or both are unbatched.
21
-
22
- Additionally, one of the following must be satisfied:
23
- - `"boxes"` and `"classes"` are both Ragged
24
- - `"boxes"` and `"classes"` are both Dense
25
- - `"boxes"` and `"classes"` are unbatched
26
-
27
- Args:
28
- bounding_boxes: dictionary of bounding boxes according to KerasCV
29
- format.
30
-
31
- Raises:
32
- ValueError if any of the above conditions are not met
33
- """
34
- if not isinstance(bounding_boxes, dict):
35
- raise ValueError(
36
- f"Expected `{variable_name}` to be a dictionary, got "
37
- f"`{variable_name}={bounding_boxes}`."
38
- )
39
- if not all([x in bounding_boxes for x in ["boxes", "classes"]]):
40
- raise ValueError(
41
- f"Expected `{variable_name}` to be a dictionary containing keys "
42
- "`'classes'` and `'boxes'`. Got "
43
- f"`{variable_name}.keys()={bounding_boxes.keys()}`."
44
- )
45
-
46
- boxes = bounding_boxes.get("boxes")
47
- classes = bounding_boxes.get("classes")
48
- info = {}
49
-
50
- is_batched = len(boxes.shape) == 3
51
- info["is_batched"] = is_batched
52
- info["ragged"] = isinstance(boxes, tf.RaggedTensor)
53
-
54
- if not is_batched:
55
- if boxes.shape[:1] != classes.shape[:1]:
56
- raise ValueError(
57
- "Expected `boxes` and `classes` to have matching dimensions "
58
- "on the first axis when operating in unbatched mode. Got "
59
- f"`boxes.shape={boxes.shape}`, `classes.shape={classes.shape}`."
60
- )
61
-
62
- info["classes_one_hot"] = len(classes.shape) == 2
63
- # No Ragged checks needed in unbatched mode.
64
- return info
65
-
66
- info["classes_one_hot"] = len(classes.shape) == 3
67
-
68
- if isinstance(boxes, tf.RaggedTensor) != isinstance(
69
- classes, tf.RaggedTensor
70
- ):
71
- raise ValueError(
72
- "Either both `boxes` and `classes` "
73
- "should be Ragged, or neither should be ragged."
74
- f" Got `type(boxes)={type(boxes)}`, type(classes)={type(classes)}."
75
- )
76
-
77
- # Batched mode checks
78
- if boxes.shape[:2] != classes.shape[:2]:
79
- raise ValueError(
80
- "Expected `boxes` and `classes` to have matching dimensions "
81
- "on the first two axes when operating in batched mode. "
82
- f"Got `boxes.shape={boxes.shape}`, `classes.shape={classes.shape}`."
83
- )
84
-
85
- return info