impy-array 2.4.5__tar.gz → 2.4.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. {impy_array-2.4.5 → impy_array-2.4.7}/PKG-INFO +3 -2
  2. impy_array-2.4.7/impy/__init__.py +63 -0
  3. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_corr.py +3 -1
  4. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_misc.py +3 -0
  5. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_skimage.py +14 -3
  6. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/big.py +0 -1
  7. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/imgarray.py +66 -9
  8. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/labeledarray.py +58 -9
  9. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/lazy.py +241 -52
  10. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/tiled.py +67 -20
  11. {impy_array-2.4.5 → impy_array-2.4.7}/impy/axes/_axis.py +40 -40
  12. {impy_array-2.4.5 → impy_array-2.4.7}/impy/core.py +21 -6
  13. {impy_array-2.4.5 → impy_array-2.4.7}/impy/io/_mrc.py +2 -0
  14. {impy_array-2.4.5 → impy_array-2.4.7}/impy/viewer/__init__.py +1 -1
  15. {impy_array-2.4.5 → impy_array-2.4.7}/pyproject.toml +2 -1
  16. impy_array-2.4.5/impy/__init__.py +0 -43
  17. {impy_array-2.4.5 → impy_array-2.4.7}/.gitignore +0 -0
  18. {impy_array-2.4.5 → impy_array-2.4.7}/LICENSE +0 -0
  19. {impy_array-2.4.5 → impy_array-2.4.7}/README.md +0 -0
  20. {impy_array-2.4.5 → impy_array-2.4.7}/impy/__main__.py +0 -0
  21. {impy_array-2.4.5 → impy_array-2.4.7}/impy/_const.py +0 -0
  22. {impy_array-2.4.5 → impy_array-2.4.7}/impy/_types.py +0 -0
  23. {impy_array-2.4.5 → impy_array-2.4.7}/impy/array_api.py +0 -0
  24. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/__init__.py +0 -0
  25. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_imshow.py +0 -0
  26. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/__init__.py +0 -0
  27. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_deconv.py +0 -0
  28. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_docs.py +0 -0
  29. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_filters.py +0 -0
  30. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_glcm.py +0 -0
  31. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_linalg.py +0 -0
  32. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_plot.py +0 -0
  33. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_process_numba.py +0 -0
  34. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_structures.py +0 -0
  35. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/_utils/_transform.py +0 -0
  36. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/axesmixin.py +0 -0
  37. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/bases/__init__.py +0 -0
  38. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/bases/metaarray.py +0 -0
  39. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/bases/overload.py +0 -0
  40. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/label.py +0 -0
  41. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/phasearray.py +0 -0
  42. {impy_array-2.4.5 → impy_array-2.4.7}/impy/arrays/specials.py +0 -0
  43. {impy_array-2.4.5 → impy_array-2.4.7}/impy/axes/__init__.py +0 -0
  44. {impy_array-2.4.5 → impy_array-2.4.7}/impy/axes/_axes.py +0 -0
  45. {impy_array-2.4.5 → impy_array-2.4.7}/impy/axes/_axes_tuple.py +0 -0
  46. {impy_array-2.4.5 → impy_array-2.4.7}/impy/axes/_slicer.py +0 -0
  47. {impy_array-2.4.5 → impy_array-2.4.7}/impy/binder.py +0 -0
  48. {impy_array-2.4.5 → impy_array-2.4.7}/impy/collections.py +0 -0
  49. {impy_array-2.4.5 → impy_array-2.4.7}/impy/correlation.py +0 -0
  50. {impy_array-2.4.5 → impy_array-2.4.7}/impy/frame/__init__.py +0 -0
  51. {impy_array-2.4.5 → impy_array-2.4.7}/impy/frame/frames.py +0 -0
  52. {impy_array-2.4.5 → impy_array-2.4.7}/impy/io/__init__.py +0 -0
  53. {impy_array-2.4.5 → impy_array-2.4.7}/impy/io/_nd2.py +0 -0
  54. {impy_array-2.4.5 → impy_array-2.4.7}/impy/io/_npy.py +0 -0
  55. {impy_array-2.4.5 → impy_array-2.4.7}/impy/io/_registry.py +0 -0
  56. {impy_array-2.4.5 → impy_array-2.4.7}/impy/io/_tiff.py +0 -0
  57. {impy_array-2.4.5 → impy_array-2.4.7}/impy/io/_utils.py +0 -0
  58. {impy_array-2.4.5 → impy_array-2.4.7}/impy/io/_zarr.py +0 -0
  59. {impy_array-2.4.5 → impy_array-2.4.7}/impy/lazy/__init__.py +0 -0
  60. {impy_array-2.4.5 → impy_array-2.4.7}/impy/lazy/core.py +0 -0
  61. {impy_array-2.4.5 → impy_array-2.4.7}/impy/lazy/random.py +0 -0
  62. {impy_array-2.4.5 → impy_array-2.4.7}/impy/random.py +0 -0
  63. {impy_array-2.4.5 → impy_array-2.4.7}/impy/roi.py +0 -0
  64. {impy_array-2.4.5 → impy_array-2.4.7}/impy/utils/__init__.py +0 -0
  65. {impy_array-2.4.5 → impy_array-2.4.7}/impy/utils/axesop.py +0 -0
  66. {impy_array-2.4.5 → impy_array-2.4.7}/impy/utils/deco.py +0 -0
  67. {impy_array-2.4.5 → impy_array-2.4.7}/impy/utils/gauss.py +0 -0
  68. {impy_array-2.4.5 → impy_array-2.4.7}/impy/utils/misc.py +0 -0
  69. {impy_array-2.4.5 → impy_array-2.4.7}/impy/utils/slicer.py +0 -0
  70. {impy_array-2.4.5 → impy_array-2.4.7}/impy/utils/utilcls.py +0 -0
  71. {impy_array-2.4.5 → impy_array-2.4.7}/impy/viewer/utils.py +0 -0
  72. {impy_array-2.4.5 → impy_array-2.4.7}/impy/viewer/viewer.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: impy-array
