Skip to content

Commit

Permalink
Merge pull request #956 from roboflow/detection-offset-percent
Browse files Browse the repository at this point in the history
Added Percent Padding to the Detection Offset Block
  • Loading branch information
grzegorz-roboflow authored Jan 17, 2025
2 parents 4f72df9 + 2d5d055 commit 6b987a7
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ class BlockManifest(WorkflowBlockManifest):
examples=[10, "$inputs.offset_y"],
validation_alias=AliasChoices("offset_height", "offset_y"),
)
units: Literal["Percent (%)", "Pixels"] = Field(
default="Pixels",
description="Units for offset dimensions",
examples=["Pixels", "Percent (%)"],
)

@classmethod
def get_parameters_accepting_batches(cls) -> List[str]:
Expand Down Expand Up @@ -111,13 +116,16 @@ def run(
predictions: Batch[sv.Detections],
offset_width: int,
offset_height: int,
units: str = "Pixels",
) -> BlockResult:
use_percentage = units == "Percent (%)"
return [
{
"predictions": offset_detections(
detections=detections,
offset_width=offset_width,
offset_height=offset_height,
use_percentage=use_percentage,
)
}
for detections in predictions
Expand All @@ -130,22 +138,42 @@ def offset_detections(
offset_height: int,
parent_id_key: str = PARENT_ID_KEY,
detection_id_key: str = DETECTION_ID_KEY,
use_percentage: bool = False,
) -> sv.Detections:
if len(detections) == 0:
return detections
_detections = deepcopy(detections)
image_dimensions = detections.data["image_dimensions"]
_detections.xyxy = np.array(
[
(
max(0, x1 - offset_width // 2),
max(0, y1 - offset_height // 2),
min(image_dimensions[i][1], x2 + offset_width // 2),
min(image_dimensions[i][0], y2 + offset_height // 2),
)
for i, (x1, y1, x2, y2) in enumerate(_detections.xyxy)
]
)
if use_percentage:
_detections.xyxy = np.array(
[
(
max(0, x1 - int(image_dimensions[i][1] * offset_width / 200)),
max(0, y1 - int(image_dimensions[i][0] * offset_height / 200)),
min(
image_dimensions[i][1],
x2 + int(image_dimensions[i][1] * offset_width / 200),
),
min(
image_dimensions[i][0],
y2 + int(image_dimensions[i][0] * offset_height / 200),
),
)
for i, (x1, y1, x2, y2) in enumerate(_detections.xyxy)
]
)
else:
_detections.xyxy = np.array(
[
(
max(0, x1 - offset_width // 2),
max(0, y1 - offset_height // 2),
min(image_dimensions[i][1], x2 + offset_width // 2),
min(image_dimensions[i][0], y2 + offset_height // 2),
)
for i, (x1, y1, x2, y2) in enumerate(_detections.xyxy)
]
)
_detections[parent_id_key] = detections[detection_id_key].copy()
_detections[detection_id_key] = [str(uuid.uuid4()) for _ in detections]
return _detections
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,33 @@ def test_offset_detection_when_nothing_predicted() -> None:

# then
assert len(detections) == 0, "Expected empty detections in output"


def test_offset_detection_with_percentage() -> None:
# given
detections = sv.Detections(
xyxy=np.array([[100, 200, 300, 400]], dtype=np.float64),
class_id=np.array([1]),
confidence=np.array([0.5], dtype=np.float64),
data={
"detection_id": np.array(["three"]),
"class_name": np.array(["truck"]),
"parent_id": np.array(["p3"]),
"image_dimensions": np.array([[640, 640]]),
},
)

# when
result = offset_detections(
detections=detections,
offset_width=10,
offset_height=10,
use_percentage=True
)

# then
x1, y1, x2, y2 = result.xyxy[0]
assert x1 == 68, "Left corner should be moved by 10% of image width to the left"
assert y1 == 168, "Top corner should be moved by 10% of image height to the top"
assert x2 == 332, "Right corner should be moved by 10% of image width to the right"
assert y2 == 432, "Bottom corner should be moved by 10% of image height to the bottom"

0 comments on commit 6b987a7

Please sign in to comment.