diff --git a/DESCRIPTION b/DESCRIPTION index a8e967de..8927643f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -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' diff --git a/NAMESPACE b/NAMESPACE index 4842c9e1..0bedb71f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -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) @@ -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) diff --git a/NEWS.md b/NEWS.md index 52d1c990..2c0718d3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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). diff --git a/R/dataset-coco.R b/R/dataset-coco.R index e7f3d817..37ee00d2 100644 --- a/R/dataset-coco.R +++ b/R/dataset-coco.R @@ -147,7 +147,9 @@ 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)) { @@ -155,8 +157,6 @@ coco_detection_dataset <- torch::dataset( } if (!is.null(self$target_transform)) { - y$image_height <- height - y$image_width <- width y <- self$target_transform(y) } @@ -298,7 +298,9 @@ 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)) { @@ -306,8 +308,6 @@ coco_segmentation_dataset <- torch::dataset( } if (!is.null(self$target_transform)) { - y$image_height <- height - y$image_width <- width y <- self$target_transform(y) } diff --git a/R/target_transform_detection.R b/R/target_transform_detection.R new file mode 100644 index 00000000..66c83972 --- /dev/null +++ b/R/target_transform_detection.R @@ -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 +} diff --git a/R/transforms-generics.R b/R/transforms-generics.R index b6168836..4b48582e 100644 --- a/R/transforms-generics.R +++ b/R/transforms-generics.R @@ -1,11 +1,11 @@ #' Convert an image to a tensor #' #' Converts a Magick Image or array (H x W x C) in the range `[0, 255]` to a -#' `torch_tensor` of shape (C x H x W) in the range `[0.0, 1.0]`. In the +#' `torch_tensor` of shape (C x H x W) in the range `[0, 1]`. In the #' other cases, tensors are returned without scaling. #' #' @note -#' Because the input image is scaled to `[0.0, 1.0]`, this transformation +#' Because the input image is scaled to `[0, 1]`, this transformation #' should not be used when transforming target image masks. #' #' @param img A `magick-image`, `array` or `torch_tensor`. @@ -45,9 +45,9 @@ transform_convert_image_dtype <- function(img, dtype = torch::torch_float()) { #' This transform acts out of place, i.e., it does not mutate the input tensor. #' #' @inheritParams transform_to_tensor -#' @param mean (sequence): Sequence of means for each channel. -#' @param std (sequence): Sequence of standard deviations for each channel. -#' @param inplace (bool,optional): Bool to make this operation in-place. +#' @param mean (numeric vector): Means for each channel. +#' @param std (numeric vector): Standard deviations for each channel. +#' @param inplace (logical, optional): Whether to make this operation in-place. #' #' @family unitary_transforms #' @@ -63,12 +63,12 @@ transform_normalize <- function(img, mean, std, inplace = FALSE) { #' of leading dimensions #' #' @inheritParams transform_to_tensor -#' @param size (sequence or int): Desired output size. If size is a sequence -#' like c(h, w), output size will be matched to this. If size is an int, -#' 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). -#' @param interpolation (int, optional) Desired interpolation. An integer +#' @param size (integer vector or integer): Desired output size. If `size` is +#' an 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)`. +#' @param interpolation (integer, optional): Desired interpolation. An integer #' `0 = nearest`, `2 = bilinear`, and `3 = bicubic` or a name from #' [magick::filter_types()]. #' @@ -86,10 +86,10 @@ transform_resize <- function(img, size, interpolation = 2) { #' of leading dimensions. #' #' @inheritParams transform_to_tensor -#' @param size (sequence or int): Desired output size of the crop. If size is -#' an int instead of sequence like c(h, w), a square crop (size, size) is -#' made. If provided a tuple or list of length 1, it will be interpreted as -#' `c(size, size)`. +#' @param size (integer vector or integer): Desired output size. +#' If `size` is either a integer vector of length 2 like `c(h, w)` or a bare integer, +#' in which case a square crop `c(size, size)` is made. If provided a list of +#' length 1, it will be interpreted as `c(size, size)`. #' #' @family unitary_transforms #' @@ -105,18 +105,19 @@ transform_center_crop <- function(img, size) { #' of leading dimensions. #' #' @inheritParams transform_to_tensor -#' @param padding (int or tuple or list): Padding on each border. If a single -#' int is provided this is used to pad all borders. If tuple of length 2 is -#' provided this is the padding on left/right and top/bottom respectively. -#' If a tuple of length 4 is provided this is the padding for the left, right, -#' top and bottom borders respectively. -#' @param fill (int or str or tuple): Pixel fill value for constant fill. -#' Default is 0. If a tuple of length 3, it is used to fill R, G, B channels -#' respectively. This value is only used when the padding_mode is constant. -#' Only int value is supported for Tensors. -#' @param padding_mode Type of padding. Should be: constant, edge, reflect or -#' symmetric. Default is constant. Mode symmetric is not yet supported for -#' Tensor inputs. +#' @param padding (integer vector or integer): Padding on each border. If a +#' single integer is provided, this value is used to pad all borders. If an +#' integer vector of length 2 is provided, it gives the padding on +#' left/right and top/bottom respectively. If an integer vector of length 4 +#' is provided, it gives the padding for the left, right, top and bottom +#' borders respectively. +#' @param fill (numeric vector or numeric): Pixel fill value for constant fill. +#' Default is `0`. If a numeric vector of length 3, it is used to fill R, G, +#' B channels respectively. This value is only used when the `padding_mode` +#' is constant. Only integer values are supported for Tensors. +#' @param padding_mode (character): Type of padding. Should be: `constant`, +#' `edge`, `reflect` or `symmetric`. Default is `constant`. Mode `symmetric` +#' is not yet supported for Tensor inputs. #' #' - constant: pads with a constant value, this value is specified with fill #' @@ -140,8 +141,8 @@ transform_pad <- function(img, padding, fill = 0, padding_mode = "constant") { #' Apply a list of transformations randomly with a given probability #' #' @inheritParams transform_to_tensor -#' @param transforms (list or tuple): list of transformations. -#' @param p (float): probability. +#' @param transforms (list): List of transformations. +#' @param p (numeric): Probability. #' #' @family combining_transforms #' @@ -178,7 +179,7 @@ transform_random_order <- function(img, transforms) { #' #' @inheritParams transform_resize #' @inheritParams transform_pad -#' @param pad_if_needed (boolean): It will pad the image if smaller than the +#' @param pad_if_needed (logical): It will pad the image if smaller than the #' desired size to avoid raising an exception. Since cropping is done #' after padding, the padding seems to be done at a random offset. #' @@ -198,7 +199,7 @@ transform_random_crop <- function(img, size, padding=NULL, pad_if_needed=FALSE, #' dimensions #' #' @inheritParams transform_to_tensor -#' @param p (float): probability of the image being flipped. +#' @param p (numeric): Probability of the image being flipped. #' Default value is 0.5 #' #' @family random_transforms @@ -209,7 +210,7 @@ transform_random_horizontal_flip <- function(img, p = 0.5) { #' Vertically flip an image randomly with a given probability #' -#' The image can be a PIL Image or a torch Tensor, in which case it is expected +#' The image can be a Magick Image or a torch Tensor, in which case it is expected #' to have `[..., H, W]` shape, where `...` means an arbitrary number of #' leading dimensions #' @@ -235,8 +236,10 @@ transform_random_vertical_flip <- function(img, p = 0.5) { #' #' @inheritParams transform_resize #' @inheritParams transform_pad -#' @param scale (tuple of float): range of size of the origin size cropped -#' @param ratio (tuple of float): range of aspect ratio of the origin aspect +#' @param scale (numeric vector of length 2): Range of size of the origin size +#' cropped. +#' @param ratio (numeric vector of length 2): Range of aspect ratio of the +#' origin aspect ratio cropped. #' ratio cropped. #' #' @family random_transforms @@ -269,7 +272,7 @@ transform_five_crop <- function(img, size) { #' inputs and targets your Dataset returns. #' #' @inheritParams transform_five_crop -#' @param vertical_flip (bool): Use vertical flipping instead of horizontal +#' @param vertical_flip (logical): Use vertical flipping instead of horizontal. #' #' @family combining_transforms #' @export @@ -302,21 +305,21 @@ transform_linear_transformation <- function(img, transformation_matrix, mean_vec #' Randomly change the brightness, contrast and saturation of an image #' -#' @param brightness (float or tuple of float (min, max)): How much to jitter -#' brightness. `brightness_factor` is chosen uniformly from +#' @param brightness (numeric or numeric vector of length 2): How much to +#' jitter brightness. `brightness_factor` is chosen uniformly from #' `[max(0, 1 - brightness), 1 + brightness]` or the given `[min, max]`. #' Should be non negative numbers. -#' @param contrast (float or tuple of float (min, max)): How much to jitter +#' @param contrast (numeric or numeric vector of length 2): How much to jitter #' contrast. `contrast_factor` is chosen uniformly from #' `[max(0, 1 - contrast), 1 + contrast]` or the given `[min, max]`. Should #' be non negative numbers. -#' @param saturation (float or tuple of float (min, max)): How much to jitter -#' saturation. `saturation_factor` is chosen uniformly from +#' @param saturation (numeric or numeric vector of length 2): How much to +#' jitter saturation. `saturation_factor` is chosen uniformly from #' `[max(0, 1 - saturation), 1 + saturation]` or the given `[min, max]`. #' Should be non negative numbers. -#' @param hue (float or tuple of float (min, max)): How much to jitter hue. +#' @param hue (numeric or numeric vector of length 2): How much to jitter hue. #' `hue_factor` is chosen uniformly from `[-hue, hue]` or the given -#' `[min, max]`. Should have 0<= hue <= 0.5 or -0.5 <= min <= max <= 0.5. +#' `[min, max]`. Should have `0 <= hue <= 0.5` or `-0.5 <= min <= max <= 0.5`. #' @inheritParams transform_to_tensor #' #' @family random_transforms @@ -327,22 +330,24 @@ transform_color_jitter <- function(img, brightness=0, contrast=0, saturation=0, #' Rotate the image by angle #' -#' @param degrees (sequence or float or int): Range of degrees to select from. -#' If degrees is a number instead of sequence like c(min, max), the range of -#' degrees will be (-degrees, +degrees). -#' @param interpolation (int, optional): Interpolation mode. 0 for nearest, 2 for bilinear. -#' Default is 0 (nearest). -#' @param resample Deprecated. Use interpolation instead. -#' @param expand (bool, optional): Optional expansion flag. If true, expands the -#' output to make it large enough to hold the entire rotated image. If false -#' or omitted, make the output image the same size as the input image. Note -#' that the expand flag assumes rotation around the center and no translation. -#' @param center (list or tuple, optional): Optional center of rotation, c(x, y). -#' Origin is the upper left corner. Default is the center of the image. -#' @param fill (n-tuple or int or float): Pixel fill value for area outside the -#' rotated image. If int or float, the value is used for all bands -#' respectively. Defaults to 0 for all bands. This option is only available -#' for Pillow>=5.2.0. This option is not supported for Tensor input. Fill +#' @param degrees (numeric vector of length 2 or numeric): Range of degrees to +#' select from. If `degrees` is a bare number instead of a numeric vector of +#' length 2 like `c(min, max)`, the range of degrees will be +#' `(-degrees, +degrees)`. +#' @param interpolation (integer, optional): Interpolation mode. `0` for +#' nearest, `2` for bilinear. Default is `0` (nearest). +#' @param resample Deprecated. Use `interpolation` instead. +#' @param expand (logical, optional): Optional expansion flag. If `TRUE`, +#' expands the output to make it large enough to hold the entire rotated +#' image. If `FALSE` or omitted, make the output image the same size as the +#' input image. Note that the expand flag assumes rotation around the center +#' and no translation. +#' @param center (numeric vector of length 2, optional): Optional center of +#' rotation, `c(x, y)`. Origin is the upper left corner. Default is the +#' center of the image. +#' @param fill (numeric vector or numeric): Pixel fill value for area outside +#' the rotated image. If a single numeric value, the value is used for all +#' channels. Defaults to `0` for all channels. This option is not supported for Tensor input. Fill #' value for the area outside the transform in the output image is always 0. #' @inheritParams transform_to_tensor #' @@ -360,26 +365,28 @@ transform_random_rotation <- function(img, degrees, interpolation = 0, expand=FA #' Random affine transformation of the image keeping center invariant #' #' @inheritParams transform_random_rotation -#' @param translate (tuple, optional): tuple of maximum absolute fraction for -#' horizontal and vertical translations. For example `translate=c(a, b)`, then -#' horizontal shift is randomly sampled in the range -#' -img_width * a < dx < img_width * a and vertical shift is randomly sampled -#' in the range -img_height * b < dy < img_height * b. Will not translate by +#' @param translate (numeric vector of length 2, optional): Numeric vector of +#' maximum absolute fraction for horizontal and vertical translations. For +#' example `translate = c(a, b)`, then horizontal shift is randomly sampled +#' in the range `-img_width * a < dx < img_width * a` and vertical shift is +#' randomly sampled in the range +#' `-img_height * b < dy < img_height * b`. Will not translate by default. +#' @param scale (numeric vector of length 2, optional): Scaling factor +#' interval, e.g. `c(a, b)`, then scale is randomly sampled from the range +#' `a <= scale <= b`. Will keep original scale by default. +#' @param shear (numeric vector or numeric, optional): Range of degrees to +#' select from. If `shear` is a bare number, a shear parallel to the x axis +#' in the range `(-shear, +shear)` will be applied. Else if `shear` is a +#' numeric vector of length 2, a shear parallel to the x axis in the range +#' `(shear[1], shear[2])` will be applied. Else if `shear` is a numeric +#' vector of length 4, a x-axis shear in `(shear[1], shear[2])` and y-axis +#' shear in `(shear[3], shear[4])` will be applied. Will not apply shear by #' default. -#' @param scale (tuple, optional): scaling factor interval, e.g c(a, b), then -#' scale is randomly sampled from the range a <= scale <= b. Will keep -#' original scale by default. -#' @param shear (sequence or float or int, optional): Range of degrees to select -#' from. If shear is a number, a shear parallel to the x axis in the range -#' (-shear, +shear) will be applied. Else if shear is a tuple or list of 2 -#' values a shear parallel to the x axis in the range `(shear[1], shear[2])` -#' will be applied. Else if shear is a tuple or list of 4 values, a x-axis -#' shear in `(shear[1], shear[2])` and y-axis shear in `(shear[3], shear[4])` -#' will be applied. Will not apply shear by default. -#' @param fill (tuple or int): Fill color for the area outside the transform. -#' Default is 0. This option is not supported for Tensor input. -#' @param interpolation (int or character, optional): Interpolation mode. -#' Supported values are 0 / "nearest" and 2 / "bilinear". Default is 0. +#' @param fill (numeric vector or numeric): Fill color for the area outside the +#' transform. Default is `0`. This option is not supported for Tensor input. +#' @param interpolation (integer or character, optional): Interpolation mode. +#' Supported values are `0` / `"nearest"` and `2` / `"bilinear"`. Default +#' is `0`. #' @param fillcolor Deprecated. Use fill instead. #' @param resample Deprecated. Use interpolation instead. #' @@ -402,8 +409,8 @@ transform_random_affine <- function(img, degrees, translate=NULL, scale=NULL, #' Convert image to grayscale #' #' @inheritParams transform_to_tensor -#' @param num_output_channels (int): (1 or 3) number of channels desired for -#' output image +#' @param num_output_channels (integer): (`1` or `3`) number of channels +#' desired for output image. #' #' @family unitary_transforms #' @export @@ -416,8 +423,8 @@ transform_grayscale <- function(img, num_output_channels) { #' Convert image to grayscale with a probability of `p`. #' #' @inheritParams transform_to_tensor -#' @param p (float): probability that image should be converted to grayscale -#' (default 0.1). +#' @param p (numeric): Probability that image should be converted to grayscale +#' (default `0.1`). #' #' @family random_transforms #' @export @@ -431,9 +438,10 @@ transform_random_grayscale <- function(img, p = 0.1) { #' Performs a random perspective transformation of the given image with a given #' probability #' -#' @param distortion_scale (float): argument to control the degree of distortion -#' and ranges from 0 to 1. Default is 0.5. -#' @param p (float): probability of the image being transformed. Default is 0.5. +#' @param distortion_scale (numeric): Argument to control the degree of +#' distortion and ranges from 0 to 1. Default is `0.5`. +#' @param p (numeric): Probability of the image being transformed. Default +#' is `0.5`. #' @inheritParams transform_resize #' @inheritParams transform_pad #' @@ -450,14 +458,19 @@ transform_random_perspective <- function(img, distortion_scale=0.5, p=0.5, #' See #' #' @inheritParams transform_to_tensor -#' @param p probability that the random erasing operation will be performed. -#' @param scale range of proportion of erased area against input image. -#' @param ratio range of aspect ratio of erased area. -#' @param value erasing value. Default is 0. If a single int, it is used to -#' erase all pixels. If a tuple of length 3, it is used to erase -#' R, G, B channels respectively. -#' If a str of 'random', erasing each pixel with random values. -#' @param inplace boolean to make this transform inplace. Default set to FALSE. +#' @param p (numeric): Probability that the random erasing operation will be +#' performed. +#' @param scale (numeric vector of length 2): Range of proportion of erased +#' area against input image. +#' @param ratio (numeric vector of length 2): Range of aspect ratio of erased +#' area. +#' @param value (numeric vector or numeric or character): Erasing value. +#' Default is `0`. If a single numeric value, it is used to erase all +#' pixels. If a numeric vector of length 3, it is used to erase R, G, B +#' channels respectively. If the string `"random"`, erasing each pixel with +#' random values. +#' @param inplace (logical): Boolean to make this transform inplace. Default +#' set to `FALSE`. #' #' @family random_transforms #' @export @@ -471,11 +484,12 @@ transform_random_erasing <- function(img, p=0.5, scale=c(0.02, 0.33), ratio=c(0. #' Crop the given image at specified location and output size #' #' @inheritParams transform_to_tensor -#' @param top (int): Vertical component of the top left corner of the crop box. -#' @param left (int): Horizontal component of the top left corner of the crop -#' box. -#' @param height (int): Height of the crop box. -#' @param width (int): Width of the crop box. +#' @param top (integer): Vertical component of the top left corner of the +#' crop box. +#' @param left (integer): Horizontal component of the top left corner of the +#' crop box. +#' @param height (integer): Height of the crop box. +#' @param width (integer): Width of the crop box. #' #' @family unitary_transforms #' @export @@ -483,7 +497,7 @@ transform_crop <- function(img, top, left, height, width) { UseMethod("transform_crop", img) } -#' Horizontally flip a PIL Image or Tensor +#' Horizontally flip a Magick Image or Tensor #' #' @inheritParams transform_to_tensor #' @@ -493,7 +507,7 @@ transform_hflip <- function(img) { UseMethod("transform_hflip", img) } -#' Vertically flip a PIL Image or Tensor +#' Vertically flip a Magick Image or Tensor #' #' @inheritParams transform_to_tensor #' @@ -505,11 +519,7 @@ transform_vflip <- function(img) { #' Crop an image and resize it to a desired size #' -#' @param top (int): Vertical component of the top left corner of the crop box. -#' @param left (int): Horizontal component of the top left corner of the crop -#' box. -#' @param height (int): Height of the crop box. -#' @param width (int): Width of the crop box. +#' @inheritParams transform_crop #' @inheritParams transform_resize #' #' @family combining_transforms @@ -522,9 +532,9 @@ transform_resized_crop <- function(img, top, left, height, width, size, #' Adjust the brightness of an image #' -#' @param brightness_factor (float): How much to adjust the brightness. Can be -#' any non negative number. 0 gives a black image, 1 gives the -#' original image while 2 increases the brightness by a factor of 2. +#' @param brightness_factor (numeric): How much to adjust the brightness. Can +#' be any non negative number. `0` gives a black image, `1` gives the +#' original image while `2` increases the brightness by a factor of 2. #' @inheritParams transform_resize #' #' @family unitary_transforms @@ -535,9 +545,9 @@ transform_adjust_brightness <- function(img, brightness_factor) { #' Adjust the contrast of an image #' -#' @param contrast_factor (float): How much to adjust the contrast. Can be any -#' non negative number. 0 gives a solid gray image, 1 gives the -#' original image while 2 increases the contrast by a factor of 2. +#' @param contrast_factor (numeric): How much to adjust the contrast. Can be +#' any non negative number. `0` gives a solid gray image, `1` gives the +#' original image while `2` increases the contrast by a factor of 2. #' #' @inheritParams transform_resize #' @@ -549,9 +559,9 @@ transform_adjust_contrast <- function(img, contrast_factor) { #' Adjust the color saturation of an image #' -#' @param saturation_factor (float): How much to adjust the saturation. 0 will -#' give a black and white image, 1 will give the original image while -#' 2 will enhance the saturation by a factor of 2. +#' @param saturation_factor (numeric): How much to adjust the saturation. `0` +#' will give a black and white image, `1` will give the original image while +#' `2` will enhance the saturation by a factor of 2. #' #' @inheritParams transform_resize #' @@ -572,11 +582,11 @@ transform_adjust_saturation <- function(img, saturation_factor) { #' #' Search for Hue for more details. #' -#' @param hue_factor (float): How much to shift the hue channel. Should be in -#' `[-0.5, 0.5]`. 0.5 and -0.5 give complete reversal of hue channel in -#' HSV space in positive and negative direction respectively. -#' 0 means no shift. Therefore, both -0.5 and 0.5 will give an image -#' with complementary colors while 0 gives the original image. +#' @param hue_factor (numeric): How much to shift the hue channel. Should be +#' in `[-0.5, 0.5]`. `0.5` and `-0.5` give complete reversal of hue channel +#' in HSV space in positive and negative direction respectively. `0` means +#' no shift. Therefore, both `-0.5` and `0.5` will give an image with +#' complementary colors while `0` gives the original image. #' #' @inheritParams transform_resize #' @@ -590,8 +600,7 @@ transform_adjust_hue <- function(img, hue_factor) { #' #' @inheritParams transform_to_tensor #' @inheritParams transform_random_rotation -#' @param angle (float or int): rotation angle value in degrees, -#' counter-clockwise. +#' @param angle (numeric): Rotation angle value in degrees, counter-clockwise. #' #' @family unitary_transforms #' @export @@ -608,19 +617,21 @@ transform_rotate <- function(img, angle, interpolation = 0, expand = FALSE, #' #' @inheritParams transform_rotate #' @inheritParams transform_random_affine -#' @param translate (sequence of int) – horizontal and vertical translations -#' (post-rotation translation) -#' @param scale (float) – overall scale -#' @param shear (float or sequence) – shear angle value in degrees between -180 to 180, -#' clockwise direction. If a sequence is specified, the first value corresponds -#' to a shear parallel to the x-axis, while the second value corresponds to a -#' shear parallel to the y-axis. -#' @param interpolation (int or character): Interpolation mode. -#' Supported values are 0 / "nearest" and 2 / "bilinear". Default is 0. -#' @param fill Fill color for area outside the transform. Default is NULL. -#' @param resample Deprecated. Use interpolation instead. -#' @param fillcolor Deprecated. Use fill instead. -#' @param center Optional center of rotation, c(x, y). Default is image center. +#' @param translate (integer vector of length 2): Horizontal and vertical +#' translations (post-rotation translation). +#' @param scale (numeric): Overall scale. +#' @param shear (numeric vector or numeric): Shear angle value in degrees +#' between `-180` to `180`, clockwise direction. If a numeric vector is +#' specified, the first value corresponds to a shear parallel to the x-axis, +#' while the second value corresponds to a shear parallel to the y-axis. +#' @param interpolation (integer or character): Interpolation mode. +#' Supported values are `0` / `"nearest"` and `2` / `"bilinear"`. Default +#' is `0`. +#' @param fill Fill color for area outside the transform. Default is `NULL`. +#' @param center (numeric vector of length 2, optional): Optional center of +#' rotation, `c(x, y)`. Default is image center. +#' @param resample Deprecated. Use `interpolation` instead. +#' @param fillcolor Deprecated. Use `fill` instead. #' #' @family unitary_transforms #' @export @@ -640,11 +651,11 @@ transform_affine <- function(img, angle, translate, scale, shear, #' Perspective transformation of an image #' -#' @param startpoints (list of list of ints): List containing four lists of two -#' integers corresponding to four corners +#' @param startpoints (list of integer vectors of length 2): List containing +#' four integer vectors of length 2 corresponding to four corners #' `[top-left, top-right, bottom-right, bottom-left]` of the original image. -#' @param endpoints (list of list of ints): List containing four lists of two -#' integers corresponding to four corners +#' @param endpoints (list of integer vectors of length 2): List containing +#' four integer vectors of length 2 corresponding to four corners #' `[top-left, top-right, bottom-right, bottom-left]` of the transformed #' image. #' @inheritParams transform_resize @@ -668,10 +679,10 @@ transform_perspective <- function(img, startpoints, endpoints, interpolation = 2 #' #' @details Search for Gamma Correction for more details. #' -#' @param gamma (float): Non negative real number, same as \eqn{\gamma} in the -#' equation. gamma larger than 1 make the shadows darker, while gamma smaller -#' than 1 make dark regions lighter. -#' @param gain (float): The constant multiplier. +#' @param gamma (numeric): Non negative real number, same as \eqn{\gamma} in +#' the equation. `gamma` larger than 1 make the shadows darker, while +#' `gamma` smaller than 1 make dark regions lighter. +#' @param gain (numeric): The constant multiplier. #' @inheritParams transform_to_tensor #' #' @family unitary_transforms diff --git a/R/transforms-segmentation.R b/R/transforms-segmentation.R index 2b11c94e..74ddd0a2 100644 --- a/R/transforms-segmentation.R +++ b/R/transforms-segmentation.R @@ -20,7 +20,7 @@ #' draw_segmentation_masks(item) #' } #' -#' @family target_transforms +#' @family target_transforms_segmentation #' @export target_transform_coco_masks <- function(y) { @@ -80,7 +80,7 @@ target_transform_coco_masks <- function(y) { #' draw_segmentation_masks(item) #' } #' -#' @family target_transforms +#' @family target_transforms_segmentation #' @export target_transform_trimap_masks <- function(y) { if (!"trimap" %in% names(y)) { diff --git a/R/transforms-tensor.R b/R/transforms-tensor.R index a4d3d830..26c127e0 100644 --- a/R/transforms-tensor.R +++ b/R/transforms-tensor.R @@ -477,6 +477,7 @@ check_img <- function(x) { } #' @importFrom utils tail +#' @export get_image_size.torch_tensor <- function(img) { check_img(img) diff --git a/_pkgdown.yml b/_pkgdown.yml index 03ccb65a..21aef695 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -44,12 +44,18 @@ reference: - subtitle: Combining / multiplying transformations contents: - has_concept("combining_transforms") +- subtitle: Target transformations for object detection + desc: > + Functions to convert dataset native targets annotations into object-detection compatible + with draw_bounding_boxes() and object-detection models. + contents: + - has_concept("target_transforms_detection") - subtitle: Target transformations for segmentation desc: > Functions to convert dataset native targets annotations into segmentation masks compatible with draw_segmentation_masks() and segmentation models. contents: - - has_concept("target_transforms") + - has_concept("target_transforms_segmentation") - title: Models desc: Computer Vision deep-learning Model architectures diff --git a/man/nms.Rd b/man/nms.Rd index ec24cb5c..5d25b3a9 100644 --- a/man/nms.Rd +++ b/man/nms.Rd @@ -34,7 +34,7 @@ criterion with respect to a reference box, the selected box is not guaranteed to be the same between CPU and GPU. This is similar to the behavior of argsort in torch when repeated values are present. -When the optional \pkg{torchvisionlib} package and its native library are +When the optional \code{torchvisionlib} package and its native library are installed, \code{nms()} uses \code{torchvisionlib::ops_nms()} for faster inference. -Otherwise, it falls back to the pure R algorithm. +Otherwise, it falls back to the pure R algorithm below. } diff --git a/man/target_transform_coco_masks.Rd b/man/target_transform_coco_masks.Rd index 5470d61b..a9ce6c15 100644 --- a/man/target_transform_coco_masks.Rd +++ b/man/target_transform_coco_masks.Rd @@ -31,7 +31,7 @@ draw_segmentation_masks(item) } \seealso{ -Other target_transforms: +Other target_transforms_segmentation: \code{\link[=target_transform_trimap_masks]{target_transform_trimap_masks()}} } -\concept{target_transforms} +\concept{target_transforms_segmentation} diff --git a/man/target_transform_resize.Rd b/man/target_transform_resize.Rd new file mode 100644 index 00000000..040e2a79 --- /dev/null +++ b/man/target_transform_resize.Rd @@ -0,0 +1,60 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/target_transform_detection.R +\name{target_transform_resize} +\alias{target_transform_resize} +\title{Resize the bounding boxes of a detection target} +\usage{ +target_transform_resize(target, size) +} +\arguments{ +\item{target}{A list containing at least: +\itemize{ +\item \code{boxes} — tensor of shape \verb{(N, 4)} with bounding boxes in xyxy format +\item \code{orig_size} — integer vector or tensor of length 2 with \verb{(height, width)} +\item Other fields (labels, image_id, etc.) are preserved unchanged +}} + +\item{size}{Desired output size. If \code{size} is a integer vector of length 2 +like \code{c(h, w)}, output size will be matched to this. If \code{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 +\verb{(size * height / width, size)}.} +} +\value{ +A list with the same structure as the input target, where: +\itemize{ +\item \code{boxes} are rescaled according to the resize factors +\item \code{orig_size} is updated to the new dimensions +} +} +\description{ +Adjusts the bounding box coordinates in a detection target to match a +resized image. The target is expected to contain a \code{boxes} field with +shape \verb{(N, 4)} in xyxy format and an \code{orig_size} field with the original +image dimensions \verb{(H, W)}. +} +\details{ +This function should be composed with a \code{\link[=transform_resize]{transform_resize()}} in the +\code{transform} pipeline having the same \code{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) +} + +} +\concept{target_transforms_detection} diff --git a/man/target_transform_trimap_masks.Rd b/man/target_transform_trimap_masks.Rd index f415b385..1e916141 100644 --- a/man/target_transform_trimap_masks.Rd +++ b/man/target_transform_trimap_masks.Rd @@ -38,7 +38,7 @@ draw_segmentation_masks(item) } \seealso{ -Other target_transforms: +Other target_transforms_segmentation: \code{\link[=target_transform_coco_masks]{target_transform_coco_masks()}} } -\concept{target_transforms} +\concept{target_transforms_segmentation} diff --git a/man/transform_adjust_brightness.Rd b/man/transform_adjust_brightness.Rd index ad0f6781..07c50184 100644 --- a/man/transform_adjust_brightness.Rd +++ b/man/transform_adjust_brightness.Rd @@ -9,9 +9,9 @@ transform_adjust_brightness(img, brightness_factor) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{brightness_factor}{(float): How much to adjust the brightness. Can be -any non negative number. 0 gives a black image, 1 gives the -original image while 2 increases the brightness by a factor of 2.} +\item{brightness_factor}{(numeric): How much to adjust the brightness. Can +be any non negative number. \code{0} gives a black image, \code{1} gives the +original image while \code{2} increases the brightness by a factor of 2.} } \description{ Adjust the brightness of an image diff --git a/man/transform_adjust_contrast.Rd b/man/transform_adjust_contrast.Rd index d402f27a..3d40329a 100644 --- a/man/transform_adjust_contrast.Rd +++ b/man/transform_adjust_contrast.Rd @@ -9,9 +9,9 @@ transform_adjust_contrast(img, contrast_factor) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{contrast_factor}{(float): How much to adjust the contrast. Can be any -non negative number. 0 gives a solid gray image, 1 gives the -original image while 2 increases the contrast by a factor of 2.} +\item{contrast_factor}{(numeric): How much to adjust the contrast. Can be +any non negative number. \code{0} gives a solid gray image, \code{1} gives the +original image while \code{2} increases the contrast by a factor of 2.} } \description{ Adjust the contrast of an image diff --git a/man/transform_adjust_gamma.Rd b/man/transform_adjust_gamma.Rd index f84bd845..0b83a293 100644 --- a/man/transform_adjust_gamma.Rd +++ b/man/transform_adjust_gamma.Rd @@ -9,11 +9,11 @@ transform_adjust_gamma(img, gamma, gain = 1) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{gamma}{(float): Non negative real number, same as \eqn{\gamma} in the -equation. gamma larger than 1 make the shadows darker, while gamma smaller -than 1 make dark regions lighter.} +\item{gamma}{(numeric): Non negative real number, same as \eqn{\gamma} in +the equation. \code{gamma} larger than 1 make the shadows darker, while +\code{gamma} smaller than 1 make dark regions lighter.} -\item{gain}{(float): The constant multiplier.} +\item{gain}{(numeric): The constant multiplier.} } \description{ Also known as Power Law Transform. Intensities in RGB mode are adjusted diff --git a/man/transform_adjust_hue.Rd b/man/transform_adjust_hue.Rd index df9d09d1..744e8450 100644 --- a/man/transform_adjust_hue.Rd +++ b/man/transform_adjust_hue.Rd @@ -9,11 +9,11 @@ transform_adjust_hue(img, hue_factor) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{hue_factor}{(float): How much to shift the hue channel. Should be in -\verb{[-0.5, 0.5]}. 0.5 and -0.5 give complete reversal of hue channel in -HSV space in positive and negative direction respectively. -0 means no shift. Therefore, both -0.5 and 0.5 will give an image -with complementary colors while 0 gives the original image.} +\item{hue_factor}{(numeric): How much to shift the hue channel. Should be +in \verb{[-0.5, 0.5]}. \code{0.5} and \code{-0.5} give complete reversal of hue channel +in HSV space in positive and negative direction respectively. \code{0} means +no shift. Therefore, both \code{-0.5} and \code{0.5} will give an image with +complementary colors while \code{0} gives the original image.} } \description{ The image hue is adjusted by converting the image to HSV and diff --git a/man/transform_adjust_saturation.Rd b/man/transform_adjust_saturation.Rd index 12ea817e..93886465 100644 --- a/man/transform_adjust_saturation.Rd +++ b/man/transform_adjust_saturation.Rd @@ -9,9 +9,9 @@ transform_adjust_saturation(img, saturation_factor) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{saturation_factor}{(float): How much to adjust the saturation. 0 will -give a black and white image, 1 will give the original image while -2 will enhance the saturation by a factor of 2.} +\item{saturation_factor}{(numeric): How much to adjust the saturation. \code{0} +will give a black and white image, \code{1} will give the original image while +\code{2} will enhance the saturation by a factor of 2.} } \description{ Adjust the color saturation of an image diff --git a/man/transform_affine.Rd b/man/transform_affine.Rd index a733db3f..230f22f0 100644 --- a/man/transform_affine.Rd +++ b/man/transform_affine.Rd @@ -20,29 +20,30 @@ transform_affine( \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{angle}{(float or int): rotation angle value in degrees, -counter-clockwise.} +\item{angle}{(numeric): Rotation angle value in degrees, counter-clockwise.} -\item{translate}{(sequence of int) – horizontal and vertical translations -(post-rotation translation)} +\item{translate}{(integer vector of length 2): Horizontal and vertical +translations (post-rotation translation).} -\item{scale}{(float) – overall scale} +\item{scale}{(numeric): Overall scale.} -\item{shear}{(float or sequence) – shear angle value in degrees between -180 to 180, -clockwise direction. If a sequence is specified, the first value corresponds -to a shear parallel to the x-axis, while the second value corresponds to a -shear parallel to the y-axis.} +\item{shear}{(numeric vector or numeric): Shear angle value in degrees +between \code{-180} to \code{180}, clockwise direction. If a numeric vector is +specified, the first value corresponds to a shear parallel to the x-axis, +while the second value corresponds to a shear parallel to the y-axis.} -\item{interpolation}{(int or character): Interpolation mode. -Supported values are 0 / "nearest" and 2 / "bilinear". Default is 0.} +\item{interpolation}{(integer or character): Interpolation mode. +Supported values are \code{0} / \code{"nearest"} and \code{2} / \code{"bilinear"}. Default +is \code{0}.} -\item{fill}{Fill color for area outside the transform. Default is NULL.} +\item{fill}{Fill color for area outside the transform. Default is \code{NULL}.} -\item{resample}{Deprecated. Use interpolation instead.} +\item{resample}{Deprecated. Use \code{interpolation} instead.} -\item{fillcolor}{Deprecated. Use fill instead.} +\item{fillcolor}{Deprecated. Use \code{fill} instead.} -\item{center}{Optional center of rotation, c(x, y). Default is image center.} +\item{center}{(numeric vector of length 2, optional): Optional center of +rotation, \code{c(x, y)}. Default is image center.} } \description{ Apply affine transformation on an image keeping image center invariant diff --git a/man/transform_center_crop.Rd b/man/transform_center_crop.Rd index e5c57cd9..cb2d3a55 100644 --- a/man/transform_center_crop.Rd +++ b/man/transform_center_crop.Rd @@ -9,10 +9,10 @@ transform_center_crop(img, size) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{size}{(sequence or int): Desired output size of the crop. If size is -an int instead of sequence like c(h, w), a square crop (size, size) is -made. If provided a tuple or list of length 1, it will be interpreted as -\code{c(size, size)}.} +\item{size}{(integer vector or integer): Desired output size. +If \code{size} is either a integer vector of length 2 like \code{c(h, w)} or a bare integer, +in which case a square crop \code{c(size, size)} is made. If provided a list of +length 1, it will be interpreted as \code{c(size, size)}.} } \description{ The image can be a Magick Image or a torch Tensor, in which case it is diff --git a/man/transform_color_jitter.Rd b/man/transform_color_jitter.Rd index d8f8bb3e..1f5845c5 100644 --- a/man/transform_color_jitter.Rd +++ b/man/transform_color_jitter.Rd @@ -15,24 +15,24 @@ transform_color_jitter( \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{brightness}{(float or tuple of float (min, max)): How much to jitter -brightness. \code{brightness_factor} is chosen uniformly from +\item{brightness}{(numeric or numeric vector of length 2): How much to +jitter brightness. \code{brightness_factor} is chosen uniformly from \verb{[max(0, 1 - brightness), 1 + brightness]} or the given \verb{[min, max]}. Should be non negative numbers.} -\item{contrast}{(float or tuple of float (min, max)): How much to jitter +\item{contrast}{(numeric or numeric vector of length 2): How much to jitter contrast. \code{contrast_factor} is chosen uniformly from \verb{[max(0, 1 - contrast), 1 + contrast]} or the given \verb{[min, max]}. Should be non negative numbers.} -\item{saturation}{(float or tuple of float (min, max)): How much to jitter -saturation. \code{saturation_factor} is chosen uniformly from +\item{saturation}{(numeric or numeric vector of length 2): How much to +jitter saturation. \code{saturation_factor} is chosen uniformly from \verb{[max(0, 1 - saturation), 1 + saturation]} or the given \verb{[min, max]}. Should be non negative numbers.} -\item{hue}{(float or tuple of float (min, max)): How much to jitter hue. +\item{hue}{(numeric or numeric vector of length 2): How much to jitter hue. \code{hue_factor} is chosen uniformly from \verb{[-hue, hue]} or the given -\verb{[min, max]}. Should have 0<= hue <= 0.5 or -0.5 <= min <= max <= 0.5.} +\verb{[min, max]}. Should have \verb{0 <= hue <= 0.5} or \verb{-0.5 <= min <= max <= 0.5}.} } \description{ Randomly change the brightness, contrast and saturation of an image diff --git a/man/transform_crop.Rd b/man/transform_crop.Rd index d8dfd22f..0a71bdc1 100644 --- a/man/transform_crop.Rd +++ b/man/transform_crop.Rd @@ -9,14 +9,15 @@ transform_crop(img, top, left, height, width) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{top}{(int): Vertical component of the top left corner of the crop box.} +\item{top}{(integer): Vertical component of the top left corner of the +crop box.} -\item{left}{(int): Horizontal component of the top left corner of the crop -box.} +\item{left}{(integer): Horizontal component of the top left corner of the +crop box.} -\item{height}{(int): Height of the crop box.} +\item{height}{(integer): Height of the crop box.} -\item{width}{(int): Width of the crop box.} +\item{width}{(integer): Width of the crop box.} } \description{ Crop the given image at specified location and output size diff --git a/man/transform_five_crop.Rd b/man/transform_five_crop.Rd index ff53abec..4d5c659c 100644 --- a/man/transform_five_crop.Rd +++ b/man/transform_five_crop.Rd @@ -9,11 +9,11 @@ transform_five_crop(img, size) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{size}{(sequence or int): Desired output size. If size is a sequence -like c(h, w), output size will be matched to this. If size is an int, -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).} +\item{size}{(integer vector or integer): Desired output size. If \code{size} is +an integer vector of length 2 like \code{c(h, w)}, output size will be matched +to this. If \code{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 \verb{(size * height / width, size)}.} } \description{ Crop the given image into four corners and the central crop. This transform diff --git a/man/transform_grayscale.Rd b/man/transform_grayscale.Rd index a51bf550..522333bf 100644 --- a/man/transform_grayscale.Rd +++ b/man/transform_grayscale.Rd @@ -9,8 +9,8 @@ transform_grayscale(img, num_output_channels) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{num_output_channels}{(int): (1 or 3) number of channels desired for -output image} +\item{num_output_channels}{(integer): (\code{1} or \code{3}) number of channels +desired for output image.} } \description{ Convert image to grayscale diff --git a/man/transform_hflip.Rd b/man/transform_hflip.Rd index bfa7799d..e8416327 100644 --- a/man/transform_hflip.Rd +++ b/man/transform_hflip.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/transforms-generics.R \name{transform_hflip} \alias{transform_hflip} -\title{Horizontally flip a PIL Image or Tensor} +\title{Horizontally flip a Magick Image or Tensor} \usage{ transform_hflip(img) } @@ -10,7 +10,7 @@ transform_hflip(img) \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} } \description{ -Horizontally flip a PIL Image or Tensor +Horizontally flip a Magick Image or Tensor } \seealso{ Other unitary_transforms: diff --git a/man/transform_normalize.Rd b/man/transform_normalize.Rd index 1bc14285..06a7124b 100644 --- a/man/transform_normalize.Rd +++ b/man/transform_normalize.Rd @@ -9,11 +9,11 @@ transform_normalize(img, mean, std, inplace = FALSE) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{mean}{(sequence): Sequence of means for each channel.} +\item{mean}{(numeric vector): Means for each channel.} -\item{std}{(sequence): Sequence of standard deviations for each channel.} +\item{std}{(numeric vector): Standard deviations for each channel.} -\item{inplace}{(bool,optional): Bool to make this operation in-place.} +\item{inplace}{(logical, optional): Whether to make this operation in-place.} } \description{ Given mean: \verb{(mean[1],...,mean[n])} and std: \verb{(std[1],..,std[n])} for \code{n} diff --git a/man/transform_pad.Rd b/man/transform_pad.Rd index d6a9ef8d..e110565f 100644 --- a/man/transform_pad.Rd +++ b/man/transform_pad.Rd @@ -9,20 +9,21 @@ transform_pad(img, padding, fill = 0, padding_mode = "constant") \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{padding}{(int or tuple or list): Padding on each border. If a single -int is provided this is used to pad all borders. If tuple of length 2 is -provided this is the padding on left/right and top/bottom respectively. -If a tuple of length 4 is provided this is the padding for the left, right, -top and bottom borders respectively.} +\item{padding}{(integer vector or integer): Padding on each border. If a +single integer is provided, this value is used to pad all borders. If an +integer vector of length 2 is provided, it gives the padding on +left/right and top/bottom respectively. If an integer vector of length 4 +is provided, it gives the padding for the left, right, top and bottom +borders respectively.} -\item{fill}{(int or str or tuple): Pixel fill value for constant fill. -Default is 0. If a tuple of length 3, it is used to fill R, G, B channels -respectively. This value is only used when the padding_mode is constant. -Only int value is supported for Tensors.} +\item{fill}{(numeric vector or numeric): Pixel fill value for constant fill. +Default is \code{0}. If a numeric vector of length 3, it is used to fill R, G, +B channels respectively. This value is only used when the \code{padding_mode} +is constant. Only integer values are supported for Tensors.} -\item{padding_mode}{Type of padding. Should be: constant, edge, reflect or -symmetric. Default is constant. Mode symmetric is not yet supported for -Tensor inputs. +\item{padding_mode}{(character): Type of padding. Should be: \code{constant}, +\code{edge}, \code{reflect} or \code{symmetric}. Default is \code{constant}. Mode \code{symmetric} +is not yet supported for Tensor inputs. \itemize{ \item constant: pads with a constant value, this value is specified with fill \item edge: pads with the last value on the edge of the image diff --git a/man/transform_perspective.Rd b/man/transform_perspective.Rd index ccc1ac6f..a43e7b22 100644 --- a/man/transform_perspective.Rd +++ b/man/transform_perspective.Rd @@ -15,23 +15,23 @@ transform_perspective( \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{startpoints}{(list of list of ints): List containing four lists of two -integers corresponding to four corners +\item{startpoints}{(list of integer vectors of length 2): List containing +four integer vectors of length 2 corresponding to four corners \verb{[top-left, top-right, bottom-right, bottom-left]} of the original image.} -\item{endpoints}{(list of list of ints): List containing four lists of two -integers corresponding to four corners +\item{endpoints}{(list of integer vectors of length 2): List containing +four integer vectors of length 2 corresponding to four corners \verb{[top-left, top-right, bottom-right, bottom-left]} of the transformed image.} -\item{interpolation}{(int, optional) Desired interpolation. An integer +\item{interpolation}{(integer, optional): Desired interpolation. An integer \code{0 = nearest}, \code{2 = bilinear}, and \code{3 = bicubic} or a name from \code{\link[magick:filter_types]{magick::filter_types()}}.} -\item{fill}{(int or str or tuple): Pixel fill value for constant fill. -Default is 0. If a tuple of length 3, it is used to fill R, G, B channels -respectively. This value is only used when the padding_mode is constant. -Only int value is supported for Tensors.} +\item{fill}{(numeric vector or numeric): Pixel fill value for constant fill. +Default is \code{0}. If a numeric vector of length 3, it is used to fill R, G, +B channels respectively. This value is only used when the \code{padding_mode} +is constant. Only integer values are supported for Tensors.} } \description{ Perspective transformation of an image diff --git a/man/transform_random_affine.Rd b/man/transform_random_affine.Rd index 502378f2..d49e1979 100644 --- a/man/transform_random_affine.Rd +++ b/man/transform_random_affine.Rd @@ -19,34 +19,37 @@ transform_random_affine( \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{degrees}{(sequence or float or int): Range of degrees to select from. -If degrees is a number instead of sequence like c(min, max), the range of -degrees will be (-degrees, +degrees).} +\item{degrees}{(numeric vector of length 2 or numeric): Range of degrees to +select from. If \code{degrees} is a bare number instead of a numeric vector of +length 2 like \code{c(min, max)}, the range of degrees will be +\verb{(-degrees, +degrees)}.} -\item{translate}{(tuple, optional): tuple of maximum absolute fraction for -horizontal and vertical translations. For example \code{translate=c(a, b)}, then -horizontal shift is randomly sampled in the range --img_width * a < dx < img_width * a and vertical shift is randomly sampled -in the range -img_height * b < dy < img_height * b. Will not translate by -default.} +\item{translate}{(numeric vector of length 2, optional): Numeric vector of +maximum absolute fraction for horizontal and vertical translations. For +example \code{translate = c(a, b)}, then horizontal shift is randomly sampled +in the range \verb{-img_width * a < dx < img_width * a} and vertical shift is +randomly sampled in the range +\verb{-img_height * b < dy < img_height * b}. Will not translate by default.} -\item{scale}{(tuple, optional): scaling factor interval, e.g c(a, b), then -scale is randomly sampled from the range a <= scale <= b. Will keep -original scale by default.} +\item{scale}{(numeric vector of length 2, optional): Scaling factor +interval, e.g. \code{c(a, b)}, then scale is randomly sampled from the range +\verb{a <= scale <= b}. Will keep original scale by default.} -\item{shear}{(sequence or float or int, optional): Range of degrees to select -from. If shear is a number, a shear parallel to the x axis in the range -(-shear, +shear) will be applied. Else if shear is a tuple or list of 2 -values a shear parallel to the x axis in the range \verb{(shear[1], shear[2])} -will be applied. Else if shear is a tuple or list of 4 values, a x-axis -shear in \verb{(shear[1], shear[2])} and y-axis shear in \verb{(shear[3], shear[4])} -will be applied. Will not apply shear by default.} +\item{shear}{(numeric vector or numeric, optional): Range of degrees to +select from. If \code{shear} is a bare number, a shear parallel to the x axis +in the range \verb{(-shear, +shear)} will be applied. Else if \code{shear} is a +numeric vector of length 2, a shear parallel to the x axis in the range +\verb{(shear[1], shear[2])} will be applied. Else if \code{shear} is a numeric +vector of length 4, a x-axis shear in \verb{(shear[1], shear[2])} and y-axis +shear in \verb{(shear[3], shear[4])} will be applied. Will not apply shear by +default.} -\item{interpolation}{(int or character, optional): Interpolation mode. -Supported values are 0 / "nearest" and 2 / "bilinear". Default is 0.} +\item{interpolation}{(integer or character, optional): Interpolation mode. +Supported values are \code{0} / \code{"nearest"} and \code{2} / \code{"bilinear"}. Default +is \code{0}.} -\item{fill}{(tuple or int): Fill color for the area outside the transform. -Default is 0. This option is not supported for Tensor input.} +\item{fill}{(numeric vector or numeric): Fill color for the area outside the +transform. Default is \code{0}. This option is not supported for Tensor input.} \item{resample}{Deprecated. Use interpolation instead.} diff --git a/man/transform_random_apply.Rd b/man/transform_random_apply.Rd index 9ded32d4..275ced20 100644 --- a/man/transform_random_apply.Rd +++ b/man/transform_random_apply.Rd @@ -9,9 +9,9 @@ transform_random_apply(img, transforms, p = 0.5) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{transforms}{(list or tuple): list of transformations.} +\item{transforms}{(list): List of transformations.} -\item{p}{(float): probability.} +\item{p}{(numeric): Probability.} } \description{ Apply a list of transformations randomly with a given probability diff --git a/man/transform_random_choice.Rd b/man/transform_random_choice.Rd index 0c10260c..dcf75188 100644 --- a/man/transform_random_choice.Rd +++ b/man/transform_random_choice.Rd @@ -9,7 +9,7 @@ transform_random_choice(img, transforms) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{transforms}{(list or tuple): list of transformations.} +\item{transforms}{(list): List of transformations.} } \description{ Apply single transformation randomly picked from a list diff --git a/man/transform_random_crop.Rd b/man/transform_random_crop.Rd index 04cce526..00a04296 100644 --- a/man/transform_random_crop.Rd +++ b/man/transform_random_crop.Rd @@ -16,30 +16,31 @@ transform_random_crop( \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{size}{(sequence or int): Desired output size. If size is a sequence -like c(h, w), output size will be matched to this. If size is an int, -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).} +\item{size}{(integer vector or integer): Desired output size. If \code{size} is +an integer vector of length 2 like \code{c(h, w)}, output size will be matched +to this. If \code{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 \verb{(size * height / width, size)}.} -\item{padding}{(int or tuple or list): Padding on each border. If a single -int is provided this is used to pad all borders. If tuple of length 2 is -provided this is the padding on left/right and top/bottom respectively. -If a tuple of length 4 is provided this is the padding for the left, right, -top and bottom borders respectively.} +\item{padding}{(integer vector or integer): Padding on each border. If a +single integer is provided, this value is used to pad all borders. If an +integer vector of length 2 is provided, it gives the padding on +left/right and top/bottom respectively. If an integer vector of length 4 +is provided, it gives the padding for the left, right, top and bottom +borders respectively.} -\item{pad_if_needed}{(boolean): It will pad the image if smaller than the +\item{pad_if_needed}{(logical): It will pad the image if smaller than the desired size to avoid raising an exception. Since cropping is done after padding, the padding seems to be done at a random offset.} -\item{fill}{(int or str or tuple): Pixel fill value for constant fill. -Default is 0. If a tuple of length 3, it is used to fill R, G, B channels -respectively. This value is only used when the padding_mode is constant. -Only int value is supported for Tensors.} +\item{fill}{(numeric vector or numeric): Pixel fill value for constant fill. +Default is \code{0}. If a numeric vector of length 3, it is used to fill R, G, +B channels respectively. This value is only used when the \code{padding_mode} +is constant. Only integer values are supported for Tensors.} -\item{padding_mode}{Type of padding. Should be: constant, edge, reflect or -symmetric. Default is constant. Mode symmetric is not yet supported for -Tensor inputs. +\item{padding_mode}{(character): Type of padding. Should be: \code{constant}, +\code{edge}, \code{reflect} or \code{symmetric}. Default is \code{constant}. Mode \code{symmetric} +is not yet supported for Tensor inputs. \itemize{ \item constant: pads with a constant value, this value is specified with fill \item edge: pads with the last value on the edge of the image diff --git a/man/transform_random_erasing.Rd b/man/transform_random_erasing.Rd index 56767b21..1d2a16af 100644 --- a/man/transform_random_erasing.Rd +++ b/man/transform_random_erasing.Rd @@ -16,18 +16,23 @@ transform_random_erasing( \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{p}{probability that the random erasing operation will be performed.} +\item{p}{(numeric): Probability that the random erasing operation will be +performed.} -\item{scale}{range of proportion of erased area against input image.} +\item{scale}{(numeric vector of length 2): Range of proportion of erased +area against input image.} -\item{ratio}{range of aspect ratio of erased area.} +\item{ratio}{(numeric vector of length 2): Range of aspect ratio of erased +area.} -\item{value}{erasing value. Default is 0. If a single int, it is used to -erase all pixels. If a tuple of length 3, it is used to erase -R, G, B channels respectively. -If a str of 'random', erasing each pixel with random values.} +\item{value}{(numeric vector or numeric or character): Erasing value. +Default is \code{0}. If a single numeric value, it is used to erase all +pixels. If a numeric vector of length 3, it is used to erase R, G, B +channels respectively. If the string \code{"random"}, erasing each pixel with +random values.} -\item{inplace}{boolean to make this transform inplace. Default set to FALSE.} +\item{inplace}{(logical): Boolean to make this transform inplace. Default +set to \code{FALSE}.} } \description{ 'Random Erasing Data Augmentation' by Zhong \emph{et al.} diff --git a/man/transform_random_grayscale.Rd b/man/transform_random_grayscale.Rd index d9283816..ab584c65 100644 --- a/man/transform_random_grayscale.Rd +++ b/man/transform_random_grayscale.Rd @@ -9,8 +9,8 @@ transform_random_grayscale(img, p = 0.1) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{p}{(float): probability that image should be converted to grayscale -(default 0.1).} +\item{p}{(numeric): Probability that image should be converted to grayscale +(default \code{0.1}).} } \description{ Convert image to grayscale with a probability of \code{p}. diff --git a/man/transform_random_horizontal_flip.Rd b/man/transform_random_horizontal_flip.Rd index 86a41331..49231683 100644 --- a/man/transform_random_horizontal_flip.Rd +++ b/man/transform_random_horizontal_flip.Rd @@ -9,7 +9,7 @@ transform_random_horizontal_flip(img, p = 0.5) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{p}{(float): probability of the image being flipped. +\item{p}{(numeric): Probability of the image being flipped. Default value is 0.5} } \description{ diff --git a/man/transform_random_order.Rd b/man/transform_random_order.Rd index fff2abd2..2e4c8bdb 100644 --- a/man/transform_random_order.Rd +++ b/man/transform_random_order.Rd @@ -9,7 +9,7 @@ transform_random_order(img, transforms) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{transforms}{(list or tuple): list of transformations.} +\item{transforms}{(list): List of transformations.} } \description{ Apply a list of transformations in a random order diff --git a/man/transform_random_perspective.Rd b/man/transform_random_perspective.Rd index 1d95b5c2..e46181d6 100644 --- a/man/transform_random_perspective.Rd +++ b/man/transform_random_perspective.Rd @@ -15,19 +15,20 @@ transform_random_perspective( \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{distortion_scale}{(float): argument to control the degree of distortion -and ranges from 0 to 1. Default is 0.5.} +\item{distortion_scale}{(numeric): Argument to control the degree of +distortion and ranges from 0 to 1. Default is \code{0.5}.} -\item{p}{(float): probability of the image being transformed. Default is 0.5.} +\item{p}{(numeric): Probability of the image being transformed. Default +is \code{0.5}.} -\item{interpolation}{(int, optional) Desired interpolation. An integer +\item{interpolation}{(integer, optional): Desired interpolation. An integer \code{0 = nearest}, \code{2 = bilinear}, and \code{3 = bicubic} or a name from \code{\link[magick:filter_types]{magick::filter_types()}}.} -\item{fill}{(int or str or tuple): Pixel fill value for constant fill. -Default is 0. If a tuple of length 3, it is used to fill R, G, B channels -respectively. This value is only used when the padding_mode is constant. -Only int value is supported for Tensors.} +\item{fill}{(numeric vector or numeric): Pixel fill value for constant fill. +Default is \code{0}. If a numeric vector of length 3, it is used to fill R, G, +B channels respectively. This value is only used when the \code{padding_mode} +is constant. Only integer values are supported for Tensors.} } \description{ Performs a random perspective transformation of the given image with a given diff --git a/man/transform_random_resized_crop.Rd b/man/transform_random_resized_crop.Rd index 994f2d9b..5b74581e 100644 --- a/man/transform_random_resized_crop.Rd +++ b/man/transform_random_resized_crop.Rd @@ -15,18 +15,20 @@ transform_random_resized_crop( \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{size}{(sequence or int): Desired output size. If size is a sequence -like c(h, w), output size will be matched to this. If size is an int, -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).} +\item{size}{(integer vector or integer): Desired output size. If \code{size} is +an integer vector of length 2 like \code{c(h, w)}, output size will be matched +to this. If \code{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 \verb{(size * height / width, size)}.} -\item{scale}{(tuple of float): range of size of the origin size cropped} +\item{scale}{(numeric vector of length 2): Range of size of the origin size +cropped.} -\item{ratio}{(tuple of float): range of aspect ratio of the origin aspect +\item{ratio}{(numeric vector of length 2): Range of aspect ratio of the +origin aspect ratio cropped. ratio cropped.} -\item{interpolation}{(int, optional) Desired interpolation. An integer +\item{interpolation}{(integer, optional): Desired interpolation. An integer \code{0 = nearest}, \code{2 = bilinear}, and \code{3 = bicubic} or a name from \code{\link[magick:filter_types]{magick::filter_types()}}.} } diff --git a/man/transform_random_rotation.Rd b/man/transform_random_rotation.Rd index 47d78b54..80b88285 100644 --- a/man/transform_random_rotation.Rd +++ b/man/transform_random_rotation.Rd @@ -17,28 +17,30 @@ transform_random_rotation( \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{degrees}{(sequence or float or int): Range of degrees to select from. -If degrees is a number instead of sequence like c(min, max), the range of -degrees will be (-degrees, +degrees).} +\item{degrees}{(numeric vector of length 2 or numeric): Range of degrees to +select from. If \code{degrees} is a bare number instead of a numeric vector of +length 2 like \code{c(min, max)}, the range of degrees will be +\verb{(-degrees, +degrees)}.} -\item{interpolation}{(int, optional): Interpolation mode. 0 for nearest, 2 for bilinear. -Default is 0 (nearest).} +\item{interpolation}{(integer, optional): Interpolation mode. \code{0} for +nearest, \code{2} for bilinear. Default is \code{0} (nearest).} -\item{expand}{(bool, optional): Optional expansion flag. If true, expands the -output to make it large enough to hold the entire rotated image. If false -or omitted, make the output image the same size as the input image. Note -that the expand flag assumes rotation around the center and no translation.} +\item{expand}{(logical, optional): Optional expansion flag. If \code{TRUE}, +expands the output to make it large enough to hold the entire rotated +image. If \code{FALSE} or omitted, make the output image the same size as the +input image. Note that the expand flag assumes rotation around the center +and no translation.} -\item{center}{(list or tuple, optional): Optional center of rotation, c(x, y). -Origin is the upper left corner. Default is the center of the image.} +\item{center}{(numeric vector of length 2, optional): Optional center of +rotation, \code{c(x, y)}. Origin is the upper left corner. Default is the +center of the image.} -\item{fill}{(n-tuple or int or float): Pixel fill value for area outside the -rotated image. If int or float, the value is used for all bands -respectively. Defaults to 0 for all bands. This option is only available -for Pillow>=5.2.0. This option is not supported for Tensor input. Fill +\item{fill}{(numeric vector or numeric): Pixel fill value for area outside +the rotated image. If a single numeric value, the value is used for all +channels. Defaults to \code{0} for all channels. This option is not supported for Tensor input. Fill value for the area outside the transform in the output image is always 0.} -\item{resample}{Deprecated. Use interpolation instead.} +\item{resample}{Deprecated. Use \code{interpolation} instead.} } \description{ Rotate the image by angle diff --git a/man/transform_random_vertical_flip.Rd b/man/transform_random_vertical_flip.Rd index 6de76b18..a3e86e7c 100644 --- a/man/transform_random_vertical_flip.Rd +++ b/man/transform_random_vertical_flip.Rd @@ -9,11 +9,11 @@ transform_random_vertical_flip(img, p = 0.5) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{p}{(float): probability of the image being flipped. +\item{p}{(numeric): Probability of the image being flipped. Default value is 0.5} } \description{ -The image can be a PIL Image or a torch Tensor, in which case it is expected +The image can be a Magick Image or a torch Tensor, in which case it is expected to have \verb{[..., H, W]} shape, where \code{...} means an arbitrary number of leading dimensions } diff --git a/man/transform_resize.Rd b/man/transform_resize.Rd index 4e9762a9..fec17e2a 100644 --- a/man/transform_resize.Rd +++ b/man/transform_resize.Rd @@ -9,13 +9,13 @@ transform_resize(img, size, interpolation = 2) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{size}{(sequence or int): Desired output size. If size is a sequence -like c(h, w), output size will be matched to this. If size is an int, -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).} +\item{size}{(integer vector or integer): Desired output size. If \code{size} is +an integer vector of length 2 like \code{c(h, w)}, output size will be matched +to this. If \code{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 \verb{(size * height / width, size)}.} -\item{interpolation}{(int, optional) Desired interpolation. An integer +\item{interpolation}{(integer, optional): Desired interpolation. An integer \code{0 = nearest}, \code{2 = bilinear}, and \code{3 = bicubic} or a name from \code{\link[magick:filter_types]{magick::filter_types()}}.} } diff --git a/man/transform_resized_crop.Rd b/man/transform_resized_crop.Rd index 243a698d..84c74473 100644 --- a/man/transform_resized_crop.Rd +++ b/man/transform_resized_crop.Rd @@ -9,22 +9,23 @@ transform_resized_crop(img, top, left, height, width, size, interpolation = 2) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{top}{(int): Vertical component of the top left corner of the crop box.} +\item{top}{(integer): Vertical component of the top left corner of the +crop box.} -\item{left}{(int): Horizontal component of the top left corner of the crop -box.} +\item{left}{(integer): Horizontal component of the top left corner of the +crop box.} -\item{height}{(int): Height of the crop box.} +\item{height}{(integer): Height of the crop box.} -\item{width}{(int): Width of the crop box.} +\item{width}{(integer): Width of the crop box.} -\item{size}{(sequence or int): Desired output size. If size is a sequence -like c(h, w), output size will be matched to this. If size is an int, -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).} +\item{size}{(integer vector or integer): Desired output size. If \code{size} is +an integer vector of length 2 like \code{c(h, w)}, output size will be matched +to this. If \code{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 \verb{(size * height / width, size)}.} -\item{interpolation}{(int, optional) Desired interpolation. An integer +\item{interpolation}{(integer, optional): Desired interpolation. An integer \code{0 = nearest}, \code{2 = bilinear}, and \code{3 = bicubic} or a name from \code{\link[magick:filter_types]{magick::filter_types()}}.} } diff --git a/man/transform_rotate.Rd b/man/transform_rotate.Rd index efe95fc3..20278623 100644 --- a/man/transform_rotate.Rd +++ b/man/transform_rotate.Rd @@ -17,27 +17,27 @@ transform_rotate( \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{angle}{(float or int): rotation angle value in degrees, -counter-clockwise.} +\item{angle}{(numeric): Rotation angle value in degrees, counter-clockwise.} -\item{interpolation}{(int, optional): Interpolation mode. 0 for nearest, 2 for bilinear. -Default is 0 (nearest).} +\item{interpolation}{(integer, optional): Interpolation mode. \code{0} for +nearest, \code{2} for bilinear. Default is \code{0} (nearest).} -\item{expand}{(bool, optional): Optional expansion flag. If true, expands the -output to make it large enough to hold the entire rotated image. If false -or omitted, make the output image the same size as the input image. Note -that the expand flag assumes rotation around the center and no translation.} +\item{expand}{(logical, optional): Optional expansion flag. If \code{TRUE}, +expands the output to make it large enough to hold the entire rotated +image. If \code{FALSE} or omitted, make the output image the same size as the +input image. Note that the expand flag assumes rotation around the center +and no translation.} -\item{center}{(list or tuple, optional): Optional center of rotation, c(x, y). -Origin is the upper left corner. Default is the center of the image.} +\item{center}{(numeric vector of length 2, optional): Optional center of +rotation, \code{c(x, y)}. Origin is the upper left corner. Default is the +center of the image.} -\item{fill}{(n-tuple or int or float): Pixel fill value for area outside the -rotated image. If int or float, the value is used for all bands -respectively. Defaults to 0 for all bands. This option is only available -for Pillow>=5.2.0. This option is not supported for Tensor input. Fill +\item{fill}{(numeric vector or numeric): Pixel fill value for area outside +the rotated image. If a single numeric value, the value is used for all +channels. Defaults to \code{0} for all channels. This option is not supported for Tensor input. Fill value for the area outside the transform in the output image is always 0.} -\item{resample}{Deprecated. Use interpolation instead.} +\item{resample}{Deprecated. Use \code{interpolation} instead.} } \description{ Angular rotation of an image diff --git a/man/transform_ten_crop.Rd b/man/transform_ten_crop.Rd index b7c88253..d933c1f6 100644 --- a/man/transform_ten_crop.Rd +++ b/man/transform_ten_crop.Rd @@ -9,13 +9,13 @@ transform_ten_crop(img, size, vertical_flip = FALSE) \arguments{ \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} -\item{size}{(sequence or int): Desired output size. If size is a sequence -like c(h, w), output size will be matched to this. If size is an int, -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).} +\item{size}{(integer vector or integer): Desired output size. If \code{size} is +an integer vector of length 2 like \code{c(h, w)}, output size will be matched +to this. If \code{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 \verb{(size * height / width, size)}.} -\item{vertical_flip}{(bool): Use vertical flipping instead of horizontal} +\item{vertical_flip}{(logical): Use vertical flipping instead of horizontal.} } \description{ Crop the given image into four corners and the central crop, plus the flipped diff --git a/man/transform_to_tensor.Rd b/man/transform_to_tensor.Rd index dcf169d7..a9df551e 100644 --- a/man/transform_to_tensor.Rd +++ b/man/transform_to_tensor.Rd @@ -11,11 +11,11 @@ transform_to_tensor(img) } \description{ Converts a Magick Image or array (H x W x C) in the range \verb{[0, 255]} to a -\code{torch_tensor} of shape (C x H x W) in the range \verb{[0.0, 1.0]}. In the +\code{torch_tensor} of shape (C x H x W) in the range \verb{[0, 1]}. In the other cases, tensors are returned without scaling. } \note{ -Because the input image is scaled to \verb{[0.0, 1.0]}, this transformation +Because the input image is scaled to \verb{[0, 1]}, this transformation should not be used when transforming target image masks. } \seealso{ diff --git a/man/transform_vflip.Rd b/man/transform_vflip.Rd index 2b28faad..7c9d827e 100644 --- a/man/transform_vflip.Rd +++ b/man/transform_vflip.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/transforms-generics.R \name{transform_vflip} \alias{transform_vflip} -\title{Vertically flip a PIL Image or Tensor} +\title{Vertically flip a Magick Image or Tensor} \usage{ transform_vflip(img) } @@ -10,7 +10,7 @@ transform_vflip(img) \item{img}{A \code{magick-image}, \code{array} or \code{torch_tensor}.} } \description{ -Vertically flip a PIL Image or Tensor +Vertically flip a Magick Image or Tensor } \seealso{ Other unitary_transforms: diff --git a/tests/testthat/test-dataset-coco.R b/tests/testthat/test-dataset-coco.R index 79c8c0a4..4cfba5ac 100644 --- a/tests/testthat/test-dataset-coco.R +++ b/tests/testthat/test-dataset-coco.R @@ -32,7 +32,7 @@ test_that("coco_detection_dataset loads a single example correctly", { expect_length(dim(item$x), 3) expect_type(y, "list") - expect_named(y, c("boxes", "labels", "area", "iscrowd")) + expect_named(y, c("boxes", "labels", "area", "iscrowd", "image_height", "image_width")) expect_tensor(y$boxes) expect_equal(y$boxes$ndim, 2) @@ -85,7 +85,7 @@ test_that("coco_detection_dataset batches correctly using dataloader", { expect_true(all(vapply(batch$x, is_torch_tensor, logical(1)))) expect_type(batch$y, "list") - expect_named(batch$y[[1]], c("boxes", "labels", "area", "iscrowd")) + expect_named(batch$y[[1]], c("boxes", "labels", "area", "iscrowd", "image_height", "image_width")) expect_tensor(batch$y[[1]]$boxes) expect_equal(batch$y[[1]]$boxes$ndim, 2) expect_equal(batch$y[[1]]$boxes$size(2), 4) diff --git a/tests/testthat/test-target_transform_detection.R b/tests/testthat/test-target_transform_detection.R new file mode 100644 index 00000000..af771ef6 --- /dev/null +++ b/tests/testthat/test-target_transform_detection.R @@ -0,0 +1,306 @@ +# Helper to build a test target +make_target <- function(boxes, labels = NULL, orig_size = c(100L, 200L), image_id = 1L, area = NULL, iscrowd = NULL) { + if (is.matrix(boxes)) { + boxes <- torch_tensor(boxes, dtype = torch_float32()) + } + if (is.null(labels)) { + labels <- torch_ones(boxes$size(1), dtype = torch_long()) + } + if (is.null(area)) { + area <- (boxes[, 3] - boxes[, 1]) * (boxes[, 4] - boxes[, 2]) + } + if (is.null(iscrowd)) { + iscrowd <- torch_zeros(boxes$size(1), dtype = torch_uint8()) + } + list( + boxes = boxes, + labels = labels, + image_height = orig_size[1], + image_width = orig_size[2], + image_id = torch_tensor(image_id, dtype = torch_long()), + area = area, + iscrowd = iscrowd + ) +} + +test_that("target_transform_resize with c(h, w) rescales boxes correctly", { + # Image 100x200 (H x W), resize to 200x400 -> scale 2x + target <- make_target( + boxes = matrix(c(10, 20, 50, 60), ncol = 4), + orig_size = c(100L, 200L) + ) + + out <- target_transform_resize(target, c(200L, 400L)) + + # scale_h = 200/100 = 2, scale_w = 400/200 = 2 + expected_boxes <- matrix(c(20, 40, 100, 120), ncol = 4) + expect_equal_to_r(out$boxes, expected_boxes, tolerance = 1e-5) + expect_tensor_dtype(out$boxes, torch_float32()) +}) + +test_that("target_transform_resize with integer rescales proportionally", { + # Image 100x200 (H x W), size = 50 + # max(100, 200) = 200, scale = 50/200 = 0.25 + # new_h = round(100 * 0.25) = 25, new_w = round(200 * 0.25) = 50 + target <- make_target( + boxes = matrix(c(40, 20, 80, 60), ncol = 4), + orig_size = c(100L, 200L) + ) + + out <- target_transform_resize(target, 50L) + + # scale_h = 25/100 = 0.25, scale_w = 50/200 = 0.25 + expected_boxes <- matrix(c(10, 5, 20, 15), ncol = 4) + expect_equal_to_r(out$boxes, expected_boxes, tolerance = 1e-5) + expect_equal(out$image_height, 25L) + expect_equal(out$image_width, 50L) +}) + +test_that("target_transform_resize updates original size", { + target <- make_target( + boxes = matrix(c(0, 0, 10, 10), ncol = 4), + orig_size = c(100L, 100L) + ) + + out <- target_transform_resize(target, c(300L, 400L)) + + expect_equal(out$image_height, 300L) + expect_equal(out$image_width, 400L) +}) + +test_that("target_transform_resize preserves other target fields", { + target <- make_target( + boxes = matrix(c(10, 20, 50, 60), ncol = 4), + labels = torch_tensor(c(3L, 5L), dtype = torch_long()), + orig_size = c(100L, 200L), + image_id = 42L, + area = torch_tensor(c(100, 200), dtype = torch_float32()), + iscrowd = torch_tensor(c(0L, 1L), dtype = torch::torch_uint8()) + ) + + out <- target_transform_resize(target, c(200L, 400L)) + + # labels, image_id, area, iscrowd must remain unchanged + expect_equal_to_r(out$labels, c(3L, 5L)) + expect_tensor_dtype(out$labels, torch_long()) + expect_equal_to_r(out$image_id, 42L) + expect_equal_to_r(out$area, c(100, 200), tolerance = 1e-5) + expect_tensor_dtype(out$area, torch_float32()) + expect_equal_to_r(out$iscrowd, as.raw(c(0, 1))) + expect_tensor_dtype(out$iscrowd, torch::torch_uint8()) +}) + +test_that("target_transform_resize handles non-uniform scaling", { + # Image 100x200, resize to 300x200 -> scale_h = 3, scale_w = 1 + target <- make_target( + boxes = matrix(c(10, 20, 180, 70), ncol = 4), + orig_size = c(100L, 200L) + ) + + out <- target_transform_resize(target, c(300L, 200L)) + + # xmin=10*1=10, ymin=20*3=60, xmax=180*1=180, ymax=70*3=210 + expected_boxes <- matrix(c(10, 60, 180, 210), ncol = 4) + expect_equal_to_r(out$boxes, expected_boxes, tolerance = 1e-5) +}) + +test_that("target_transform_resize handles empty boxes", { + target <- make_target( + boxes = matrix(numeric(0), ncol = 4), + labels = torch_zeros(0L, dtype = torch_long()), + orig_size = c(100L, 200L) + ) + + out <- target_transform_resize(target, c(200L, 400L)) + + expect_equal(out$boxes$shape, c(0L, 4L)) + expect_tensor(out$boxes) + expect_equal(out$image_height, 200L) + expect_equal(out$image_width, 400L) +}) + +test_that("target_transform_resize handles multiple boxes", { + target <- make_target( + boxes = matrix( + c( + 10, + 20, + 50, + 60, + 0, + 0, + 100, + 100, + 25, + 50, + 75, + 150 + ), + ncol = 4, + byrow = TRUE + ), + orig_size = c(100L, 200L) + ) + + out <- target_transform_resize(target, c(200L, 400L)) + + # scale_h = 2, scale_w = 2 + expected_boxes <- matrix( + c( + 20, + 40, + 100, + 120, + 0, + 0, + 200, + 200, + 50, + 100, + 150, + 300 + ), + ncol = 4, + byrow = TRUE + ) + expect_equal_to_r(out$boxes, expected_boxes, tolerance = 1e-5) +}) + +test_that("target_transform_resize handles boxes at image boundaries", { + target <- make_target( + boxes = matrix(c(0, 0, 200, 100), ncol = 4), + orig_size = c(100L, 200L) + ) + + out <- target_transform_resize(target, c(200L, 400L)) + + expected_boxes <- matrix(c(0, 0, 400, 200), ncol = 4) + expect_equal_to_r(out$boxes, expected_boxes, tolerance = 1e-5) +}) + +test_that("target_transform_resize with integer handles square image", { + # Square image 100x100, size = 50 + # max(100, 100) = 100, scale = 50/100 = 0.5 + # new_h = 50, new_w = 50 + target <- make_target( + boxes = matrix(c(10, 20, 50, 60), ncol = 4), + orig_size = c(100L, 100L) + ) + + out <- target_transform_resize(target, 50L) + + expected_boxes <- matrix(c(5, 10, 25, 30), ncol = 4) + expect_equal_to_r(out$boxes, expected_boxes, tolerance = 1e-5) + expect_equal(out$image_height, 50L) + expect_equal(out$image_width, 50L) +}) + +test_that("target_transform_resize with integer handles portrait image", { + # Portrait image 200x100 (H > W), size = 50 + # max(200, 100) = 200, scale = 50/200 = 0.25 + # new_h = 50, new_w = 25 + target <- make_target( + boxes = matrix(c(10, 40, 50, 120), ncol = 4), + orig_size = c(200L, 100L) + ) + + out <- target_transform_resize(target, 50L) + + # scale_h = 50/200 = 0.25, scale_w = 25/100 = 0.25 + expected_boxes <- matrix(c(2.5, 10, 12.5, 30), ncol = 4) + expect_equal_to_r(out$boxes, expected_boxes, tolerance = 1e-5) + expect_equal(out$image_height, 50L) + expect_equal(out$image_width, 25L) +}) + +test_that("target_transform_resize with integer handles landscape image", { + # Landscape image 100x200 (W > H), size = 50 + # max(100, 200) = 200, scale = 50/200 = 0.25 + # new_h = 25, new_w = 50 + target <- make_target( + boxes = matrix(c(20, 10, 120, 50), ncol = 4), + orig_size = c(100L, 200L) + ) + + out <- target_transform_resize(target, 50L) + + # scale_h = 25/100 = 0.25, scale_w = 50/200 = 0.25 + expected_boxes <- matrix(c(5, 2.5, 30, 12.5), ncol = 4) + expect_equal_to_r(out$boxes, expected_boxes, tolerance = 1e-5) + expect_equal(out$image_height, 25L) + expect_equal(out$image_width, 50L) +}) + +test_that("target_transform_resize is composable in a pipeline", { + target <- make_target( + boxes = matrix(c(10, 20, 50, 60), ncol = 4), + orig_size = c(100L, 200L) + ) + + # Pipeline: resize 2x then resize 0.5x -> back to original + out1 <- target_transform_resize(target, c(200L, 400L)) + out2 <- target_transform_resize(out1, c(100L, 200L)) + + expect_equal_to_r(out2$boxes, as.matrix(target$boxes$cpu()), tolerance = 1e-4) + expect_equal(out2$image_height, target$image_height) + expect_equal(out2$image_width, target$image_width) +}) + +test_that("target_transform_resize works with pipe", { + skip_if_not_installed("magrittr") + + target <- make_target( + boxes = matrix(c(10, 20, 50, 60), ncol = 4), + orig_size = c(100L, 200L) + ) + + # Usage with the magrittr pipe + out <- target |> + target_transform_resize(size = c(200L, 400L)) |> + target_transform_resize(size = c(100L, 200L)) + + expect_equal_to_r(out$boxes, as.matrix(target$boxes$cpu()), tolerance = 1e-4) + expect_equal(out$image_height, target$image_height) + expect_equal(out$image_width, target$image_width) + + out <- target %>% + target_transform_resize(size = c(200L, 400L)) %>% + target_transform_resize(size = c(100L, 200L)) + + expect_equal_to_r(out$boxes, as.matrix(target$boxes$cpu()), tolerance = 1e-4) + expect_equal(out$image_height, target$image_height) + expect_equal(out$image_width, target$image_width) +}) + +test_that("target_transform_resize errors when one of image size is missing", { + target <- list( + boxes = torch_tensor(matrix(c(10, 20, 50, 60), ncol = 4)), + labels = torch_ones(1L, dtype = torch_long()) + ) + + expect_error( + target_transform_resize(target, c(200L, 400L)), + "image_width" + ) +}) + +test_that("target_transform_resize does not mutate the input target", { + target <- make_target( + boxes = matrix(c(10, 20, 50, 60), ncol = 4), + orig_size = c(100L, 200L) + ) + + original_boxes <- as.matrix(target$boxes$cpu()) + original_height <- target$image_height + original_width <- target$image_width + + out <- target_transform_resize(target, c(200L, 400L)) + + # Original target must not be modified + expect_equal_to_r(target$boxes, original_boxes) + expect_equal(target$image_height, original_height) + expect_equal(target$image_width, original_width) + + # Result must be different + expect_false(identical(as.matrix(out$boxes$cpu()), original_boxes)) +})