3
- Version: 2.4.5
3
+ Version: 2.4.7
4
4
  Summary: Speed up coding/extending image analysis in Python.
5
5
  Project-URL: Download, https://github.com/hanjinliu/impy
6
6
  Author-email: Hanjin Liu <liuhanjin-sc@g.ecc.u-tokyo.ac.jp>
@@ -39,6 +39,7 @@ Classifier: Programming Language :: Python :: 3.9
39
39
  Classifier: Programming Language :: Python :: 3.10
40
40
  Classifier: Programming Language :: Python :: 3.11
41
41
  Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Programming Language :: Python :: 3.13
42
43
  Classifier: Programming Language :: Python :: Implementation :: CPython
43
44
  Classifier: Programming Language :: Python :: Implementation :: PyPy
44
45
  Requires-Python: >=3.9
@@ -0,0 +1,63 @@
1
+ __version__ = "2.4.7"
2
+ __author__ = "Hanjin Liu"
3
+ __email__ = "liuhanjin-sc@g.ecc.u-tokyo.ac.jp"
4
+
5
+ import logging
6
+ from typing import TYPE_CHECKING
7
+
8
+ from impy._const import Const, SetConst, use # noqa
9
+
10
+ from impy.collections import DataList, DataDict # noqa
11
+ from impy.core import * # noqa
12
+ from impy.binder import bind # noqa
13
+ from impy.correlation import * # noqa
14
+ from impy.arrays import ImgArray, LazyImgArray, BigImgArray, Label # noqa
15
+ from impy import random, io, lazy # noqa
16
+ from impy.axes import slicer # noqa
17
+
18
+ # Inheritance
19
+ # -----------
20
+ #
21
+ # AxesMixin -----> LazyImgArray ------> BigImgArray
22
+ # |
23
+ # +-----> MetaArray --+--> LabeledArray --+--> ImgArray
24
+ # | | |
25
+ # np.ndarray +--> Label +--> PhaseArray
26
+ # |
27
+ # +--> PropArray
28
+
29
+
30
+ logging.getLogger("skimage").setLevel(logging.ERROR)
31
+ logging.getLogger("tifffile").setLevel(logging.ERROR)
32
+
33
+
34
+ del logging
35
+
36
+ # dtypes
37
+ from numpy import ( # noqa
38
+ uint8, uint16, uint32, uint64,
39
+ int8, int16, int32, int64,
40
+ float16, float32, float64,
41
+ complex64, complex128,
42
+ bool_,
43
+ )
44
+
45
+ # lazy loading
46
+
47
+ _VIEWER_CACHE = None
48
+ if TYPE_CHECKING:
49
+ from impy.viewer import napariViewers
50
+
51
+ gui: "napariViewers"
52
+
53
+ def __getattr__(key):
54
+ global _VIEWER_CACHE
55
+
56
+ if key == "gui":
57
+ from impy.viewer import napariViewers
58
+
59
+ if _VIEWER_CACHE is None:
60
+ _VIEWER_CACHE = napariViewers()
61
+ return _VIEWER_CACHE
62
+ else:
63
+ raise AttributeError(f"module 'impy' has no attribute '{key}'")
@@ -34,7 +34,7 @@ def subpixel_pcc(
34
34
  f0: np.ndarray,
35
35
  f1: np.ndarray,
36
36
  upsample_factor: int,
37
- max_shifts: tuple[float, ...] | None = None,
37
+ max_shifts: float | tuple[float, ...] | None = None,
38
38
  ):
