normalization.py 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296
  1. """Functions dealing with normalization of user input data to imgaug classes."""
  2. from __future__ import print_function, division, absolute_import
  3. import functools
  4. import numpy as np
  5. from .. import imgaug as ia
  6. from .. import dtypes as iadt
  7. from .base import IAugmentable
  8. def _preprocess_shapes(shapes):
  9. if shapes is None:
  10. return None
  11. if ia.is_np_array(shapes):
  12. assert shapes.ndim in [3, 4], (
  13. "Expected array 'shapes' to be 3- or 4-dimensional, got %d "
  14. "dimensions and shape %s instead." % (shapes.ndim, shapes.shape))
  15. return [image.shape for image in shapes]
  16. assert isinstance(shapes, list), (
  17. "Expected 'shapes' to be None or ndarray or list, got type %s "
  18. "instead." % (type(shapes),))
  19. result = []
  20. for shape_i in shapes:
  21. if isinstance(shape_i, tuple):
  22. result.append(shape_i)
  23. else:
  24. assert ia.is_np_array(shape_i), (
  25. "Expected each entry in list 'shapes' to be either a "
  26. "tuple or an ndarray, got type %s." % (type(shape_i),))
  27. result.append(shape_i.shape)
  28. return result
  29. def _assert_exactly_n_shapes(shapes, n, from_ntype, to_ntype):
  30. if shapes is None:
  31. raise ValueError(
  32. "Tried to convert data of form '%s' to '%s'. This required %d "
  33. "corresponding image shapes, but argument 'shapes' was set to "
  34. "None. This can happen e.g. if no images were provided in a "
  35. "Batch, as these would usually be used to automatically derive "
  36. "image shapes." % (from_ntype, to_ntype, n))
  37. if len(shapes) != n:
  38. raise ValueError(
  39. "Tried to convert data of form '%s' to '%s'. This required "
  40. "exactly %d corresponding image shapes, but instead %d were "
  41. "provided. This can happen e.g. if more images were provided "
  42. "than corresponding augmentables, e.g. 10 images but only 5 "
  43. "segmentation maps. It can also happen if there was a "
  44. "misunderstanding about how an augmentable input would be "
  45. "parsed. E.g. if a list of N (x,y)-tuples was provided as "
  46. "keypoints and the expectation was that this would be parsed "
  47. "as one keypoint per image for N images, but instead it was "
  48. "parsed as N keypoints on 1 image (i.e. 'shapes' would have to "
  49. "contain 1 shape, but N would be provided). To avoid this, it "
  50. "is recommended to provide imgaug standard classes, e.g. "
  51. "KeypointsOnImage for keypoints instead of lists of "
  52. "tuples." % (from_ntype, to_ntype, n, len(shapes)))
  53. def _assert_single_array_ndim(arr, ndim, shape_str, to_ntype):
  54. if arr.ndim != ndim:
  55. raise ValueError(
  56. "Tried to convert an array to list of %s. Expected "
  57. "that array to be of shape %s, i.e. %d-dimensional, but "
  58. "got %d dimensions instead." % (
  59. to_ntype, shape_str, ndim, arr.ndim,))
  60. def _assert_many_arrays_ndim(arrs, ndim, shape_str, to_ntype):
  61. # For polygons, this can be a list of lists of arrays, hence we must
  62. # flatten the lists here.
  63. # itertools.chain.from_iterable() seems to flatten the arrays too, so it
  64. # cannot be used here.
  65. iterable_type_str = "iterable"
  66. if len(arrs) == 0:
  67. arrs_flat = []
  68. elif ia.is_np_array(arrs[0]):
  69. arrs_flat = arrs
  70. else:
  71. iterable_type_str = "iterable of iterable"
  72. arrs_flat = [arr for arrs_sublist in arrs for arr in arrs_sublist]
  73. if any([arr.ndim != ndim for arr in arrs_flat]):
  74. raise ValueError(
  75. "Tried to convert an %s of arrays to a list of "
  76. "%s. Expected each array to be of shape %s, "
  77. "i.e. to be %d-dimensional, but got dimensions %s "
  78. "instead (array shapes: %s)." % (
  79. iterable_type_str, to_ntype, shape_str, ndim,
  80. ", ".join([str(arr.ndim) for arr in arrs_flat]),
  81. ", ".join([str(arr.shape) for arr in arrs_flat])))
  82. def _assert_single_array_last_dim_exactly(arr, size, to_ntype):
  83. if arr.shape[-1] != size:
  84. raise ValueError(
  85. "Tried to convert an array to a list of %s. Expected the array's "
  86. "last dimension to have size %d, but got %d instead (array "
  87. "shape: %s)." % (
  88. to_ntype, size, arr.shape[-1], str(arr.shape)))
  89. def _assert_many_arrays_last_dim_exactly(arrs, size, to_ntype):
  90. # For polygons, this can be a list of lists of arrays, hence we must
  91. # flatten the lists here.
  92. # itertools.chain.from_iterable() seems to flatten the arrays too, so it
  93. # cannot be used here.
  94. iterable_type_str = "iterable"
  95. if len(arrs) == 0:
  96. arrs_flat = []
  97. elif ia.is_np_array(arrs[0]):
  98. arrs_flat = arrs
  99. else:
  100. iterable_type_str = "iterable of iterable"
  101. arrs_flat = [arr for arrs_sublist in arrs for arr in arrs_sublist]
  102. if any([arr.shape[-1] != size for arr in arrs_flat]):
  103. raise ValueError(
  104. "Tried to convert an %s of array to a list of %s. Expected the "
  105. "arrays' last dimensions to have size %d, but got %s instead "
  106. "(array shapes: %s)." % (
  107. iterable_type_str, to_ntype, size,
  108. ", ".join([str(arr.shape[-1]) for arr in arrs_flat]),
  109. ", ".join([str(arr.shape) for arr in arrs_flat])))
  110. def normalize_images(images):
  111. if images is None:
  112. return None
  113. if ia.is_np_array(images):
  114. if images.ndim == 2:
  115. return images[np.newaxis, ..., np.newaxis]
  116. if images.ndim == 3:
  117. return images[..., np.newaxis]
  118. return images
  119. if ia.is_iterable(images):
  120. result = []
  121. for image in images:
  122. assert image.ndim in [2, 3], (
  123. "Got a list of arrays as argument 'images'. Expected each "
  124. "array in that list to have 2 or 3 dimensions, i.e. shape "
  125. "(H,W) or (H,W,C). Got %d dimensions "
  126. "instead." % (image.ndim,))
  127. if image.ndim == 2:
  128. result.append(image[..., np.newaxis])
  129. else:
  130. result.append(image)
  131. return result
  132. raise ValueError(
  133. "Expected argument 'images' to be any of the following: "
  134. "None or array or iterable of array. Got type: %s." % (
  135. type(images),))
  136. def normalize_heatmaps(inputs, shapes=None):
  137. # TODO get rid of this deferred import
  138. from imgaug.augmentables.heatmaps import HeatmapsOnImage
  139. shapes = _preprocess_shapes(shapes)
  140. ntype = estimate_heatmaps_norm_type(inputs)
  141. _assert_exactly_n_shapes_partial = functools.partial(
  142. _assert_exactly_n_shapes,
  143. from_ntype=ntype, to_ntype="List[HeatmapsOnImage]", shapes=shapes)
  144. if ntype == "None":
  145. return None
  146. if ntype == "array[float]":
  147. _assert_single_array_ndim(inputs, 4, "(N,H,W,C)", "HeatmapsOnImage")
  148. _assert_exactly_n_shapes_partial(n=len(inputs))
  149. return [HeatmapsOnImage(attr_i, shape=shape_i)
  150. for attr_i, shape_i in zip(inputs, shapes)]
  151. if ntype == "HeatmapsOnImage":
  152. return [inputs]
  153. if ntype == "iterable[empty]":
  154. return None
  155. if ntype == "iterable-array[float]":
  156. _assert_many_arrays_ndim(inputs, 3, "(H,W,C)", "HeatmapsOnImage")
  157. _assert_exactly_n_shapes_partial(n=len(inputs))
  158. return [HeatmapsOnImage(attr_i, shape=shape_i)
  159. for attr_i, shape_i in zip(inputs, shapes)]
  160. assert ntype == "iterable-HeatmapsOnImage", (
  161. "Got unknown normalization type '%s'." % (ntype,))
  162. return inputs # len allowed to differ from len of images
  163. def normalize_segmentation_maps(inputs, shapes=None):
  164. # TODO get rid of this deferred import
  165. from imgaug.augmentables.segmaps import SegmentationMapsOnImage
  166. shapes = _preprocess_shapes(shapes)
  167. ntype = estimate_segmaps_norm_type(inputs)
  168. _assert_exactly_n_shapes_partial = functools.partial(
  169. _assert_exactly_n_shapes,
  170. from_ntype=ntype, to_ntype="List[SegmentationMapsOnImage]",
  171. shapes=shapes)
  172. if ntype == "None":
  173. return None
  174. if ntype in ["array[int]", "array[uint]", "array[bool]"]:
  175. _assert_single_array_ndim(inputs, 4, "(N,H,W,#SegmapsPerImage)",
  176. "SegmentationMapsOnImage")
  177. _assert_exactly_n_shapes_partial(n=len(inputs))
  178. if ntype == "array[bool]":
  179. return [SegmentationMapsOnImage(attr_i, shape=shape)
  180. for attr_i, shape in zip(inputs, shapes)]
  181. return [SegmentationMapsOnImage(attr_i, shape=shape)
  182. for attr_i, shape in zip(inputs, shapes)]
  183. if ntype == "SegmentationMapsOnImage":
  184. return [inputs]
  185. if ntype == "iterable[empty]":
  186. return None
  187. if ntype in ["iterable-array[int]",
  188. "iterable-array[uint]",
  189. "iterable-array[bool]"]:
  190. _assert_many_arrays_ndim(inputs, 3, "(H,W,#SegmapsPerImage)",
  191. "SegmentationMapsOnImage")
  192. _assert_exactly_n_shapes_partial(n=len(inputs))
  193. if ntype == "iterable-array[bool]":
  194. return [SegmentationMapsOnImage(attr_i, shape=shape)
  195. for attr_i, shape in zip(inputs, shapes)]
  196. return [SegmentationMapsOnImage(attr_i, shape=shape)
  197. for attr_i, shape in zip(inputs, shapes)]
  198. assert ntype == "iterable-SegmentationMapsOnImage", (
  199. "Got unknown normalization type '%s'." % (ntype,))
  200. return inputs # len allowed to differ from len of images
  201. def normalize_keypoints(inputs, shapes=None):
  202. # TODO get rid of this deferred import
  203. from imgaug.augmentables.kps import Keypoint, KeypointsOnImage
  204. shapes = _preprocess_shapes(shapes)
  205. ntype = estimate_keypoints_norm_type(inputs)
  206. _assert_exactly_n_shapes_partial = functools.partial(
  207. _assert_exactly_n_shapes,
  208. from_ntype=ntype, to_ntype="List[KeypointsOnImage]",
  209. shapes=shapes)
  210. if ntype == "None":
  211. return inputs
  212. if ntype in ["array[float]", "array[int]", "array[uint]"]:
  213. _assert_single_array_ndim(inputs, 3, "(N,K,2)", "KeypointsOnImage")
  214. _assert_single_array_last_dim_exactly(inputs, 2, "KeypointsOnImage")
  215. _assert_exactly_n_shapes_partial(n=len(inputs))
  216. return [
  217. KeypointsOnImage.from_xy_array(attr_i, shape=shape)
  218. for attr_i, shape
  219. in zip(inputs, shapes)
  220. ]
  221. if ntype == "tuple[number,size=2]":
  222. _assert_exactly_n_shapes_partial(n=1)
  223. return [KeypointsOnImage([Keypoint(x=inputs[0], y=inputs[1])],
  224. shape=shapes[0])]
  225. if ntype == "Keypoint":
  226. _assert_exactly_n_shapes_partial(n=1)
  227. return [KeypointsOnImage([inputs], shape=shapes[0])]
  228. if ntype == "KeypointsOnImage":
  229. return [inputs]
  230. if ntype == "iterable[empty]":
  231. return None
  232. if ntype in ["iterable-array[float]",
  233. "iterable-array[int]",
  234. "iterable-array[uint]"]:
  235. _assert_many_arrays_ndim(inputs, 2, "(K,2)", "KeypointsOnImage")
  236. _assert_many_arrays_last_dim_exactly(inputs, 2, "KeypointsOnImage")
  237. _assert_exactly_n_shapes_partial(n=len(inputs))
  238. return [
  239. KeypointsOnImage.from_xy_array(attr_i, shape=shape)
  240. for attr_i, shape
  241. in zip(inputs, shapes)
  242. ]
  243. if ntype == "iterable-tuple[number,size=2]":
  244. _assert_exactly_n_shapes_partial(n=1)
  245. return [KeypointsOnImage([Keypoint(x=x, y=y) for x, y in inputs],
  246. shape=shapes[0])]
  247. if ntype == "iterable-Keypoint":
  248. _assert_exactly_n_shapes_partial(n=1)
  249. return [KeypointsOnImage(inputs, shape=shapes[0])]
  250. if ntype == "iterable-KeypointsOnImage":
  251. return inputs
  252. if ntype == "iterable-iterable[empty]":
  253. return None
  254. if ntype == "iterable-iterable-tuple[number,size=2]":
  255. _assert_exactly_n_shapes_partial(n=len(inputs))
  256. return [
  257. KeypointsOnImage.from_xy_array(
  258. np.array(attr_i, dtype=np.float32),
  259. shape=shape)
  260. for attr_i, shape
  261. in zip(inputs, shapes)
  262. ]
  263. assert ntype == "iterable-iterable-Keypoint", (
  264. "Got unknown normalization type '%s'." % (ntype,))
  265. _assert_exactly_n_shapes_partial(n=len(inputs))
  266. return [KeypointsOnImage(attr_i, shape=shape)
  267. for attr_i, shape
  268. in zip(inputs, shapes)]
  269. def normalize_bounding_boxes(inputs, shapes=None):
  270. # TODO get rid of this deferred import
  271. from imgaug.augmentables.bbs import BoundingBox, BoundingBoxesOnImage
  272. shapes = _preprocess_shapes(shapes)
  273. ntype = estimate_bounding_boxes_norm_type(inputs)
  274. _assert_exactly_n_shapes_partial = functools.partial(
  275. _assert_exactly_n_shapes,
  276. from_ntype=ntype, to_ntype="List[BoundingBoxesOnImage]",
  277. shapes=shapes)
  278. if ntype == "None":
  279. return None
  280. if ntype in ["array[float]", "array[int]", "array[uint]"]:
  281. _assert_single_array_ndim(inputs, 3, "(N,B,4)", "BoundingBoxesOnImage")
  282. _assert_single_array_last_dim_exactly(
  283. inputs, 4, "BoundingBoxesOnImage")
  284. _assert_exactly_n_shapes_partial(n=len(inputs))
  285. return [
  286. BoundingBoxesOnImage.from_xyxy_array(attr_i, shape=shape)
  287. for attr_i, shape
  288. in zip(inputs, shapes)
  289. ]
  290. if ntype == "tuple[number,size=4]":
  291. _assert_exactly_n_shapes_partial(n=1)
  292. return [
  293. BoundingBoxesOnImage(
  294. [BoundingBox(
  295. x1=inputs[0], y1=inputs[1],
  296. x2=inputs[2], y2=inputs[3])],
  297. shape=shapes[0])
  298. ]
  299. if ntype == "BoundingBox":
  300. _assert_exactly_n_shapes_partial(n=1)
  301. return [BoundingBoxesOnImage([inputs], shape=shapes[0])]
  302. if ntype == "BoundingBoxesOnImage":
  303. return [inputs]
  304. if ntype == "iterable[empty]":
  305. return None
  306. if ntype in ["iterable-array[float]",
  307. "iterable-array[int]",
  308. "iterable-array[uint]"]:
  309. _assert_many_arrays_ndim(inputs, 2, "(B,4)", "BoundingBoxesOnImage")
  310. _assert_many_arrays_last_dim_exactly(inputs, 4, "BoundingBoxesOnImage")
  311. _assert_exactly_n_shapes_partial(n=len(inputs))
  312. return [
  313. BoundingBoxesOnImage.from_xyxy_array(attr_i, shape=shape)
  314. for attr_i, shape
  315. in zip(inputs, shapes)
  316. ]
  317. if ntype == "iterable-tuple[number,size=4]":
  318. _assert_exactly_n_shapes_partial(n=1)
  319. return [
  320. BoundingBoxesOnImage(
  321. [BoundingBox(x1=x1, y1=y1, x2=x2, y2=y2)
  322. for x1, y1, x2, y2 in inputs],
  323. shape=shapes[0])
  324. ]
  325. if ntype == "iterable-BoundingBox":
  326. _assert_exactly_n_shapes_partial(n=1)
  327. return [BoundingBoxesOnImage(inputs, shape=shapes[0])]
  328. if ntype == "iterable-BoundingBoxesOnImage":
  329. return inputs
  330. if ntype == "iterable-iterable[empty]":
  331. return None
  332. if ntype == "iterable-iterable-tuple[number,size=4]":
  333. _assert_exactly_n_shapes_partial(n=len(inputs))
  334. return [
  335. BoundingBoxesOnImage.from_xyxy_array(
  336. np.array(attr_i, dtype=np.float32),
  337. shape=shape)
  338. for attr_i, shape
  339. in zip(inputs, shapes)
  340. ]
  341. assert ntype == "iterable-iterable-BoundingBox", (
  342. "Got unknown normalization type '%s'." % (ntype,))
  343. _assert_exactly_n_shapes_partial(n=len(inputs))
  344. return [BoundingBoxesOnImage(attr_i, shape=shape)
  345. for attr_i, shape
  346. in zip(inputs, shapes)]
  347. def normalize_polygons(inputs, shapes=None):
  348. # TODO get rid of this deferred import
  349. from imgaug.augmentables.polys import Polygon, PolygonsOnImage
  350. return _normalize_polygons_and_line_strings(
  351. cls_single=Polygon,
  352. cls_oi=PolygonsOnImage,
  353. axis_names=["#polys", "#points"],
  354. estimate_ntype_func=estimate_polygons_norm_type,
  355. inputs=inputs, shapes=shapes
  356. )
  357. def normalize_line_strings(inputs, shapes=None):
  358. # TODO get rid of this deferred import
  359. from imgaug.augmentables.lines import LineString, LineStringsOnImage
  360. return _normalize_polygons_and_line_strings(
  361. cls_single=LineString,
  362. cls_oi=LineStringsOnImage,
  363. axis_names=["#lines", "#points"],
  364. estimate_ntype_func=estimate_line_strings_norm_type,
  365. inputs=inputs, shapes=shapes
  366. )
  367. def _normalize_polygons_and_line_strings(cls_single, cls_oi, axis_names,
  368. estimate_ntype_func,
  369. inputs, shapes=None):
  370. cls_single_name = cls_single.__name__
  371. cls_oi_name = cls_oi.__name__
  372. axis_names_4_str = "(N,%s,%s,2)" % (axis_names[0], axis_names[1])
  373. axis_names_3_str = "(%s,%s,2)" % (axis_names[0], axis_names[1])
  374. axis_names_2_str = "(%s,2)" % (axis_names[1],)
  375. shapes = _preprocess_shapes(shapes)
  376. ntype = estimate_ntype_func(inputs)
  377. _assert_exactly_n_shapes_partial = functools.partial(
  378. _assert_exactly_n_shapes,
  379. from_ntype=ntype, to_ntype=("List[%s]" % (cls_oi_name,)),
  380. shapes=shapes)
  381. if ntype == "None":
  382. return None
  383. if ntype in ["array[float]", "array[int]", "array[uint]"]:
  384. _assert_single_array_ndim(inputs, 4, axis_names_4_str,
  385. cls_oi_name)
  386. _assert_single_array_last_dim_exactly(inputs, 2, cls_oi_name)
  387. _assert_exactly_n_shapes_partial(n=len(inputs))
  388. return [
  389. cls_oi(
  390. [cls_single(points) for points in attr_i],
  391. shape=shape)
  392. for attr_i, shape
  393. in zip(inputs, shapes)
  394. ]
  395. if ntype == cls_single_name:
  396. _assert_exactly_n_shapes_partial(n=1)
  397. return [cls_oi([inputs], shape=shapes[0])]
  398. if ntype == cls_oi_name:
  399. return [inputs]
  400. if ntype == "iterable[empty]":
  401. return None
  402. if ntype in ["iterable-array[float]",
  403. "iterable-array[int]",
  404. "iterable-array[uint]"]:
  405. _assert_many_arrays_ndim(inputs, 3, axis_names_3_str,
  406. cls_oi_name)
  407. _assert_many_arrays_last_dim_exactly(inputs, 2, cls_oi_name)
  408. _assert_exactly_n_shapes_partial(n=len(inputs))
  409. return [
  410. cls_oi([cls_single(points) for points in attr_i], shape=shape)
  411. for attr_i, shape
  412. in zip(inputs, shapes)
  413. ]
  414. if ntype == "iterable-tuple[number,size=2]":
  415. _assert_exactly_n_shapes_partial(n=1)
  416. return [cls_oi([cls_single(inputs)], shape=shapes[0])]
  417. if ntype == "iterable-Keypoint":
  418. _assert_exactly_n_shapes_partial(n=1)
  419. return [cls_oi([cls_single(inputs)], shape=shapes[0])]
  420. if ntype == ("iterable-%s" % (cls_single_name,)):
  421. _assert_exactly_n_shapes_partial(n=1)
  422. return [cls_oi(inputs, shape=shapes[0])]
  423. if ntype == ("iterable-%s" % (cls_oi_name,)):
  424. return inputs
  425. if ntype == "iterable-iterable[empty]":
  426. return None
  427. if ntype in ["iterable-iterable-array[float]",
  428. "iterable-iterable-array[int]",
  429. "iterable-iterable-array[uint]"]:
  430. _assert_many_arrays_ndim(inputs, 2, axis_names_2_str, cls_oi_name)
  431. _assert_many_arrays_last_dim_exactly(inputs, 2, cls_oi_name)
  432. _assert_exactly_n_shapes_partial(n=len(inputs))
  433. return [
  434. cls_oi(
  435. [cls_single(points) for points in attr_i],
  436. shape=shape)
  437. for attr_i, shape
  438. in zip(inputs, shapes)
  439. ]
  440. if ntype == "iterable-iterable-tuple[number,size=2]":
  441. _assert_exactly_n_shapes_partial(n=1)
  442. return [
  443. cls_oi([cls_single(attr_i) for attr_i in inputs],
  444. shape=shapes[0])
  445. ]
  446. if ntype == "iterable-iterable-Keypoint":
  447. _assert_exactly_n_shapes_partial(n=1)
  448. return [
  449. cls_oi([cls_single(attr_i) for attr_i in inputs],
  450. shape=shapes[0])
  451. ]
  452. if ntype == ("iterable-iterable-%s" % (cls_single_name,)):
  453. _assert_exactly_n_shapes_partial(n=len(inputs))
  454. return [
  455. cls_oi(attr_i, shape=shape)
  456. for attr_i, shape
  457. in zip(inputs, shapes)
  458. ]
  459. if ntype == "iterable-iterable-iterable[empty]":
  460. return None
  461. assert ntype in ["iterable-iterable-iterable-tuple[number,size=2]",
  462. "iterable-iterable-iterable-Keypoint"], (
  463. "Got unknown normalization type '%s'." % (ntype,))
  464. _assert_exactly_n_shapes_partial(n=len(inputs))
  465. return [
  466. cls_oi(
  467. [cls_single(points) for points in attr_i],
  468. shape=shape)
  469. for attr_i, shape
  470. in zip(inputs, shapes)
  471. ]
  472. def invert_normalize_images(images, images_old):
  473. if images_old is None:
  474. assert images is None, (
  475. "Expected (normalized) 'images' to be None due to (unnormalized) "
  476. "'images_old' being None. Got type %s instead." % (type(images),))
  477. return None
  478. if ia.is_np_array(images_old):
  479. if not ia.is_np_array(images):
  480. # Images were turned from array to list during augmentation.
  481. # This can happen for e.g. crop operations.
  482. # We will proceed as if the old images were a list.
  483. # One could also generate an array-output if all shapes and dtypes
  484. # in `images` are the same. This was not done here, because
  485. # (a) that would incur a performance penalty and (b) it would
  486. # lead to less consistent outputs.
  487. if images_old.ndim == 2:
  488. # dont interpret first axis as N if `images_old` was a single
  489. # image
  490. return invert_normalize_images(images, [images_old])
  491. return invert_normalize_images(images, list(images_old))
  492. if images_old.ndim == 2:
  493. assert images.shape[0] == 1, (
  494. "Expected normalized images of shape (N,H,W,C) to have "
  495. "N=1 due to the unnormalized images being a single 2D "
  496. "image. Got instead N=%d and shape %s." % (
  497. images.shape[0], images.shape))
  498. assert images.shape[3] == 1, (
  499. "Expected normalized images of shape (N,H,W,C) to have "
  500. "C=1 due to the unnormalized images being a single 2D "
  501. "image. Got instead C=%d and shape %s." % (
  502. images.shape[3], images.shape))
  503. return images[0, ..., 0]
  504. if images_old.ndim == 3:
  505. assert images.shape[3] == 1, (
  506. "Expected normalized images of shape (N,H,W,C) to have "
  507. "C=1 due to unnormalized images being a single 3D image. "
  508. "Got instead C=%d and shape %s" % (
  509. images.shape[3], images.shape))
  510. return images[..., 0]
  511. return images
  512. if ia.is_iterable(images_old):
  513. result = []
  514. for image, image_old in zip(images, images_old):
  515. if image_old.ndim == 2:
  516. assert image.shape[2] == 1, (
  517. "Expected each image of shape (H,W,C) to have C=1 due to "
  518. "the corresponding unnormalized image being a 2D image. "
  519. "Got instead C=%d and shape %s." % (
  520. image.shape[2], image.shape))
  521. result.append(image[:, :, 0])
  522. else:
  523. assert image_old.ndim == 3, (
  524. "Expected 'image_old' to be three-dimensional, got %d "
  525. "dimensions and shape %s." % (
  526. image_old.ndim, image_old.shape))
  527. result.append(image)
  528. return result
  529. raise ValueError(
  530. "Expected argument 'images_old' to be any of the following: "
  531. "None or array or iterable of array. Got type: %s." % (
  532. type(images_old),))
  533. def invert_normalize_heatmaps(heatmaps, heatmaps_old):
  534. ntype = estimate_heatmaps_norm_type(heatmaps_old)
  535. if ntype == "None":
  536. assert heatmaps is None, (
  537. "Expected (normalized) 'heatmaps' to be None due (unnormalized) "
  538. "'heatmaps_old' being None. Got type %s instead." % (
  539. type(heatmaps),))
  540. return heatmaps
  541. if ntype == "array[float]":
  542. assert len(heatmaps) == heatmaps_old.shape[0], (
  543. "Expected as many heatmaps after normalization as before "
  544. "normalization. Got %d (after) and %d (before)." % (
  545. len(heatmaps), heatmaps_old.shape[0]))
  546. input_dtype = heatmaps_old.dtype
  547. return restore_dtype_and_merge(
  548. [hm_i.arr_0to1 for hm_i in heatmaps],
  549. input_dtype)
  550. if ntype == "HeatmapsOnImage":
  551. assert len(heatmaps) == 1, (
  552. "Expected as many heatmaps after normalization as before "
  553. "normalization. Got %d (after) and %d (before)." % (
  554. len(heatmaps), 1))
  555. return heatmaps[0]
  556. if ntype == "iterable[empty]":
  557. assert heatmaps is None, (
  558. "Expected heatmaps after normalization to be None, due to the "
  559. "heatmaps before normalization being an empty iterable. "
  560. "Got type %s instead." % (type(heatmaps),))
  561. return []
  562. if ntype == "iterable-array[float]":
  563. nonempty, _, _ = find_first_nonempty(heatmaps_old)
  564. input_dtype = nonempty.dtype
  565. return [restore_dtype_and_merge(hm_i.arr_0to1, input_dtype)
  566. for hm_i in heatmaps]
  567. assert ntype == "iterable-HeatmapsOnImage", (
  568. "Got unknown normalization type '%s'." % (ntype,))
  569. return heatmaps
  570. def invert_normalize_segmentation_maps(segmentation_maps,
  571. segmentation_maps_old):
  572. ntype = estimate_segmaps_norm_type(segmentation_maps_old)
  573. if ntype == "None":
  574. assert segmentation_maps is None, (
  575. "Expected (normalized) 'segmentation_maps' to be None due "
  576. "(unnormalized) 'segmentation_maps_old' being None. Got type %s "
  577. "instead." % (type(segmentation_maps),))
  578. return segmentation_maps
  579. if ntype in ["array[int]", "array[uint]", "array[bool]"]:
  580. assert len(segmentation_maps) == segmentation_maps_old.shape[0], (
  581. "Expected as many segmentation maps after normalization as before "
  582. "normalization. Got %d (after) and %d (before)." % (
  583. len(segmentation_maps), segmentation_maps_old.shape[0]))
  584. input_dtype = segmentation_maps_old.dtype
  585. return restore_dtype_and_merge(
  586. [segmap_i.get_arr() for segmap_i in segmentation_maps],
  587. input_dtype)
  588. if ntype == "SegmentationMapsOnImage":
  589. assert len(segmentation_maps) == 1, (
  590. "Expected as many segmentation maps after normalization as before "
  591. "normalization. Got %d (after) and %d (before)." % (
  592. len(segmentation_maps), 1))
  593. return segmentation_maps[0]
  594. if ntype == "iterable[empty]":
  595. assert segmentation_maps is None, (
  596. "Expected segmentation maps after normalization to be None, due "
  597. "to the segmentation maps before normalization being an empty "
  598. "iterable. Got type %s instead." % (type(segmentation_maps),))
  599. return []
  600. if ntype in ["iterable-array[int]",
  601. "iterable-array[uint]",
  602. "iterable-array[bool]"]:
  603. nonempty, _, _ = find_first_nonempty(segmentation_maps_old)
  604. input_dtype = nonempty.dtype
  605. return [restore_dtype_and_merge(segmap_i.get_arr(), input_dtype)
  606. for segmap_i in segmentation_maps]
  607. assert ntype == "iterable-SegmentationMapsOnImage", (
  608. "Got unknown normalization type '%s'." % (ntype,))
  609. return segmentation_maps
  610. def invert_normalize_keypoints(keypoints, keypoints_old):
  611. ntype = estimate_keypoints_norm_type(keypoints_old)
  612. if ntype == "None":
  613. assert keypoints is None, (
  614. "Expected (normalized) 'keypoints' to be None due (unnormalized) "
  615. "'keypoints_old' being None. Got type %s instead." % (
  616. type(keypoints),))
  617. return keypoints
  618. if ntype in ["array[float]", "array[int]", "array[uint]"]:
  619. assert len(keypoints) == 1, (
  620. "Expected a single KeypointsOnImage instance after normalization "
  621. "due to getting a single ndarray before normalization. "
  622. "Got %d instances instead." % (len(keypoints),))
  623. input_dtype = keypoints_old.dtype
  624. return restore_dtype_and_merge(
  625. [kpsoi.to_xy_array() for kpsoi in keypoints],
  626. input_dtype)
  627. if ntype == "tuple[number,size=2]":
  628. assert len(keypoints) == 1, (
  629. "Expected a single KeypointsOnImage instance after normalization "
  630. "due to getting a single (x,y) tuple before normalization. "
  631. "Got %d instances instead." % (len(keypoints),))
  632. assert len(keypoints[0].keypoints) == 1, (
  633. "Expected a KeypointsOnImage instance containing a single "
  634. "Keypoint after normalization due to getting a single (x,y) tuple "
  635. "before normalization. Got %d keypoints instead." % (
  636. len(keypoints[0].keypoints)
  637. ))
  638. return (keypoints[0].keypoints[0].x,
  639. keypoints[0].keypoints[0].y)
  640. if ntype == "Keypoint":
  641. assert len(keypoints) == 1, (
  642. "Expected a single KeypointsOnImage instance after normalization "
  643. "due to getting a single Keypoint before normalization. "
  644. "Got %d instances instead." % (len(keypoints),))
  645. assert len(keypoints[0].keypoints) == 1, (
  646. "Expected a KeypointsOnImage instance containing a single "
  647. "Keypoint after normalization due to getting a single Keypoint "
  648. "before normalization. Got %d keypoints instead." % (
  649. len(keypoints[0].keypoints)
  650. ))
  651. return keypoints[0].keypoints[0]
  652. if ntype == "KeypointsOnImage":
  653. assert len(keypoints) == 1, (
  654. "Expected a single KeypointsOnImage instance after normalization "
  655. "due to getting a single KeypointsOnImage before normalization. "
  656. "Got %d instances instead." % (len(keypoints),))
  657. return keypoints[0]
  658. if ntype == "iterable[empty]":
  659. assert keypoints is None, (
  660. "Expected keypoints after normalization to be None, due "
  661. "to the keypoints before normalization being an empty "
  662. "iterable. Got type %s instead." % (type(keypoints),))
  663. return []
  664. if ntype in ["iterable-array[float]",
  665. "iterable-array[int]",
  666. "iterable-array[uint]"]:
  667. nonempty, _, _ = find_first_nonempty(keypoints_old)
  668. input_dtype = nonempty.dtype
  669. return [
  670. restore_dtype_and_merge(kps_i.to_xy_array(), input_dtype)
  671. for kps_i in keypoints]
  672. if ntype == "iterable-tuple[number,size=2]":
  673. assert len(keypoints) == 1, (
  674. "Expected a single KeypointsOnImage instance after normalization "
  675. "due to getting an iterable of (x,y) tuples before "
  676. "normalization. Got %d instances instead." % (len(keypoints),))
  677. return [
  678. (kp.x, kp.y) for kp in keypoints[0].keypoints]
  679. if ntype == "iterable-Keypoint":
  680. assert len(keypoints) == 1, (
  681. "Expected a single KeypointsOnImage instance after normalization "
  682. "due to getting an iterable of Keypoint before "
  683. "normalization. Got %d instances instead." % (len(keypoints),))
  684. return keypoints[0].keypoints
  685. if ntype == "iterable-KeypointsOnImage":
  686. return keypoints
  687. if ntype == "iterable-iterable[empty]":
  688. assert keypoints is None, (
  689. "Expected keypoints after normalization to be None, due "
  690. "to the keypoints before normalization being an empty "
  691. "iterable of iterables. Got type %s instead." % (type(keypoints),))
  692. return keypoints_old[:]
  693. if ntype == "iterable-iterable-tuple[number,size=2]":
  694. return [
  695. [(kp.x, kp.y) for kp in kpsoi.keypoints]
  696. for kpsoi in keypoints]
  697. assert ntype == "iterable-iterable-Keypoint", (
  698. "Got unknown normalization type '%s'." % (ntype,))
  699. return [kpsoi.keypoints[:] for kpsoi in keypoints]
  700. def invert_normalize_bounding_boxes(bounding_boxes, bounding_boxes_old):
  701. ntype = estimate_normalization_type(bounding_boxes_old)
  702. if ntype == "None":
  703. assert bounding_boxes is None, (
  704. "Expected (normalized) 'bounding_boxes' to be None due "
  705. "(unnormalized) 'bounding_boxes_old' being None. Got type %s "
  706. "instead." % (type(bounding_boxes),))
  707. return bounding_boxes
  708. if ntype in ["array[float]", "array[int]", "array[uint]"]:
  709. assert len(bounding_boxes) == 1, (
  710. "Expected a single BoundingBoxesOnImage instance after "
  711. "normalization due to getting a single ndarray before "
  712. "normalization. Got %d instances instead." % (
  713. len(bounding_boxes),))
  714. input_dtype = bounding_boxes_old.dtype
  715. return restore_dtype_and_merge([
  716. bbsoi.to_xyxy_array() for bbsoi in bounding_boxes
  717. ], input_dtype)
  718. if ntype == "tuple[number,size=4]":
  719. assert len(bounding_boxes) == 1, (
  720. "Expected a single BoundingBoxesOnImage instance after "
  721. "normalization due to getting a single (x1,y1,x2,y2) tuple before "
  722. "normalization. Got %d instances instead." % (
  723. len(bounding_boxes),))
  724. assert len(bounding_boxes[0].bounding_boxes) == 1, (
  725. "Expected a BoundingBoxesOnImage instance containing a single "
  726. "BoundingBox after normalization due to getting a single "
  727. "(x1,y1,x2,y2) tuple before normalization. Got %d bounding boxes "
  728. "instead." % (len(bounding_boxes[0].bounding_boxes)))
  729. bb = bounding_boxes[0].bounding_boxes[0]
  730. return bb.x1, bb.y1, bb.x2, bb.y2
  731. if ntype == "BoundingBox":
  732. assert len(bounding_boxes) == 1, (
  733. "Expected a single BoundingBoxesOnImage instance after "
  734. "normalization due to getting a single BoundingBox before "
  735. "normalization. Got %d instances instead." % (
  736. len(bounding_boxes),))
  737. assert len(bounding_boxes[0].bounding_boxes) == 1, (
  738. "Expected a BoundingBoxesOnImage instance containing a single "
  739. "BoundingBox after normalization due to getting a single "
  740. "BoundingBox before normalization. Got %d bounding boxes "
  741. "instead." % (len(bounding_boxes[0].bounding_boxes)))
  742. return bounding_boxes[0].bounding_boxes[0]
  743. if ntype == "BoundingBoxesOnImage":
  744. assert len(bounding_boxes) == 1, (
  745. "Expected a single BoundingBoxesOnImage instance after "
  746. "normalization due to getting a single BoundingBoxesOnImage "
  747. "before normalization. Got %d instances instead." % (
  748. len(bounding_boxes),))
  749. return bounding_boxes[0]
  750. if ntype == "iterable[empty]":
  751. assert bounding_boxes is None, (
  752. "Expected bounding boxes after normalization to be None, due "
  753. "to the bounding boxes before normalization being an empty "
  754. "iterable. Got type %s instead." % (type(bounding_boxes),))
  755. return []
  756. if ntype in ["iterable-array[float]",
  757. "iterable-array[int]",
  758. "iterable-array[uint]"]:
  759. nonempty, _, _ = find_first_nonempty(bounding_boxes_old)
  760. input_dtype = nonempty.dtype
  761. return [
  762. restore_dtype_and_merge(bbsoi.to_xyxy_array(), input_dtype)
  763. for bbsoi in bounding_boxes]
  764. if ntype == "iterable-tuple[number,size=4]":
  765. assert len(bounding_boxes) == 1, (
  766. "Expected a single BoundingBoxesOnImage instance after "
  767. "normalization due to getting a an iterable of (x1,y1,x2,y2) "
  768. "tuples before normalization. Got %d instances instead." % (
  769. len(bounding_boxes),))
  770. return [
  771. (bb.x1, bb.y1, bb.x2, bb.y2)
  772. for bb in bounding_boxes[0].bounding_boxes]
  773. if ntype == "iterable-BoundingBox":
  774. assert len(bounding_boxes) == 1, (
  775. "Expected a single BoundingBoxesOnImage instance after "
  776. "normalization due to getting an iterable of BoundingBox before "
  777. "normalization. Got %d instances instead." % (
  778. len(bounding_boxes),))
  779. return bounding_boxes[0].bounding_boxes
  780. if ntype == "iterable-BoundingBoxesOnImage":
  781. return bounding_boxes
  782. if ntype == "iterable-iterable[empty]":
  783. assert bounding_boxes is None, (
  784. "Expected bounding boxes after normalization to be None, due "
  785. "to the bounding boxes before normalization being an empty "
  786. "iterable of iterables. Got type %s instead." % (
  787. type(bounding_boxes),))
  788. return bounding_boxes_old[:]
  789. if ntype == "iterable-iterable-tuple[number,size=4]":
  790. return [
  791. [(bb.x1, bb.y1, bb.x2, bb.y2) for bb in bbsoi.bounding_boxes]
  792. for bbsoi in bounding_boxes]
  793. assert ntype == "iterable-iterable-BoundingBox", (
  794. "Got unknown normalization type '%s'." % (ntype,))
  795. return [bbsoi.bounding_boxes[:] for bbsoi in bounding_boxes]
  796. def invert_normalize_polygons(polygons, polygons_old):
  797. return _invert_normalize_polygons_and_line_strings(
  798. polygons, polygons_old, estimate_polygons_norm_type,
  799. "Polygon",
  800. "PolygonsOnImage",
  801. lambda psoi: psoi.polygons,
  802. lambda poly: poly.exterior)
  803. def invert_normalize_line_strings(line_strings, line_strings_old):
  804. return _invert_normalize_polygons_and_line_strings(
  805. line_strings, line_strings_old, estimate_line_strings_norm_type,
  806. "LineString",
  807. "LineStringsOnImage",
  808. lambda lsoi: lsoi.line_strings,
  809. lambda ls: ls.coords)
  810. def _invert_normalize_polygons_and_line_strings(inputs, inputs_old,
  811. estimate_ntype_func,
  812. cls_single_name,
  813. cls_oi_name,
  814. get_entities_func,
  815. get_points_func):
  816. # TODO get rid of this deferred import
  817. from imgaug.augmentables.kps import Keypoint
  818. ntype = estimate_ntype_func(inputs_old)
  819. if ntype == "None":
  820. assert inputs is None, (
  821. "Expected (normalized) polygons/line strings to be None due "
  822. "(unnormalized) polygons/line strings being None. Got type %s "
  823. "instead." % (type(inputs),))
  824. return inputs
  825. if ntype in ["array[float]", "array[int]", "array[uint]"]:
  826. input_dtype = inputs_old.dtype
  827. return restore_dtype_and_merge([
  828. [get_points_func(entity) for entity in get_entities_func(oi)]
  829. for oi in inputs
  830. ], input_dtype)
  831. if ntype == cls_single_name:
  832. assert len(inputs) == 1, (
  833. "Expected a single %s instance after normalization "
  834. "due to getting a single %s before normalization. "
  835. "Got %d instances instead." % (
  836. cls_oi_name, cls_single_name, len(inputs),))
  837. assert len(get_entities_func(inputs[0])) == 1, (
  838. "Expected a %s instance containing a single "
  839. "%s after normalization due to getting a single %s "
  840. "before normalization. Got %d instances instead." % (
  841. cls_oi_name, cls_single_name, cls_single_name,
  842. len(get_entities_func(inputs[0]))))
  843. return get_entities_func(inputs[0])[0]
  844. if ntype == cls_oi_name:
  845. assert len(inputs) == 1, (
  846. "Expected a single %s instance after normalization "
  847. "due to getting a single %s before normalization. "
  848. "Got %d instances instead." % (
  849. cls_oi_name, cls_oi_name, len(inputs),))
  850. return inputs[0]
  851. if ntype == "iterable[empty]":
  852. assert inputs is None, (
  853. "Expected polygons/line strings after normalization to be None, "
  854. "due to the polygons/line strings before normalization being an "
  855. "empty iterable. Got type %s instead." % (type(inputs),))
  856. return []
  857. if ntype in ["iterable-array[float]",
  858. "iterable-array[int]",
  859. "iterable-array[uint]"]:
  860. nonempty, _, _ = find_first_nonempty(inputs_old)
  861. input_dtype = nonempty.dtype
  862. return [
  863. restore_dtype_and_merge(
  864. [get_points_func(entity) for entity in get_entities_func(oi)],
  865. input_dtype)
  866. for oi in inputs
  867. ]
  868. if ntype == "iterable-tuple[number,size=2]":
  869. assert len(inputs) == 1, (
  870. "Expected a single %s instance after normalization "
  871. "due to getting an iterable of (x,y) tuples before "
  872. "normalization. Got %d instances instead." % (
  873. cls_oi_name, len(inputs),))
  874. assert len(get_entities_func(inputs[0])) == 1, (
  875. "Expected a %s instance after normalization "
  876. "containing a single %s instance due to getting an iterable "
  877. "of (x,y) tuples before normalization. "
  878. "Got a %s with %d %s instances instead." % (
  879. cls_oi_name, cls_single_name, cls_oi_name, cls_single_name,
  880. len(inputs),))
  881. return [(point[0], point[1])
  882. for point in get_points_func(get_entities_func(inputs[0])[0])]
  883. if ntype == "iterable-Keypoint":
  884. assert len(inputs) == 1, (
  885. "Expected a single %s instance after normalization "
  886. "due to getting an iterable of Keypoint before "
  887. "normalization. Got %d instances instead." % (
  888. cls_oi_name, len(inputs),))
  889. assert len(get_entities_func(inputs[0])) == 1, (
  890. "Expected a %s instance after normalization "
  891. "containing a single %s instance due to getting an iterable "
  892. "of Keypoint before normalization. "
  893. "Got a %s with %d %s instances instead." % (
  894. cls_oi_name, cls_single_name, cls_oi_name, cls_single_name,
  895. len(inputs),))
  896. return [Keypoint(x=point[0], y=point[1])
  897. for point in get_points_func(get_entities_func(inputs[0])[0])]
  898. if ntype == ("iterable-%s" % (cls_single_name,)):
  899. assert len(inputs) == 1, (
  900. "Expected a single %s instance after normalization "
  901. "due to getting an iterable of %s before "
  902. "normalization. Got %d instances instead." % (
  903. cls_oi_name, cls_single_name, len(inputs),))
  904. assert len(get_entities_func(inputs[0])) == len(inputs_old), (
  905. "Expected a %s instance after normalization "
  906. "containing a single %s instance due to getting an iterable "
  907. "of %s before normalization. "
  908. "Got a %s with %d %s instances instead." % (
  909. cls_oi_name, cls_single_name, cls_single_name, cls_oi_name,
  910. cls_single_name, len(inputs),))
  911. return get_entities_func(inputs[0])
  912. if ntype == ("iterable-%s" % (cls_oi_name,)):
  913. return inputs
  914. if ntype == "iterable-iterable[empty]":
  915. assert inputs is None, (
  916. "Expected polygons/line strings after normalization to be None, "
  917. "due to the polygons/line strings before normalization being an "
  918. "empty iterable of iterables. Got type %s instead." % (
  919. type(inputs),))
  920. return inputs_old[:]
  921. if ntype in ["iterable-iterable-array[float]",
  922. "iterable-iterable-array[int]",
  923. "iterable-iterable-array[uint]"]:
  924. nonempty, _, _ = find_first_nonempty(inputs_old)
  925. input_dtype = nonempty.dtype
  926. return [
  927. [restore_dtype_and_merge(get_points_func(entity), input_dtype)
  928. for entity in get_entities_func(oi)]
  929. for oi in inputs
  930. ]
  931. if ntype == "iterable-iterable-tuple[number,size=2]":
  932. assert len(inputs) == 1, (
  933. "Expected a single %s instance after normalization "
  934. "due to getting an iterable of iterables of (x,y) tuples before "
  935. "normalization. Got %d instances instead." % (
  936. cls_oi_name, len(inputs),))
  937. return [
  938. [(point[0], point[1]) for point in get_points_func(entity)]
  939. for entity in get_entities_func(inputs[0])]
  940. if ntype == "iterable-iterable-Keypoint":
  941. assert len(inputs) == 1, (
  942. "Expected a single %s instance after normalization "
  943. "due to getting an iterable of iterables of Keypoint before "
  944. "normalization. Got %d instances instead." % (
  945. cls_oi_name, len(inputs),))
  946. return [
  947. [Keypoint(x=point[0], y=point[1])
  948. for point in get_points_func(entity)]
  949. for entity in get_entities_func(inputs[0])]
  950. if ntype == ("iterable-iterable-%s" % (cls_single_name,)):
  951. return [get_entities_func(oi) for oi in inputs]
  952. if ntype == "iterable-iterable-iterable[empty]":
  953. return inputs_old[:]
  954. if ntype == "iterable-iterable-iterable-tuple[number,size=2]":
  955. return [
  956. [
  957. [
  958. (point[0], point[1])
  959. for point in get_points_func(entity)
  960. ]
  961. for entity in get_entities_func(oi)
  962. ]
  963. for oi in inputs]
  964. assert ntype == "iterable-iterable-iterable-Keypoint", (
  965. "Got unknown normalization type '%s'." % (ntype,))
  966. return [
  967. [
  968. [
  969. Keypoint(x=point[0], y=point[1])
  970. for point in get_points_func(entity)
  971. ]
  972. for entity in get_entities_func(oi)
  973. ]
  974. for oi in inputs]
  975. def _assert_is_of_norm_type(type_str, valid_type_strs, arg_name):
  976. assert type_str in valid_type_strs, (
  977. "Got an unknown datatype for argument '%s'. "
  978. "Expected datatypes were: %s. Got: %s." % (
  979. arg_name, ", ".join(valid_type_strs), type_str))
  980. def estimate_heatmaps_norm_type(heatmaps):
  981. type_str = estimate_normalization_type(heatmaps)
  982. valid_type_strs = [
  983. "None",
  984. "array[float]",
  985. "HeatmapsOnImage",
  986. "iterable[empty]",
  987. "iterable-array[float]",
  988. "iterable-HeatmapsOnImage"
  989. ]
  990. _assert_is_of_norm_type(type_str, valid_type_strs, "heatmaps")
  991. return type_str
  992. def estimate_segmaps_norm_type(segmentation_maps):
  993. type_str = estimate_normalization_type(segmentation_maps)
  994. valid_type_strs = [
  995. "None",
  996. "array[int]",
  997. "array[uint]",
  998. "array[bool]",
  999. "SegmentationMapsOnImage",
  1000. "iterable[empty]",
  1001. "iterable-array[int]",
  1002. "iterable-array[uint]",
  1003. "iterable-array[bool]",
  1004. "iterable-SegmentationMapsOnImage"
  1005. ]
  1006. _assert_is_of_norm_type(
  1007. type_str, valid_type_strs, "segmentation_maps")
  1008. return type_str
  1009. def estimate_keypoints_norm_type(keypoints):
  1010. type_str = estimate_normalization_type(keypoints)
  1011. valid_type_strs = [
  1012. "None",
  1013. "array[float]",
  1014. "array[int]",
  1015. "array[uint]",
  1016. "tuple[number,size=2]",
  1017. "Keypoint",
  1018. "KeypointsOnImage",
  1019. "iterable[empty]",
  1020. "iterable-array[float]",
  1021. "iterable-array[int]",
  1022. "iterable-array[uint]",
  1023. "iterable-tuple[number,size=2]",
  1024. "iterable-Keypoint",
  1025. "iterable-KeypointsOnImage",
  1026. "iterable-iterable[empty]",
  1027. "iterable-iterable-tuple[number,size=2]",
  1028. "iterable-iterable-Keypoint"
  1029. ]
  1030. _assert_is_of_norm_type(type_str, valid_type_strs, "keypoints")
  1031. return type_str
  1032. def estimate_bounding_boxes_norm_type(bounding_boxes):
  1033. type_str = estimate_normalization_type(bounding_boxes)
  1034. valid_type_strs = [
  1035. "None",
  1036. "array[float]",
  1037. "array[int]",
  1038. "array[uint]",
  1039. "tuple[number,size=4]",
  1040. "BoundingBox",
  1041. "BoundingBoxesOnImage",
  1042. "iterable[empty]",
  1043. "iterable-array[float]",
  1044. "iterable-array[int]",
  1045. "iterable-array[uint]",
  1046. "iterable-tuple[number,size=4]",
  1047. "iterable-BoundingBox",
  1048. "iterable-BoundingBoxesOnImage",
  1049. "iterable-iterable[empty]",
  1050. "iterable-iterable-tuple[number,size=4]",
  1051. "iterable-iterable-BoundingBox"
  1052. ]
  1053. _assert_is_of_norm_type(
  1054. type_str, valid_type_strs, "bounding_boxes")
  1055. return type_str
  1056. def estimate_polygons_norm_type(polygons):
  1057. return _estimate_polygons_and_line_segments_norm_type(
  1058. polygons, "Polygon", "PolygonsOnImage", "polygons")
  1059. def estimate_line_strings_norm_type(line_strings):
  1060. return _estimate_polygons_and_line_segments_norm_type(
  1061. line_strings, "LineString", "LineStringsOnImage", "line_strings")
  1062. def _estimate_polygons_and_line_segments_norm_type(inputs, cls_single_name,
  1063. cls_oi_name,
  1064. augmentable_name):
  1065. type_str = estimate_normalization_type(inputs)
  1066. valid_type_strs = [
  1067. "None",
  1068. "array[float]",
  1069. "array[int]",
  1070. "array[uint]",
  1071. cls_single_name,
  1072. cls_oi_name,
  1073. "iterable[empty]",
  1074. "iterable-array[float]",
  1075. "iterable-array[int]",
  1076. "iterable-array[uint]",
  1077. "iterable-tuple[number,size=2]",
  1078. "iterable-Keypoint",
  1079. "iterable-%s" % (cls_single_name,),
  1080. "iterable-%s" % (cls_oi_name,),
  1081. "iterable-iterable[empty]",
  1082. "iterable-iterable-array[float]",
  1083. "iterable-iterable-array[int]",
  1084. "iterable-iterable-array[uint]",
  1085. "iterable-iterable-tuple[number,size=2]",
  1086. "iterable-iterable-Keypoint",
  1087. "iterable-iterable-%s" % (cls_single_name,),
  1088. "iterable-iterable-iterable[empty]",
  1089. "iterable-iterable-iterable-tuple[number,size=2]",
  1090. "iterable-iterable-iterable-Keypoint"
  1091. ]
  1092. _assert_is_of_norm_type(type_str, valid_type_strs, augmentable_name)
  1093. return type_str
  1094. def estimate_normalization_type(inputs):
  1095. nonempty, success, parents = find_first_nonempty(inputs)
  1096. type_str = _nonempty_info_to_type_str(nonempty, success, parents)
  1097. return type_str
  1098. def restore_dtype_and_merge(arr, input_dtype):
  1099. if isinstance(arr, list):
  1100. arr = [restore_dtype_and_merge(arr_i, input_dtype)
  1101. for arr_i in arr]
  1102. shapes = [arr_i.shape for arr_i in arr]
  1103. if len(set(shapes)) == 1:
  1104. arr = np.array(arr)
  1105. if ia.is_np_array(arr):
  1106. arr = iadt.restore_dtypes_(arr, input_dtype)
  1107. return arr
  1108. def _is_iterable(obj):
  1109. return (
  1110. ia.is_iterable(obj)
  1111. and not isinstance(obj, IAugmentable) # not e.g. KeypointsOnImage
  1112. and not hasattr(obj, "coords") # not BBs, Polys, LS
  1113. and not ia.is_string(obj)
  1114. )
  1115. def find_first_nonempty(attr, parents=None):
  1116. if parents is None:
  1117. parents = []
  1118. if attr is None or ia.is_np_array(attr):
  1119. return attr, True, parents
  1120. # we exclude strings here, as otherwise we would get the first
  1121. # character, while we want to get the whole string
  1122. if _is_iterable(attr):
  1123. if len(attr) == 0:
  1124. return None, False, parents
  1125. # this prevents the loop below from becoming infinite if the
  1126. # element in the iterable is identical with the iterable,
  1127. # as is the case for e.g. strings
  1128. if attr[0] is attr:
  1129. return attr, True, parents
  1130. # Usually in case of empty lists, all lists should have similar
  1131. # depth. We are a bit more tolerant here and pick the deepest one.
  1132. # Only parents would really need to be tracked here, we could
  1133. # ignore nonempty and success as they will always have the same
  1134. # values (if only empty lists exist).
  1135. nonempty_deepest = None
  1136. success_deepest = False
  1137. parents_deepest = parents
  1138. for attr_i in attr:
  1139. nonempty, success, parents_found = find_first_nonempty(
  1140. attr_i, parents=parents+[attr])
  1141. if success:
  1142. # on any nonempty hit we return immediately as we assume
  1143. # that the datatypes do not change between child branches
  1144. return nonempty, success, parents_found
  1145. if len(parents_found) > len(parents_deepest):
  1146. nonempty_deepest = nonempty
  1147. success_deepest = success
  1148. parents_deepest = parents_found
  1149. return nonempty_deepest, success_deepest, parents_deepest
  1150. return attr, True, parents
  1151. def _nonempty_info_to_type_str(nonempty, success, parents):
  1152. assert len(parents) <= 4, "Expected 'parents' to be <=4, got %d." % (
  1153. len(parents),)
  1154. parent_iters = ""
  1155. if len(parents) > 0:
  1156. parent_iters = "%s-" % ("-".join(["iterable"] * len(parents)),)
  1157. if not success:
  1158. return "%siterable[empty]" % (parent_iters,)
  1159. is_parent_tuple = (
  1160. len(parents) >= 1
  1161. and isinstance(parents[-1], tuple)
  1162. )
  1163. if is_parent_tuple:
  1164. is_only_numbers_in_tuple = (
  1165. len(parents[-1]) > 0
  1166. and all([ia.is_single_number(val) for val in parents[-1]])
  1167. )
  1168. if is_only_numbers_in_tuple:
  1169. parent_iters = "-".join(["iterable"] * (len(parents)-1))
  1170. tpl_name = "tuple[number,size=%d]" % (len(parents[-1]),)
  1171. return "-".join([parent_iters, tpl_name]).lstrip("-")
  1172. if nonempty is None:
  1173. return "None"
  1174. if ia.is_np_array(nonempty):
  1175. kind = nonempty.dtype.kind
  1176. kind_map = {"f": "float", "u": "uint", "i": "int", "b": "bool"}
  1177. return "%sarray[%s]" % (
  1178. parent_iters, kind_map[kind] if kind in kind_map else kind)
  1179. # even int, str etc. are objects in python, so anything left should
  1180. # offer a __class__ attribute
  1181. assert isinstance(nonempty, object), (
  1182. "Expected 'nonempty' to be an object, got type %s." % (
  1183. type(nonempty),))
  1184. return "%s%s" % (parent_iters, nonempty.__class__.__name__)