Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ Collate:
'models-vit.R'
'ops-box_convert.R'
'ops-boxes.R'
'target_transform_detection.R'
'transforms-array.R'
'transforms-defaults.R'
'transforms-generics.R'
Expand Down
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ S3method(draw_segmentation_masks,default)
S3method(draw_segmentation_masks,image_with_segmentation_mask)
S3method(draw_segmentation_masks,torch_tensor)
S3method(get_image_size,"magick-image")
S3method(get_image_size,torch_tensor)
S3method(transform_adjust_brightness,default)
S3method(transform_adjust_brightness,torch_tensor)
S3method(transform_adjust_contrast,default)
Expand Down Expand Up @@ -208,6 +209,7 @@ export(rf100_peixos_segmentation_dataset)
export(rf100_underwater_collection)
export(search_collection)
export(target_transform_coco_masks)
export(target_transform_resize)
export(target_transform_trimap_masks)
export(tensor_image_browse)
export(tensor_image_display)
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

* Added `model_lw_detr_tiny()`, `model_lw_detr_small()`, `model_lw_detr_medium()` and `model_lw_detr_large()` for real-time object detection (@srishtiii28, #328).

## New features

* Added `target_transform_resize` to manage bounding_box resizing in parallel to `transform_resize` for images (#337).

## Bug fixes and improvements

* `nms()` now uses `torchvisionlib::ops_nms()` when torchvisionlib is installed, speeding up inference for `model_fasterrcnn_*()` and `model_maskrcnn_*()` (#321, #322).
Expand Down
12 changes: 6 additions & 6 deletions R/dataset-coco.R
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,16 @@ coco_detection_dataset <- torch::dataset(
boxes = boxes,
labels = labels,
area = area,
iscrowd = iscrowd
iscrowd = iscrowd,
image_height = height,
image_width = width
)

if (!is.null(self$transform)) {
x <- self$transform(x)
}

if (!is.null(self$target_transform)) {
y$image_height <- height
y$image_width <- width
y <- self$target_transform(y)
}

Expand Down Expand Up @@ -298,16 +298,16 @@ coco_segmentation_dataset <- torch::dataset(
y <- list(
labels = labels,
iscrowd = iscrowd,
segmentation = anns$segmentation
segmentation = anns$segmentation,
image_height = height,
image_width = width
)

if (!is.null(self$transform)) {
x <- self$transform(x)
}

if (!is.null(self$target_transform)) {
y$image_height <- height
y$image_width <- width
y <- self$target_transform(y)
}

Expand Down
89 changes: 89 additions & 0 deletions R/target_transform_detection.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#' Resize the bounding boxes of a detection target
#'
#' Adjusts the bounding box coordinates in a detection target to match a
#' resized image. The target is expected to contain a `boxes` field with
#' shape `(N, 4)` in xyxy format and an `orig_size` field with the original
#' image dimensions `(H, W)`.
#'
#' @param target A list containing at least:
#' \itemize{
#' \item `boxes` — tensor of shape `(N, 4)` with bounding boxes in xyxy format
#' \item `orig_size` — integer vector or tensor of length 2 with `(height, width)`
#' \item Other fields (labels, image_id, etc.) are preserved unchanged
#' }
#' @param size Desired output size. If `size` is a integer vector of length 2
#' like `c(h, w)`, output size will be matched to this. If `size` is a bare integer,
#' smaller edge of the image will be matched to this number.
#' i.e, if height > width, then image will be rescaled to
#' `(size * height / width, size)`.
#'
#' @return A list with the same structure as the input target, where:
#' \itemize{
#' \item `boxes` are rescaled according to the resize factors
#' \item `orig_size` is updated to the new dimensions
#' }
#'
#' @details
#' This function should be composed with a [transform_resize()] in the
#' `transform` pipeline having the same `size` to ensure resized bounding boxes
#' remain aligned with the resized image.
#'
#' @examples
#' \dontrun{
#' target <- list(
#' boxes = torch_tensor(matrix(c(10, 20, 50, 60), ncol = 4)),
#' labels = torch_tensor(1L, dtype = torch_long()),
#' image_height = 100L,
#' image_width = 100L)
#' )
#'
#' # Resize to fixed size
#' transform_fn <- target_transform_resize(c(200L, 200L))
#' new_target <- transform_fn(target)
#'
#' # Resize with proportional scaling
#' transform_fn <- target_transform_resize(50L)
#' new_target <- transform_fn(target)
#' }
#'
#' @family target_transforms_detection
#'
#' @export
target_transform_resize <- function(target, size) {
if (!"image_height" %in% names(target) || !"image_width" %in% names(target)) {
cli::cli_abort("Target must contain both 'image_height' and 'image_width' field")
}
# Extract original dimensions
orig_h <- target$image_height
orig_w <- target$image_width

# Compute new dimensions
if (length(size) == 1L) {
# Proportional resize: match smaller edge to size
scale <- size / max(orig_h, orig_w)
new_h <- round(orig_h * scale)
new_w <- round(orig_w * scale)
} else {
# Fixed size resize
c(new_h, new_w) %<-% size
}

# Compute scale factors (reuse orig_h / orig_w)
scale_h <- new_h / orig_h
scale_w <- new_w / orig_w

# Resize bounding boxes (xyxy format)
boxes <- target$boxes$clone()
boxes_resized <- boxes
boxes_resized[, 1L] <- boxes[, 1L] * scale_w # xmin
boxes_resized[, 2L] <- boxes[, 2L] * scale_h # ymin
boxes_resized[, 3L] <- boxes[, 3L] * scale_w # xmax
boxes_resized[, 4L] <- boxes[, 4L] * scale_h # ymax

# Update target
target$boxes <- boxes_resized
target$image_height <- new_h
target$image_width <- new_w

target
}
Loading
Loading