39
39
  power, product = _pcc_and_power_spec(f0, f1, max_shifts)
40
40
  maxima = xp.unravel_index(xp.argmax(power), power.shape)
@@ -60,6 +60,8 @@ def subpixel_pcc(
60
60
  power = abs2(cross_correlation)
61
61
 
62
62
  if max_shifts is not None:
63
+ if np.isscalar(max_shifts):
64
+ max_shifts = (max_shifts,) * f0.ndim
63
65
  max_shifts = xp.asarray(max_shifts)
64
66
  _upsampled_left_shifts = (shifts + max_shifts) * upsample_factor
65
67
  _upsampled_right_shifts = (max_shifts - shifts) * upsample_factor
@@ -41,6 +41,9 @@ def make_rotated_axis(src, dst):
41
41
  n = int(round(d))
42
42
  return np.linspace(src, src + dr / d * (n - 1), n)
43
43
 
44
+ def make_rotated_axis_by_vec(src, unit_vec, n: int):
45
+ return np.linspace(src, src + unit_vec * (n - 1), n)
46
+
44
47
  def make_pad(pad_width, dims, all_axes, **kwargs):
45
48
  """More flexible padding than `np.pad`."""
46
49
  pad_width_ = []
@@ -6,8 +6,19 @@ from functools import reduce, lru_cache
6
6
 
7
7
  # same as the function in skimage.filters._fft_based (available in scikit-image >= 0.19)
8
8
  @lru_cache(maxsize=4)
9
- def _get_ND_butterworth_filter(shape: tuple[int, ...], cutoff: float, order: int,
10
- high_pass: bool, real: bool):
9
+ def _get_ND_butterworth_filter(
10
+ shape: tuple[int, ...],
11
+ cutoff: float,
12
+ order: int,
13
+ high_pass: bool,
14
+ real: bool,
15
+ ):
16
+ if cutoff == 0:
17
+ if high_pass:
18
+ wfilt = np.ones(shape, dtype=np.float32)
19
+ else:
20
+ wfilt = np.zeros(shape, dtype=np.float32)
21
+ return wfilt
11
22
  ranges = []
12
23
  for d, fc in zip(shape, cutoff):
13
24
  axis = np.arange(-(d - 1) // 2, (d - 1) // 2 + 1, dtype=np.float32) / (d*fc)
@@ -19,4 +30,4 @@ def _get_ND_butterworth_filter(shape: tuple[int, ...], cutoff: float, order: int
19
30
  wfilt = 1 / (1 + q2**order)
20
31
  if high_pass:
21
32
  wfilt = 1 - wfilt
22
- return wfilt
33
+ return wfilt
@@ -31,7 +31,6 @@ class BigImgArray(LazyImgArray):
31
31
  fft = wrap_method(LazyImgArray.fft)
32
32
  ifft = wrap_method(LazyImgArray.ifft)
33
33
  power_spectra = wrap_method(LazyImgArray.power_spectra)
34
- tiled_lowpass_filter = wrap_method(LazyImgArray.tiled_lowpass_filter)
35
34
  proj = wrap_method(LazyImgArray.proj)
36
35
  binning = wrap_method(LazyImgArray.binning)
37
36
  track_drift = wrap_method(LazyImgArray.track_drift)
@@ -217,13 +217,13 @@ class ImgArray(LabeledArray):
217
217
  c_axes=complement_axes(dims, self.axes),
218
218
  kwargs=dict(matrix=mx, order=order, mode=mode, cval=cval),
219
219
  )
220
-
220
+
221
221
  @_docs.write_docs
222
222
  @dims_to_spatial_axes
223
223
  @same_dtype(asfloat=True)
224
224
  @check_input_and_output
225
225
  def shift(
226
- self, translation, order: int = 3, mode: PaddingMode = "constant",
226
+ self, translation, order: int = 3, mode: PaddingMode = "constant",
227
227
  cval: float = 0, prefilter: bool | None = None, dims: Dims = None,
228
228
  update: bool = False,
229
229
  ) -> ImgArray:
@@ -247,12 +247,11 @@ class ImgArray(LabeledArray):
247
247
  cval = cval(self.value)
248
248
 
249
249
  prefilter = prefilter or order > 1
250
- mtx = _transform.compose_affine_matrix(translation=translation)
251
250
 
252
251
  return self._apply_dask(
253
- _transform.warp,
252
+ _transform.shift,
254
253
  c_axes=complement_axes(dims, self.axes),
255
- kwargs=dict(matrix=mtx, order=order, mode=mode, cval=cval,
254
+ kwargs=dict(shift=translation, order=order, mode=mode, cval=cval,
256
255
  prefilter=prefilter)
257
256
  )
258
257
 
@@ -329,7 +328,9 @@ class ImgArray(LabeledArray):
329
328
  out.set_scale({a: self.scale[a]/scale for a, scale in zip(self.axes, zoom_)})
330
329
  return out
331
330
 
332
- rescale = zoom # backward compatibility
331
+ def log(self, eps: float = 1e-8) -> ImgArray:
332
+ """Calculate natural logarithm of the image, with a small epsilon."""
333
+ return np.log(self.as_float() + eps)
333
334
 
334
335
  @_docs.write_docs
335
336
  @dims_to_spatial_axes
@@ -902,6 +903,51 @@ class ImgArray(LabeledArray):
902
903
  return xp.asnumpy(out)
903
904
 
904
905
 
906
+ @_docs.write_docs
907
+ @dims_to_spatial_axes
908
+ @same_dtype(asfloat=True)
909
+ @check_input_and_output
910
+ def bandpass_filter(
911
+ self,
912
+ cuton: nDFloat = 0.02,
913
+ cutoff: nDFloat = 0.2,
914
+ order: float = 2,
915
+ *,
916
+ dims: Dims = None,
917
+ update: bool = False
918
+ ):
919
+ """
920
+ Butterworth band-pass filter.
921
+
922
+ Parameters
923
+ ----------
924
+ cuton, cutoff : float or array-like
925
+ Cuton and Cutoff frequency. Fequency domain between these two values will be
926
+ passed.
927
+ order : float, default is 2
928
+ Steepness of cutoff.
929
+ {dims}{update}
930
+
931
+ Returns
932
+ -------
933
+ ImgArray
934
+ Filtered image
935
+ """
936
+ from ._utils._skimage import _get_ND_butterworth_filter
937
+ cuton = check_nd(cuton, len(dims))
938
+ cutoff = check_nd(cutoff, len(dims))
939
+ spatial_shape = self.sizesof(dims)
940
+ spatial_axes = [self.axisof(a) for a in dims]
941
+ weight_on = _get_ND_butterworth_filter(spatial_shape, cuton, order, True, True)
942
+ weight_off = _get_ND_butterworth_filter(spatial_shape, cutoff, order, False, True)
943
+ weight = weight_off * weight_on
944
+ input = xp.asarray(self.value)
945
+ if len(dims) < self.ndim:
946
+ weight = add_axes(self.axes, self.shape, weight, dims)
947
+ out = xp.fft.irfftn(xp.asarray(weight)*xp.fft.rfftn(input, axes=spatial_axes),
948
+ s=spatial_shape, axes=spatial_axes)
949
+ return xp.asnumpy(out)
950
+
905
951
  @_docs.write_docs
906
952
  @dims_to_spatial_axes
907
953
  @same_dtype(asfloat=True)
@@ -3939,6 +3985,7 @@ class ImgArray(LabeledArray):
3939
3985
  along: AxisLike | None = None,
3940
3986
  show_drift: bool = False,
3941
3987
  upsample_factor: int = 10,
3988
+ max_shift: nDFloat | None = None,
3942
3989
  ) -> MarkerFrame:
3943
3990
  """
3944
3991
  Calculate yx-directional drift using the method equivalent to
@@ -3952,6 +3999,8 @@ class ImgArray(LabeledArray):
3952
3999
  If True, plot the result.
3953
4000
  upsample_factor : int, default is 10
3954
4001
  Up-sampling factor when calculating phase cross correlation.
4002
+ max_shift : tuple of float, optional
4003
+ Maximum shift in spatial directions.
3955
4004
 
3956
4005
  Returns
3957
4006
  -------
@@ -3966,7 +4015,9 @@ class ImgArray(LabeledArray):
3966
4015
  raise ValueError("`along` must be single character.")
3967
4016
  if not isinstance(upsample_factor, int):
3968
4017
  raise TypeError(f"upsample-factor must be integer but got {type(upsample_factor)}")
3969
-
4018
+ if max_shift is not None:
4019
+ if np.isscalar(max_shift):
4020
+ max_shift = np.full(self.ndim - 1, max_shift)
3970
4021
  result = np.zeros((self.sizeof(along), self.ndim-1), dtype=np.float32)
3971
4022
  c_axes = complement_axes(along, self.axes)
3972
4023
  last_img = None
@@ -3975,7 +4026,12 @@ class ImgArray(LabeledArray):
3975
4026
  img = xp.asarray(img)
3976
4027
  if last_img is not None:
3977
4028
  result[i] = xp.asnumpy(
3978
- _corr.subpixel_pcc(last_img, img, upsample_factor=upsample_factor)[0]
4029
+ _corr.subpixel_pcc(
4030
+ last_img,
4031
+ img,
4032
+ max_shifts=max_shift,
4033
+ upsample_factor=upsample_factor,
4034
+ )[0]
3979
4035
  )
3980
4036
  last_img = img
3981
4037
  else:
@@ -4000,6 +4056,7 @@ class ImgArray(LabeledArray):
4000
4056
  *,
4001
4057
  zero_ave: bool = True,
4002
4058
  along: AxisLike | None = None,
4059
+ max_shift: nDFloat | None = None,
4003
4060
  order: int = 1,
4004
4061
  mode: str = "constant",
4005
4062
  cval: float = 0,
@@ -4062,7 +4119,7 @@ class ImgArray(LabeledArray):
4062
4119
  )
4063
4120
  return out
4064
4121
 
4065
- shift = ref.track_drift(along=along).values
4122
+ shift = ref.track_drift(along=along, max_shift=max_shift).values
4066
4123
 
4067
4124
  else:
4068
4125
  shift = np.asarray(shift, dtype=np.float32)
@@ -848,8 +848,8 @@ class LabeledArray(MetaArray):
848
848
  Parameters
849
849
  ----------
850
850
  pixel : int or array-like, default is 1
851
- Number of pixels to remove. If an array is given, each axis will be cropped with different pixels,
852
- using each value respectively.
851
+ Number of pixels to remove. If an array is given, each axis will be cropped
852
+ with different pixels, using each value respectively.
853
853
  {dims}
854
854
 
855
855
  Returns
@@ -869,16 +869,65 @@ class LabeledArray(MetaArray):
869
869
  out = self[fmt[sl]]
870
870
  return out
871
871
 
872
+ def crop_subregion(
873
+ self,
874
+ centers: Coords,
875
+ shape: tuple[int, int],
876
+ angles: float | Sequence[float] = 0,
877
+ *,
878
+ order=3,
879
+ ) -> Self:
880
+ """
881
+ Crop a subragion of an image.
882
+
883
+ Parameters
884
+ ----------
885
+ centers : sequence of (float, float)
886
+ Center coordinates in pixels.
887
+ shape : (int, int)
888
+ Shape of the subregion.
889
+ angles : float or sequence of float, default is 0
890
+ Clockwise angle of the subregion.
891
+ {dims}
892
+ """
893
+ if order > 1:
894
+ self_filt = self.spline_filter(order).value
895
+ else:
896
+ self_filt = self.value
897
+ centers = np.asarray(centers)
898
+ if np.isscalar(angles):
899
+ angles = [angles] * len(centers)
900
+ else:
901
+ if len(centers) != len(angles):
902
+ raise ValueError("Length of centers and angles must be the same.")
903
+ cropped_imgs = []
904
+ for center, angle in zip(centers, angles, strict=True):
905
+ center = np.asarray(center)
906
+ rad = np.deg2rad(angle)
907
+ ey = np.array([np.sin(rad), np.cos(rad)])
908
+ ex = np.array([np.cos(rad), -np.sin(rad)])
909
+ ny, nx = shape
910
+ origin = center - ey * (nx - 1) / 2 - ex * (ny - 1) / 2
911
+ ax0 = _misc.make_rotated_axis_by_vec(origin, ex, nx)
912
+ ax1 = _misc.make_rotated_axis_by_vec(origin, ey, ny)
913
+ all_coords = ax0[:, np.newaxis] + ax1[np.newaxis] - origin
914
+ all_coords = np.moveaxis(all_coords, -1, 0)
915
+ cropped_img = ndi.map_coordinates(self_filt, all_coords, prefilter=False, order=order)
916
+ cropped_imgs.append(cropped_img)
917
+ cropped_imgs = np.stack(cropped_imgs, axis=0).view(self.__class__)
918
+ return cropped_imgs._set_info(self, new_axes="p" + self.axes)
919
+
872
920
  @_docs.write_docs
873
921
  @check_input_and_output
874
922
  @dims_to_spatial_axes
875
- def rotated_crop(self, origin, dst1, dst2, dims=2) -> Self:
923
+ def rotated_crop(self, origin, dst1, dst2, *, crop_labels: bool = True, dims=2) -> Self:
876
924
  """
877
- Crop the image at four courners of an rotated rectangle. Currently only supports rotation within
878
- yx-plane. An rotated rectangle is specified with positions of a origin and two destinations `dst1`
879
- and `dst2`, i.e., vectors (dst1-origin) and (dst2-origin) represent a rotated rectangle. Let
880
- origin be the origin of a xy-plane, the rotation direction from dst1 to dst2 must be counter-
881
- clockwise, or the cropped image will be reversed.
925
+ Crop the image at four courners of an rotated rectangle. Currently only supports
926
+ rotation within yx-plane. An rotated rectangle is specified with positions of a
927
+ origin and two destinations `dst1` and `dst2`, i.e., vectors (dst1-origin) and
928
+ (dst2-origin) represent a rotated rectangle. Let origin be the origin of a
929
+ xy-plane, the rotation direction from dst1 to dst2 must be counter-clockwise,
930
+ or the cropped image will be reversed.
882
931
 
883
932
  Parameters
884
933
  ----------
@@ -907,7 +956,7 @@ class LabeledArray(MetaArray):
907
956
  )
908
957
  cropped_img = cropped_img.view(self.__class__)
909
958
  cropped_img.axes = self.axes
910
- if self.labels is not None:
959
+ if crop_labels and self.labels is not None:
911
960
  try:
912
961
  lbl = self.labels
913
962
  cropped_labels = np.empty(lbl.shape[:-2] + all_coords.shape[1:], dtype=lbl.dtype)