Functional implementation of rotate. This function operates eagerly or lazily according to ``lazy`` (default ``False``). Args: img: data to be changed, assuming `img` is channel-first. angle: Rotation angle(s) in radians. should a float for 2D, three floats for 3D.
(img, angle, output_shape, mode, padding_mode, align_corners, dtype, lazy, transform_info)
| 383 | |
| 384 | |
| 385 | def rotate(img, angle, output_shape, mode, padding_mode, align_corners, dtype, lazy, transform_info): |
| 386 | """ |
| 387 | Functional implementation of rotate. |
| 388 | This function operates eagerly or lazily according to |
| 389 | ``lazy`` (default ``False``). |
| 390 | |
| 391 | Args: |
| 392 | img: data to be changed, assuming `img` is channel-first. |
| 393 | angle: Rotation angle(s) in radians. should a float for 2D, three floats for 3D. |
| 394 | output_shape: output shape of the rotated data. |
| 395 | mode: {``"bilinear"``, ``"nearest"``} |
| 396 | Interpolation mode to calculate output values. |
| 397 | See also: https://pytorch.org/docs/stable/generated/torch.nn.functional.grid_sample.html |
| 398 | padding_mode: {``"zeros"``, ``"border"``, ``"reflection"``} |
| 399 | Padding mode for outside grid values. |
| 400 | See also: https://pytorch.org/docs/stable/generated/torch.nn.functional.grid_sample.html |
| 401 | align_corners: See also: https://pytorch.org/docs/stable/generated/torch.nn.functional.grid_sample.html |
| 402 | dtype: data type for resampling computation. |
| 403 | If None, use the data type of input data. To be compatible with other modules, |
| 404 | the output data type is always ``float32``. |
| 405 | lazy: a flag that indicates whether the operation should be performed lazily or not |
| 406 | transform_info: a dictionary with the relevant information pertaining to an applied transform. |
| 407 | |
| 408 | """ |
| 409 | |
| 410 | im_shape = img.peek_pending_shape() if isinstance(img, MetaTensor) else img.shape[1:] |
| 411 | input_ndim = len(im_shape) |
| 412 | if input_ndim not in (2, 3): |
| 413 | raise ValueError(f"Unsupported image dimension: {input_ndim}, available options are [2, 3].") |
| 414 | _angle = ensure_tuple_rep(angle, 1 if input_ndim == 2 else 3) |
| 415 | transform = create_rotate(input_ndim, _angle) |
| 416 | if output_shape is None: |
| 417 | corners = np.asarray(np.meshgrid(*[(0, dim) for dim in im_shape], indexing="ij")).reshape((len(im_shape), -1)) |
| 418 | corners = transform[:-1, :-1] @ corners # type: ignore |
| 419 | output_shape = np.asarray(np.ptp(corners, axis=1) + 0.5, dtype=int) |
| 420 | else: |
| 421 | output_shape = np.asarray(output_shape, dtype=int) |
| 422 | shift = create_translate(input_ndim, ((np.array(im_shape) - 1) / 2).tolist()) |
| 423 | shift_1 = create_translate(input_ndim, (-(np.asarray(output_shape, dtype=int) - 1) / 2).tolist()) |
| 424 | transform = shift @ transform @ shift_1 |
| 425 | extra_info = { |
| 426 | "rot_mat": transform, |
| 427 | "mode": mode, |
| 428 | "padding_mode": padding_mode, |
| 429 | "align_corners": align_corners if align_corners is not None else TraceKeys.NONE, |
| 430 | "dtype": str(dtype)[6:], # dtype as string; remove "torch": torch.float32 -> float32 |
| 431 | } |
| 432 | meta_info = TraceableTransform.track_transform_meta( |
| 433 | img, |
| 434 | sp_size=output_shape, |
| 435 | affine=transform, |
| 436 | extra_info=extra_info, |
| 437 | orig_size=im_shape, |
| 438 | transform_info=transform_info, |
| 439 | lazy=lazy, |
| 440 | ) |
| 441 | out = _maybe_new_metatensor(img) |
| 442 | if lazy: |
searching dependent graphs…