imgaug.py 80 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497
  1. """Collection of basic functions used throughout imgaug."""
  2. from __future__ import print_function, division, absolute_import
  3. import math
  4. import numbers
  5. import sys
  6. import os
  7. import json
  8. import types
  9. import functools
  10. # collections.abc exists since 3.3 and is expected to be used for 3.8+
  11. try:
  12. from collections.abc import Iterable
  13. except ImportError:
  14. from collections import Iterable
  15. import numpy as np
  16. import cv2
  17. import imageio
  18. import six
  19. import six.moves as sm
  20. import skimage.draw
  21. import skimage.measure
  22. ALL = "ALL"
  23. FILE_DIR = os.path.dirname(os.path.abspath(__file__))
  24. # filepath to the quokka image, its annotations and depth map
  25. QUOKKA_FP = os.path.join(FILE_DIR, "quokka.jpg")
  26. QUOKKA_ANNOTATIONS_FP = os.path.join(FILE_DIR, "quokka_annotations.json")
  27. QUOKKA_DEPTH_MAP_HALFRES_FP = os.path.join(
  28. FILE_DIR, "quokka_depth_map_halfres.png")
  29. DEFAULT_FONT_FP = os.path.join(
  30. os.path.dirname(os.path.abspath(__file__)),
  31. "DejaVuSans.ttf"
  32. )
  33. # to check if a dtype instance is among these dtypes, use e.g.
  34. # `dtype.type in NP_FLOAT_TYPES` do not just use `dtype in NP_FLOAT_TYPES` as
  35. # that would fail
  36. NP_FLOAT_TYPES = set(np.sctypes["float"])
  37. NP_INT_TYPES = set(np.sctypes["int"])
  38. NP_UINT_TYPES = set(np.sctypes["uint"])
  39. IMSHOW_BACKEND_DEFAULT = "matplotlib"
  40. IMRESIZE_VALID_INTERPOLATIONS = [
  41. "nearest", "linear", "area", "cubic",
  42. cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_AREA, cv2.INTER_CUBIC]
  43. ###############################################################################
  44. # Helpers for deprecation
  45. ###############################################################################
  46. class DeprecationWarning(Warning): # pylint: disable=redefined-builtin
  47. """Warning for deprecated calls.
  48. Since python 2.7 DeprecatedWarning is silent by default. So we define
  49. our own DeprecatedWarning here so that it is not silent by default.
  50. """
  51. def warn(msg, category=UserWarning, stacklevel=2):
  52. """Generate a a warning with stacktrace.
  53. Parameters
  54. ----------
  55. msg : str
  56. The message of the warning.
  57. category : class
  58. The class of the warning to produce.
  59. stacklevel : int, optional
  60. How many steps above this function to "jump" in the stacktrace when
  61. displaying file and line number of the error message.
  62. Usually ``2``.
  63. """
  64. import warnings
  65. warnings.warn(msg, category=category, stacklevel=stacklevel)
  66. def warn_deprecated(msg, stacklevel=2):
  67. """Generate a non-silent deprecation warning with stacktrace.
  68. The used warning is ``imgaug.imgaug.DeprecationWarning``.
  69. Parameters
  70. ----------
  71. msg : str
  72. The message of the warning.
  73. stacklevel : int, optional
  74. How many steps above this function to "jump" in the stacktrace when
  75. displaying file and line number of the error message.
  76. Usually ``2``
  77. """
  78. warn(msg, category=DeprecationWarning, stacklevel=stacklevel)
  79. class deprecated(object): # pylint: disable=invalid-name
  80. """Decorator to mark deprecated functions with warning.
  81. Adapted from
  82. <https://github.com/scikit-image/scikit-image/blob/master/skimage/_shared/utils.py>.
  83. Parameters
  84. ----------
  85. alt_func : None or str, optional
  86. If given, tell user what function to use instead.
  87. behavior : {'warn', 'raise'}, optional
  88. Behavior during call to deprecated function: ``warn`` means that the
  89. user is warned that the function is deprecated; ``raise`` means that
  90. an error is raised.
  91. removed_version : None or str, optional
  92. The package version in which the deprecated function will be removed.
  93. comment : None or str, optional
  94. An optional comment that will be appended to the warning message.
  95. """
  96. def __init__(self, alt_func=None, behavior="warn", removed_version=None,
  97. comment=None):
  98. self.alt_func = alt_func
  99. self.behavior = behavior
  100. self.removed_version = removed_version
  101. self.comment = comment
  102. def __call__(self, func):
  103. alt_msg = None
  104. if self.alt_func is not None:
  105. alt_msg = "Use ``%s`` instead." % (self.alt_func,)
  106. rmv_msg = None
  107. if self.removed_version is not None:
  108. rmv_msg = "It will be removed in version %s." % (
  109. self.removed_version,)
  110. comment_msg = None
  111. if self.comment is not None and len(self.comment) > 0:
  112. comment_msg = "%s." % (self.comment.rstrip(". "),)
  113. addendum = " ".join([submsg
  114. for submsg
  115. in [alt_msg, rmv_msg, comment_msg]
  116. if submsg is not None])
  117. @functools.wraps(func)
  118. def wrapped(*args, **kwargs):
  119. # getargpec() is deprecated
  120. # pylint: disable=deprecated-method
  121. # TODO add class name if class method
  122. import inspect
  123. # arg_names = func.__code__.co_varnames
  124. # getargspec() was deprecated in py3, but doesn't exist in py2
  125. if hasattr(inspect, "getfullargspec"):
  126. arg_names = inspect.getfullargspec(func)[0]
  127. else:
  128. arg_names = inspect.getargspec(func)[0]
  129. if "self" in arg_names or "cls" in arg_names:
  130. main_msg = "Method ``%s.%s()`` is deprecated." % (
  131. args[0].__class__.__name__, func.__name__)
  132. else:
  133. main_msg = "Function ``%s()`` is deprecated." % (
  134. func.__name__,)
  135. msg = (main_msg + " " + addendum).rstrip(" ").replace("``", "`")
  136. if self.behavior == "warn":
  137. warn_deprecated(msg, stacklevel=3)
  138. elif self.behavior == "raise":
  139. raise DeprecationWarning(msg)
  140. return func(*args, **kwargs)
  141. # modify doc string to display deprecation warning
  142. doc = "**Deprecated**. " + addendum
  143. if wrapped.__doc__ is None:
  144. wrapped.__doc__ = doc
  145. else:
  146. wrapped.__doc__ = doc + "\n\n " + wrapped.__doc__
  147. return wrapped
  148. ###############################################################################
  149. def is_np_array(val):
  150. """Check whether a variable is a numpy array.
  151. Parameters
  152. ----------
  153. val
  154. The variable to check.
  155. Returns
  156. -------
  157. bool
  158. ``True`` if the variable is a numpy array. Otherwise ``False``.
  159. """
  160. # using np.generic here via isinstance(val, (np.ndarray, np.generic))
  161. # seems to also fire for scalar numpy values even though those are not
  162. # arrays
  163. return isinstance(val, np.ndarray)
  164. def is_np_scalar(val):
  165. """Check whether a variable is a numpy scalar.
  166. Parameters
  167. ----------
  168. val
  169. The variable to check.
  170. Returns
  171. -------
  172. bool
  173. ``True`` if the variable is a numpy scalar. Otherwise ``False``.
  174. """
  175. # Note that isscalar() alone also fires for thinks like python strings
  176. # or booleans.
  177. # The isscalar() was added to make this function not fire for non-scalar
  178. # numpy types. Not sure if it is necessary.
  179. return isinstance(val, np.generic) and np.isscalar(val)
  180. def is_single_integer(val):
  181. """Check whether a variable is an ``int``.
  182. Parameters
  183. ----------
  184. val
  185. The variable to check.
  186. Returns
  187. -------
  188. bool
  189. ``True`` if the variable is an ``int``. Otherwise ``False``.
  190. """
  191. return isinstance(val, numbers.Integral) and not isinstance(val, bool)
  192. def is_single_float(val):
  193. """Check whether a variable is a ``float``.
  194. Parameters
  195. ----------
  196. val
  197. The variable to check.
  198. Returns
  199. -------
  200. bool
  201. ``True`` if the variable is a ``float``. Otherwise ``False``.
  202. """
  203. return (
  204. isinstance(val, numbers.Real)
  205. and not is_single_integer(val)
  206. and not isinstance(val, bool)
  207. )
  208. def is_single_number(val):
  209. """Check whether a variable is a ``number``, i.e. an ``int`` or ``float``.
  210. Parameters
  211. ----------
  212. val
  213. The variable to check.
  214. Returns
  215. -------
  216. bool
  217. ``True`` if the variable is a ``number``. Otherwise ``False``.
  218. """
  219. return is_single_integer(val) or is_single_float(val)
  220. def is_iterable(val):
  221. """
  222. Checks whether a variable is iterable.
  223. Parameters
  224. ----------
  225. val
  226. The variable to check.
  227. Returns
  228. -------
  229. bool
  230. ``True`` if the variable is an iterable. Otherwise ``False``.
  231. """
  232. return isinstance(val, Iterable)
  233. # TODO convert to is_single_string() or rename is_single_integer/float/number()
  234. def is_string(val):
  235. """Check whether a variable is a string.
  236. Parameters
  237. ----------
  238. val
  239. The variable to check.
  240. Returns
  241. -------
  242. bool
  243. ``True`` if the variable is a string. Otherwise ``False``.
  244. """
  245. return isinstance(val, six.string_types)
  246. def is_single_bool(val):
  247. """Check whether a variable is a ``bool``.
  248. Parameters
  249. ----------
  250. val
  251. The variable to check.
  252. Returns
  253. -------
  254. bool
  255. ``True`` if the variable is a ``bool``. Otherwise ``False``.
  256. """
  257. # pylint: disable=unidiomatic-typecheck
  258. return type(val) == type(True)
  259. def is_integer_array(val):
  260. """Check whether a variable is a numpy integer array.
  261. Parameters
  262. ----------
  263. val
  264. The variable to check.
  265. Returns
  266. -------
  267. bool
  268. ``True`` if the variable is a numpy integer array. Otherwise ``False``.
  269. """
  270. return is_np_array(val) and issubclass(val.dtype.type, np.integer)
  271. def is_float_array(val):
  272. """Check whether a variable is a numpy float array.
  273. Parameters
  274. ----------
  275. val
  276. The variable to check.
  277. Returns
  278. -------
  279. bool
  280. ``True`` if the variable is a numpy float array. Otherwise ``False``.
  281. """
  282. return is_np_array(val) and issubclass(val.dtype.type, np.floating)
  283. def is_callable(val):
  284. """Check whether a variable is a callable, e.g. a function.
  285. Parameters
  286. ----------
  287. val
  288. The variable to check.
  289. Returns
  290. -------
  291. bool
  292. ``True`` if the variable is a callable. Otherwise ``False``.
  293. """
  294. # python 3.x with x <= 2 does not support callable(), apparently
  295. if sys.version_info[0] == 3 and sys.version_info[1] <= 2:
  296. return hasattr(val, '__call__')
  297. return callable(val)
  298. def is_generator(val):
  299. """Check whether a variable is a generator.
  300. Parameters
  301. ----------
  302. val
  303. The variable to check.
  304. Returns
  305. -------
  306. bool
  307. ``True`` is the variable is a generator. Otherwise ``False``.
  308. """
  309. return isinstance(val, types.GeneratorType)
  310. def flatten(nested_iterable):
  311. """Flatten arbitrarily nested lists/tuples.
  312. Code partially taken from https://stackoverflow.com/a/10824420.
  313. Parameters
  314. ----------
  315. nested_iterable
  316. A ``list`` or ``tuple`` of arbitrarily nested values.
  317. Yields
  318. ------
  319. any
  320. All values in `nested_iterable`, flattened.
  321. """
  322. # don't just check if something is iterable here, because then strings
  323. # and arrays will be split into their characters and components
  324. if not isinstance(nested_iterable, (list, tuple)):
  325. yield nested_iterable
  326. else:
  327. for i in nested_iterable:
  328. if isinstance(i, (list, tuple)):
  329. for j in flatten(i):
  330. yield j
  331. else:
  332. yield i
  333. # TODO no longer used anywhere. deprecate?
  334. def caller_name():
  335. """Return the name of the caller, e.g. a function.
  336. Returns
  337. -------
  338. str
  339. The name of the caller as a string
  340. """
  341. # pylint: disable=protected-access
  342. return sys._getframe(1).f_code.co_name
  343. def seed(entropy=None, seedval=None):
  344. """Set the seed of imgaug's global RNG.
  345. The global RNG controls most of the "randomness" in imgaug.
  346. The global RNG is the default one used by all augmenters. Under special
  347. circumstances (e.g. when an augmenter is switched to deterministic mode),
  348. the global RNG is replaced with a local one. The state of that replacement
  349. may be dependent on the global RNG's state at the time of creating the
  350. child RNG.
  351. .. note::
  352. This function is not yet marked as deprecated, but might be in the
  353. future. The preferred way to seed `imgaug` is via
  354. :func:`~imgaug.random.seed`.
  355. Parameters
  356. ----------
  357. entropy : int
  358. The seed value to use.
  359. seedval : None or int, optional
  360. Deprecated since 0.4.0.
  361. """
  362. assert entropy is not None or seedval is not None, (
  363. "Expected argument 'entropy' or 'seedval' to be not-None, but both"
  364. "were None.")
  365. if seedval is not None:
  366. assert entropy is None, (
  367. "Argument 'seedval' is the outdated name for 'entropy'. Hence, "
  368. "if it is provided, 'entropy' must be None. Got 'entropy' value "
  369. "of type %s." % (type(entropy),))
  370. warn_deprecated("Parameter 'seedval' is deprecated. Use "
  371. "'entropy' instead.")
  372. entropy = seedval
  373. import imgaug.random
  374. imgaug.random.seed(entropy)
  375. @deprecated("imgaug.random.normalize_generator")
  376. def normalize_random_state(random_state):
  377. """Normalize various inputs to a numpy random generator.
  378. Parameters
  379. ----------
  380. random_state : None or int or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.bit_generator.SeedSequence or numpy.random.RandomState
  381. See :func:`~imgaug.random.normalize_generator`.
  382. Returns
  383. -------
  384. numpy.random.Generator or numpy.random.RandomState
  385. In numpy <=1.16 a ``RandomState``, in 1.17+ a ``Generator`` (even if
  386. the input was a ``RandomState``).
  387. """
  388. import imgaug.random
  389. return imgaug.random.normalize_generator_(random_state)
  390. @deprecated("imgaug.random.get_global_rng")
  391. def current_random_state():
  392. """Get or create the current global RNG of imgaug.
  393. Note that the first call to this function will create a global RNG.
  394. Returns
  395. -------
  396. imgaug.random.RNG
  397. The global RNG to use.
  398. """
  399. import imgaug.random
  400. return imgaug.random.get_global_rng()
  401. @deprecated("imgaug.random.convert_seed_to_rng")
  402. def new_random_state(seed=None, fully_random=False):
  403. """Create a new numpy random number generator.
  404. Parameters
  405. ----------
  406. seed : None or int, optional
  407. The seed value to use. If ``None`` and `fully_random` is ``False``,
  408. the seed will be derived from the global RNG. If `fully_random` is
  409. ``True``, the seed will be provided by the OS.
  410. fully_random : bool, optional
  411. Whether the seed will be provided by the OS.
  412. Returns
  413. -------
  414. numpy.random.Generator or numpy.random.RandomState
  415. In numpy <=1.16 a ``RandomState``, in 1.17+ a ``Generator``.
  416. Both are initialized with the provided seed.
  417. """
  418. # pylint: disable=redefined-outer-name
  419. import imgaug.random
  420. if seed is None:
  421. if fully_random:
  422. return imgaug.random.RNG.create_fully_random()
  423. return imgaug.random.RNG.create_pseudo_random_()
  424. return imgaug.random.RNG(seed)
  425. # TODO seems to not be used anywhere anymore
  426. @deprecated("imgaug.random.convert_seed_to_rng")
  427. def dummy_random_state():
  428. """Create a dummy random state using a seed of ``1``.
  429. Returns
  430. -------
  431. imgaug.random.RNG
  432. The new random state.
  433. """
  434. import imgaug.random
  435. return imgaug.random.RNG(1)
  436. @deprecated("imgaug.random.copy_generator_unless_global_rng")
  437. def copy_random_state(random_state, force_copy=False):
  438. """Copy an existing numpy (random number) generator.
  439. Parameters
  440. ----------
  441. random_state : numpy.random.Generator or numpy.random.RandomState
  442. The generator to copy.
  443. force_copy : bool, optional
  444. If ``True``, this function will always create a copy of every random
  445. state. If ``False``, it will not copy numpy's default random state,
  446. but all other random states.
  447. Returns
  448. -------
  449. rs_copy : numpy.random.RandomState
  450. The copied random state.
  451. """
  452. import imgaug.random
  453. if force_copy:
  454. return imgaug.random.copy_generator(random_state)
  455. return imgaug.random.copy_generator_unless_global_generator(random_state)
  456. @deprecated("imgaug.random.derive_generator_")
  457. def derive_random_state(random_state):
  458. """Derive a child numpy random generator from another one.
  459. Parameters
  460. ----------
  461. random_state : numpy.random.Generator or numpy.random.RandomState
  462. The generator from which to derive a new child generator.
  463. Returns
  464. -------
  465. numpy.random.Generator or numpy.random.RandomState
  466. In numpy <=1.16 a ``RandomState``, in 1.17+ a ``Generator``.
  467. In both cases a derived child generator.
  468. """
  469. import imgaug.random
  470. return imgaug.random.derive_generator_(random_state)
  471. @deprecated("imgaug.random.derive_generators_")
  472. def derive_random_states(random_state, n=1):
  473. """Derive child numpy random generators from another one.
  474. Parameters
  475. ----------
  476. random_state : numpy.random.Generator or numpy.random.RandomState
  477. The generator from which to derive new child generators.
  478. n : int, optional
  479. Number of child generators to derive.
  480. Returns
  481. -------
  482. list of numpy.random.Generator or list of numpy.random.RandomState
  483. In numpy <=1.16 a ``list`` of ``RandomState`` s,
  484. in 1.17+ a ``list`` of ``Generator`` s.
  485. In both cases lists of derived child generators.
  486. """
  487. import imgaug.random
  488. return imgaug.random.derive_generators_(random_state, n=n)
  489. @deprecated("imgaug.random.advance_generator_")
  490. def forward_random_state(random_state):
  491. """Advance a numpy random generator's internal state.
  492. Parameters
  493. ----------
  494. random_state : numpy.random.Generator or numpy.random.RandomState
  495. Generator of which to advance the internal state.
  496. """
  497. import imgaug.random
  498. imgaug.random.advance_generator_(random_state)
  499. def _quokka_normalize_extract(extract):
  500. """Generate a normalized rectangle for the standard quokka image.
  501. Parameters
  502. ----------
  503. extract : 'square' or tuple of number or imgaug.augmentables.bbs.BoundingBox or imgaug.augmentables.bbs.BoundingBoxesOnImage
  504. Unnormalized representation of the image subarea to be extracted.
  505. * If ``str`` ``square``, then a squared area
  506. ``(x: 0 to max 643, y: 0 to max 643)`` will be extracted from
  507. the image.
  508. * If a ``tuple``, then expected to contain four ``number`` s
  509. denoting ``(x1, y1, x2, y2)``.
  510. * If a :class:`~imgaug.augmentables.bbs.BoundingBox`, then that
  511. bounding box's area will be extracted from the image.
  512. * If a :class:`~imgaug.augmentables.bbs.BoundingBoxesOnImage`,
  513. then expected to contain exactly one bounding box and a shape
  514. matching the full image dimensions (i.e. ``(643, 960, *)``).
  515. Then the one bounding box will be used similar to
  516. ``BoundingBox`` above.
  517. Returns
  518. -------
  519. imgaug.augmentables.bbs.BoundingBox
  520. Normalized representation of the area to extract from the standard
  521. quokka image.
  522. """
  523. # TODO get rid of this deferred import
  524. from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage
  525. if extract == "square":
  526. bb = BoundingBox(x1=0, y1=0, x2=643, y2=643)
  527. elif isinstance(extract, tuple) and len(extract) == 4:
  528. bb = BoundingBox(x1=extract[0], y1=extract[1],
  529. x2=extract[2], y2=extract[3])
  530. elif isinstance(extract, BoundingBox):
  531. bb = extract
  532. elif isinstance(extract, BoundingBoxesOnImage):
  533. assert len(extract.bounding_boxes) == 1, (
  534. "Provided BoundingBoxesOnImage instance may currently only "
  535. "contain a single bounding box.")
  536. assert extract.shape[0:2] == (643, 960), (
  537. "Expected BoundingBoxesOnImage instance on an image of shape "
  538. "(643, 960, ?). Got shape %s." % (extract.shape,))
  539. bb = extract.bounding_boxes[0]
  540. else:
  541. raise Exception(
  542. "Expected 'square' or tuple of four entries or BoundingBox or "
  543. "BoundingBoxesOnImage for parameter 'extract', "
  544. "got %s." % (type(extract),)
  545. )
  546. return bb
  547. # TODO is this the same as the project functions in augmentables?
  548. def _compute_resized_shape(from_shape, to_shape):
  549. """Compute the intended new shape of an image-like array after resizing.
  550. Parameters
  551. ----------
  552. from_shape : tuple or ndarray
  553. Old shape of the array. Usually expected to be a ``tuple`` of form
  554. ``(H, W)`` or ``(H, W, C)`` or alternatively an array with two or
  555. three dimensions.
  556. to_shape : None or tuple of ints or tuple of floats or int or float or ndarray
  557. New shape of the array.
  558. * If ``None``, then `from_shape` will be used as the new shape.
  559. * If an ``int`` ``V``, then the new shape will be ``(V, V, [C])``,
  560. where ``C`` will be added if it is part of `from_shape`.
  561. * If a ``float`` ``V``, then the new shape will be
  562. ``(H*V, W*V, [C])``, where ``H`` and ``W`` are the old
  563. height/width.
  564. * If a ``tuple`` ``(H', W', [C'])`` of ints, then ``H'`` and ``W'``
  565. will be used as the new height and width.
  566. * If a ``tuple`` ``(H', W', [C'])`` of floats (except ``C``), then
  567. ``H'`` and ``W'`` will be used as the new height and width.
  568. * If a numpy array, then the array's shape will be used.
  569. Returns
  570. -------
  571. tuple of int
  572. New shape.
  573. """
  574. if is_np_array(from_shape):
  575. from_shape = from_shape.shape
  576. if is_np_array(to_shape):
  577. to_shape = to_shape.shape
  578. to_shape_computed = list(from_shape)
  579. if to_shape is None:
  580. pass
  581. elif isinstance(to_shape, tuple):
  582. assert len(from_shape) in [2, 3]
  583. assert len(to_shape) in [2, 3]
  584. if len(from_shape) == 3 and len(to_shape) == 3:
  585. assert from_shape[2] == to_shape[2]
  586. elif len(to_shape) == 3:
  587. to_shape_computed.append(to_shape[2])
  588. is_to_s_valid_values = all(
  589. [v is None or is_single_number(v) for v in to_shape[0:2]])
  590. assert is_to_s_valid_values, (
  591. "Expected the first two entries in to_shape to be None or "
  592. "numbers, got types %s." % (
  593. str([type(v) for v in to_shape[0:2]]),))
  594. for i, from_shape_i in enumerate(from_shape[0:2]):
  595. if to_shape[i] is None:
  596. to_shape_computed[i] = from_shape_i
  597. elif is_single_integer(to_shape[i]):
  598. to_shape_computed[i] = to_shape[i]
  599. else: # float
  600. to_shape_computed[i] = int(np.round(from_shape_i * to_shape[i]))
  601. elif is_single_integer(to_shape) or is_single_float(to_shape):
  602. to_shape_computed = _compute_resized_shape(
  603. from_shape, (to_shape, to_shape))
  604. else:
  605. raise Exception(
  606. "Expected to_shape to be None or ndarray or tuple of floats or "
  607. "tuple of ints or single int or single float, "
  608. "got %s." % (type(to_shape),))
  609. return tuple(to_shape_computed)
  610. def quokka(size=None, extract=None):
  611. """Return an image of a quokka as a numpy array.
  612. Parameters
  613. ----------
  614. size : None or float or tuple of int, optional
  615. Size of the output image. Input into
  616. :func:`~imgaug.imgaug.imresize_single_image`. Usually expected to be a
  617. ``tuple`` ``(H, W)``, where ``H`` is the desired height and ``W`` is
  618. the width. If ``None``, then the image will not be resized.
  619. extract : None or 'square' or tuple of number or imgaug.augmentables.bbs.BoundingBox or imgaug.augmentables.bbs.BoundingBoxesOnImage
  620. Subarea of the quokka image to extract:
  621. * If ``None``, then the whole image will be used.
  622. * If ``str`` ``square``, then a squared area
  623. ``(x: 0 to max 643, y: 0 to max 643)`` will be extracted from
  624. the image.
  625. * If a ``tuple``, then expected to contain four ``number`` s
  626. denoting ``(x1, y1, x2, y2)``.
  627. * If a :class:`~imgaug.augmentables.bbs.BoundingBox`, then that
  628. bounding box's area will be extracted from the image.
  629. * If a :class:`~imgaug.augmentables.bbs.BoundingBoxesOnImage`,
  630. then expected to contain exactly one bounding box and a shape
  631. matching the full image dimensions (i.e. ``(643, 960, *)``).
  632. Then the one bounding box will be used similar to
  633. ``BoundingBox`` above.
  634. Returns
  635. -------
  636. (H,W,3) ndarray
  637. The image array of dtype ``uint8``.
  638. """
  639. img = imageio.imread(QUOKKA_FP, pilmode="RGB")
  640. if extract is not None:
  641. bb = _quokka_normalize_extract(extract)
  642. img = bb.extract_from_image(img)
  643. if size is not None:
  644. shape_resized = _compute_resized_shape(img.shape, size)
  645. img = imresize_single_image(img, shape_resized[0:2])
  646. return img
  647. def quokka_square(size=None):
  648. """Return an (square) image of a quokka as a numpy array.
  649. Parameters
  650. ----------
  651. size : None or float or tuple of int, optional
  652. Size of the output image. Input into
  653. :func:`~imgaug.imgaug.imresize_single_image`. Usually expected to be a
  654. ``tuple`` ``(H, W)``, where ``H`` is the desired height and ``W`` is
  655. the width. If ``None``, then the image will not be resized.
  656. Returns
  657. -------
  658. (H,W,3) ndarray
  659. The image array of dtype ``uint8``.
  660. """
  661. return quokka(size=size, extract="square")
  662. def quokka_heatmap(size=None, extract=None):
  663. """Return a heatmap (here: depth map) for the standard example quokka image.
  664. Parameters
  665. ----------
  666. size : None or float or tuple of int, optional
  667. See :func:`~imgaug.imgaug.quokka`.
  668. extract : None or 'square' or tuple of number or imgaug.augmentables.bbs.BoundingBox or imgaug.augmentables.bbs.BoundingBoxesOnImage
  669. See :func:`~imgaug.imgaug.quokka`.
  670. Returns
  671. -------
  672. imgaug.augmentables.heatmaps.HeatmapsOnImage
  673. Depth map as an heatmap object. Values close to ``0.0`` denote objects
  674. that are close to the camera. Values close to ``1.0`` denote objects
  675. that are furthest away (among all shown objects).
  676. """
  677. # TODO get rid of this deferred import
  678. from imgaug.augmentables.heatmaps import HeatmapsOnImage
  679. img = imageio.imread(QUOKKA_DEPTH_MAP_HALFRES_FP, pilmode="RGB")
  680. img = imresize_single_image(img, (643, 960), interpolation="cubic")
  681. if extract is not None:
  682. bb = _quokka_normalize_extract(extract)
  683. img = bb.extract_from_image(img)
  684. if size is None:
  685. size = img.shape[0:2]
  686. shape_resized = _compute_resized_shape(img.shape, size)
  687. img = imresize_single_image(img, shape_resized[0:2])
  688. img_0to1 = img[..., 0] # depth map was saved as 3-channel RGB
  689. img_0to1 = img_0to1.astype(np.float32) / 255.0
  690. img_0to1 = 1 - img_0to1 # depth map was saved as 0 being furthest away
  691. return HeatmapsOnImage(img_0to1, shape=img_0to1.shape[0:2] + (3,))
  692. def quokka_segmentation_map(size=None, extract=None):
  693. """Return a segmentation map for the standard example quokka image.
  694. Parameters
  695. ----------
  696. size : None or float or tuple of int, optional
  697. See :func:`~imgaug.imgaug.quokka`.
  698. extract : None or 'square' or tuple of number or imgaug.augmentables.bbs.BoundingBox or imgaug.augmentables.bbs.BoundingBoxesOnImage
  699. See :func:`~imgaug.imgaug.quokka`.
  700. Returns
  701. -------
  702. imgaug.augmentables.segmaps.SegmentationMapsOnImage
  703. Segmentation map object.
  704. """
  705. # pylint: disable=invalid-name
  706. # TODO get rid of this deferred import
  707. from imgaug.augmentables.segmaps import SegmentationMapsOnImage
  708. with open(QUOKKA_ANNOTATIONS_FP, "r") as f:
  709. json_dict = json.load(f)
  710. xx = []
  711. yy = []
  712. for kp_dict in json_dict["polygons"][0]["keypoints"]:
  713. x = kp_dict["x"]
  714. y = kp_dict["y"]
  715. xx.append(x)
  716. yy.append(y)
  717. img_seg = np.zeros((643, 960, 1), dtype=np.int32)
  718. rr, cc = skimage.draw.polygon(
  719. np.array(yy), np.array(xx), shape=img_seg.shape)
  720. img_seg[rr, cc, 0] = 1
  721. if extract is not None:
  722. bb = _quokka_normalize_extract(extract)
  723. img_seg = bb.extract_from_image(img_seg)
  724. segmap = SegmentationMapsOnImage(img_seg, shape=img_seg.shape[0:2] + (3,))
  725. if size is not None:
  726. shape_resized = _compute_resized_shape(img_seg.shape, size)
  727. segmap = segmap.resize(shape_resized[0:2])
  728. segmap.shape = tuple(shape_resized[0:2]) + (3,)
  729. return segmap
  730. def quokka_keypoints(size=None, extract=None):
  731. """Return example keypoints on the standard example quokke image.
  732. The keypoints cover the eyes, ears, nose and paws.
  733. Parameters
  734. ----------
  735. size : None or float or tuple of int or tuple of float, optional
  736. Size of the output image on which the keypoints are placed. If
  737. ``None``, then the keypoints are not projected to any new size
  738. (positions on the original image are used). ``float`` s lead to
  739. relative size changes, ``int`` s to absolute sizes in pixels.
  740. extract : None or 'square' or tuple of number or imgaug.augmentables.bbs.BoundingBox or imgaug.augmentables.bbs.BoundingBoxesOnImage
  741. Subarea to extract from the image. See :func:`~imgaug.imgaug.quokka`.
  742. Returns
  743. -------
  744. imgaug.augmentables.kps.KeypointsOnImage
  745. Example keypoints on the quokka image.
  746. """
  747. # TODO get rid of this deferred import
  748. from imgaug.augmentables.kps import Keypoint, KeypointsOnImage
  749. left, top = 0, 0
  750. if extract is not None:
  751. bb_extract = _quokka_normalize_extract(extract)
  752. left = bb_extract.x1
  753. top = bb_extract.y1
  754. with open(QUOKKA_ANNOTATIONS_FP, "r") as f:
  755. json_dict = json.load(f)
  756. keypoints = []
  757. for kp_dict in json_dict["keypoints"]:
  758. keypoints.append(Keypoint(x=kp_dict["x"] - left, y=kp_dict["y"] - top))
  759. if extract is not None:
  760. shape = (bb_extract.height, bb_extract.width, 3)
  761. else:
  762. shape = (643, 960, 3)
  763. kpsoi = KeypointsOnImage(keypoints, shape=shape)
  764. if size is not None:
  765. shape_resized = _compute_resized_shape(shape, size)
  766. kpsoi = kpsoi.on(shape_resized)
  767. return kpsoi
  768. def quokka_bounding_boxes(size=None, extract=None):
  769. """Return example bounding boxes on the standard example quokke image.
  770. Currently only a single bounding box is returned that covers the quokka.
  771. Parameters
  772. ----------
  773. size : None or float or tuple of int or tuple of float, optional
  774. Size of the output image on which the BBs are placed. If ``None``, then
  775. the BBs are not projected to any new size (positions on the original
  776. image are used). ``float`` s lead to relative size changes, ``int`` s
  777. to absolute sizes in pixels.
  778. extract : None or 'square' or tuple of number or imgaug.augmentables.bbs.BoundingBox or imgaug.augmentables.bbs.BoundingBoxesOnImage
  779. Subarea to extract from the image. See :func:`~imgaug.imgaug.quokka`.
  780. Returns
  781. -------
  782. imgaug.augmentables.bbs.BoundingBoxesOnImage
  783. Example BBs on the quokka image.
  784. """
  785. # TODO get rid of this deferred import
  786. from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage
  787. left, top = 0, 0
  788. if extract is not None:
  789. bb_extract = _quokka_normalize_extract(extract)
  790. left = bb_extract.x1
  791. top = bb_extract.y1
  792. with open(QUOKKA_ANNOTATIONS_FP, "r") as f:
  793. json_dict = json.load(f)
  794. bbs = []
  795. for bb_dict in json_dict["bounding_boxes"]:
  796. bbs.append(
  797. BoundingBox(
  798. x1=bb_dict["x1"] - left,
  799. y1=bb_dict["y1"] - top,
  800. x2=bb_dict["x2"] - left,
  801. y2=bb_dict["y2"] - top
  802. )
  803. )
  804. if extract is not None:
  805. shape = (bb_extract.height, bb_extract.width, 3)
  806. else:
  807. shape = (643, 960, 3)
  808. bbsoi = BoundingBoxesOnImage(bbs, shape=shape)
  809. if size is not None:
  810. shape_resized = _compute_resized_shape(shape, size)
  811. bbsoi = bbsoi.on(shape_resized)
  812. return bbsoi
  813. def quokka_polygons(size=None, extract=None):
  814. """
  815. Returns example polygons on the standard example quokke image.
  816. The result contains one polygon, covering the quokka's outline.
  817. Parameters
  818. ----------
  819. size : None or float or tuple of int or tuple of float, optional
  820. Size of the output image on which the polygons are placed. If ``None``,
  821. then the polygons are not projected to any new size (positions on the
  822. original image are used). ``float`` s lead to relative size changes,
  823. ``int`` s to absolute sizes in pixels.
  824. extract : None or 'square' or tuple of number or imgaug.augmentables.bbs.BoundingBox or imgaug.augmentables.bbs.BoundingBoxesOnImage
  825. Subarea to extract from the image. See :func:`~imgaug.imgaug.quokka`.
  826. Returns
  827. -------
  828. imgaug.augmentables.polys.PolygonsOnImage
  829. Example polygons on the quokka image.
  830. """
  831. # TODO get rid of this deferred import
  832. from imgaug.augmentables.polys import Polygon, PolygonsOnImage
  833. left, top = 0, 0
  834. if extract is not None:
  835. bb_extract = _quokka_normalize_extract(extract)
  836. left = bb_extract.x1
  837. top = bb_extract.y1
  838. with open(QUOKKA_ANNOTATIONS_FP, "r") as f:
  839. json_dict = json.load(f)
  840. polygons = []
  841. for poly_json in json_dict["polygons"]:
  842. polygons.append(
  843. Polygon([(point["x"] - left, point["y"] - top)
  844. for point in poly_json["keypoints"]])
  845. )
  846. if extract is not None:
  847. shape = (bb_extract.height, bb_extract.width, 3)
  848. else:
  849. shape = (643, 960, 3)
  850. psoi = PolygonsOnImage(polygons, shape=shape)
  851. if size is not None:
  852. shape_resized = _compute_resized_shape(shape, size)
  853. psoi = psoi.on(shape_resized)
  854. return psoi
  855. # TODO change this to some atan2 stuff?
  856. def angle_between_vectors(v1, v2):
  857. """Calculcate the angle in radians between vectors `v1` and `v2`.
  858. From
  859. http://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python
  860. Parameters
  861. ----------
  862. v1 : (N,) ndarray
  863. First vector.
  864. v2 : (N,) ndarray
  865. Second vector.
  866. Returns
  867. -------
  868. float
  869. Angle in radians.
  870. Examples
  871. --------
  872. >>> angle_between_vectors(np.float32([1, 0, 0]), np.float32([0, 1, 0]))
  873. 1.570796...
  874. >>> angle_between_vectors(np.float32([1, 0, 0]), np.float32([1, 0, 0]))
  875. 0.0
  876. >>> angle_between_vectors(np.float32([1, 0, 0]), np.float32([-1, 0, 0]))
  877. 3.141592...
  878. """
  879. # pylint: disable=invalid-name
  880. length1 = np.linalg.norm(v1)
  881. length2 = np.linalg.norm(v2)
  882. v1_unit = (v1 / length1) if length1 > 0 else np.float32(v1) * 0
  883. v2_unit = (v2 / length2) if length2 > 0 else np.float32(v2) * 0
  884. return np.arccos(np.clip(np.dot(v1_unit, v2_unit), -1.0, 1.0))
  885. # TODO is this used anywhere?
  886. # TODO this might also be covered by augmentables.utils or
  887. # augmentables.polys/lines
  888. def compute_line_intersection_point(x1, y1, x2, y2, x3, y3, x4, y4):
  889. """Compute the intersection point of two lines.
  890. Taken from https://stackoverflow.com/a/20679579 .
  891. Parameters
  892. ----------
  893. x1 : number
  894. x coordinate of the first point on line 1.
  895. (The lines extends beyond this point.)
  896. y1 : number
  897. y coordinate of the first point on line 1.
  898. (The lines extends beyond this point.)
  899. x2 : number
  900. x coordinate of the second point on line 1.
  901. (The lines extends beyond this point.)
  902. y2 : number
  903. y coordinate of the second point on line 1.
  904. (The lines extends beyond this point.)
  905. x3 : number
  906. x coordinate of the first point on line 2.
  907. (The lines extends beyond this point.)
  908. y3 : number
  909. y coordinate of the first point on line 2.
  910. (The lines extends beyond this point.)
  911. x4 : number
  912. x coordinate of the second point on line 2.
  913. (The lines extends beyond this point.)
  914. y4 : number
  915. y coordinate of the second point on line 2.
  916. (The lines extends beyond this point.)
  917. Returns
  918. -------
  919. tuple of number or bool
  920. The coordinate of the intersection point as a ``tuple`` ``(x, y)``.
  921. If the lines are parallel (no intersection point or an infinite number
  922. of them), the result is ``False``.
  923. """
  924. # pylint: disable=invalid-name
  925. def _make_line(point1, point2):
  926. line_y = (point1[1] - point2[1])
  927. line_x = (point2[0] - point1[0])
  928. slope = (point1[0] * point2[1] - point2[0] * point1[1])
  929. return line_y, line_x, -slope
  930. line1 = _make_line((x1, y1), (x2, y2))
  931. line2 = _make_line((x3, y3), (x4, y4))
  932. D = line1[0] * line2[1] - line1[1] * line2[0]
  933. Dx = line1[2] * line2[1] - line1[1] * line2[2]
  934. Dy = line1[0] * line2[2] - line1[2] * line2[0]
  935. if D != 0:
  936. x = Dx / D
  937. y = Dy / D
  938. return x, y
  939. return False
  940. # TODO replace by cv2.putText()?
  941. def draw_text(img, y, x, text, color=(0, 255, 0), size=25):
  942. """Draw text on an image.
  943. This uses by default DejaVuSans as its font, which is included in this
  944. library.
  945. **Supported dtypes**:
  946. * ``uint8``: yes; fully tested
  947. * ``uint16``: no
  948. * ``uint32``: no
  949. * ``uint64``: no
  950. * ``int8``: no
  951. * ``int16``: no
  952. * ``int32``: no
  953. * ``int64``: no
  954. * ``float16``: no
  955. * ``float32``: yes; not tested
  956. * ``float64``: no
  957. * ``float128``: no
  958. * ``bool``: no
  959. TODO check if other dtypes could be enabled
  960. Parameters
  961. ----------
  962. img : (H,W,3) ndarray
  963. The image array to draw text on.
  964. Expected to be of dtype ``uint8`` or ``float32`` (expected value
  965. range is ``[0.0, 255.0]``).
  966. y : int
  967. x-coordinate of the top left corner of the text.
  968. x : int
  969. y- coordinate of the top left corner of the text.
  970. text : str
  971. The text to draw.
  972. color : iterable of int, optional
  973. Color of the text to draw. For RGB-images this is expected to be an
  974. RGB color.
  975. size : int, optional
  976. Font size of the text to draw.
  977. Returns
  978. -------
  979. (H,W,3) ndarray
  980. Input image with text drawn on it.
  981. """
  982. from PIL import (
  983. Image as PIL_Image,
  984. ImageDraw as PIL_ImageDraw,
  985. ImageFont as PIL_ImageFont
  986. )
  987. assert img.dtype.name in ["uint8", "float32"], (
  988. "Can currently draw text only on images of dtype 'uint8' or "
  989. "'float32'. Got dtype %s." % (img.dtype.name,))
  990. input_dtype = img.dtype
  991. if img.dtype == np.float32:
  992. img = img.astype(np.uint8)
  993. img = PIL_Image.fromarray(img)
  994. font = PIL_ImageFont.truetype(DEFAULT_FONT_FP, size)
  995. context = PIL_ImageDraw.Draw(img)
  996. context.text((x, y), text, fill=tuple(color), font=font)
  997. img_np = np.asarray(img)
  998. # PIL/asarray returns read only array
  999. if not img_np.flags["WRITEABLE"]:
  1000. try:
  1001. # this seems to no longer work with np 1.16 (or was pillow
  1002. # updated?)
  1003. img_np.setflags(write=True)
  1004. except ValueError as ex:
  1005. if "cannot set WRITEABLE flag to True of this array" in str(ex):
  1006. img_np = np.copy(img_np)
  1007. if img_np.dtype != input_dtype:
  1008. img_np = img_np.astype(input_dtype)
  1009. return img_np
  1010. # TODO rename sizes to size?
  1011. def imresize_many_images(images, sizes=None, interpolation=None):
  1012. """Resize each image in a list or array to a specified size.
  1013. **Supported dtypes**:
  1014. * ``uint8``: yes; fully tested
  1015. * ``uint16``: yes; tested
  1016. * ``uint32``: no (1)
  1017. * ``uint64``: no (2)
  1018. * ``int8``: yes; tested (3)
  1019. * ``int16``: yes; tested
  1020. * ``int32``: limited; tested (4)
  1021. * ``int64``: no (2)
  1022. * ``float16``: yes; tested (5)
  1023. * ``float32``: yes; tested
  1024. * ``float64``: yes; tested
  1025. * ``float128``: no (1)
  1026. * ``bool``: yes; tested (6)
  1027. - (1) rejected by ``cv2.imresize``
  1028. - (2) results too inaccurate
  1029. - (3) mapped internally to ``int16`` when interpolation!="nearest"
  1030. - (4) only supported for interpolation="nearest", other interpolations
  1031. lead to cv2 error
  1032. - (5) mapped internally to ``float32``
  1033. - (6) mapped internally to ``uint8``
  1034. Parameters
  1035. ----------
  1036. images : (N,H,W,[C]) ndarray or list of (H,W,[C]) ndarray
  1037. Array of the images to resize.
  1038. Usually recommended to be of dtype ``uint8``.
  1039. sizes : float or iterable of int or iterable of float
  1040. The new size of the images, given either as a fraction (a single
  1041. float) or as a ``(height, width)`` ``tuple`` of two integers or as a
  1042. ``(height fraction, width fraction)`` ``tuple`` of two floats.
  1043. interpolation : None or str or int, optional
  1044. The interpolation to use during resize.
  1045. If ``int``, then expected to be one of:
  1046. * ``cv2.INTER_NEAREST`` (nearest neighbour interpolation)
  1047. * ``cv2.INTER_LINEAR`` (linear interpolation)
  1048. * ``cv2.INTER_AREA`` (area interpolation)
  1049. * ``cv2.INTER_CUBIC`` (cubic interpolation)
  1050. If ``str``, then expected to be one of:
  1051. * ``nearest`` (identical to ``cv2.INTER_NEAREST``)
  1052. * ``linear`` (identical to ``cv2.INTER_LINEAR``)
  1053. * ``area`` (identical to ``cv2.INTER_AREA``)
  1054. * ``cubic`` (identical to ``cv2.INTER_CUBIC``)
  1055. If ``None``, the interpolation will be chosen automatically. For size
  1056. increases, ``area`` interpolation will be picked and for size
  1057. decreases, ``linear`` interpolation will be picked.
  1058. Returns
  1059. -------
  1060. (N,H',W',[C]) ndarray
  1061. Array of the resized images.
  1062. Examples
  1063. --------
  1064. >>> import imgaug as ia
  1065. >>> images = np.zeros((2, 8, 16, 3), dtype=np.uint8)
  1066. >>> images_resized = ia.imresize_many_images(images, 2.0)
  1067. >>> images_resized.shape
  1068. (2, 16, 32, 3)
  1069. Convert two RGB images of height ``8`` and width ``16`` to images of
  1070. height ``2*8=16`` and width ``2*16=32``.
  1071. >>> images_resized = ia.imresize_many_images(images, (2.0, 4.0))
  1072. >>> images_resized.shape
  1073. (2, 16, 64, 3)
  1074. Convert two RGB images of height ``8`` and width ``16`` to images of
  1075. height ``2*8=16`` and width ``4*16=64``.
  1076. >>> images_resized = ia.imresize_many_images(images, (16, 32))
  1077. >>> images_resized.shape
  1078. (2, 16, 32, 3)
  1079. Converts two RGB images of height ``8`` and width ``16`` to images of
  1080. height ``16`` and width ``32``.
  1081. """
  1082. # pylint: disable=too-many-statements
  1083. # we just do nothing if the input contains zero images
  1084. # one could also argue that an exception would be appropriate here
  1085. if len(images) == 0:
  1086. return images
  1087. # verify that sizes contains only values >0
  1088. if is_single_number(sizes) and sizes <= 0:
  1089. raise ValueError(
  1090. "If 'sizes' is given as a single number, it is expected to "
  1091. "be >= 0, got %.8f." % (sizes,))
  1092. # change after the validation to make the above error messages match the
  1093. # original input
  1094. if is_single_number(sizes):
  1095. sizes = (sizes, sizes)
  1096. else:
  1097. assert len(sizes) == 2, (
  1098. "If 'sizes' is given as a tuple, it is expected be a tuple of two "
  1099. "entries, got %d entries." % (len(sizes),))
  1100. assert all([is_single_number(val) and val >= 0 for val in sizes]), (
  1101. "If 'sizes' is given as a tuple, it is expected be a tuple of two "
  1102. "ints or two floats, each >= 0, got types %s with values %s." % (
  1103. str([type(val) for val in sizes]), str(sizes)))
  1104. # if input is a list, call this function N times for N images
  1105. # but check beforehand if all images have the same shape, then just
  1106. # convert to a single array and de-convert afterwards
  1107. if isinstance(images, list):
  1108. nb_shapes = len({image.shape for image in images})
  1109. if nb_shapes == 1:
  1110. return list(imresize_many_images(
  1111. np.array(images), sizes=sizes, interpolation=interpolation))
  1112. return [
  1113. imresize_many_images(
  1114. image[np.newaxis, ...],
  1115. sizes=sizes,
  1116. interpolation=interpolation)[0, ...]
  1117. for image in images]
  1118. shape = images.shape
  1119. assert images.ndim in [3, 4], "Expected array of shape (N, H, W, [C]), " \
  1120. "got shape %s" % (str(shape),)
  1121. nb_images = shape[0]
  1122. height_image, width_image = shape[1], shape[2]
  1123. nb_channels = shape[3] if images.ndim > 3 else None
  1124. height_target, width_target = sizes[0], sizes[1]
  1125. height_target = (int(np.round(height_image * height_target))
  1126. if is_single_float(height_target)
  1127. else height_target)
  1128. width_target = (int(np.round(width_image * width_target))
  1129. if is_single_float(width_target)
  1130. else width_target)
  1131. if height_target == height_image and width_target == width_image:
  1132. return np.copy(images)
  1133. # return empty array if input array contains zero-sized axes
  1134. # note that None==0 is not True (for case nb_channels=None)
  1135. if 0 in [height_target, width_target, nb_channels]:
  1136. shape_out = tuple([shape[0], height_target, width_target]
  1137. + list(shape[3:]))
  1138. return np.zeros(shape_out, dtype=images.dtype)
  1139. # place this after the (h==h' and w==w') check so that images with
  1140. # zero-sized don't result in errors if the aren't actually resized
  1141. # verify that all input images have height/width > 0
  1142. has_zero_size_axes = any([axis == 0 for axis in images.shape[1:]])
  1143. assert not has_zero_size_axes, (
  1144. "Cannot resize images, because at least one image has a height and/or "
  1145. "width and/or number of channels of zero. "
  1146. "Observed shapes were: %s." % (
  1147. str([image.shape for image in images]),))
  1148. inter = interpolation
  1149. assert inter is None or inter in IMRESIZE_VALID_INTERPOLATIONS, (
  1150. "Expected 'interpolation' to be None or one of %s. Got %s." % (
  1151. ", ".join(
  1152. [str(valid_ip) for valid_ip in IMRESIZE_VALID_INTERPOLATIONS]
  1153. ),
  1154. str(inter)
  1155. )
  1156. )
  1157. if inter is None:
  1158. if height_target > height_image or width_target > width_image:
  1159. inter = cv2.INTER_AREA
  1160. else:
  1161. inter = cv2.INTER_LINEAR
  1162. elif inter in ["nearest", cv2.INTER_NEAREST]:
  1163. inter = cv2.INTER_NEAREST
  1164. elif inter in ["linear", cv2.INTER_LINEAR]:
  1165. inter = cv2.INTER_LINEAR
  1166. elif inter in ["area", cv2.INTER_AREA]:
  1167. inter = cv2.INTER_AREA
  1168. else: # if ip in ["cubic", cv2.INTER_CUBIC]:
  1169. inter = cv2.INTER_CUBIC
  1170. # TODO find more beautiful way to avoid circular imports
  1171. from . import dtypes as iadt
  1172. if inter == cv2.INTER_NEAREST:
  1173. iadt.gate_dtypes(
  1174. images,
  1175. allowed=["bool",
  1176. "uint8", "uint16",
  1177. "int8", "int16", "int32",
  1178. "float16", "float32", "float64"],
  1179. disallowed=["uint32", "uint64", "uint128", "uint256",
  1180. "int64", "int128", "int256",
  1181. "float96", "float128", "float256"],
  1182. augmenter=None)
  1183. else:
  1184. iadt.gate_dtypes(
  1185. images,
  1186. allowed=["bool",
  1187. "uint8", "uint16",
  1188. "int8", "int16",
  1189. "float16", "float32", "float64"],
  1190. disallowed=["uint32", "uint64", "uint128", "uint256",
  1191. "int32", "int64", "int128", "int256",
  1192. "float96", "float128", "float256"],
  1193. augmenter=None)
  1194. result_shape = (nb_images, height_target, width_target)
  1195. if nb_channels is not None:
  1196. result_shape = result_shape + (nb_channels,)
  1197. result = np.zeros(result_shape, dtype=images.dtype)
  1198. for i, image in enumerate(images):
  1199. input_dtype = image.dtype
  1200. input_dtype_name = input_dtype.name
  1201. if input_dtype_name == "bool":
  1202. image = image.astype(np.uint8) * 255
  1203. elif input_dtype_name == "int8" and inter != cv2.INTER_NEAREST:
  1204. image = image.astype(np.int16)
  1205. elif input_dtype_name == "float16":
  1206. image = image.astype(np.float32)
  1207. if nb_channels is not None and nb_channels > 512:
  1208. channels = [
  1209. cv2.resize(image[..., c], (width_target, height_target),
  1210. interpolation=inter) for c in sm.xrange(nb_channels)]
  1211. result_img = np.stack(channels, axis=-1)
  1212. else:
  1213. result_img = cv2.resize(
  1214. image, (width_target, height_target), interpolation=inter)
  1215. assert result_img.dtype.name == image.dtype.name, (
  1216. "Expected cv2.resize() to keep the input dtype '%s', but got "
  1217. "'%s'. This is an internal error. Please report." % (
  1218. image.dtype.name, result_img.dtype.name
  1219. )
  1220. )
  1221. # cv2 removes the channel axis if input was (H, W, 1)
  1222. # we re-add it (but only if input was not (H, W))
  1223. if (len(result_img.shape) == 2 and nb_channels is not None
  1224. and nb_channels == 1):
  1225. result_img = result_img[:, :, np.newaxis]
  1226. if input_dtype_name == "bool":
  1227. result_img = result_img > 127
  1228. elif input_dtype_name == "int8" and inter != cv2.INTER_NEAREST:
  1229. # TODO somehow better avoid circular imports here
  1230. from . import dtypes as iadt
  1231. result_img = iadt.restore_dtypes_(result_img, np.int8)
  1232. elif input_dtype_name == "float16":
  1233. # TODO see above
  1234. from . import dtypes as iadt
  1235. result_img = iadt.restore_dtypes_(result_img, np.float16)
  1236. result[i] = result_img
  1237. return result
  1238. def _assert_two_or_three_dims(shape):
  1239. if hasattr(shape, "shape"):
  1240. shape = shape.shape
  1241. assert len(shape) in [2, 3], (
  1242. "Expected image with two or three dimensions, but got %d dimensions "
  1243. "and shape %s." % (len(shape), shape))
  1244. def imresize_single_image(image, sizes, interpolation=None):
  1245. """Resize a single image.
  1246. **Supported dtypes**:
  1247. See :func:`~imgaug.imgaug.imresize_many_images`.
  1248. Parameters
  1249. ----------
  1250. image : (H,W,C) ndarray or (H,W) ndarray
  1251. Array of the image to resize.
  1252. Usually recommended to be of dtype ``uint8``.
  1253. sizes : float or iterable of int or iterable of float
  1254. See :func:`~imgaug.imgaug.imresize_many_images`.
  1255. interpolation : None or str or int, optional
  1256. See :func:`~imgaug.imgaug.imresize_many_images`.
  1257. Returns
  1258. -------
  1259. (H',W',C) ndarray or (H',W') ndarray
  1260. The resized image.
  1261. """
  1262. _assert_two_or_three_dims(image)
  1263. grayscale = False
  1264. if image.ndim == 2:
  1265. grayscale = True
  1266. image = image[:, :, np.newaxis]
  1267. rs = imresize_many_images(
  1268. image[np.newaxis, :, :, :], sizes, interpolation=interpolation)
  1269. if grayscale:
  1270. return rs[0, :, :, 0]
  1271. return rs[0, ...]
  1272. def pool(arr, block_size, func, pad_mode="constant", pad_cval=0,
  1273. preserve_dtype=True, cval=None):
  1274. """Resize an array by pooling values within blocks.
  1275. **Supported dtypes**:
  1276. * ``uint8``: yes; fully tested
  1277. * ``uint16``: yes; tested
  1278. * ``uint32``: yes; tested (2)
  1279. * ``uint64``: no (1)
  1280. * ``int8``: yes; tested
  1281. * ``int16``: yes; tested
  1282. * ``int32``: yes; tested (2)
  1283. * ``int64``: no (1)
  1284. * ``float16``: yes; tested
  1285. * ``float32``: yes; tested
  1286. * ``float64``: yes; tested
  1287. * ``float128``: yes; tested (2)
  1288. * ``bool``: yes; tested
  1289. - (1) results too inaccurate (at least when using np.average as func)
  1290. - (2) Note that scikit-image documentation says that the wrapped
  1291. pooling function converts inputs to ``float64``. Actual tests
  1292. showed no indication of that happening (at least when using
  1293. preserve_dtype=True).
  1294. Parameters
  1295. ----------
  1296. arr : (H,W) ndarray or (H,W,C) ndarray
  1297. Image-like array to pool. Ideally of datatype ``float64``.
  1298. block_size : int or tuple of int
  1299. Spatial size of each group of values to pool, aka kernel size.
  1300. * If a single ``int``, then a symmetric block of that size along
  1301. height and width will be used.
  1302. * If a ``tuple`` of two values, it is assumed to be the block size
  1303. along height and width of the image-like, with pooling happening
  1304. per channel.
  1305. * If a ``tuple`` of three values, it is assumed to be the block size
  1306. along height, width and channels.
  1307. func : callable
  1308. Function to apply to a given block in order to convert it to a single
  1309. number, e.g. :func:`numpy.average`, :func:`numpy.min`,
  1310. :func:`numpy.max`.
  1311. pad_mode : str, optional
  1312. Padding mode to use if the array cannot be divided by `block_size`
  1313. without remainder. See :func:`~imgaug.imgaug.pad` for details.
  1314. pad_cval : number, optional
  1315. Value to use for padding if `mode` is ``constant``.
  1316. See :func:`numpy.pad` for details.
  1317. preserve_dtype : bool, optional
  1318. Whether to convert the array back to the input datatype if it is
  1319. changed away from that in the pooling process.
  1320. cval : None or number, optional
  1321. Deprecated. Old name for `pad_cval`.
  1322. Returns
  1323. -------
  1324. (H',W') ndarray or (H',W',C') ndarray
  1325. Array after pooling.
  1326. """
  1327. # TODO find better way to avoid circular import
  1328. from . import dtypes as iadt
  1329. from .augmenters import size as iasize
  1330. if arr.size == 0:
  1331. return np.copy(arr)
  1332. iadt.gate_dtypes(arr,
  1333. allowed=["bool",
  1334. "uint8", "uint16", "uint32",
  1335. "int8", "int16", "int32",
  1336. "float16", "float32", "float64", "float128"],
  1337. disallowed=["uint64", "uint128", "uint256",
  1338. "int64", "int128", "int256",
  1339. "float256"],
  1340. augmenter=None)
  1341. if cval is not None:
  1342. warn_deprecated("`cval` is a deprecated argument in pool(). "
  1343. "Use `pad_cval` instead.")
  1344. pad_cval = cval
  1345. _assert_two_or_three_dims(arr)
  1346. is_valid_int = is_single_integer(block_size) and block_size >= 1
  1347. is_valid_tuple = is_iterable(block_size) and len(block_size) in [2, 3] \
  1348. and [is_single_integer(val) and val >= 1 for val in block_size]
  1349. assert is_valid_int or is_valid_tuple, (
  1350. "Expected argument 'block_size' to be a single integer >0 or "
  1351. "a tuple of 2 or 3 values with each one being >0. Got %s." % (
  1352. str(block_size)))
  1353. if is_single_integer(block_size):
  1354. block_size = [block_size, block_size]
  1355. if len(block_size) < arr.ndim:
  1356. block_size = list(block_size) + [1]
  1357. # We use custom padding here instead of the one from block_reduce(),
  1358. # because (1) it is expected to be faster and (2) it allows us more
  1359. # flexibility wrt to padding modes.
  1360. arr = iasize.pad_to_multiples_of(
  1361. arr,
  1362. height_multiple=block_size[0],
  1363. width_multiple=block_size[1],
  1364. mode=pad_mode,
  1365. cval=pad_cval
  1366. )
  1367. input_dtype = arr.dtype
  1368. arr_reduced = skimage.measure.block_reduce(arr, tuple(block_size), func,
  1369. cval=cval)
  1370. if preserve_dtype and arr_reduced.dtype.name != input_dtype.name:
  1371. arr_reduced = arr_reduced.astype(input_dtype)
  1372. return arr_reduced
  1373. # TODO does OpenCV have a faster avg pooling method?
  1374. def avg_pool(arr, block_size, pad_mode="reflect", pad_cval=128,
  1375. preserve_dtype=True, cval=None):
  1376. """Resize an array using average pooling.
  1377. Defaults to ``pad_mode="reflect"`` to ensure that padded values do not
  1378. affect the average.
  1379. **Supported dtypes**:
  1380. See :func:`~imgaug.imgaug.pool`.
  1381. Parameters
  1382. ----------
  1383. arr : (H,W) ndarray or (H,W,C) ndarray
  1384. Image-like array to pool.
  1385. See :func:`~imgaug.imgaug.pool` for details.
  1386. block_size : int or tuple of int or tuple of int
  1387. Size of each block of values to pool.
  1388. See :func:`~imgaug.imgaug.pool` for details.
  1389. pad_mode : str, optional
  1390. Padding mode to use if the array cannot be divided by `block_size`
  1391. without remainder.
  1392. See :func:`~imgaug.imgaug.pad` for details.
  1393. pad_cval : number, optional
  1394. Padding value.
  1395. See :func:`~imgaug.imgaug.pool` for details.
  1396. preserve_dtype : bool, optional
  1397. Whether to preserve the input array dtype.
  1398. See :func:`~imgaug.imgaug.pool` for details.
  1399. cval : None or number, optional
  1400. Deprecated. Old name for `pad_cval`.
  1401. Returns
  1402. -------
  1403. (H',W') ndarray or (H',W',C') ndarray
  1404. Array after average pooling.
  1405. """
  1406. return pool(arr, block_size, np.average, pad_mode=pad_mode,
  1407. pad_cval=pad_cval, preserve_dtype=preserve_dtype, cval=cval)
  1408. def max_pool(arr, block_size, pad_mode="edge", pad_cval=0,
  1409. preserve_dtype=True, cval=None):
  1410. """Resize an array using max-pooling.
  1411. Defaults to ``pad_mode="edge"`` to ensure that padded values do not affect
  1412. the maximum, even if the dtype was something else than ``uint8``.
  1413. **Supported dtypes**:
  1414. See :func:`~imgaug.imgaug.pool`.
  1415. Parameters
  1416. ----------
  1417. arr : (H,W) ndarray or (H,W,C) ndarray
  1418. Image-like array to pool.
  1419. See :func:`~imgaug.imgaug.pool` for details.
  1420. block_size : int or tuple of int or tuple of int
  1421. Size of each block of values to pool.
  1422. See :func:`~imgaug.imgaug.pool` for details.
  1423. pad_mode : str, optional
  1424. Padding mode to use if the array cannot be divided by `block_size`
  1425. without remainder.
  1426. See :func:`~imgaug.imgaug.pad` for details.
  1427. pad_cval : number, optional
  1428. Padding value.
  1429. See :func:`~imgaug.imgaug.pool` for details.
  1430. preserve_dtype : bool, optional
  1431. Whether to preserve the input array dtype.
  1432. See :func:`~imgaug.imgaug.pool` for details.
  1433. cval : None or number, optional
  1434. Deprecated. Old name for `pad_cval`.
  1435. Returns
  1436. -------
  1437. (H',W') ndarray or (H',W',C') ndarray
  1438. Array after max-pooling.
  1439. """
  1440. return pool(arr, block_size, np.max, pad_mode=pad_mode,
  1441. pad_cval=pad_cval, preserve_dtype=preserve_dtype, cval=cval)
  1442. def min_pool(arr, block_size, pad_mode="edge", pad_cval=255,
  1443. preserve_dtype=True):
  1444. """Resize an array using min-pooling.
  1445. Defaults to ``pad_mode="edge"`` to ensure that padded values do not affect
  1446. the minimum, even if the dtype was something else than ``uint8``.
  1447. **Supported dtypes**:
  1448. See :func:`~imgaug.imgaug.pool`.
  1449. Parameters
  1450. ----------
  1451. arr : (H,W) ndarray or (H,W,C) ndarray
  1452. Image-like array to pool.
  1453. See :func:`~imgaug.imgaug.pool` for details.
  1454. block_size : int or tuple of int or tuple of int
  1455. Size of each block of values to pool.
  1456. See :func:`~imgaug.imgaug.pool` for details.
  1457. pad_mode : str, optional
  1458. Padding mode to use if the array cannot be divided by `block_size`
  1459. without remainder.
  1460. See :func:`~imgaug.imgaug.pad` for details.
  1461. pad_cval : number, optional
  1462. Padding value.
  1463. See :func:`~imgaug.imgaug.pool` for details.
  1464. preserve_dtype : bool, optional
  1465. Whether to preserve the input array dtype.
  1466. See :func:`~imgaug.imgaug.pool` for details.
  1467. Returns
  1468. -------
  1469. (H',W') ndarray or (H',W',C') ndarray
  1470. Array after min-pooling.
  1471. """
  1472. return pool(arr, block_size, np.min, pad_mode=pad_mode, pad_cval=pad_cval,
  1473. preserve_dtype=preserve_dtype)
  1474. def median_pool(arr, block_size, pad_mode="reflect", pad_cval=128,
  1475. preserve_dtype=True):
  1476. """Resize an array using median-pooling.
  1477. Defaults to ``pad_mode="reflect"`` to ensure that padded values do not
  1478. affect the average.
  1479. **Supported dtypes**:
  1480. See :func:`~imgaug.imgaug.pool`.
  1481. Parameters
  1482. ----------
  1483. arr : (H,W) ndarray or (H,W,C) ndarray
  1484. Image-like array to pool.
  1485. See :func:`~imgaug.imgaug.pool` for details.
  1486. block_size : int or tuple of int or tuple of int
  1487. Size of each block of values to pool.
  1488. See :func:`~imgaug.imgaug.pool` for details.
  1489. pad_mode : str, optional
  1490. Padding mode to use if the array cannot be divided by `block_size`
  1491. without remainder.
  1492. See :func:`~imgaug.imgaug.pad` for details.
  1493. pad_cval : number, optional
  1494. Padding value.
  1495. See :func:`~imgaug.imgaug.pool` for details.
  1496. preserve_dtype : bool, optional
  1497. Whether to preserve the input array dtype.
  1498. See :func:`~imgaug.imgaug.pool` for details.
  1499. Returns
  1500. -------
  1501. (H',W') ndarray or (H',W',C') ndarray
  1502. Array after min-pooling.
  1503. """
  1504. return pool(arr, block_size, np.median, pad_mode=pad_mode,
  1505. pad_cval=pad_cval, preserve_dtype=preserve_dtype)
  1506. def draw_grid(images, rows=None, cols=None):
  1507. """Combine multiple images into a single grid-like image.
  1508. Calling this function with four images of the same shape and ``rows=2``,
  1509. ``cols=2`` will combine the four images to a single image array of shape
  1510. ``(2*H, 2*W, C)``, where ``H`` is the height of any of the images
  1511. (analogous ``W``) and ``C`` is the number of channels of any image.
  1512. Calling this function with four images of the same shape and ``rows=4``,
  1513. ``cols=1`` is analogous to calling :func:`numpy.vstack` on the images.
  1514. **Supported dtypes**:
  1515. * ``uint8``: yes; fully tested
  1516. * ``uint16``: yes; fully tested
  1517. * ``uint32``: yes; fully tested
  1518. * ``uint64``: yes; fully tested
  1519. * ``int8``: yes; fully tested
  1520. * ``int16``: yes; fully tested
  1521. * ``int32``: yes; fully tested
  1522. * ``int64``: yes; fully tested
  1523. * ``float16``: yes; fully tested
  1524. * ``float32``: yes; fully tested
  1525. * ``float64``: yes; fully tested
  1526. * ``float128``: yes; fully tested
  1527. * ``bool``: yes; fully tested
  1528. Parameters
  1529. ----------
  1530. images : (N,H,W,3) ndarray or iterable of (H,W,3) array
  1531. The input images to convert to a grid.
  1532. rows : None or int, optional
  1533. The number of rows to show in the grid.
  1534. If ``None``, it will be automatically derived.
  1535. cols : None or int, optional
  1536. The number of cols to show in the grid.
  1537. If ``None``, it will be automatically derived.
  1538. Returns
  1539. -------
  1540. (H',W',3) ndarray
  1541. Image of the generated grid.
  1542. """
  1543. nb_images = len(images)
  1544. assert nb_images > 0, "Expected to get at least one image, got none."
  1545. if is_np_array(images):
  1546. assert images.ndim == 4, (
  1547. "Expected to get an array of four dimensions denoting "
  1548. "(N, H, W, C), got %d dimensions and shape %s." % (
  1549. images.ndim, images.shape))
  1550. else:
  1551. assert is_iterable(images), (
  1552. "Expected to get an iterable of ndarrays, "
  1553. "got %s." % (type(images),))
  1554. assert all([is_np_array(image) for image in images]), (
  1555. "Expected to get an iterable of ndarrays, "
  1556. "got types %s." % (
  1557. ", ".join([str(type(image)) for image in images],)))
  1558. assert all([image.ndim == 3 for image in images]), (
  1559. "Expected to get images with three dimensions. Got shapes %s." % (
  1560. ", ".join([str(image.shape) for image in images])))
  1561. assert len({image.dtype.name for image in images}) == 1, (
  1562. "Expected to get images with the same dtypes, got dtypes %s." % (
  1563. ", ".join([image.dtype.name for image in images])))
  1564. assert len({image.shape[-1] for image in images}) == 1, (
  1565. "Expected to get images with the same number of channels, "
  1566. "got shapes %s." % (
  1567. ", ".join([str(image.shape) for image in images])))
  1568. cell_height = max([image.shape[0] for image in images])
  1569. cell_width = max([image.shape[1] for image in images])
  1570. nb_channels = images[0].shape[2]
  1571. if rows is None and cols is None:
  1572. rows = cols = int(math.ceil(math.sqrt(nb_images)))
  1573. elif rows is not None:
  1574. cols = int(math.ceil(nb_images / rows))
  1575. elif cols is not None:
  1576. rows = int(math.ceil(nb_images / cols))
  1577. assert rows * cols >= nb_images, (
  1578. "Expected rows*cols to lead to at least as many cells as there were "
  1579. "images provided, but got %d rows, %d cols (=%d cells) for %d "
  1580. "images. " % (rows, cols, rows*cols, nb_images))
  1581. width = cell_width * cols
  1582. height = cell_height * rows
  1583. dtype = images.dtype if is_np_array(images) else images[0].dtype
  1584. grid = np.zeros((height, width, nb_channels), dtype=dtype)
  1585. cell_idx = 0
  1586. for row_idx in sm.xrange(rows):
  1587. for col_idx in sm.xrange(cols):
  1588. if cell_idx < nb_images:
  1589. image = images[cell_idx]
  1590. cell_y1 = cell_height * row_idx
  1591. cell_y2 = cell_y1 + image.shape[0]
  1592. cell_x1 = cell_width * col_idx
  1593. cell_x2 = cell_x1 + image.shape[1]
  1594. grid[cell_y1:cell_y2, cell_x1:cell_x2, :] = image
  1595. cell_idx += 1
  1596. return grid
  1597. def show_grid(images, rows=None, cols=None):
  1598. """Combine multiple images into a single image and plot the result.
  1599. This will show a window of the results of :func:`~imgaug.imgaug.draw_grid`.
  1600. **Supported dtypes**:
  1601. minimum of (
  1602. :func:`~imgaug.imgaug.draw_grid`,
  1603. :func:`~imgaug.imgaug.imshow`
  1604. )
  1605. Parameters
  1606. ----------
  1607. images : (N,H,W,3) ndarray or iterable of (H,W,3) array
  1608. See :func:`~imgaug.imgaug.draw_grid`.
  1609. rows : None or int, optional
  1610. See :func:`~imgaug.imgaug.draw_grid`.
  1611. cols : None or int, optional
  1612. See :func:`~imgaug.imgaug.draw_grid`.
  1613. """
  1614. grid = draw_grid(images, rows=rows, cols=cols)
  1615. imshow(grid)
  1616. def imshow(image, backend=IMSHOW_BACKEND_DEFAULT):
  1617. """Show an image in a window.
  1618. **Supported dtypes**:
  1619. * ``uint8``: yes; not tested
  1620. * ``uint16``: ?
  1621. * ``uint32``: ?
  1622. * ``uint64``: ?
  1623. * ``int8``: ?
  1624. * ``int16``: ?
  1625. * ``int32``: ?
  1626. * ``int64``: ?
  1627. * ``float16``: ?
  1628. * ``float32``: ?
  1629. * ``float64``: ?
  1630. * ``float128``: ?
  1631. * ``bool``: ?
  1632. Parameters
  1633. ----------
  1634. image : (H,W,3) ndarray
  1635. Image to show.
  1636. backend : {'matplotlib', 'cv2'}, optional
  1637. Library to use to show the image. May be either matplotlib or
  1638. OpenCV ('cv2'). OpenCV tends to be faster, but apparently causes more
  1639. technical issues.
  1640. """
  1641. assert backend in ["matplotlib", "cv2"], (
  1642. "Expected backend 'matplotlib' or 'cv2', got %s." % (backend,))
  1643. if backend == "cv2":
  1644. image_bgr = image
  1645. if image.ndim == 3 and image.shape[2] in [3, 4]:
  1646. image_bgr = image[..., 0:3][..., ::-1]
  1647. win_name = "imgaug-default-window"
  1648. cv2.namedWindow(win_name, cv2.WINDOW_NORMAL)
  1649. cv2.imshow(win_name, image_bgr)
  1650. cv2.waitKey(0)
  1651. cv2.destroyWindow(win_name)
  1652. else:
  1653. # import only when necessary (faster startup; optional dependency;
  1654. # less fragile -- see issue #225)
  1655. import matplotlib.pyplot as plt
  1656. dpi = 96
  1657. h, w = image.shape[0] / dpi, image.shape[1] / dpi
  1658. # if the figure is too narrow, the footer may appear and make the fig
  1659. # suddenly wider (ugly)
  1660. w = max(w, 6)
  1661. fig, ax = plt.subplots(figsize=(w, h), dpi=dpi)
  1662. fig.canvas.set_window_title("imgaug.imshow(%s)" % (image.shape,))
  1663. # cmap=gray is automatically only activate for grayscale images
  1664. ax.imshow(image, cmap="gray")
  1665. plt.show()
  1666. def do_assert(condition, message="Assertion failed."):
  1667. """Assert that a ``condition`` holds or raise an ``Exception`` otherwise.
  1668. This was added because `assert` statements are removed in optimized code.
  1669. It replaced `assert` statements throughout the library, but that was
  1670. reverted again for readability and performance reasons.
  1671. Parameters
  1672. ----------
  1673. condition : bool
  1674. If ``False``, an exception is raised.
  1675. message : str, optional
  1676. Error message.
  1677. """
  1678. if not condition:
  1679. raise AssertionError(str(message))
  1680. # Added in 0.4.0.
  1681. def _normalize_cv2_input_arr_(arr):
  1682. flags = arr.flags
  1683. if not flags["OWNDATA"]:
  1684. arr = np.copy(arr)
  1685. flags = arr.flags
  1686. if not flags["C_CONTIGUOUS"]:
  1687. arr = np.ascontiguousarray(arr)
  1688. return arr
  1689. def apply_lut(image, table):
  1690. """Map an input image to a new one using a lookup table.
  1691. Added in 0.4.0.
  1692. **Supported dtypes**:
  1693. See :func:`~imgaug.imgaug.apply_lut_`.
  1694. Parameters
  1695. ----------
  1696. image : ndarray
  1697. See :func:`~imgaug.imgaug.apply_lut_`.
  1698. table : ndarray or list of ndarray
  1699. See :func:`~imgaug.imgaug.apply_lut_`.
  1700. Returns
  1701. -------
  1702. ndarray
  1703. Image after mapping via lookup table.
  1704. """
  1705. return apply_lut_(np.copy(image), table)
  1706. # TODO make this function compatible with short max sized images, probably
  1707. # isn't right now
  1708. def apply_lut_(image, table):
  1709. """Map an input image in-place to a new one using a lookup table.
  1710. Added in 0.4.0.
  1711. **Supported dtypes**:
  1712. * ``uint8``: yes; fully tested
  1713. * ``uint16``: no
  1714. * ``uint32``: no
  1715. * ``uint64``: no
  1716. * ``int8``: no
  1717. * ``int16``: no
  1718. * ``int32``: no
  1719. * ``int64``: no
  1720. * ``float16``: no
  1721. * ``float32``: no
  1722. * ``float64``: no
  1723. * ``float128``: no
  1724. * ``bool``: no
  1725. Parameters
  1726. ----------
  1727. image : ndarray
  1728. Image of dtype ``uint8`` and shape ``(H,W)`` or ``(H,W,C)``.
  1729. table : ndarray or list of ndarray
  1730. Table of dtype ``uint8`` containing the mapping from old to new
  1731. values. Either a ``list`` of ``C`` ``(256,)`` arrays or a single
  1732. array of shape ``(256,)`` or ``(256, C)`` or ``(1, 256, C)``.
  1733. In case of ``(256,)`` the same table is used for all channels,
  1734. otherwise a channelwise table is used and ``C`` is expected to match
  1735. the number of channels.
  1736. Returns
  1737. -------
  1738. ndarray
  1739. Image after mapping via lookup table.
  1740. This *might* be the same array instance as provided via `image`.
  1741. """
  1742. image_shape_orig = image.shape
  1743. nb_channels = 1 if len(image_shape_orig) == 2 else image_shape_orig[-1]
  1744. if 0 in image_shape_orig:
  1745. return image
  1746. image = _normalize_cv2_input_arr_(image)
  1747. # [(256,), (256,), ...] => (256, C)
  1748. if isinstance(table, list):
  1749. assert len(table) == nb_channels, (
  1750. "Expected to get %d tables (one per channel), got %d instead." % (
  1751. nb_channels, len(table)))
  1752. table = np.stack(table, axis=-1)
  1753. # (256, C) => (1, 256, C)
  1754. if table.shape == (256, nb_channels):
  1755. table = table[np.newaxis, :, :]
  1756. assert table.shape == (256,) or table.shape == (1, 256, nb_channels), (
  1757. "Expected 'table' to be any of the following: "
  1758. "A list of C (256,) arrays, an array of shape (256,), an array of "
  1759. "shape (256, C), an array of shape (1, 256, C). Transformed 'table' "
  1760. "up to shape %s for image with shape %s (C=%d)." % (
  1761. table.shape, image_shape_orig, nb_channels))
  1762. if nb_channels > 512:
  1763. if table.shape == (256,):
  1764. table = np.tile(table[np.newaxis, :, np.newaxis],
  1765. (1, 1, nb_channels))
  1766. subluts = []
  1767. for group_idx in np.arange(int(np.ceil(nb_channels / 512))):
  1768. c_start = group_idx * 512
  1769. c_end = c_start + 512
  1770. subluts.append(apply_lut_(image[:, :, c_start:c_end],
  1771. table[:, :, c_start:c_end]))
  1772. return np.concatenate(subluts, axis=2)
  1773. assert image.dtype.name == "uint8", (
  1774. "Expected uint8 image, got dtype %s." % (image.dtype.name,))
  1775. assert table.dtype.name == "uint8", (
  1776. "Expected uint8 table, got dtype %s." % (table.dtype.name,))
  1777. image = cv2.LUT(image, table, dst=image)
  1778. return image
  1779. class HooksImages(object):
  1780. """Class to intervene with image augmentation runs.
  1781. This is e.g. useful to dynamically deactivate some augmenters.
  1782. Parameters
  1783. ----------
  1784. activator : None or callable, optional
  1785. A function that gives permission to execute an augmenter.
  1786. The expected interface is::
  1787. ``f(images, augmenter, parents, default)``
  1788. where ``images`` are the input images to augment, ``augmenter`` is the
  1789. instance of the augmenter to execute, ``parents`` are previously
  1790. executed augmenters and ``default`` is an expected default value to be
  1791. returned if the activator function does not plan to make a decision
  1792. for the given inputs.
  1793. propagator : None or callable, optional
  1794. A function that gives permission to propagate the augmentation further
  1795. to the children of an augmenter. This happens after the activator.
  1796. In theory, an augmenter may augment images itself (if allowed by the
  1797. activator) and then execute child augmenters afterwards (if allowed by
  1798. the propagator). If the activator returned ``False``, the propagation
  1799. step will never be executed.
  1800. The expected interface is::
  1801. ``f(images, augmenter, parents, default)``
  1802. with all arguments having identical meaning to the activator.
  1803. preprocessor : None or callable, optional
  1804. A function to call before an augmenter performed any augmentations.
  1805. The interface is:
  1806. ``f(images, augmenter, parents)``
  1807. with all arguments having identical meaning to the activator.
  1808. It is expected to return the input images, optionally modified.
  1809. postprocessor : None or callable, optional
  1810. A function to call after an augmenter performed augmentations.
  1811. The interface is the same as for the `preprocessor`.
  1812. Examples
  1813. --------
  1814. >>> import numpy as np
  1815. >>> import imgaug as ia
  1816. >>> import imgaug.augmenters as iaa
  1817. >>> seq = iaa.Sequential([
  1818. >>> iaa.GaussianBlur(3.0, name="blur"),
  1819. >>> iaa.Dropout(0.05, name="dropout"),
  1820. >>> iaa.Affine(translate_px=-5, name="affine")
  1821. >>> ])
  1822. >>> images = [np.zeros((10, 10), dtype=np.uint8)]
  1823. >>>
  1824. >>> def activator(images, augmenter, parents, default):
  1825. >>> return False if augmenter.name in ["blur", "dropout"] else default
  1826. >>>
  1827. >>> seq_det = seq.to_deterministic()
  1828. >>> images_aug = seq_det.augment_images(images)
  1829. >>> heatmaps = [np.random.rand(*(3, 10, 10))]
  1830. >>> heatmaps_aug = seq_det.augment_images(
  1831. >>> heatmaps,
  1832. >>> hooks=ia.HooksImages(activator=activator)
  1833. >>> )
  1834. This augments images and their respective heatmaps in the same way.
  1835. The heatmaps however are only modified by ``Affine``, not by
  1836. ``GaussianBlur`` or ``Dropout``.
  1837. """
  1838. def __init__(self, activator=None, propagator=None, preprocessor=None,
  1839. postprocessor=None):
  1840. self.activator = activator
  1841. self.propagator = propagator
  1842. self.preprocessor = preprocessor
  1843. self.postprocessor = postprocessor
  1844. def is_activated(self, images, augmenter, parents, default):
  1845. """Estimate whether an augmenter may be executed.
  1846. This also affects propagation of data to child augmenters.
  1847. Returns
  1848. -------
  1849. bool
  1850. If ``True``, the augmenter may be executed.
  1851. Otherwise ``False``.
  1852. """
  1853. if self.activator is None:
  1854. return default
  1855. return self.activator(images, augmenter, parents, default)
  1856. def is_propagating(self, images, augmenter, parents, default):
  1857. """Estimate whether an augmenter may call its children.
  1858. This function decides whether an augmenter with children is allowed
  1859. to call these in order to further augment the inputs.
  1860. Note that if the augmenter itself performs augmentations (before/after
  1861. calling its children), these may still be executed, even if this
  1862. method returns ``False``.
  1863. Returns
  1864. -------
  1865. bool
  1866. If ``True``, the augmenter may propagate data to its children.
  1867. Otherwise ``False``.
  1868. """
  1869. if self.propagator is None:
  1870. return default
  1871. return self.propagator(images, augmenter, parents, default)
  1872. def preprocess(self, images, augmenter, parents):
  1873. """Preprocess input data per augmenter before augmentation.
  1874. Returns
  1875. -------
  1876. (N,H,W,C) ndarray or (N,H,W) ndarray or list of (H,W,C) ndarray or list of (H,W) ndarray
  1877. The input images, optionally modified.
  1878. """
  1879. if self.preprocessor is None:
  1880. return images
  1881. return self.preprocessor(images, augmenter, parents)
  1882. def postprocess(self, images, augmenter, parents):
  1883. """Postprocess input data per augmenter after augmentation.
  1884. Returns
  1885. -------
  1886. (N,H,W,C) ndarray or (N,H,W) ndarray or list of (H,W,C) ndarray or list of (H,W) ndarray
  1887. The input images, optionally modified.
  1888. """
  1889. if self.postprocessor is None:
  1890. return images
  1891. return self.postprocessor(images, augmenter, parents)
  1892. class HooksHeatmaps(HooksImages):
  1893. """Class to intervene with heatmap augmentation runs.
  1894. This is e.g. useful to dynamically deactivate some augmenters.
  1895. This class is currently the same as the one for images. This may or may
  1896. not change in the future.
  1897. """
  1898. class HooksKeypoints(HooksImages):
  1899. """Class to intervene with keypoint augmentation runs.
  1900. This is e.g. useful to dynamically deactivate some augmenters.
  1901. This class is currently the same as the one for images. This may or may
  1902. not change in the future.
  1903. """
  1904. #####################################################################
  1905. # Create classes/functions that were moved to other files and create
  1906. # DeprecatedWarnings when they are called.
  1907. #####################################################################
  1908. def _mark_moved_class_or_function(class_name_old, module_name_new,
  1909. class_name_new):
  1910. # pylint: disable=redefined-outer-name
  1911. class_name_new = (class_name_new
  1912. if class_name_new is not None
  1913. else class_name_old)
  1914. def _func(*args, **kwargs):
  1915. import importlib
  1916. warn_deprecated(
  1917. "Using imgaug.imgaug.%s is deprecated. Use %s.%s instead." % (
  1918. class_name_old, module_name_new, class_name_new
  1919. ))
  1920. module = importlib.import_module(module_name_new)
  1921. return getattr(module, class_name_new)(*args, **kwargs)
  1922. return _func
  1923. MOVED = [
  1924. ("Keypoint", "imgaug.augmentables.kps", None),
  1925. ("KeypointsOnImage", "imgaug.augmentables.kps", None),
  1926. ("BoundingBox", "imgaug.augmentables.bbs", None),
  1927. ("BoundingBoxesOnImage", "imgaug.augmentables.bbs", None),
  1928. ("Polygon", "imgaug.augmentables.polys", None),
  1929. ("PolygonsOnImage", "imgaug.augmentables.polys", None),
  1930. ("MultiPolygon", "imgaug.augmentables.polys", None),
  1931. ("_ConcavePolygonRecoverer", "imgaug.augmentables.polys", None),
  1932. ("HeatmapsOnImage", "imgaug.augmentables.heatmaps", None),
  1933. ("SegmentationMapsOnImage", "imgaug.augmentables.segmaps", None),
  1934. ("Batch", "imgaug.augmentables.batches", None),
  1935. ("BatchLoader", "imgaug.multicore", None),
  1936. ("BackgroundAugmenter", "imgaug.multicore", None),
  1937. ("compute_geometric_median", "imgaug.augmentables.kps", None),
  1938. ("_convert_points_to_shapely_line_string", "imgaug.augmentables.polys",
  1939. None),
  1940. ("_interpolate_point_pair", "imgaug.augmentables.polys", None),
  1941. ("_interpolate_points", "imgaug.augmentables.polys", None),
  1942. ("_interpolate_points_by_max_distance", "imgaug.augmentables.polys", None),
  1943. ("pad", "imgaug.augmenters.size", None),
  1944. ("pad_to_aspect_ratio", "imgaug.augmenters.size", None),
  1945. ("pad_to_multiples_of", "imgaug.augmenters.size", None),
  1946. ("compute_paddings_for_aspect_ratio", "imgaug.augmenters.size",
  1947. "compute_paddings_to_reach_aspect_ratio"),
  1948. ("compute_paddings_to_reach_multiples_of", "imgaug.augmenters.size", None),
  1949. ("compute_paddings_to_reach_exponents_of", "imgaug.augmenters.size", None)
  1950. ]
  1951. for class_name_old, module_name_new, class_name_new in MOVED:
  1952. locals()[class_name_old] = _mark_moved_class_or_function(
  1953. class_name_old, module_name_new, class_name_new)