blur.py 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251
  1. """
  2. Augmenters that blur images.
  3. List of augmenters:
  4. * :class:`GaussianBlur`
  5. * :class:`AverageBlur`
  6. * :class:`MedianBlur`
  7. * :class:`BilateralBlur`
  8. * :class:`MotionBlur`
  9. * :class:`MeanShiftBlur`
  10. """
  11. from __future__ import print_function, division, absolute_import
  12. import numpy as np
  13. from scipy import ndimage
  14. import cv2
  15. import six.moves as sm
  16. import imgaug as ia
  17. from imgaug.imgaug import _normalize_cv2_input_arr_
  18. from . import meta
  19. from . import convolutional as iaa_convolutional
  20. from .. import parameters as iap
  21. from .. import dtypes as iadt
  22. # TODO add border mode, cval
  23. def blur_gaussian_(image, sigma, ksize=None, backend="auto", eps=1e-3):
  24. """Blur an image using gaussian blurring in-place.
  25. This operation *may* change the input image in-place.
  26. **Supported dtypes**:
  27. if (backend="auto"):
  28. * ``uint8``: yes; fully tested (1)
  29. * ``uint16``: yes; tested (1)
  30. * ``uint32``: yes; tested (2)
  31. * ``uint64``: yes; tested (2)
  32. * ``int8``: yes; tested (1)
  33. * ``int16``: yes; tested (1)
  34. * ``int32``: yes; tested (1)
  35. * ``int64``: yes; tested (2)
  36. * ``float16``: yes; tested (1)
  37. * ``float32``: yes; tested (1)
  38. * ``float64``: yes; tested (1)
  39. * ``float128``: no
  40. * ``bool``: yes; tested (1)
  41. - (1) Handled by ``cv2``. See ``backend="cv2"``.
  42. - (2) Handled by ``scipy``. See ``backend="scipy"``.
  43. if (backend="cv2"):
  44. * ``uint8``: yes; fully tested
  45. * ``uint16``: yes; tested
  46. * ``uint32``: no (2)
  47. * ``uint64``: no (3)
  48. * ``int8``: yes; tested (4)
  49. * ``int16``: yes; tested
  50. * ``int32``: yes; tested (5)
  51. * ``int64``: no (6)
  52. * ``float16``: yes; tested (7)
  53. * ``float32``: yes; tested
  54. * ``float64``: yes; tested
  55. * ``float128``: no (8)
  56. * ``bool``: yes; tested (1)
  57. - (1) Mapped internally to ``float32``. Otherwise causes
  58. ``TypeError: src data type = 0 is not supported``.
  59. - (2) Causes ``TypeError: src data type = 6 is not supported``.
  60. - (3) Causes ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957:
  61. error: (-213:The function/feature is not implemented)
  62. Unsupported combination of source format (=4), and buffer
  63. format (=5) in function 'getLinearRowFilter'``.
  64. - (4) Mapped internally to ``int16``. Otherwise causes
  65. ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957: error:
  66. (-213:The function/feature is not implemented) Unsupported
  67. combination of source format (=1), and buffer format (=5)
  68. in function 'getLinearRowFilter'``.
  69. - (5) Mapped internally to ``float64``. Otherwise causes
  70. ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957: error:
  71. (-213:The function/feature is not implemented) Unsupported
  72. combination of source format (=4), and buffer format (=5)
  73. in function 'getLinearRowFilter'``.
  74. - (6) Causes ``cv2.error: OpenCV(3.4.5) (...)/filter.cpp:2957:
  75. error: (-213:The function/feature is not implemented)
  76. Unsupported combination of source format (=4), and buffer
  77. format (=5) in function 'getLinearRowFilter'``.
  78. - (7) Mapped internally to ``float32``. Otherwise causes
  79. ``TypeError: src data type = 23 is not supported``.
  80. - (8) Causes ``TypeError: src data type = 13 is not supported``.
  81. if (backend="scipy"):
  82. * ``uint8``: yes; fully tested
  83. * ``uint16``: yes; tested
  84. * ``uint32``: yes; tested
  85. * ``uint64``: yes; tested
  86. * ``int8``: yes; tested
  87. * ``int16``: yes; tested
  88. * ``int32``: yes; tested
  89. * ``int64``: yes; tested
  90. * ``float16``: yes; tested (1)
  91. * ``float32``: yes; tested
  92. * ``float64``: yes; tested
  93. * ``float128``: no (2)
  94. * ``bool``: yes; tested (3)
  95. - (1) Mapped internally to ``float32``. Otherwise causes
  96. ``RuntimeError: array type dtype('float16') not supported``.
  97. - (2) Causes ``RuntimeError: array type dtype('float128') not
  98. supported``.
  99. - (3) Mapped internally to ``float32``. Otherwise too inaccurate.
  100. Parameters
  101. ----------
  102. image : numpy.ndarray
  103. The image to blur. Expected to be of shape ``(H, W)`` or ``(H, W, C)``.
  104. sigma : number
  105. Standard deviation of the gaussian blur. Larger numbers result in
  106. more large-scale blurring, which is overall slower than small-scale
  107. blurring.
  108. ksize : None or int, optional
  109. Size in height/width of the gaussian kernel. This argument is only
  110. understood by the ``cv2`` backend. If it is set to ``None``, an
  111. appropriate value for `ksize` will automatically be derived from
  112. `sigma`. The value is chosen tighter for larger sigmas to avoid as
  113. much as possible very large kernel sizes and therey improve
  114. performance.
  115. backend : {'auto', 'cv2', 'scipy'}, optional
  116. Backend library to use. If ``auto``, then the likely best library
  117. will be automatically picked per image. That is usually equivalent
  118. to ``cv2`` (OpenCV) and it will fall back to ``scipy`` for datatypes
  119. not supported by OpenCV.
  120. eps : number, optional
  121. A threshold used to decide whether `sigma` can be considered zero.
  122. Returns
  123. -------
  124. numpy.ndarray
  125. The blurred image. Same shape and dtype as the input.
  126. (Input image *might* have been altered in-place.)
  127. """
  128. has_zero_sized_axes = (image.size == 0)
  129. if sigma > 0 + eps and not has_zero_sized_axes:
  130. dtype = image.dtype
  131. iadt.gate_dtypes(image,
  132. allowed=["bool",
  133. "uint8", "uint16", "uint32",
  134. "int8", "int16", "int32", "int64", "uint64",
  135. "float16", "float32", "float64"],
  136. disallowed=["uint128", "uint256",
  137. "int128", "int256",
  138. "float96", "float128", "float256"],
  139. augmenter=None)
  140. dts_not_supported_by_cv2 = ["uint32", "uint64", "int64", "float128"]
  141. backend_to_use = backend
  142. if backend == "auto":
  143. backend_to_use = (
  144. "cv2"
  145. if image.dtype.name not in dts_not_supported_by_cv2
  146. else "scipy")
  147. elif backend == "cv2":
  148. assert image.dtype.name not in dts_not_supported_by_cv2, (
  149. "Requested 'cv2' backend, but provided %s input image, which "
  150. "cannot be handled by that backend. Choose a different "
  151. "backend or set backend to 'auto' or use a different "
  152. "datatype." % (
  153. image.dtype.name,))
  154. elif backend == "scipy":
  155. # can handle all dtypes that were allowed in gate_dtypes()
  156. pass
  157. if backend_to_use == "scipy":
  158. if dtype.name == "bool":
  159. # We convert bool to float32 here, because gaussian_filter()
  160. # seems to only return True when the underlying value is
  161. # approximately 1.0, not when it is above 0.5. So we do that
  162. # here manually. cv2 does not support bool for gaussian blur.
  163. image = image.astype(np.float32, copy=False)
  164. elif dtype.name == "float16":
  165. image = image.astype(np.float32, copy=False)
  166. # gaussian_filter() has no ksize argument
  167. # TODO it does have a truncate argument that truncates at x
  168. # standard deviations -- maybe can be used similarly to ksize
  169. if ksize is not None:
  170. ia.warn(
  171. "Requested 'scipy' backend or picked it automatically by "
  172. "backend='auto' n blur_gaussian_(), but also provided "
  173. "'ksize' argument, which is not understood by that "
  174. "backend and will be ignored.")
  175. # Note that while gaussian_filter can be applied to all channels
  176. # at the same time, that should not be done here, because then
  177. # the blurring would also happen across channels (e.g. red values
  178. # might be mixed with blue values in RGB)
  179. if image.ndim == 2:
  180. image[:, :] = ndimage.gaussian_filter(image[:, :], sigma,
  181. mode="mirror")
  182. else:
  183. nb_channels = image.shape[2]
  184. for channel in sm.xrange(nb_channels):
  185. image[:, :, channel] = ndimage.gaussian_filter(
  186. image[:, :, channel], sigma, mode="mirror")
  187. else:
  188. if dtype.name == "bool":
  189. image = image.astype(np.float32, copy=False)
  190. elif dtype.name == "float16":
  191. image = image.astype(np.float32, copy=False)
  192. elif dtype.name == "int8":
  193. image = image.astype(np.int16, copy=False)
  194. elif dtype.name == "int32":
  195. image = image.astype(np.float64, copy=False)
  196. # ksize here is derived from the equation to compute sigma based
  197. # on ksize, see
  198. # https://docs.opencv.org/3.1.0/d4/d86/group__imgproc__filter.html
  199. # -> cv::getGaussianKernel()
  200. # example values:
  201. # sig = 0.1 -> ksize = -1.666
  202. # sig = 0.5 -> ksize = 0.9999
  203. # sig = 1.0 -> ksize = 1.0
  204. # sig = 2.0 -> ksize = 11.0
  205. # sig = 3.0 -> ksize = 17.666
  206. # ksize = ((sig - 0.8)/0.3 + 1)/0.5 + 1
  207. if ksize is None:
  208. ksize = _compute_gaussian_blur_ksize(sigma)
  209. else:
  210. assert ia.is_single_integer(ksize), (
  211. "Expected 'ksize' argument to be a number, "
  212. "got %s." % (type(ksize),))
  213. ksize = ksize + 1 if ksize % 2 == 0 else ksize
  214. if ksize > 0:
  215. image_warped = cv2.GaussianBlur(
  216. _normalize_cv2_input_arr_(image),
  217. (ksize, ksize),
  218. sigmaX=sigma,
  219. sigmaY=sigma,
  220. borderType=cv2.BORDER_REFLECT_101)
  221. # re-add channel axis removed by cv2 if input was (H, W, 1)
  222. image = (
  223. image_warped[..., np.newaxis]
  224. if image.ndim == 3 and image_warped.ndim == 2
  225. else image_warped)
  226. if dtype.name == "bool":
  227. image = image > 0.5
  228. elif dtype.name != image.dtype.name:
  229. image = iadt.restore_dtypes_(image, dtype)
  230. return image
  231. def blur_mean_shift_(image, spatial_window_radius, color_window_radius):
  232. """Apply a pyramidic mean shift filter to the input image in-place.
  233. This produces an output image that has similarity with one modified by
  234. a bilateral filter. That is different from mean shift *segmentation*,
  235. which averages the colors in segments found by mean shift clustering.
  236. This function is a thin wrapper around ``cv2.pyrMeanShiftFiltering``.
  237. .. note::
  238. This function does *not* change the image's colorspace to ``RGB``
  239. before applying the mean shift filter. A non-``RGB`` colorspace will
  240. hence influence the results.
  241. .. note::
  242. This function is quite slow.
  243. Added in 0.4.0.
  244. **Supported dtypes**:
  245. * ``uint8``: yes; fully tested
  246. * ``uint16``: no (1)
  247. * ``uint32``: no (1)
  248. * ``uint64``: no (1)
  249. * ``int8``: no (1)
  250. * ``int16``: no (1)
  251. * ``int32``: no (1)
  252. * ``int64``: no (1)
  253. * ``float16``: no (1)
  254. * ``float32``: no (1)
  255. * ``float64``: no (1)
  256. * ``float128``: no (1)
  257. * ``bool``: no (1)
  258. - (1) Not supported by ``cv2.pyrMeanShiftFiltering``.
  259. Parameters
  260. ----------
  261. image : ndarray
  262. ``(H,W)`` or ``(H,W,1)`` or ``(H,W,3)`` image to blur.
  263. Images with no or one channel will be temporarily tiled to have
  264. three channels.
  265. spatial_window_radius : number
  266. Spatial radius for pixels that are assumed to be similar.
  267. color_window_radius : number
  268. Color radius for pixels that are assumed to be similar.
  269. Returns
  270. -------
  271. ndarray
  272. Blurred input image. Same shape and dtype as the input.
  273. (Input image *might* have been altered in-place.)
  274. """
  275. if 0 in image.shape[0:2]:
  276. return image
  277. # opencv method only supports uint8
  278. assert image.dtype.name == "uint8", (
  279. "Expected image with dtype \"uint8\", "
  280. "got \"%s\"." % (image.dtype.name,))
  281. shape_is_hw = (image.ndim == 2)
  282. shape_is_hw1 = (image.ndim == 3 and image.shape[-1] == 1)
  283. shape_is_hw3 = (image.ndim == 3 and image.shape[-1] == 3)
  284. assert shape_is_hw or shape_is_hw1 or shape_is_hw3, (
  285. "Expected (H,W) or (H,W,1) or (H,W,3) image, "
  286. "got shape %s." % (image.shape,))
  287. # opencv method only supports (H,W,3), so we have to tile here for (H,W)
  288. # and (H,W,1)
  289. if shape_is_hw:
  290. image = np.tile(image[..., np.newaxis], (1, 1, 3))
  291. elif shape_is_hw1:
  292. image = np.tile(image, (1, 1, 3))
  293. spatial_window_radius = max(spatial_window_radius, 0)
  294. color_window_radius = max(color_window_radius, 0)
  295. image = _normalize_cv2_input_arr_(image)
  296. image = cv2.pyrMeanShiftFiltering(
  297. image,
  298. sp=spatial_window_radius,
  299. sr=color_window_radius,
  300. dst=image)
  301. if shape_is_hw:
  302. image = image[..., 0]
  303. elif shape_is_hw1:
  304. image = image[..., 0:1]
  305. return image
  306. def _compute_gaussian_blur_ksize(sigma):
  307. if sigma < 3.0:
  308. ksize = 3.3 * sigma # 99% of weight
  309. elif sigma < 5.0:
  310. ksize = 2.9 * sigma # 97% of weight
  311. else:
  312. ksize = 2.6 * sigma # 95% of weight
  313. # we use 5x5 here as the minimum size as that simplifies
  314. # comparisons with gaussian_filter() in the tests
  315. # TODO reduce this to 3x3
  316. ksize = int(max(ksize, 5))
  317. return ksize
  318. # TODO offer different values for sigma on x/y-axis, supported by cv2 but not
  319. # by scipy
  320. # TODO add channelwise flag - channelwise=False would be supported by scipy
  321. class GaussianBlur(meta.Augmenter):
  322. """Augmenter to blur images using gaussian kernels.
  323. **Supported dtypes**:
  324. See ``~imgaug.augmenters.blur.blur_gaussian_(backend="auto")``.
  325. Parameters
  326. ----------
  327. sigma : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  328. Standard deviation of the gaussian kernel.
  329. Values in the range ``0.0`` (no blur) to ``3.0`` (strong blur) are
  330. common.
  331. * If a single ``float``, that value will always be used as the
  332. standard deviation.
  333. * If a tuple ``(a, b)``, then a random value from the interval
  334. ``[a, b]`` will be picked per image.
  335. * If a list, then a random value will be sampled per image from
  336. that list.
  337. * If a ``StochasticParameter``, then ``N`` samples will be drawn
  338. from that parameter per ``N`` input images.
  339. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  340. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  341. name : None or str, optional
  342. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  343. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  344. Old name for parameter `seed`.
  345. Its usage will not yet cause a deprecation warning,
  346. but it is still recommended to use `seed` now.
  347. Outdated since 0.4.0.
  348. deterministic : bool, optional
  349. Deprecated since 0.4.0.
  350. See method ``to_deterministic()`` for an alternative and for
  351. details about what the "deterministic mode" actually does.
  352. Examples
  353. --------
  354. >>> import imgaug.augmenters as iaa
  355. >>> aug = iaa.GaussianBlur(sigma=1.5)
  356. Blur all images using a gaussian kernel with a standard deviation of
  357. ``1.5``.
  358. >>> aug = iaa.GaussianBlur(sigma=(0.0, 3.0))
  359. Blur images using a gaussian kernel with a random standard deviation
  360. sampled uniformly (per image) from the interval ``[0.0, 3.0]``.
  361. """
  362. def __init__(self, sigma=(0.0, 3.0),
  363. seed=None, name=None,
  364. random_state="deprecated", deterministic="deprecated"):
  365. super(GaussianBlur, self).__init__(
  366. seed=seed, name=name,
  367. random_state=random_state, deterministic=deterministic)
  368. self.sigma = iap.handle_continuous_param(
  369. sigma, "sigma", value_range=(0, None), tuple_to_uniform=True,
  370. list_to_choice=True)
  371. # epsilon value to estimate whether sigma is sufficently above 0 to
  372. # apply the blur
  373. self.eps = 1e-3
  374. # Added in 0.4.0.
  375. def _augment_batch_(self, batch, random_state, parents, hooks):
  376. if batch.images is None:
  377. return batch
  378. images = batch.images
  379. nb_images = len(images)
  380. samples = self.sigma.draw_samples((nb_images,),
  381. random_state=random_state)
  382. for image, sig in zip(images, samples):
  383. image[...] = blur_gaussian_(image, sigma=sig, eps=self.eps)
  384. return batch
  385. def get_parameters(self):
  386. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  387. return [self.sigma]
  388. class AverageBlur(meta.Augmenter):
  389. """Blur an image by computing simple means over neighbourhoods.
  390. The padding behaviour around the image borders is cv2's
  391. ``BORDER_REFLECT_101``.
  392. **Supported dtypes**:
  393. * ``uint8``: yes; fully tested
  394. * ``uint16``: yes; tested
  395. * ``uint32``: no (1)
  396. * ``uint64``: no (2)
  397. * ``int8``: yes; tested (3)
  398. * ``int16``: yes; tested
  399. * ``int32``: no (4)
  400. * ``int64``: no (5)
  401. * ``float16``: yes; tested (6)
  402. * ``float32``: yes; tested
  403. * ``float64``: yes; tested
  404. * ``float128``: no
  405. * ``bool``: yes; tested (7)
  406. - (1) rejected by ``cv2.blur()``
  407. - (2) loss of resolution in ``cv2.blur()`` (result is ``int32``)
  408. - (3) ``int8`` is mapped internally to ``int16``, ``int8`` itself
  409. leads to cv2 error "Unsupported combination of source format
  410. (=1), and buffer format (=4) in function 'getRowSumFilter'" in
  411. ``cv2``
  412. - (4) results too inaccurate
  413. - (5) loss of resolution in ``cv2.blur()`` (result is ``int32``)
  414. - (6) ``float16`` is mapped internally to ``float32``
  415. - (7) ``bool`` is mapped internally to ``float32``
  416. Parameters
  417. ----------
  418. k : int or tuple of int or tuple of tuple of int or imgaug.parameters.StochasticParameter or tuple of StochasticParameter, optional
  419. Kernel size to use.
  420. * If a single ``int``, then that value will be used for the height
  421. and width of the kernel.
  422. * If a tuple of two ``int`` s ``(a, b)``, then the kernel size will
  423. be sampled from the interval ``[a..b]``.
  424. * If a tuple of two tuples of ``int`` s ``((a, b), (c, d))``,
  425. then per image a random kernel height will be sampled from the
  426. interval ``[a..b]`` and a random kernel width will be sampled
  427. from the interval ``[c..d]``.
  428. * If a ``StochasticParameter``, then ``N`` samples will be drawn
  429. from that parameter per ``N`` input images, each representing
  430. the kernel size for the n-th image.
  431. * If a tuple ``(a, b)``, where either ``a`` or ``b`` is a tuple,
  432. then ``a`` and ``b`` will be treated according to the rules
  433. above. This leads to different values for height and width of
  434. the kernel.
  435. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  436. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  437. name : None or str, optional
  438. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  439. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  440. Old name for parameter `seed`.
  441. Its usage will not yet cause a deprecation warning,
  442. but it is still recommended to use `seed` now.
  443. Outdated since 0.4.0.
  444. deterministic : bool, optional
  445. Deprecated since 0.4.0.
  446. See method ``to_deterministic()`` for an alternative and for
  447. details about what the "deterministic mode" actually does.
  448. Examples
  449. --------
  450. >>> import imgaug.augmenters as iaa
  451. >>> aug = iaa.AverageBlur(k=5)
  452. Blur all images using a kernel size of ``5x5``.
  453. >>> aug = iaa.AverageBlur(k=(2, 5))
  454. Blur images using a varying kernel size, which is sampled (per image)
  455. uniformly from the interval ``[2..5]``.
  456. >>> aug = iaa.AverageBlur(k=((5, 7), (1, 3)))
  457. Blur images using a varying kernel size, which's height is sampled
  458. (per image) uniformly from the interval ``[5..7]`` and which's width is
  459. sampled (per image) uniformly from ``[1..3]``.
  460. """
  461. def __init__(self, k=(1, 7),
  462. seed=None, name=None,
  463. random_state="deprecated", deterministic="deprecated"):
  464. super(AverageBlur, self).__init__(
  465. seed=seed, name=name,
  466. random_state=random_state, deterministic=deterministic)
  467. # TODO replace this by iap.handle_discrete_kernel_size()
  468. self.mode = "single"
  469. if ia.is_single_number(k):
  470. self.k = iap.Deterministic(int(k))
  471. elif ia.is_iterable(k):
  472. assert len(k) == 2, (
  473. "Expected iterable 'k' to contain exactly 2 entries, "
  474. "got %d." % (len(k),))
  475. if all([ia.is_single_number(ki) for ki in k]):
  476. self.k = iap.DiscreteUniform(int(k[0]), int(k[1]))
  477. elif all([isinstance(ki, iap.StochasticParameter) for ki in k]):
  478. self.mode = "two"
  479. self.k = (k[0], k[1])
  480. else:
  481. k_tuple = [None, None]
  482. if ia.is_single_number(k[0]):
  483. k_tuple[0] = iap.Deterministic(int(k[0]))
  484. elif (ia.is_iterable(k[0])
  485. and all([ia.is_single_number(ki) for ki in k[0]])):
  486. k_tuple[0] = iap.DiscreteUniform(int(k[0][0]),
  487. int(k[0][1]))
  488. else:
  489. raise Exception(
  490. "k[0] expected to be int or tuple of two ints, "
  491. "got %s" % (type(k[0]),))
  492. if ia.is_single_number(k[1]):
  493. k_tuple[1] = iap.Deterministic(int(k[1]))
  494. elif (ia.is_iterable(k[1])
  495. and all([ia.is_single_number(ki) for ki in k[1]])):
  496. k_tuple[1] = iap.DiscreteUniform(int(k[1][0]),
  497. int(k[1][1]))
  498. else:
  499. raise Exception(
  500. "k[1] expected to be int or tuple of two ints, "
  501. "got %s" % (type(k[1]),))
  502. self.mode = "two"
  503. self.k = k_tuple
  504. elif isinstance(k, iap.StochasticParameter):
  505. self.k = k
  506. else:
  507. raise Exception(
  508. "Expected int, tuple/list with 2 entries or "
  509. "StochasticParameter. Got %s." % (type(k),))
  510. # Added in 0.4.0.
  511. def _augment_batch_(self, batch, random_state, parents, hooks):
  512. if batch.images is None:
  513. return batch
  514. images = batch.images
  515. iadt.gate_dtypes(
  516. images,
  517. allowed=["bool",
  518. "uint8", "uint16", "int8", "int16",
  519. "float16", "float32", "float64"],
  520. disallowed=["uint32", "uint64", "uint128", "uint256",
  521. "int32", "int64", "int128", "int256",
  522. "float96", "float128", "float256"],
  523. augmenter=self)
  524. nb_images = len(images)
  525. if self.mode == "single":
  526. samples = self.k.draw_samples((nb_images,),
  527. random_state=random_state)
  528. samples = (samples, samples)
  529. else:
  530. rss = random_state.duplicate(2)
  531. samples = (
  532. self.k[0].draw_samples((nb_images,), random_state=rss[0]),
  533. self.k[1].draw_samples((nb_images,), random_state=rss[1]),
  534. )
  535. gen = enumerate(zip(images, samples[0], samples[1]))
  536. for i, (image, ksize_h, ksize_w) in gen:
  537. kernel_impossible = (ksize_h == 0 or ksize_w == 0)
  538. kernel_does_nothing = (ksize_h == 1 and ksize_w == 1)
  539. has_zero_sized_axes = (image.size == 0)
  540. if (not kernel_impossible and not kernel_does_nothing
  541. and not has_zero_sized_axes):
  542. input_dtype = image.dtype
  543. if image.dtype.name in ["bool", "float16"]:
  544. image = image.astype(np.float32, copy=False)
  545. elif image.dtype.name == "int8":
  546. image = image.astype(np.int16, copy=False)
  547. if image.ndim == 2 or image.shape[-1] <= 512:
  548. image_aug = cv2.blur(
  549. _normalize_cv2_input_arr_(image),
  550. (ksize_h, ksize_w))
  551. # cv2.blur() removes channel axis for single-channel images
  552. if image_aug.ndim == 2:
  553. image_aug = image_aug[..., np.newaxis]
  554. else:
  555. # TODO this is quite inefficient
  556. # handling more than 512 channels in cv2.blur()
  557. channels = [
  558. cv2.blur(
  559. _normalize_cv2_input_arr_(image[..., c]),
  560. (ksize_h, ksize_w))
  561. for c in sm.xrange(image.shape[-1])
  562. ]
  563. image_aug = np.stack(channels, axis=-1)
  564. if input_dtype.name == "bool":
  565. image_aug = image_aug > 0.5
  566. elif input_dtype.name in ["int8", "float16"]:
  567. image_aug = iadt.restore_dtypes_(image_aug, input_dtype)
  568. batch.images[i] = image_aug
  569. return batch
  570. def get_parameters(self):
  571. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  572. return [self.k]
  573. class MedianBlur(meta.Augmenter):
  574. """Blur an image by computing median values over neighbourhoods.
  575. Median blurring can be used to remove small dirt from images.
  576. At larger kernel sizes, its effects have some similarity with Superpixels.
  577. **Supported dtypes**:
  578. * ``uint8``: yes; fully tested
  579. * ``uint16``: ?
  580. * ``uint32``: ?
  581. * ``uint64``: ?
  582. * ``int8``: ?
  583. * ``int16``: ?
  584. * ``int32``: ?
  585. * ``int64``: ?
  586. * ``float16``: ?
  587. * ``float32``: ?
  588. * ``float64``: ?
  589. * ``float128``: ?
  590. * ``bool``: ?
  591. Parameters
  592. ----------
  593. k : int or tuple of int or list of int or imgaug.parameters.StochasticParameter, optional
  594. Kernel size.
  595. * If a single ``int``, then that value will be used for the
  596. height and width of the kernel. Must be an odd value.
  597. * If a tuple of two ints ``(a, b)``, then the kernel size will be
  598. an odd value sampled from the interval ``[a..b]``. ``a`` and
  599. ``b`` must both be odd values.
  600. * If a list, then a random value will be sampled from that list
  601. per image.
  602. * If a ``StochasticParameter``, then ``N`` samples will be drawn
  603. from that parameter per ``N`` input images, each representing
  604. the kernel size for the nth image. Expected to be discrete. If
  605. a sampled value is not odd, then that value will be increased
  606. by ``1``.
  607. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  608. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  609. name : None or str, optional
  610. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  611. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  612. Old name for parameter `seed`.
  613. Its usage will not yet cause a deprecation warning,
  614. but it is still recommended to use `seed` now.
  615. Outdated since 0.4.0.
  616. deterministic : bool, optional
  617. Deprecated since 0.4.0.
  618. See method ``to_deterministic()`` for an alternative and for
  619. details about what the "deterministic mode" actually does.
  620. Examples
  621. --------
  622. >>> import imgaug.augmenters as iaa
  623. >>> aug = iaa.MedianBlur(k=5)
  624. Blur all images using a kernel size of ``5x5``.
  625. >>> aug = iaa.MedianBlur(k=(3, 7))
  626. Blur images using varying kernel sizes, which are sampled uniformly from
  627. the interval ``[3..7]``. Only odd values will be sampled, i.e. ``3``
  628. or ``5`` or ``7``.
  629. """
  630. def __init__(self, k=(1, 7),
  631. seed=None, name=None,
  632. random_state="deprecated", deterministic="deprecated"):
  633. super(MedianBlur, self).__init__(
  634. seed=seed, name=name,
  635. random_state=random_state, deterministic=deterministic)
  636. # TODO replace this by iap.handle_discrete_kernel_size()
  637. self.k = iap.handle_discrete_param(
  638. k, "k", value_range=(1, None), tuple_to_uniform=True,
  639. list_to_choice=True, allow_floats=False)
  640. if ia.is_single_integer(k):
  641. assert k % 2 != 0, (
  642. "Expected k to be odd, got %d. Add or subtract 1." % (
  643. int(k),))
  644. elif ia.is_iterable(k):
  645. assert all([ki % 2 != 0 for ki in k]), (
  646. "Expected all values in iterable k to be odd, but at least "
  647. "one was not. Add or subtract 1 to/from that value.")
  648. # Added in 0.4.0.
  649. def _augment_batch_(self, batch, random_state, parents, hooks):
  650. if batch.images is None:
  651. return batch
  652. images = batch.images
  653. nb_images = len(images)
  654. samples = self.k.draw_samples((nb_images,), random_state=random_state)
  655. for i, (image, ksize) in enumerate(zip(images, samples)):
  656. has_zero_sized_axes = (image.size == 0)
  657. if ksize > 1 and not has_zero_sized_axes:
  658. ksize = ksize + 1 if ksize % 2 == 0 else ksize
  659. if image.ndim == 2 or image.shape[-1] <= 512:
  660. image_aug = cv2.medianBlur(
  661. _normalize_cv2_input_arr_(image), ksize)
  662. # cv2.medianBlur() removes channel axis for single-channel
  663. # images
  664. if image_aug.ndim == 2:
  665. image_aug = image_aug[..., np.newaxis]
  666. else:
  667. # TODO this is quite inefficient
  668. # handling more than 512 channels in cv2.medainBlur()
  669. channels = [
  670. cv2.medianBlur(
  671. _normalize_cv2_input_arr_(image[..., c]), ksize)
  672. for c in sm.xrange(image.shape[-1])
  673. ]
  674. image_aug = np.stack(channels, axis=-1)
  675. batch.images[i] = image_aug
  676. return batch
  677. def get_parameters(self):
  678. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  679. return [self.k]
  680. # TODO tests
  681. class BilateralBlur(meta.Augmenter):
  682. """Blur/Denoise an image using a bilateral filter.
  683. Bilateral filters blur homogenous and textured areas, while trying to
  684. preserve edges.
  685. See
  686. http://docs.opencv.org/2.4/modules/imgproc/doc/filtering.html#bilateralfilter
  687. for more information regarding the parameters.
  688. **Supported dtypes**:
  689. * ``uint8``: yes; not tested
  690. * ``uint16``: ?
  691. * ``uint32``: ?
  692. * ``uint64``: ?
  693. * ``int8``: ?
  694. * ``int16``: ?
  695. * ``int32``: ?
  696. * ``int64``: ?
  697. * ``float16``: ?
  698. * ``float32``: ?
  699. * ``float64``: ?
  700. * ``float128``: ?
  701. * ``bool``: ?
  702. Parameters
  703. ----------
  704. d : int or tuple of int or list of int or imgaug.parameters.StochasticParameter, optional
  705. Diameter of each pixel neighborhood with value range ``[1 .. inf)``.
  706. High values for `d` lead to significantly worse performance. Values
  707. equal or less than ``10`` seem to be good. Use ``<5`` for real-time
  708. applications.
  709. * If a single ``int``, then that value will be used for the
  710. diameter.
  711. * If a tuple of two ``int`` s ``(a, b)``, then the diameter will
  712. be a value sampled from the interval ``[a..b]``.
  713. * If a list, then a random value will be sampled from that list
  714. per image.
  715. * If a ``StochasticParameter``, then ``N`` samples will be drawn
  716. from that parameter per ``N`` input images, each representing
  717. the diameter for the n-th image. Expected to be discrete.
  718. sigma_color : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  719. Filter sigma in the color space with value range ``[1, inf)``. A
  720. large value of the parameter means that farther colors within the
  721. pixel neighborhood (see `sigma_space`) will be mixed together,
  722. resulting in larger areas of semi-equal color.
  723. * If a single ``int``, then that value will be used for the
  724. diameter.
  725. * If a tuple of two ``int`` s ``(a, b)``, then the diameter will
  726. be a value sampled from the interval ``[a, b]``.
  727. * If a list, then a random value will be sampled from that list
  728. per image.
  729. * If a ``StochasticParameter``, then ``N`` samples will be drawn
  730. from that parameter per ``N`` input images, each representing
  731. the diameter for the n-th image. Expected to be discrete.
  732. sigma_space : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  733. Filter sigma in the coordinate space with value range ``[1, inf)``. A
  734. large value of the parameter means that farther pixels will influence
  735. each other as long as their colors are close enough (see
  736. `sigma_color`).
  737. * If a single ``int``, then that value will be used for the
  738. diameter.
  739. * If a tuple of two ``int`` s ``(a, b)``, then the diameter will
  740. be a value sampled from the interval ``[a, b]``.
  741. * If a list, then a random value will be sampled from that list
  742. per image.
  743. * If a ``StochasticParameter``, then ``N`` samples will be drawn
  744. from that parameter per ``N`` input images, each representing
  745. the diameter for the n-th image. Expected to be discrete.
  746. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  747. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  748. name : None or str, optional
  749. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  750. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  751. Old name for parameter `seed`.
  752. Its usage will not yet cause a deprecation warning,
  753. but it is still recommended to use `seed` now.
  754. Outdated since 0.4.0.
  755. deterministic : bool, optional
  756. Deprecated since 0.4.0.
  757. See method ``to_deterministic()`` for an alternative and for
  758. details about what the "deterministic mode" actually does.
  759. Examples
  760. --------
  761. >>> import imgaug.augmenters as iaa
  762. >>> aug = iaa.BilateralBlur(
  763. >>> d=(3, 10), sigma_color=(10, 250), sigma_space=(10, 250))
  764. Blur all images using a bilateral filter with a `max distance` sampled
  765. uniformly from the interval ``[3, 10]`` and wide ranges for `sigma_color`
  766. and `sigma_space`.
  767. """
  768. def __init__(self, d=(1, 9), sigma_color=(10, 250), sigma_space=(10, 250),
  769. seed=None, name=None,
  770. random_state="deprecated", deterministic="deprecated"):
  771. # pylint: disable=invalid-name
  772. super(BilateralBlur, self).__init__(
  773. seed=seed, name=name,
  774. random_state=random_state, deterministic=deterministic)
  775. self.d = iap.handle_discrete_param(
  776. d, "d", value_range=(1, None), tuple_to_uniform=True,
  777. list_to_choice=True, allow_floats=False)
  778. self.sigma_color = iap.handle_continuous_param(
  779. sigma_color, "sigma_color", value_range=(1, None),
  780. tuple_to_uniform=True, list_to_choice=True)
  781. self.sigma_space = iap.handle_continuous_param(
  782. sigma_space, "sigma_space", value_range=(1, None),
  783. tuple_to_uniform=True, list_to_choice=True)
  784. # Added in 0.4.0.
  785. def _augment_batch_(self, batch, random_state, parents, hooks):
  786. # pylint: disable=invalid-name
  787. if batch.images is None:
  788. return batch
  789. images = batch.images
  790. # Make sure that all images have 3 channels
  791. assert all([image.shape[2] == 3 for image in images]), (
  792. "BilateralBlur can currently only be applied to images with 3 "
  793. "channels. Got channels: %s" % (
  794. [image.shape[2] for image in images],))
  795. nb_images = len(images)
  796. rss = random_state.duplicate(3)
  797. samples_d = self.d.draw_samples((nb_images,), random_state=rss[0])
  798. samples_sigma_color = self.sigma_color.draw_samples(
  799. (nb_images,), random_state=rss[1])
  800. samples_sigma_space = self.sigma_space.draw_samples(
  801. (nb_images,), random_state=rss[2])
  802. gen = enumerate(zip(images, samples_d, samples_sigma_color,
  803. samples_sigma_space))
  804. for i, (image, di, sigma_color_i, sigma_space_i) in gen:
  805. has_zero_sized_axes = (image.size == 0)
  806. if di != 1 and not has_zero_sized_axes:
  807. batch.images[i] = cv2.bilateralFilter(
  808. _normalize_cv2_input_arr_(image),
  809. di, sigma_color_i, sigma_space_i)
  810. return batch
  811. def get_parameters(self):
  812. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  813. return [self.d, self.sigma_color, self.sigma_space]
  814. # TODO add k sizing via float/percentage
  815. class MotionBlur(iaa_convolutional.Convolve):
  816. """Blur images in a way that fakes camera or object movements.
  817. **Supported dtypes**:
  818. See :class:`~imgaug.augmenters.convolutional.Convolve`.
  819. Parameters
  820. ----------
  821. k : int or tuple of int or list of int or imgaug.parameters.StochasticParameter, optional
  822. Kernel size to use.
  823. * If a single ``int``, then that value will be used for the height
  824. and width of the kernel.
  825. * If a tuple of two ``int`` s ``(a, b)``, then the kernel size
  826. will be sampled from the interval ``[a..b]``.
  827. * If a list, then a random value will be sampled from that list
  828. per image.
  829. * If a ``StochasticParameter``, then ``N`` samples will be drawn
  830. from that parameter per ``N`` input images, each representing
  831. the kernel size for the n-th image.
  832. angle : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  833. Angle of the motion blur in degrees (clockwise, relative to top center
  834. direction).
  835. * If a number, exactly that value will be used.
  836. * If a tuple ``(a, b)``, a random value from the interval
  837. ``[a, b]`` will be uniformly sampled per image.
  838. * If a list, then a random value will be sampled from that list
  839. per image.
  840. * If a ``StochasticParameter``, a value will be sampled from the
  841. parameter per image.
  842. direction : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  843. Forward/backward direction of the motion blur. Lower values towards
  844. ``-1.0`` will point the motion blur towards the back (with angle
  845. provided via `angle`). Higher values towards ``1.0`` will point the
  846. motion blur forward. A value of ``0.0`` leads to a uniformly (but
  847. still angled) motion blur.
  848. * If a number, exactly that value will be used.
  849. * If a tuple ``(a, b)``, a random value from the interval
  850. ``[a, b]`` will be uniformly sampled per image.
  851. * If a list, then a random value will be sampled from that list
  852. per image.
  853. * If a ``StochasticParameter``, a value will be sampled from the
  854. parameter per image.
  855. order : int or iterable of int or imgaug.ALL or imgaug.parameters.StochasticParameter, optional
  856. Interpolation order to use when rotating the kernel according to
  857. `angle`.
  858. See :func:`~imgaug.augmenters.geometric.Affine.__init__`.
  859. Recommended to be ``0`` or ``1``, with ``0`` being faster, but less
  860. continuous/smooth as `angle` is changed, particularly around multiple
  861. of ``45`` degrees.
  862. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  863. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  864. name : None or str, optional
  865. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  866. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  867. Old name for parameter `seed`.
  868. Its usage will not yet cause a deprecation warning,
  869. but it is still recommended to use `seed` now.
  870. Outdated since 0.4.0.
  871. deterministic : bool, optional
  872. Deprecated since 0.4.0.
  873. See method ``to_deterministic()`` for an alternative and for
  874. details about what the "deterministic mode" actually does.
  875. Examples
  876. --------
  877. >>> import imgaug.augmenters as iaa
  878. >>> aug = iaa.MotionBlur(k=15)
  879. Apply motion blur with a kernel size of ``15x15`` pixels to images.
  880. >>> aug = iaa.MotionBlur(k=15, angle=[-45, 45])
  881. Apply motion blur with a kernel size of ``15x15`` pixels and a blur angle
  882. of either ``-45`` or ``45`` degrees (randomly picked per image).
  883. """
  884. def __init__(self, k=(3, 7), angle=(0, 360), direction=(-1.0, 1.0), order=1,
  885. seed=None, name=None,
  886. random_state="deprecated", deterministic="deprecated"):
  887. # TODO allow (1, None) and set to identity matrix if k == 1
  888. k_param = iap.handle_discrete_param(
  889. k, "k", value_range=(3, None), tuple_to_uniform=True,
  890. list_to_choice=True, allow_floats=False)
  891. angle_param = iap.handle_continuous_param(
  892. angle, "angle", value_range=None, tuple_to_uniform=True,
  893. list_to_choice=True)
  894. direction_param = iap.handle_continuous_param(
  895. direction, "direction", value_range=(-1.0-1e-6, 1.0+1e-6),
  896. tuple_to_uniform=True, list_to_choice=True)
  897. matrix_gen = _MotionBlurMatrixGenerator(k_param, angle_param,
  898. direction_param, order)
  899. super(MotionBlur, self).__init__(
  900. matrix_gen,
  901. seed=seed, name=name,
  902. random_state=random_state, deterministic=deterministic)
  903. # Added in 0.4.0.
  904. class _MotionBlurMatrixGenerator(object):
  905. # Added in 0.4.0.
  906. def __init__(self, k, angle, direction, order):
  907. self.k = k
  908. self.angle = angle
  909. self.direction = direction
  910. self.order = order
  911. # Added in 0.4.0.
  912. def __call__(self, _image, nb_channels, random_state):
  913. # avoid cyclic import between blur and geometric
  914. from . import geometric as iaa_geometric
  915. # force discrete for k_sample via int() in case of stochastic
  916. # parameter
  917. k_sample = int(
  918. self.k.draw_sample(random_state=random_state))
  919. angle_sample = self.angle.draw_sample(
  920. random_state=random_state)
  921. direction_sample = self.direction.draw_sample(
  922. random_state=random_state)
  923. k_sample = k_sample if k_sample % 2 != 0 else k_sample + 1
  924. direction_sample = np.clip(direction_sample, -1.0, 1.0)
  925. direction_sample = (direction_sample + 1.0) / 2.0
  926. matrix = np.zeros((k_sample, k_sample), dtype=np.float32)
  927. matrix[:, k_sample//2] = np.linspace(
  928. float(direction_sample),
  929. 1.0 - float(direction_sample),
  930. num=k_sample)
  931. rot = iaa_geometric.Affine(rotate=angle_sample, order=self.order)
  932. matrix = (
  933. rot.augment_image(
  934. (matrix * 255).astype(np.uint8)
  935. ).astype(np.float32) / 255.0
  936. )
  937. return [matrix/np.sum(matrix)] * nb_channels
  938. # TODO add a per_channel flag?
  939. # TODO make spatial_radius a fraction of the input image size?
  940. class MeanShiftBlur(meta.Augmenter):
  941. """Apply a pyramidic mean shift filter to each image.
  942. See also :func:`blur_mean_shift_` for details.
  943. This augmenter expects input images of shape ``(H,W)`` or ``(H,W,1)``
  944. or ``(H,W,3)``.
  945. .. note::
  946. This augmenter is quite slow.
  947. Added in 0.4.0.
  948. **Supported dtypes**:
  949. See :func:`~imgaug.augmenters.blur.blur_mean_shift_`.
  950. Parameters
  951. ----------
  952. spatial_radius : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  953. Spatial radius for pixels that are assumed to be similar.
  954. * If ``number``: Exactly that value will be used for all images.
  955. * If ``tuple`` ``(a, b)``: A random value will be uniformly
  956. sampled per image from the interval ``[a, b)``.
  957. * If ``list``: A random value will be sampled from that ``list``
  958. per image.
  959. * If ``StochasticParameter``: The parameter will be queried once
  960. per batch for ``(N,)`` values with ``N`` denoting the number of
  961. images.
  962. color_radius : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  963. Color radius for pixels that are assumed to be similar.
  964. * If ``number``: Exactly that value will be used for all images.
  965. * If ``tuple`` ``(a, b)``: A random value will be uniformly
  966. sampled per image from the interval ``[a, b)``.
  967. * If ``list``: A random value will be sampled from that ``list``
  968. per image.
  969. * If ``StochasticParameter``: The parameter will be queried once
  970. per batch for ``(N,)`` values with ``N`` denoting the number of
  971. images.
  972. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  973. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  974. name : None or str, optional
  975. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  976. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  977. Old name for parameter `seed`.
  978. Its usage will not yet cause a deprecation warning,
  979. but it is still recommended to use `seed` now.
  980. Outdated since 0.4.0.
  981. deterministic : bool, optional
  982. Deprecated since 0.4.0.
  983. See method ``to_deterministic()`` for an alternative and for
  984. details about what the "deterministic mode" actually does.
  985. Examples
  986. --------
  987. >>> import imgaug.augmenters as iaa
  988. >>> aug = iaa.MeanShiftBlur()
  989. Create a mean shift blur augmenter.
  990. """
  991. # Added in 0.4.0.
  992. def __init__(self, spatial_radius=(5.0, 40.0), color_radius=(5.0, 40.0),
  993. seed=None, name=None,
  994. random_state="deprecated", deterministic="deprecated"):
  995. super(MeanShiftBlur, self).__init__(
  996. seed=seed, name=name,
  997. random_state=random_state, deterministic=deterministic)
  998. self.spatial_window_radius = iap.handle_continuous_param(
  999. spatial_radius, "spatial_radius",
  1000. value_range=(0.01, None), tuple_to_uniform=True,
  1001. list_to_choice=True)
  1002. self.color_window_radius = iap.handle_continuous_param(
  1003. color_radius, "color_radius",
  1004. value_range=(0.01, None), tuple_to_uniform=True,
  1005. list_to_choice=True)
  1006. # Added in 0.4.0.
  1007. def _augment_batch_(self, batch, random_state, parents, hooks):
  1008. if batch.images is not None:
  1009. samples = self._draw_samples(batch, random_state)
  1010. for i, image in enumerate(batch.images):
  1011. batch.images[i] = blur_mean_shift_(
  1012. image,
  1013. spatial_window_radius=samples[0][i],
  1014. color_window_radius=samples[1][i]
  1015. )
  1016. return batch
  1017. # Added in 0.4.0.
  1018. def _draw_samples(self, batch, random_state):
  1019. nb_rows = batch.nb_rows
  1020. return (
  1021. self.spatial_window_radius.draw_samples((nb_rows,),
  1022. random_state=random_state),
  1023. self.color_window_radius.draw_samples((nb_rows,),
  1024. random_state=random_state)
  1025. )
  1026. # Added in 0.4.0.
  1027. def get_parameters(self):
  1028. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  1029. return [self.spatial_window_radius, self.color_window_radius]