size.py 203 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930
  1. """
  2. Augmenters that somehow change the size of the images.
  3. List of augmenters:
  4. * :class:`Resize`
  5. * :class:`CropAndPad`
  6. * :class:`Crop`
  7. * :class:`Pad`
  8. * :class:`PadToFixedSize`
  9. * :class:`CenterPadToFixedSize`
  10. * :class:`CropToFixedSize`
  11. * :class:`CenterCropToFixedSize`
  12. * :class:`CropToMultiplesOf`
  13. * :class:`CenterCropToMultiplesOf`
  14. * :class:`PadToMultiplesOf`
  15. * :class:`CenterPadToMultiplesOf`
  16. * :class:`CropToPowersOf`
  17. * :class:`CenterCropToPowersOf`
  18. * :class:`PadToPowersOf`
  19. * :class:`CenterPadToPowersOf`
  20. * :class:`CropToAspectRatio`
  21. * :class:`CenterCropToAspectRatio`
  22. * :class:`PadToAspectRatio`
  23. * :class:`CenterPadToAspectRatio`
  24. * :class:`CropToSquare`
  25. * :class:`CenterCropToSquare`
  26. * :class:`PadToSquare`
  27. * :class:`CenterPadToSquare`
  28. * :class:`KeepSizeByResize`
  29. """
  30. from __future__ import print_function, division, absolute_import
  31. import re
  32. import functools
  33. import numpy as np
  34. import cv2
  35. import imgaug as ia
  36. from imgaug.imgaug import _normalize_cv2_input_arr_
  37. from . import meta
  38. from .. import parameters as iap
  39. def _crop_trbl_to_xyxy(shape, top, right, bottom, left, prevent_zero_size=True):
  40. if prevent_zero_size:
  41. top, right, bottom, left = _crop_prevent_zero_size(
  42. shape[0], shape[1], top, right, bottom, left)
  43. height, width = shape[0:2]
  44. x1 = left
  45. x2 = width - right
  46. y1 = top
  47. y2 = height - bottom
  48. # these steps prevent negative sizes
  49. # if x2==x1 or y2==y1 then the output arr has size 0 for the respective axis
  50. # note that if height/width of arr is zero, then y2==y1 or x2==x1, which
  51. # is still valid, even if height/width is zero and results in a zero-sized
  52. # axis
  53. x2 = max(x2, x1)
  54. y2 = max(y2, y1)
  55. return x1, y1, x2, y2
  56. def _crop_arr_(arr, top, right, bottom, left, prevent_zero_size=True):
  57. x1, y1, x2, y2 = _crop_trbl_to_xyxy(arr.shape, top, right, bottom, left,
  58. prevent_zero_size=prevent_zero_size)
  59. return arr[y1:y2, x1:x2, ...]
  60. def _crop_and_pad_arr(arr, croppings, paddings, pad_mode="constant",
  61. pad_cval=0, keep_size=False):
  62. height, width = arr.shape[0:2]
  63. image_cr = _crop_arr_(arr, *croppings)
  64. image_cr_pa = pad(
  65. image_cr,
  66. top=paddings[0], right=paddings[1],
  67. bottom=paddings[2], left=paddings[3],
  68. mode=pad_mode, cval=pad_cval)
  69. if keep_size:
  70. image_cr_pa = ia.imresize_single_image(image_cr_pa, (height, width))
  71. return image_cr_pa
  72. def _crop_and_pad_heatmap_(heatmap, croppings_img, paddings_img,
  73. pad_mode="constant", pad_cval=0.0, keep_size=False):
  74. return _crop_and_pad_hms_or_segmaps_(heatmap, croppings_img,
  75. paddings_img, pad_mode, pad_cval,
  76. keep_size)
  77. def _crop_and_pad_segmap_(segmap, croppings_img, paddings_img,
  78. pad_mode="constant", pad_cval=0, keep_size=False):
  79. return _crop_and_pad_hms_or_segmaps_(segmap, croppings_img,
  80. paddings_img, pad_mode, pad_cval,
  81. keep_size)
  82. def _crop_and_pad_hms_or_segmaps_(augmentable, croppings_img,
  83. paddings_img, pad_mode="constant",
  84. pad_cval=None, keep_size=False):
  85. if isinstance(augmentable, ia.HeatmapsOnImage):
  86. arr_attr_name = "arr_0to1"
  87. pad_cval = pad_cval if pad_cval is not None else 0.0
  88. else:
  89. assert isinstance(augmentable, ia.SegmentationMapsOnImage), (
  90. "Expected HeatmapsOnImage or SegmentationMapsOnImage, got %s." % (
  91. type(augmentable)))
  92. arr_attr_name = "arr"
  93. pad_cval = pad_cval if pad_cval is not None else 0
  94. arr = getattr(augmentable, arr_attr_name)
  95. arr_shape_orig = arr.shape
  96. augm_shape = augmentable.shape
  97. croppings_proj = _project_size_changes(croppings_img, augm_shape, arr.shape)
  98. paddings_proj = _project_size_changes(paddings_img, augm_shape, arr.shape)
  99. croppings_proj = _crop_prevent_zero_size(arr.shape[0], arr.shape[1],
  100. *croppings_proj)
  101. arr_cr = _crop_arr_(arr,
  102. croppings_proj[0], croppings_proj[1],
  103. croppings_proj[2], croppings_proj[3])
  104. arr_cr_pa = pad(
  105. arr_cr,
  106. top=paddings_proj[0], right=paddings_proj[1],
  107. bottom=paddings_proj[2], left=paddings_proj[3],
  108. mode=pad_mode,
  109. cval=pad_cval)
  110. setattr(augmentable, arr_attr_name, arr_cr_pa)
  111. if keep_size:
  112. augmentable = augmentable.resize(arr_shape_orig[0:2])
  113. else:
  114. augmentable.shape = _compute_shape_after_crop_and_pad(
  115. augmentable.shape, croppings_img, paddings_img)
  116. return augmentable
  117. def _crop_and_pad_kpsoi_(kpsoi, croppings_img, paddings_img, keep_size):
  118. # using the trbl function instead of croppings_img has the advantage
  119. # of incorporating prevent_zero_size, dealing with zero-sized input image
  120. # axis and dealing the negative crop amounts
  121. x1, y1, _x2, _y2 = _crop_trbl_to_xyxy(kpsoi.shape, *croppings_img)
  122. crop_left = x1
  123. crop_top = y1
  124. shape_orig = kpsoi.shape
  125. shifted = kpsoi.shift_(
  126. x=-crop_left+paddings_img[3],
  127. y=-crop_top+paddings_img[0])
  128. shifted.shape = _compute_shape_after_crop_and_pad(
  129. shape_orig, croppings_img, paddings_img)
  130. if keep_size:
  131. shifted = shifted.on_(shape_orig)
  132. return shifted
  133. def _compute_shape_after_crop_and_pad(old_shape, croppings, paddings):
  134. x1, y1, x2, y2 = _crop_trbl_to_xyxy(old_shape, *croppings)
  135. new_shape = list(old_shape)
  136. new_shape[0] = y2 - y1 + paddings[0] + paddings[2]
  137. new_shape[1] = x2 - x1 + paddings[1] + paddings[3]
  138. return tuple(new_shape)
  139. def _crop_prevent_zero_size(height, width, crop_top, crop_right, crop_bottom,
  140. crop_left):
  141. remaining_height = height - (crop_top + crop_bottom)
  142. remaining_width = width - (crop_left + crop_right)
  143. if remaining_height < 1:
  144. regain = abs(remaining_height) + 1
  145. regain_top = regain // 2
  146. regain_bottom = regain // 2
  147. if regain_top + regain_bottom < regain:
  148. regain_top += 1
  149. if regain_top > crop_top:
  150. diff = regain_top - crop_top
  151. regain_top = crop_top
  152. regain_bottom += diff
  153. elif regain_bottom > crop_bottom:
  154. diff = regain_bottom - crop_bottom
  155. regain_bottom = crop_bottom
  156. regain_top += diff
  157. crop_top = crop_top - regain_top
  158. crop_bottom = crop_bottom - regain_bottom
  159. if remaining_width < 1:
  160. regain = abs(remaining_width) + 1
  161. regain_right = regain // 2
  162. regain_left = regain // 2
  163. if regain_right + regain_left < regain:
  164. regain_right += 1
  165. if regain_right > crop_right:
  166. diff = regain_right - crop_right
  167. regain_right = crop_right
  168. regain_left += diff
  169. elif regain_left > crop_left:
  170. diff = regain_left - crop_left
  171. regain_left = crop_left
  172. regain_right += diff
  173. crop_right = crop_right - regain_right
  174. crop_left = crop_left - regain_left
  175. return (
  176. max(crop_top, 0), max(crop_right, 0), max(crop_bottom, 0),
  177. max(crop_left, 0))
  178. def _project_size_changes(trbl, from_shape, to_shape):
  179. if from_shape[0:2] == to_shape[0:2]:
  180. return trbl
  181. height_to = to_shape[0]
  182. width_to = to_shape[1]
  183. height_from = from_shape[0]
  184. width_from = from_shape[1]
  185. top = trbl[0]
  186. right = trbl[1]
  187. bottom = trbl[2]
  188. left = trbl[3]
  189. # Adding/subtracting 1e-4 here helps for the case where a heatmap/segmap
  190. # is exactly half the size of an image and the size change on an axis is
  191. # an odd value. Then the projected value would end up being <something>.5
  192. # and the rounding would always round up to the next integer. If both
  193. # sides then have the same change, they are both rounded up, resulting
  194. # in more change than expected.
  195. # E.g. image height is 8, map height is 4, change is 3 at the top and 3 at
  196. # the bottom. The changes are projected to 4*(3/8) = 1.5 and both rounded
  197. # up to 2.0. Hence, the maps are changed by 4 (100% of the map height,
  198. # vs. 6 for images, which is 75% of the image height).
  199. top = _int_r(height_to * (top/height_from) - 1e-4)
  200. right = _int_r(width_to * (right/width_from) + 1e-4)
  201. bottom = _int_r(height_to * (bottom/height_from) + 1e-4)
  202. left = _int_r(width_to * (left/width_from) - 1e-4)
  203. return top, right, bottom, left
  204. def _int_r(value):
  205. return int(np.round(value))
  206. # TODO somehow integrate this with pad()
  207. def _handle_pad_mode_param(pad_mode):
  208. pad_modes_available = {
  209. "constant", "edge", "linear_ramp", "maximum", "mean", "median",
  210. "minimum", "reflect", "symmetric", "wrap"}
  211. if pad_mode == ia.ALL:
  212. return iap.Choice(list(pad_modes_available))
  213. if ia.is_string(pad_mode):
  214. assert pad_mode in pad_modes_available, (
  215. "Value '%s' is not a valid pad mode. Valid pad modes are: %s." % (
  216. pad_mode, ", ".join(pad_modes_available)))
  217. return iap.Deterministic(pad_mode)
  218. if isinstance(pad_mode, list):
  219. assert all([v in pad_modes_available for v in pad_mode]), (
  220. "At least one in list %s is not a valid pad mode. Valid pad "
  221. "modes are: %s." % (str(pad_mode), ", ".join(pad_modes_available)))
  222. return iap.Choice(pad_mode)
  223. if isinstance(pad_mode, iap.StochasticParameter):
  224. return pad_mode
  225. raise Exception(
  226. "Expected pad_mode to be ia.ALL or string or list of strings or "
  227. "StochasticParameter, got %s." % (type(pad_mode),))
  228. def _handle_position_parameter(position):
  229. if position == "uniform":
  230. return iap.Uniform(0.0, 1.0), iap.Uniform(0.0, 1.0)
  231. if position == "normal":
  232. return (
  233. iap.Clip(iap.Normal(loc=0.5, scale=0.35 / 2),
  234. minval=0.0, maxval=1.0),
  235. iap.Clip(iap.Normal(loc=0.5, scale=0.35 / 2),
  236. minval=0.0, maxval=1.0)
  237. )
  238. if position == "center":
  239. return iap.Deterministic(0.5), iap.Deterministic(0.5)
  240. if (ia.is_string(position)
  241. and re.match(r"^(left|center|right)-(top|center|bottom)$",
  242. position)):
  243. mapping = {"top": 0.0, "center": 0.5, "bottom": 1.0, "left": 0.0,
  244. "right": 1.0}
  245. return (
  246. iap.Deterministic(mapping[position.split("-")[0]]),
  247. iap.Deterministic(mapping[position.split("-")[1]])
  248. )
  249. if isinstance(position, iap.StochasticParameter):
  250. return position
  251. if isinstance(position, tuple):
  252. assert len(position) == 2, (
  253. "Expected tuple with two entries as position parameter. "
  254. "Got %d entries with types %s.." % (
  255. len(position), str([type(item) for item in position])))
  256. for item in position:
  257. if ia.is_single_number(item) and (item < 0 or item > 1.0):
  258. raise Exception(
  259. "Both position values must be within the value range "
  260. "[0.0, 1.0]. Got type %s with value %.8f." % (
  261. type(item), item,))
  262. position = [iap.Deterministic(item)
  263. if ia.is_single_number(item)
  264. else item for item in position]
  265. only_sparams = all([isinstance(item, iap.StochasticParameter)
  266. for item in position])
  267. assert only_sparams, (
  268. "Expected tuple with two entries that are both either "
  269. "StochasticParameter or float/int. Got types %s." % (
  270. str([type(item) for item in position])
  271. ))
  272. return tuple(position)
  273. raise Exception(
  274. "Expected one of the following as position parameter: string "
  275. "'uniform', string 'normal', string 'center', a string matching "
  276. "regex ^(left|center|right)-(top|center|bottom)$, a single "
  277. "StochasticParameter or a tuple of two entries, both being either "
  278. "StochasticParameter or floats or int. Got instead type %s with "
  279. "content '%s'." % (
  280. type(position),
  281. (str(position)
  282. if len(str(position)) < 20
  283. else str(position)[0:20] + "...")
  284. )
  285. )
  286. # TODO this is the same as in imgaug.py, make DRY
  287. # Added in 0.4.0.
  288. def _assert_two_or_three_dims(shape):
  289. if hasattr(shape, "shape"):
  290. shape = shape.shape
  291. assert len(shape) in [2, 3], (
  292. "Expected image with two or three dimensions, but got %d dimensions "
  293. "and shape %s." % (len(shape), shape))
  294. def pad(arr, top=0, right=0, bottom=0, left=0, mode="constant", cval=0):
  295. """Pad an image-like array on its top/right/bottom/left side.
  296. This function is a wrapper around :func:`numpy.pad`.
  297. Added in 0.4.0. (Previously named ``imgaug.imgaug.pad()``.)
  298. **Supported dtypes**:
  299. * ``uint8``: yes; fully tested (1)
  300. * ``uint16``: yes; fully tested (1)
  301. * ``uint32``: yes; fully tested (2) (3)
  302. * ``uint64``: yes; fully tested (2) (3)
  303. * ``int8``: yes; fully tested (1)
  304. * ``int16``: yes; fully tested (1)
  305. * ``int32``: yes; fully tested (1)
  306. * ``int64``: yes; fully tested (2) (3)
  307. * ``float16``: yes; fully tested (2) (3)
  308. * ``float32``: yes; fully tested (1)
  309. * ``float64``: yes; fully tested (1)
  310. * ``float128``: yes; fully tested (2) (3)
  311. * ``bool``: yes; tested (2) (3)
  312. - (1) Uses ``cv2`` if `mode` is one of: ``"constant"``, ``"edge"``,
  313. ``"reflect"``, ``"symmetric"``. Otherwise uses ``numpy``.
  314. - (2) Uses ``numpy``.
  315. - (3) Rejected by ``cv2``.
  316. Parameters
  317. ----------
  318. arr : (H,W) ndarray or (H,W,C) ndarray
  319. Image-like array to pad.
  320. top : int, optional
  321. Amount of pixels to add to the top side of the image.
  322. Must be ``0`` or greater.
  323. right : int, optional
  324. Amount of pixels to add to the right side of the image.
  325. Must be ``0`` or greater.
  326. bottom : int, optional
  327. Amount of pixels to add to the bottom side of the image.
  328. Must be ``0`` or greater.
  329. left : int, optional
  330. Amount of pixels to add to the left side of the image.
  331. Must be ``0`` or greater.
  332. mode : str, optional
  333. Padding mode to use. See :func:`numpy.pad` for details.
  334. In case of mode ``constant``, the parameter `cval` will be used as
  335. the ``constant_values`` parameter to :func:`numpy.pad`.
  336. In case of mode ``linear_ramp``, the parameter `cval` will be used as
  337. the ``end_values`` parameter to :func:`numpy.pad`.
  338. cval : number or iterable of number, optional
  339. Value to use for padding if `mode` is ``constant``.
  340. See :func:`numpy.pad` for details. The cval is expected to match the
  341. input array's dtype and value range. If an iterable is used, it is
  342. expected to contain one value per channel. The number of values
  343. and number of channels are expected to match.
  344. Returns
  345. -------
  346. (H',W') ndarray or (H',W',C) ndarray
  347. Padded array with height ``H'=H+top+bottom`` and width
  348. ``W'=W+left+right``.
  349. """
  350. import imgaug.dtypes as iadt
  351. _assert_two_or_three_dims(arr)
  352. assert all([v >= 0 for v in [top, right, bottom, left]]), (
  353. "Expected padding amounts that are >=0, but got %d, %d, %d, %d "
  354. "(top, right, bottom, left)" % (top, right, bottom, left))
  355. is_multi_cval = ia.is_iterable(cval)
  356. if top > 0 or right > 0 or bottom > 0 or left > 0:
  357. min_value, _, max_value = iadt.get_value_range_of_dtype(arr.dtype)
  358. # without the if here there are crashes for float128, e.g. if
  359. # cval is an int (just using float(cval) seems to not be accurate
  360. # enough)
  361. if arr.dtype.name == "float128":
  362. cval = np.float128(cval) # pylint: disable=no-member
  363. if is_multi_cval:
  364. cval = np.clip(cval, min_value, max_value)
  365. else:
  366. cval = max(min(cval, max_value), min_value)
  367. # Note that copyMakeBorder() hangs/runs endlessly if arr has an
  368. # axis of size 0 and mode is "reflect".
  369. # Numpy also complains in these cases if mode is not "constant".
  370. has_zero_sized_axis = any([axis == 0 for axis in arr.shape])
  371. if has_zero_sized_axis:
  372. mode = "constant"
  373. mapping_mode_np_to_cv2 = {
  374. "constant": cv2.BORDER_CONSTANT,
  375. "edge": cv2.BORDER_REPLICATE,
  376. "linear_ramp": None,
  377. "maximum": None,
  378. "mean": None,
  379. "median": None,
  380. "minimum": None,
  381. "reflect": cv2.BORDER_REFLECT_101,
  382. "symmetric": cv2.BORDER_REFLECT,
  383. "wrap": None,
  384. cv2.BORDER_CONSTANT: cv2.BORDER_CONSTANT,
  385. cv2.BORDER_REPLICATE: cv2.BORDER_REPLICATE,
  386. cv2.BORDER_REFLECT_101: cv2.BORDER_REFLECT_101,
  387. cv2.BORDER_REFLECT: cv2.BORDER_REFLECT
  388. }
  389. bad_mode_cv2 = mapping_mode_np_to_cv2.get(mode, None) is None
  390. # these datatypes all simply generate a "TypeError: src data type = X
  391. # is not supported" error
  392. bad_datatype_cv2 = (
  393. arr.dtype.name
  394. in ["uint32", "uint64", "int64", "float16", "float128", "bool"]
  395. )
  396. # OpenCV turns the channel axis for arrays with 0 channels to 512
  397. # TODO add direct test for this. indirectly tested via Pad
  398. bad_shape_cv2 = (arr.ndim == 3 and arr.shape[-1] == 0)
  399. if not bad_datatype_cv2 and not bad_mode_cv2 and not bad_shape_cv2:
  400. # convert cval to expected type, as otherwise we get TypeError
  401. # for np inputs
  402. kind = arr.dtype.kind
  403. if is_multi_cval:
  404. cval = [float(cval_c) if kind == "f" else int(cval_c)
  405. for cval_c in cval]
  406. else:
  407. cval = float(cval) if kind == "f" else int(cval)
  408. if arr.ndim == 2 or arr.shape[2] <= 4:
  409. # without this, only the first channel is padded with the cval,
  410. # all following channels with 0
  411. if arr.ndim == 3 and not is_multi_cval:
  412. cval = tuple([cval] * arr.shape[2])
  413. arr_pad = cv2.copyMakeBorder(
  414. _normalize_cv2_input_arr_(arr),
  415. top=top, bottom=bottom, left=left, right=right,
  416. borderType=mapping_mode_np_to_cv2[mode], value=cval)
  417. if arr.ndim == 3 and arr_pad.ndim == 2:
  418. arr_pad = arr_pad[..., np.newaxis]
  419. else:
  420. result = []
  421. channel_start_idx = 0
  422. cval = cval if is_multi_cval else tuple([cval] * arr.shape[2])
  423. while channel_start_idx < arr.shape[2]:
  424. arr_c = arr[..., channel_start_idx:channel_start_idx+4]
  425. cval_c = cval[channel_start_idx:channel_start_idx+4]
  426. arr_pad_c = cv2.copyMakeBorder(
  427. _normalize_cv2_input_arr_(arr_c),
  428. top=top, bottom=bottom, left=left, right=right,
  429. borderType=mapping_mode_np_to_cv2[mode], value=cval_c)
  430. arr_pad_c = np.atleast_3d(arr_pad_c)
  431. result.append(arr_pad_c)
  432. channel_start_idx += 4
  433. arr_pad = np.concatenate(result, axis=2)
  434. else:
  435. # paddings for 2d case
  436. paddings_np = [(top, bottom), (left, right)]
  437. # add paddings for 3d case
  438. if arr.ndim == 3:
  439. paddings_np.append((0, 0))
  440. if mode == "constant":
  441. if arr.ndim > 2 and is_multi_cval:
  442. arr_pad_chans = [
  443. np.pad(arr[..., c], paddings_np[0:2], mode=mode,
  444. constant_values=cval[c])
  445. for c in np.arange(arr.shape[2])]
  446. arr_pad = np.stack(arr_pad_chans, axis=-1)
  447. else:
  448. arr_pad = np.pad(arr, paddings_np, mode=mode,
  449. constant_values=cval)
  450. elif mode == "linear_ramp":
  451. if arr.ndim > 2 and is_multi_cval:
  452. arr_pad_chans = [
  453. np.pad(arr[..., c], paddings_np[0:2], mode=mode,
  454. end_values=cval[c])
  455. for c in np.arange(arr.shape[2])]
  456. arr_pad = np.stack(arr_pad_chans, axis=-1)
  457. else:
  458. arr_pad = np.pad(arr, paddings_np, mode=mode,
  459. end_values=cval)
  460. else:
  461. arr_pad = np.pad(arr, paddings_np, mode=mode)
  462. return arr_pad
  463. return np.copy(arr)
  464. def pad_to_aspect_ratio(arr, aspect_ratio, mode="constant", cval=0,
  465. return_pad_amounts=False):
  466. """Pad an image array on its sides so that it matches a target aspect ratio.
  467. See :func:`~imgaug.imgaug.compute_paddings_for_aspect_ratio` for an
  468. explanation of how the required padding amounts are distributed per
  469. image axis.
  470. Added in 0.4.0. (Previously named ``imgaug.imgaug.pad_to_aspect_ratio()``.)
  471. **Supported dtypes**:
  472. See :func:`~imgaug.augmenters.size.pad`.
  473. Parameters
  474. ----------
  475. arr : (H,W) ndarray or (H,W,C) ndarray
  476. Image-like array to pad.
  477. aspect_ratio : float
  478. Target aspect ratio, given as width/height. E.g. ``2.0`` denotes the
  479. image having twice as much width as height.
  480. mode : str, optional
  481. Padding mode to use. See :func:`~imgaug.imgaug.pad` for details.
  482. cval : number, optional
  483. Value to use for padding if `mode` is ``constant``.
  484. See :func:`numpy.pad` for details.
  485. return_pad_amounts : bool, optional
  486. If ``False``, then only the padded image will be returned. If
  487. ``True``, a ``tuple`` with two entries will be returned, where the
  488. first entry is the padded image and the second entry are the amounts
  489. by which each image side was padded. These amounts are again a
  490. ``tuple`` of the form ``(top, right, bottom, left)``, with each value
  491. being an ``int``.
  492. Returns
  493. -------
  494. (H',W') ndarray or (H',W',C) ndarray
  495. Padded image as ``(H',W')`` or ``(H',W',C)`` ndarray, fulfilling the
  496. given `aspect_ratio`.
  497. tuple of int
  498. Amounts by which the image was padded on each side, given as a
  499. ``tuple`` ``(top, right, bottom, left)``.
  500. This ``tuple`` is only returned if `return_pad_amounts` was set to
  501. ``True``.
  502. """
  503. pad_top, pad_right, pad_bottom, pad_left = \
  504. compute_paddings_to_reach_aspect_ratio(arr, aspect_ratio)
  505. arr_padded = pad(
  506. arr,
  507. top=pad_top,
  508. right=pad_right,
  509. bottom=pad_bottom,
  510. left=pad_left,
  511. mode=mode,
  512. cval=cval
  513. )
  514. if return_pad_amounts:
  515. return arr_padded, (pad_top, pad_right, pad_bottom, pad_left)
  516. return arr_padded
  517. def pad_to_multiples_of(arr, height_multiple, width_multiple, mode="constant",
  518. cval=0, return_pad_amounts=False):
  519. """Pad an image array until its side lengths are multiples of given values.
  520. See :func:`~imgaug.imgaug.compute_paddings_for_aspect_ratio` for an
  521. explanation of how the required padding amounts are distributed per
  522. image axis.
  523. Added in 0.4.0. (Previously named ``imgaug.imgaug.pad_to_multiples_of()``.)
  524. **Supported dtypes**:
  525. See :func:`~imgaug.augmenters.size.pad`.
  526. Parameters
  527. ----------
  528. arr : (H,W) ndarray or (H,W,C) ndarray
  529. Image-like array to pad.
  530. height_multiple : None or int
  531. The desired multiple of the height. The computed padding amount will
  532. reflect a padding that increases the y axis size until it is a multiple
  533. of this value.
  534. width_multiple : None or int
  535. The desired multiple of the width. The computed padding amount will
  536. reflect a padding that increases the x axis size until it is a multiple
  537. of this value.
  538. mode : str, optional
  539. Padding mode to use. See :func:`~imgaug.imgaug.pad` for details.
  540. cval : number, optional
  541. Value to use for padding if `mode` is ``constant``.
  542. See :func:`numpy.pad` for details.
  543. return_pad_amounts : bool, optional
  544. If ``False``, then only the padded image will be returned. If
  545. ``True``, a ``tuple`` with two entries will be returned, where the
  546. first entry is the padded image and the second entry are the amounts
  547. by which each image side was padded. These amounts are again a
  548. ``tuple`` of the form ``(top, right, bottom, left)``, with each value
  549. being an integer.
  550. Returns
  551. -------
  552. (H',W') ndarray or (H',W',C) ndarray
  553. Padded image as ``(H',W')`` or ``(H',W',C)`` ndarray.
  554. tuple of int
  555. Amounts by which the image was padded on each side, given as a
  556. ``tuple`` ``(top, right, bottom, left)``.
  557. This ``tuple`` is only returned if `return_pad_amounts` was set to
  558. ``True``.
  559. """
  560. pad_top, pad_right, pad_bottom, pad_left = \
  561. compute_paddings_to_reach_multiples_of(
  562. arr, height_multiple, width_multiple)
  563. arr_padded = pad(
  564. arr,
  565. top=pad_top,
  566. right=pad_right,
  567. bottom=pad_bottom,
  568. left=pad_left,
  569. mode=mode,
  570. cval=cval
  571. )
  572. if return_pad_amounts:
  573. return arr_padded, (pad_top, pad_right, pad_bottom, pad_left)
  574. return arr_padded
  575. def compute_paddings_to_reach_aspect_ratio(arr, aspect_ratio):
  576. """Compute pad amounts required to fulfill an aspect ratio.
  577. "Pad amounts" here denotes the number of pixels that have to be added to
  578. each side to fulfill the desired constraint.
  579. The aspect ratio is given as ``ratio = width / height``.
  580. Depending on which dimension is smaller (height or width), only the
  581. corresponding sides (top/bottom or left/right) will be padded.
  582. The axis-wise padding amounts are always distributed equally over the
  583. sides of the respective axis (i.e. left and right, top and bottom). For
  584. odd pixel amounts, one pixel will be left over after the equal
  585. distribution and could be added to either side of the axis. This function
  586. will always add such a left over pixel to the bottom (y-axis) or
  587. right (x-axis) side.
  588. Added in 0.4.0. (Previously named
  589. ``imgaug.imgaug.compute_paddings_to_reach_aspect_ratio()``.)
  590. Parameters
  591. ----------
  592. arr : (H,W) ndarray or (H,W,C) ndarray or tuple of int
  593. Image-like array or shape tuple for which to compute pad amounts.
  594. aspect_ratio : float
  595. Target aspect ratio, given as width/height. E.g. ``2.0`` denotes the
  596. image having twice as much width as height.
  597. Returns
  598. -------
  599. tuple of int
  600. Required padding amounts to reach the target aspect ratio, given as a
  601. ``tuple`` of the form ``(top, right, bottom, left)``.
  602. """
  603. _assert_two_or_three_dims(arr)
  604. assert aspect_ratio > 0, (
  605. "Expected to get an aspect ratio >0, got %.4f." % (aspect_ratio,))
  606. pad_top = 0
  607. pad_right = 0
  608. pad_bottom = 0
  609. pad_left = 0
  610. shape = arr.shape if hasattr(arr, "shape") else arr
  611. height, width = shape[0:2]
  612. if height == 0:
  613. height = 1
  614. pad_bottom += 1
  615. if width == 0:
  616. width = 1
  617. pad_right += 1
  618. aspect_ratio_current = width / height
  619. if aspect_ratio_current < aspect_ratio:
  620. # image is more vertical than desired, width needs to be increased
  621. diff = (aspect_ratio * height) - width
  622. pad_right += int(np.ceil(diff / 2))
  623. pad_left += int(np.floor(diff / 2))
  624. elif aspect_ratio_current > aspect_ratio:
  625. # image is more horizontal than desired, height needs to be increased
  626. diff = ((1/aspect_ratio) * width) - height
  627. pad_top += int(np.floor(diff / 2))
  628. pad_bottom += int(np.ceil(diff / 2))
  629. return pad_top, pad_right, pad_bottom, pad_left
  630. def compute_croppings_to_reach_aspect_ratio(arr, aspect_ratio):
  631. """Compute crop amounts required to fulfill an aspect ratio.
  632. "Crop amounts" here denotes the number of pixels that have to be removed
  633. from each side to fulfill the desired constraint.
  634. The aspect ratio is given as ``ratio = width / height``.
  635. Depending on which dimension is smaller (height or width), only the
  636. corresponding sides (top/bottom or left/right) will be cropped.
  637. The axis-wise padding amounts are always distributed equally over the
  638. sides of the respective axis (i.e. left and right, top and bottom). For
  639. odd pixel amounts, one pixel will be left over after the equal
  640. distribution and could be added to either side of the axis. This function
  641. will always add such a left over pixel to the bottom (y-axis) or
  642. right (x-axis) side.
  643. If an aspect ratio cannot be reached exactly, this function will return
  644. rather one pixel too few than one pixel too many.
  645. Added in 0.4.0.
  646. Parameters
  647. ----------
  648. arr : (H,W) ndarray or (H,W,C) ndarray or tuple of int
  649. Image-like array or shape tuple for which to compute crop amounts.
  650. aspect_ratio : float
  651. Target aspect ratio, given as width/height. E.g. ``2.0`` denotes the
  652. image having twice as much width as height.
  653. Returns
  654. -------
  655. tuple of int
  656. Required cropping amounts to reach the target aspect ratio, given as a
  657. ``tuple`` of the form ``(top, right, bottom, left)``.
  658. """
  659. _assert_two_or_three_dims(arr)
  660. assert aspect_ratio > 0, (
  661. "Expected to get an aspect ratio >0, got %.4f." % (aspect_ratio,))
  662. shape = arr.shape if hasattr(arr, "shape") else arr
  663. assert shape[0] > 0, (
  664. "Expected to get an array with height >0, got shape %s." % (shape,))
  665. height, width = shape[0:2]
  666. aspect_ratio_current = width / height
  667. top = 0
  668. right = 0
  669. bottom = 0
  670. left = 0
  671. if aspect_ratio_current < aspect_ratio:
  672. # image is more vertical than desired, height needs to be reduced
  673. # c = H - W/r
  674. crop_amount = height - (width / aspect_ratio)
  675. crop_amount = min(crop_amount, height - 1)
  676. top = int(np.floor(crop_amount / 2))
  677. bottom = int(np.ceil(crop_amount / 2))
  678. elif aspect_ratio_current > aspect_ratio:
  679. # image is more horizontal than desired, width needs to be reduced
  680. # c = W - Hr
  681. crop_amount = width - height * aspect_ratio
  682. crop_amount = min(crop_amount, width - 1)
  683. left = int(np.floor(crop_amount / 2))
  684. right = int(np.ceil(crop_amount / 2))
  685. return top, right, bottom, left
  686. def compute_paddings_to_reach_multiples_of(arr, height_multiple,
  687. width_multiple):
  688. """Compute pad amounts until img height/width are multiples of given values.
  689. See :func:`~imgaug.imgaug.compute_paddings_for_aspect_ratio` for an
  690. explanation of how the required padding amounts are distributed per
  691. image axis.
  692. Added in 0.4.0. (Previously named
  693. ``imgaug.imgaug.compute_paddings_to_reach_multiples_of()``.)
  694. Parameters
  695. ----------
  696. arr : (H,W) ndarray or (H,W,C) ndarray or tuple of int
  697. Image-like array or shape tuple for which to compute pad amounts.
  698. height_multiple : None or int
  699. The desired multiple of the height. The computed padding amount will
  700. reflect a padding that increases the y axis size until it is a multiple
  701. of this value.
  702. width_multiple : None or int
  703. The desired multiple of the width. The computed padding amount will
  704. reflect a padding that increases the x axis size until it is a multiple
  705. of this value.
  706. Returns
  707. -------
  708. tuple of int
  709. Required padding amounts to reach multiples of the provided values,
  710. given as a ``tuple`` of the form ``(top, right, bottom, left)``.
  711. """
  712. def _compute_axis_value(axis_size, multiple):
  713. if multiple is None:
  714. return 0, 0
  715. if axis_size == 0:
  716. to_pad = multiple
  717. elif axis_size % multiple == 0:
  718. to_pad = 0
  719. else:
  720. to_pad = multiple - (axis_size % multiple)
  721. return int(np.floor(to_pad/2)), int(np.ceil(to_pad/2))
  722. _assert_two_or_three_dims(arr)
  723. if height_multiple is not None:
  724. assert height_multiple > 0, (
  725. "Can only pad to multiples of 1 or larger, got %d." % (
  726. height_multiple,))
  727. if width_multiple is not None:
  728. assert width_multiple > 0, (
  729. "Can only pad to multiples of 1 or larger, got %d." % (
  730. width_multiple,))
  731. shape = arr.shape if hasattr(arr, "shape") else arr
  732. height, width = shape[0:2]
  733. top, bottom = _compute_axis_value(height, height_multiple)
  734. left, right = _compute_axis_value(width, width_multiple)
  735. return top, right, bottom, left
  736. def compute_croppings_to_reach_multiples_of(arr, height_multiple,
  737. width_multiple):
  738. """Compute croppings to reach multiples of given heights/widths.
  739. See :func:`~imgaug.imgaug.compute_paddings_for_aspect_ratio` for an
  740. explanation of how the required cropping amounts are distributed per
  741. image axis.
  742. Added in 0.4.0.
  743. Parameters
  744. ----------
  745. arr : (H,W) ndarray or (H,W,C) ndarray or tuple of int
  746. Image-like array or shape tuple for which to compute crop amounts.
  747. height_multiple : None or int
  748. The desired multiple of the height. The computed croppings will
  749. reflect a crop operation that decreases the y axis size until it is
  750. a multiple of this value.
  751. width_multiple : None or int
  752. The desired multiple of the width. The computed croppings amount will
  753. reflect a crop operation that decreases the x axis size until it is
  754. a multiple of this value.
  755. Returns
  756. -------
  757. tuple of int
  758. Required cropping amounts to reach multiples of the provided values,
  759. given as a ``tuple`` of the form ``(top, right, bottom, left)``.
  760. """
  761. def _compute_axis_value(axis_size, multiple):
  762. if multiple is None:
  763. return 0, 0
  764. if axis_size == 0:
  765. to_crop = 0
  766. elif axis_size % multiple == 0:
  767. to_crop = 0
  768. else:
  769. to_crop = axis_size % multiple
  770. return int(np.floor(to_crop/2)), int(np.ceil(to_crop/2))
  771. _assert_two_or_three_dims(arr)
  772. if height_multiple is not None:
  773. assert height_multiple > 0, (
  774. "Can only crop to multiples of 1 or larger, got %d." % (
  775. height_multiple,))
  776. if width_multiple is not None:
  777. assert width_multiple > 0, (
  778. "Can only crop to multiples of 1 or larger, got %d." % (
  779. width_multiple,))
  780. shape = arr.shape if hasattr(arr, "shape") else arr
  781. height, width = shape[0:2]
  782. top, bottom = _compute_axis_value(height, height_multiple)
  783. left, right = _compute_axis_value(width, width_multiple)
  784. return top, right, bottom, left
  785. def compute_paddings_to_reach_powers_of(arr, height_base, width_base,
  786. allow_zero_exponent=False):
  787. """Compute paddings to reach powers of given base values.
  788. For given axis size ``S``, padded size ``S'`` (``S' >= S``) and base ``B``
  789. this function computes paddings that fulfill ``S' = B^E``, where ``E``
  790. is any exponent from the discrete interval ``[0 .. inf)``.
  791. See :func:`~imgaug.imgaug.compute_paddings_for_aspect_ratio` for an
  792. explanation of how the required padding amounts are distributed per
  793. image axis.
  794. Added in 0.4.0. (Previously named
  795. ``imgaug.imgaug.compute_paddings_to_reach_exponents_of()``.)
  796. Parameters
  797. ----------
  798. arr : (H,W) ndarray or (H,W,C) ndarray or tuple of int
  799. Image-like array or shape tuple for which to compute pad amounts.
  800. height_base : None or int
  801. The desired base of the height.
  802. width_base : None or int
  803. The desired base of the width.
  804. allow_zero_exponent : bool, optional
  805. Whether ``E=0`` in ``S'=B^E`` is a valid value. If ``True``, axes
  806. with size ``0`` or ``1`` will be padded up to size ``B^0=1`` and
  807. axes with size ``1 < S <= B`` will be padded up to ``B^1=B``.
  808. If ``False``, the minimum output axis size is always at least ``B``.
  809. Returns
  810. -------
  811. tuple of int
  812. Required padding amounts to fulfill ``S' = B^E`` given as a
  813. ``tuple`` of the form ``(top, right, bottom, left)``.
  814. """
  815. def _compute_axis_value(axis_size, base):
  816. if base is None:
  817. return 0, 0
  818. if axis_size == 0:
  819. to_pad = 1 if allow_zero_exponent else base
  820. elif axis_size <= base:
  821. to_pad = base - axis_size
  822. else:
  823. # log_{base}(axis_size) in numpy
  824. exponent = np.log(axis_size) / np.log(base)
  825. to_pad = (base ** int(np.ceil(exponent))) - axis_size
  826. return int(np.floor(to_pad/2)), int(np.ceil(to_pad/2))
  827. _assert_two_or_three_dims(arr)
  828. if height_base is not None:
  829. assert height_base > 1, (
  830. "Can only pad to base larger than 1, got %d." % (height_base,))
  831. if width_base is not None:
  832. assert width_base > 1, (
  833. "Can only pad to base larger than 1, got %d." % (width_base,))
  834. shape = arr.shape if hasattr(arr, "shape") else arr
  835. height, width = shape[0:2]
  836. top, bottom = _compute_axis_value(height, height_base)
  837. left, right = _compute_axis_value(width, width_base)
  838. return top, right, bottom, left
  839. def compute_croppings_to_reach_powers_of(arr, height_base, width_base,
  840. allow_zero_exponent=False):
  841. """Compute croppings to reach powers of given base values.
  842. For given axis size ``S``, cropped size ``S'`` (``S' <= S``) and base ``B``
  843. this function computes croppings that fulfill ``S' = B^E``, where ``E``
  844. is any exponent from the discrete interval ``[0 .. inf)``.
  845. See :func:`~imgaug.imgaug.compute_paddings_for_aspect_ratio` for an
  846. explanation of how the required cropping amounts are distributed per
  847. image axis.
  848. .. note::
  849. For axes where ``S == 0``, this function alwayws returns zeros as
  850. croppings.
  851. For axes where ``1 <= S < B`` see parameter `allow_zero_exponent`.
  852. Added in 0.4.0.
  853. Parameters
  854. ----------
  855. arr : (H,W) ndarray or (H,W,C) ndarray or tuple of int
  856. Image-like array or shape tuple for which to compute crop amounts.
  857. height_base : None or int
  858. The desired base of the height.
  859. width_base : None or int
  860. The desired base of the width.
  861. allow_zero_exponent : bool
  862. Whether ``E=0`` in ``S'=B^E`` is a valid value. If ``True``, axes
  863. with size ``1 <= S < B`` will be cropped to size ``B^0=1``.
  864. If ``False``, axes with sizes ``S < B`` will not be changed.
  865. Returns
  866. -------
  867. tuple of int
  868. Required cropping amounts to fulfill ``S' = B^E`` given as a
  869. ``tuple`` of the form ``(top, right, bottom, left)``.
  870. """
  871. def _compute_axis_value(axis_size, base):
  872. if base is None:
  873. return 0, 0
  874. if axis_size == 0:
  875. to_crop = 0
  876. elif axis_size < base:
  877. # crop down to B^0 = 1
  878. to_crop = axis_size - 1 if allow_zero_exponent else 0
  879. else:
  880. # log_{base}(axis_size) in numpy
  881. exponent = np.log(axis_size) / np.log(base)
  882. to_crop = axis_size - (base ** int(exponent))
  883. return int(np.floor(to_crop/2)), int(np.ceil(to_crop/2))
  884. _assert_two_or_three_dims(arr)
  885. if height_base is not None:
  886. assert height_base > 1, (
  887. "Can only crop to base larger than 1, got %d." % (height_base,))
  888. if width_base is not None:
  889. assert width_base > 1, (
  890. "Can only crop to base larger than 1, got %d." % (width_base,))
  891. shape = arr.shape if hasattr(arr, "shape") else arr
  892. height, width = shape[0:2]
  893. top, bottom = _compute_axis_value(height, height_base)
  894. left, right = _compute_axis_value(width, width_base)
  895. return top, right, bottom, left
  896. @ia.deprecated(alt_func="Resize",
  897. comment="Resize has the exactly same interface as Scale.")
  898. def Scale(*args, **kwargs):
  899. """Augmenter that resizes images to specified heights and widths."""
  900. # pylint: disable=invalid-name
  901. return Resize(*args, **kwargs)
  902. class Resize(meta.Augmenter):
  903. """Augmenter that resizes images to specified heights and widths.
  904. **Supported dtypes**:
  905. See :func:`~imgaug.imgaug.imresize_many_images`.
  906. Parameters
  907. ----------
  908. size : 'keep' or int or float or tuple of int or tuple of float or list of int or list of float or imgaug.parameters.StochasticParameter or dict
  909. The new size of the images.
  910. * If this has the string value ``keep``, the original height and
  911. width values will be kept (image is not resized).
  912. * If this is an ``int``, this value will always be used as the new
  913. height and width of the images.
  914. * If this is a ``float`` ``v``, then per image the image's height
  915. ``H`` and width ``W`` will be changed to ``H*v`` and ``W*v``.
  916. * If this is a ``tuple``, it is expected to have two entries
  917. ``(a, b)``. If at least one of these are ``float`` s, a value
  918. will be sampled from range ``[a, b]`` and used as the ``float``
  919. value to resize the image (see above). If both are ``int`` s, a
  920. value will be sampled from the discrete range ``[a..b]`` and
  921. used as the integer value to resize the image (see above).
  922. * If this is a ``list``, a random value from the ``list`` will be
  923. picked to resize the image. All values in the ``list`` must be
  924. ``int`` s or ``float`` s (no mixture is possible).
  925. * If this is a ``StochasticParameter``, then this parameter will
  926. first be queried once per image. The resulting value will be used
  927. for both height and width.
  928. * If this is a ``dict``, it may contain the keys ``height`` and
  929. ``width`` or the keys ``shorter-side`` and ``longer-side``. Each
  930. key may have the same datatypes as above and describes the
  931. scaling on x and y-axis or the shorter and longer axis,
  932. respectively. Both axis are sampled independently. Additionally,
  933. one of the keys may have the value ``keep-aspect-ratio``, which
  934. means that the respective side of the image will be resized so
  935. that the original aspect ratio is kept. This is useful when only
  936. resizing one image size by a pixel value (e.g. resize images to
  937. a height of ``64`` pixels and resize the width so that the
  938. overall aspect ratio is maintained).
  939. interpolation : imgaug.ALL or int or str or list of int or list of str or imgaug.parameters.StochasticParameter, optional
  940. Interpolation to use.
  941. * If ``imgaug.ALL``, then a random interpolation from ``nearest``,
  942. ``linear``, ``area`` or ``cubic`` will be picked (per image).
  943. * If ``int``, then this interpolation will always be used.
  944. Expected to be any of the following:
  945. ``cv2.INTER_NEAREST``, ``cv2.INTER_LINEAR``, ``cv2.INTER_AREA``,
  946. ``cv2.INTER_CUBIC``
  947. * If string, then this interpolation will always be used.
  948. Expected to be any of the following:
  949. ``nearest``, ``linear``, ``area``, ``cubic``
  950. * If ``list`` of ``int`` / ``str``, then a random one of the values
  951. will be picked per image as the interpolation.
  952. * If a ``StochasticParameter``, then this parameter will be
  953. queried per image and is expected to return an ``int`` or
  954. ``str``.
  955. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  956. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  957. name : None or str, optional
  958. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  959. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  960. Old name for parameter `seed`.
  961. Its usage will not yet cause a deprecation warning,
  962. but it is still recommended to use `seed` now.
  963. Outdated since 0.4.0.
  964. deterministic : bool, optional
  965. Deprecated since 0.4.0.
  966. See method ``to_deterministic()`` for an alternative and for
  967. details about what the "deterministic mode" actually does.
  968. Examples
  969. --------
  970. >>> import imgaug.augmenters as iaa
  971. >>> aug = iaa.Resize(32)
  972. Resize all images to ``32x32`` pixels.
  973. >>> aug = iaa.Resize(0.5)
  974. Resize all images to ``50`` percent of their original size.
  975. >>> aug = iaa.Resize((16, 22))
  976. Resize all images to a random height and width within the discrete
  977. interval ``[16..22]`` (uniformly sampled per image).
  978. >>> aug = iaa.Resize((0.5, 0.75))
  979. Resize all any input image so that its height (``H``) and width (``W``)
  980. become ``H*v`` and ``W*v``, where ``v`` is uniformly sampled from the
  981. interval ``[0.5, 0.75]``.
  982. >>> aug = iaa.Resize([16, 32, 64])
  983. Resize all images either to ``16x16``, ``32x32`` or ``64x64`` pixels.
  984. >>> aug = iaa.Resize({"height": 32})
  985. Resize all images to a height of ``32`` pixels and keeps the original
  986. width.
  987. >>> aug = iaa.Resize({"height": 32, "width": 48})
  988. Resize all images to a height of ``32`` pixels and a width of ``48``.
  989. >>> aug = iaa.Resize({"height": 32, "width": "keep-aspect-ratio"})
  990. Resize all images to a height of ``32`` pixels and resizes the
  991. x-axis (width) so that the aspect ratio is maintained.
  992. >>> aug = iaa.Resize(
  993. >>> {"shorter-side": 224, "longer-side": "keep-aspect-ratio"})
  994. Resize all images to a height/width of ``224`` pixels, depending on which
  995. axis is shorter and resize the other axis so that the aspect ratio is
  996. maintained.
  997. >>> aug = iaa.Resize({"height": (0.5, 0.75), "width": [16, 32, 64]})
  998. Resize all images to a height of ``H*v``, where ``H`` is the original
  999. height and ``v`` is a random value sampled from the interval
  1000. ``[0.5, 0.75]``. The width/x-axis of each image is resized to either
  1001. ``16`` or ``32`` or ``64`` pixels.
  1002. >>> aug = iaa.Resize(32, interpolation=["linear", "cubic"])
  1003. Resize all images to ``32x32`` pixels. Randomly use either ``linear``
  1004. or ``cubic`` interpolation.
  1005. """
  1006. def __init__(self, size, interpolation="cubic",
  1007. seed=None, name=None,
  1008. random_state="deprecated", deterministic="deprecated"):
  1009. super(Resize, self).__init__(
  1010. seed=seed, name=name,
  1011. random_state=random_state, deterministic=deterministic)
  1012. self.size, self.size_order = self._handle_size_arg(size, False)
  1013. self.interpolation = self._handle_interpolation_arg(interpolation)
  1014. @classmethod
  1015. def _handle_size_arg(cls, size, subcall):
  1016. def _dict_to_size_tuple(val1, val2):
  1017. kaa = "keep-aspect-ratio"
  1018. not_both_kaa = (val1 != kaa or val2 != kaa)
  1019. assert not_both_kaa, (
  1020. "Expected at least one value to not be \"keep-aspect-ratio\", "
  1021. "but got it two times.")
  1022. size_tuple = []
  1023. for k in [val1, val2]:
  1024. if k in ["keep-aspect-ratio", "keep"]:
  1025. entry = iap.Deterministic(k)
  1026. else:
  1027. entry = cls._handle_size_arg(k, True)
  1028. size_tuple.append(entry)
  1029. return tuple(size_tuple)
  1030. def _contains_any_key(dict_, keys):
  1031. return any([key in dict_ for key in keys])
  1032. # HW = height, width
  1033. # SL = shorter, longer
  1034. size_order = "HW"
  1035. if size == "keep":
  1036. result = iap.Deterministic("keep")
  1037. elif ia.is_single_number(size):
  1038. assert size > 0, "Expected only values > 0, got %s" % (size,)
  1039. result = iap.Deterministic(size)
  1040. elif not subcall and isinstance(size, dict):
  1041. if len(size.keys()) == 0:
  1042. result = iap.Deterministic("keep")
  1043. elif _contains_any_key(size, ["height", "width"]):
  1044. height = size.get("height", "keep")
  1045. width = size.get("width", "keep")
  1046. result = _dict_to_size_tuple(height, width)
  1047. elif _contains_any_key(size, ["shorter-side", "longer-side"]):
  1048. shorter = size.get("shorter-side", "keep")
  1049. longer = size.get("longer-side", "keep")
  1050. result = _dict_to_size_tuple(shorter, longer)
  1051. size_order = "SL"
  1052. else:
  1053. raise ValueError(
  1054. "Expected dictionary containing no keys, "
  1055. "the keys \"height\" and/or \"width\", "
  1056. "or the keys \"shorter-side\" and/or \"longer-side\". "
  1057. "Got keys: %s." % (str(size.keys()),))
  1058. elif isinstance(size, tuple):
  1059. assert len(size) == 2, (
  1060. "Expected size tuple to contain exactly 2 values, "
  1061. "got %d." % (len(size),))
  1062. assert size[0] > 0 and size[1] > 0, (
  1063. "Expected size tuple to only contain values >0, "
  1064. "got %d and %d." % (size[0], size[1]))
  1065. if ia.is_single_float(size[0]) or ia.is_single_float(size[1]):
  1066. result = iap.Uniform(size[0], size[1])
  1067. else:
  1068. result = iap.DiscreteUniform(size[0], size[1])
  1069. elif isinstance(size, list):
  1070. if len(size) == 0:
  1071. result = iap.Deterministic("keep")
  1072. else:
  1073. all_int = all([ia.is_single_integer(v) for v in size])
  1074. all_float = all([ia.is_single_float(v) for v in size])
  1075. assert all_int or all_float, (
  1076. "Expected to get only integers or floats.")
  1077. assert all([v > 0 for v in size]), (
  1078. "Expected all values to be >0.")
  1079. result = iap.Choice(size)
  1080. elif isinstance(size, iap.StochasticParameter):
  1081. result = size
  1082. else:
  1083. raise ValueError(
  1084. "Expected number, tuple of two numbers, list of numbers, "
  1085. "dictionary of form "
  1086. "{'height': number/tuple/list/'keep-aspect-ratio'/'keep', "
  1087. "'width': <analogous>}, dictionary of form "
  1088. "{'shorter-side': number/tuple/list/'keep-aspect-ratio'/"
  1089. "'keep', 'longer-side': <analogous>} "
  1090. "or StochasticParameter, got %s." % (type(size),)
  1091. )
  1092. if subcall:
  1093. return result
  1094. return result, size_order
  1095. @classmethod
  1096. def _handle_interpolation_arg(cls, interpolation):
  1097. if interpolation == ia.ALL:
  1098. interpolation = iap.Choice(
  1099. ["nearest", "linear", "area", "cubic"])
  1100. elif ia.is_single_integer(interpolation):
  1101. interpolation = iap.Deterministic(interpolation)
  1102. elif ia.is_string(interpolation):
  1103. interpolation = iap.Deterministic(interpolation)
  1104. elif ia.is_iterable(interpolation):
  1105. interpolation = iap.Choice(interpolation)
  1106. elif isinstance(interpolation, iap.StochasticParameter):
  1107. pass
  1108. else:
  1109. raise Exception(
  1110. "Expected int or string or iterable or StochasticParameter, "
  1111. "got %s." % (type(interpolation),))
  1112. return interpolation
  1113. # Added in 0.4.0.
  1114. def _augment_batch_(self, batch, random_state, parents, hooks):
  1115. nb_rows = batch.nb_rows
  1116. samples = self._draw_samples(nb_rows, random_state)
  1117. if batch.images is not None:
  1118. batch.images = self._augment_images_by_samples(batch.images,
  1119. samples)
  1120. if batch.heatmaps is not None:
  1121. # TODO this uses the same interpolation as for images for heatmaps
  1122. # while other augmenters resort to cubic
  1123. batch.heatmaps = self._augment_maps_by_samples(
  1124. batch.heatmaps, "arr_0to1", samples)
  1125. if batch.segmentation_maps is not None:
  1126. batch.segmentation_maps = self._augment_maps_by_samples(
  1127. batch.segmentation_maps, "arr",
  1128. (samples[0], samples[1], [None] * nb_rows))
  1129. for augm_name in ["keypoints", "bounding_boxes", "polygons",
  1130. "line_strings"]:
  1131. augm_value = getattr(batch, augm_name)
  1132. if augm_value is not None:
  1133. func = functools.partial(
  1134. self._augment_keypoints_by_samples,
  1135. samples=samples)
  1136. cbaois = self._apply_to_cbaois_as_keypoints(augm_value, func)
  1137. setattr(batch, augm_name, cbaois)
  1138. return batch
  1139. # Added in 0.4.0.
  1140. def _augment_images_by_samples(self, images, samples):
  1141. input_was_array = False
  1142. input_dtype = None
  1143. if ia.is_np_array(images):
  1144. input_was_array = True
  1145. input_dtype = images.dtype
  1146. samples_a, samples_b, samples_ip = samples
  1147. result = []
  1148. for i, image in enumerate(images):
  1149. h, w = self._compute_height_width(image.shape, samples_a[i],
  1150. samples_b[i], self.size_order)
  1151. image_rs = ia.imresize_single_image(image, (h, w),
  1152. interpolation=samples_ip[i])
  1153. result.append(image_rs)
  1154. if input_was_array:
  1155. all_same_size = (len({image.shape for image in result}) == 1)
  1156. if all_same_size:
  1157. result = np.array(result, dtype=input_dtype)
  1158. return result
  1159. # Added in 0.4.0.
  1160. def _augment_maps_by_samples(self, augmentables, arr_attr_name, samples):
  1161. result = []
  1162. samples_h, samples_w, samples_ip = samples
  1163. for i, augmentable in enumerate(augmentables):
  1164. arr = getattr(augmentable, arr_attr_name)
  1165. arr_shape = arr.shape
  1166. img_shape = augmentable.shape
  1167. h_img, w_img = self._compute_height_width(
  1168. img_shape, samples_h[i], samples_w[i], self.size_order)
  1169. h = int(np.round(h_img * (arr_shape[0] / img_shape[0])))
  1170. w = int(np.round(w_img * (arr_shape[1] / img_shape[1])))
  1171. h = max(h, 1)
  1172. w = max(w, 1)
  1173. if samples_ip[0] is not None:
  1174. # TODO change this for heatmaps to always have cubic or
  1175. # automatic interpolation?
  1176. augmentable_resize = augmentable.resize(
  1177. (h, w), interpolation=samples_ip[i])
  1178. else:
  1179. augmentable_resize = augmentable.resize((h, w))
  1180. augmentable_resize.shape = (h_img, w_img) + img_shape[2:]
  1181. result.append(augmentable_resize)
  1182. return result
  1183. # Added in 0.4.0.
  1184. def _augment_keypoints_by_samples(self, kpsois, samples):
  1185. result = []
  1186. samples_a, samples_b, _samples_ip = samples
  1187. for i, kpsoi in enumerate(kpsois):
  1188. h, w = self._compute_height_width(
  1189. kpsoi.shape, samples_a[i], samples_b[i], self.size_order)
  1190. new_shape = (h, w) + kpsoi.shape[2:]
  1191. keypoints_on_image_rs = kpsoi.on_(new_shape)
  1192. result.append(keypoints_on_image_rs)
  1193. return result
  1194. def _draw_samples(self, nb_images, random_state):
  1195. rngs = random_state.duplicate(3)
  1196. if isinstance(self.size, tuple):
  1197. samples_h = self.size[0].draw_samples(nb_images,
  1198. random_state=rngs[0])
  1199. samples_w = self.size[1].draw_samples(nb_images,
  1200. random_state=rngs[1])
  1201. else:
  1202. samples_h = self.size.draw_samples(nb_images, random_state=rngs[0])
  1203. samples_w = samples_h
  1204. samples_ip = self.interpolation.draw_samples(nb_images,
  1205. random_state=rngs[2])
  1206. return samples_h, samples_w, samples_ip
  1207. @classmethod
  1208. def _compute_height_width(cls, image_shape, sample_a, sample_b, size_order):
  1209. imh, imw = image_shape[0:2]
  1210. if size_order == 'SL':
  1211. # size order: short, long
  1212. if imh < imw:
  1213. h, w = sample_a, sample_b
  1214. else:
  1215. w, h = sample_a, sample_b
  1216. else:
  1217. # size order: height, width
  1218. h, w = sample_a, sample_b
  1219. if ia.is_single_float(h):
  1220. assert h > 0, "Expected 'h' to be >0, got %.4f" % (h,)
  1221. h = int(np.round(imh * h))
  1222. h = h if h > 0 else 1
  1223. elif h == "keep":
  1224. h = imh
  1225. if ia.is_single_float(w):
  1226. assert w > 0, "Expected 'w' to be >0, got %.4f" % (w,)
  1227. w = int(np.round(imw * w))
  1228. w = w if w > 0 else 1
  1229. elif w == "keep":
  1230. w = imw
  1231. # at least the checks for keep-aspect-ratio must come after
  1232. # the float checks, as they are dependent on the results
  1233. # this is also why these are not written as elifs
  1234. if h == "keep-aspect-ratio":
  1235. h_per_w_orig = imh / imw
  1236. h = int(np.round(w * h_per_w_orig))
  1237. if w == "keep-aspect-ratio":
  1238. w_per_h_orig = imw / imh
  1239. w = int(np.round(h * w_per_h_orig))
  1240. return h, w
  1241. def get_parameters(self):
  1242. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  1243. return [self.size, self.interpolation, self.size_order]
  1244. class _CropAndPadSamplingResult(object):
  1245. def __init__(self, crop_top, crop_right, crop_bottom, crop_left,
  1246. pad_top, pad_right, pad_bottom, pad_left, pad_mode, pad_cval):
  1247. self.crop_top = crop_top
  1248. self.crop_right = crop_right
  1249. self.crop_bottom = crop_bottom
  1250. self.crop_left = crop_left
  1251. self.pad_top = pad_top
  1252. self.pad_right = pad_right
  1253. self.pad_bottom = pad_bottom
  1254. self.pad_left = pad_left
  1255. self.pad_mode = pad_mode
  1256. self.pad_cval = pad_cval
  1257. @property
  1258. def croppings(self):
  1259. """Get absolute pixel amounts of croppings as a TRBL tuple."""
  1260. return self.crop_top, self.crop_right, self.crop_bottom, self.crop_left
  1261. @property
  1262. def paddings(self):
  1263. """Get absolute pixel amounts of paddings as a TRBL tuple."""
  1264. return self.pad_top, self.pad_right, self.pad_bottom, self.pad_left
  1265. class CropAndPad(meta.Augmenter):
  1266. """Crop/pad images by pixel amounts or fractions of image sizes.
  1267. Cropping removes pixels at the sides (i.e. extracts a subimage from
  1268. a given full image). Padding adds pixels to the sides (e.g. black pixels).
  1269. This augmenter will never crop images below a height or width of ``1``.
  1270. .. note::
  1271. This augmenter automatically resizes images back to their original size
  1272. after it has augmented them. To deactivate this, add the
  1273. parameter ``keep_size=False``.
  1274. **Supported dtypes**:
  1275. if (keep_size=False):
  1276. * ``uint8``: yes; fully tested
  1277. * ``uint16``: yes; tested
  1278. * ``uint32``: yes; tested
  1279. * ``uint64``: yes; tested
  1280. * ``int8``: yes; tested
  1281. * ``int16``: yes; tested
  1282. * ``int32``: yes; tested
  1283. * ``int64``: yes; tested
  1284. * ``float16``: yes; tested
  1285. * ``float32``: yes; tested
  1286. * ``float64``: yes; tested
  1287. * ``float128``: yes; tested
  1288. * ``bool``: yes; tested
  1289. if (keep_size=True):
  1290. minimum of (
  1291. ``imgaug.augmenters.size.CropAndPad(keep_size=False)``,
  1292. :func:`~imgaug.imgaug.imresize_many_images`
  1293. )
  1294. Parameters
  1295. ----------
  1296. px : None or int or imgaug.parameters.StochasticParameter or tuple, optional
  1297. The number of pixels to crop (negative values) or pad (positive values)
  1298. on each side of the image. Either this or the parameter `percent` may
  1299. be set, not both at the same time.
  1300. * If ``None``, then pixel-based cropping/padding will not be used.
  1301. * If ``int``, then that exact number of pixels will always be
  1302. cropped/padded.
  1303. * If ``StochasticParameter``, then that parameter will be used for
  1304. each image. Four samples will be drawn per image (top, right,
  1305. bottom, left), unless `sample_independently` is set to ``False``,
  1306. as then only one value will be sampled per image and used for
  1307. all sides.
  1308. * If a ``tuple`` of two ``int`` s with values ``a`` and ``b``,
  1309. then each side will be cropped/padded by a random amount sampled
  1310. uniformly per image and side from the inteval ``[a, b]``. If
  1311. however `sample_independently` is set to ``False``, only one
  1312. value will be sampled per image and used for all sides.
  1313. * If a ``tuple`` of four entries, then the entries represent top,
  1314. right, bottom, left. Each entry may be a single ``int`` (always
  1315. crop/pad by exactly that value), a ``tuple`` of two ``int`` s
  1316. ``a`` and ``b`` (crop/pad by an amount within ``[a, b]``), a
  1317. ``list`` of ``int`` s (crop/pad by a random value that is
  1318. contained in the ``list``) or a ``StochasticParameter`` (sample
  1319. the amount to crop/pad from that parameter).
  1320. percent : None or number or imgaug.parameters.StochasticParameter or tuple, optional
  1321. The number of pixels to crop (negative values) or pad (positive values)
  1322. on each side of the image given as a *fraction* of the image
  1323. height/width. E.g. if this is set to ``-0.1``, the augmenter will
  1324. always crop away ``10%`` of the image's height at both the top and the
  1325. bottom (both ``10%`` each), as well as ``10%`` of the width at the
  1326. right and left.
  1327. Expected value range is ``(-1.0, inf)``.
  1328. Either this or the parameter `px` may be set, not both
  1329. at the same time.
  1330. * If ``None``, then fraction-based cropping/padding will not be
  1331. used.
  1332. * If ``number``, then that fraction will always be cropped/padded.
  1333. * If ``StochasticParameter``, then that parameter will be used for
  1334. each image. Four samples will be drawn per image (top, right,
  1335. bottom, left). If however `sample_independently` is set to
  1336. ``False``, only one value will be sampled per image and used for
  1337. all sides.
  1338. * If a ``tuple`` of two ``float`` s with values ``a`` and ``b``,
  1339. then each side will be cropped/padded by a random fraction
  1340. sampled uniformly per image and side from the interval
  1341. ``[a, b]``. If however `sample_independently` is set to
  1342. ``False``, only one value will be sampled per image and used for
  1343. all sides.
  1344. * If a ``tuple`` of four entries, then the entries represent top,
  1345. right, bottom, left. Each entry may be a single ``float``
  1346. (always crop/pad by exactly that percent value), a ``tuple`` of
  1347. two ``float`` s ``a`` and ``b`` (crop/pad by a fraction from
  1348. ``[a, b]``), a ``list`` of ``float`` s (crop/pad by a random
  1349. value that is contained in the list) or a ``StochasticParameter``
  1350. (sample the percentage to crop/pad from that parameter).
  1351. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  1352. Padding mode to use. The available modes match the numpy padding modes,
  1353. i.e. ``constant``, ``edge``, ``linear_ramp``, ``maximum``, ``median``,
  1354. ``minimum``, ``reflect``, ``symmetric``, ``wrap``. The modes
  1355. ``constant`` and ``linear_ramp`` use extra values, which are provided
  1356. by ``pad_cval`` when necessary. See :func:`~imgaug.imgaug.pad` for
  1357. more details.
  1358. * If ``imgaug.ALL``, then a random mode from all available modes
  1359. will be sampled per image.
  1360. * If a ``str``, it will be used as the pad mode for all images.
  1361. * If a ``list`` of ``str``, a random one of these will be sampled
  1362. per image and used as the mode.
  1363. * If ``StochasticParameter``, a random mode will be sampled from
  1364. this parameter per image.
  1365. pad_cval : number or tuple of number list of number or imgaug.parameters.StochasticParameter, optional
  1366. The constant value to use if the pad mode is ``constant`` or the end
  1367. value to use if the mode is ``linear_ramp``.
  1368. See :func:`~imgaug.imgaug.pad` for more details.
  1369. * If ``number``, then that value will be used.
  1370. * If a ``tuple`` of two ``number`` s and at least one of them is
  1371. a ``float``, then a random number will be uniformly sampled per
  1372. image from the continuous interval ``[a, b]`` and used as the
  1373. value. If both ``number`` s are ``int`` s, the interval is
  1374. discrete.
  1375. * If a ``list`` of ``number``, then a random value will be chosen
  1376. from the elements of the ``list`` and used as the value.
  1377. * If ``StochasticParameter``, a random value will be sampled from
  1378. that parameter per image.
  1379. keep_size : bool, optional
  1380. After cropping and padding, the result image will usually have a
  1381. different height/width compared to the original input image. If this
  1382. parameter is set to ``True``, then the cropped/padded image will be
  1383. resized to the input image's size, i.e. the augmenter's output shape
  1384. is always identical to the input shape.
  1385. sample_independently : bool, optional
  1386. If ``False`` *and* the values for `px`/`percent` result in exactly
  1387. *one* probability distribution for all image sides, only one single
  1388. value will be sampled from that probability distribution and used for
  1389. all sides. I.e. the crop/pad amount then is the same for all sides.
  1390. If ``True``, four values will be sampled independently, one per side.
  1391. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  1392. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  1393. name : None or str, optional
  1394. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  1395. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  1396. Old name for parameter `seed`.
  1397. Its usage will not yet cause a deprecation warning,
  1398. but it is still recommended to use `seed` now.
  1399. Outdated since 0.4.0.
  1400. deterministic : bool, optional
  1401. Deprecated since 0.4.0.
  1402. See method ``to_deterministic()`` for an alternative and for
  1403. details about what the "deterministic mode" actually does.
  1404. Examples
  1405. --------
  1406. >>> import imgaug.augmenters as iaa
  1407. >>> aug = iaa.CropAndPad(px=(-10, 0))
  1408. Crop each side by a random pixel value sampled uniformly per image and
  1409. side from the discrete interval ``[-10..0]``.
  1410. >>> aug = iaa.CropAndPad(px=(0, 10))
  1411. Pad each side by a random pixel value sampled uniformly per image and
  1412. side from the discrete interval ``[0..10]``. The padding happens by
  1413. zero-padding, i.e. it adds black pixels (default setting).
  1414. >>> aug = iaa.CropAndPad(px=(0, 10), pad_mode="edge")
  1415. Pad each side by a random pixel value sampled uniformly per image and
  1416. side from the discrete interval ``[0..10]``. The padding uses the
  1417. ``edge`` mode from numpy's pad function, i.e. the pixel colors around
  1418. the image sides are repeated.
  1419. >>> aug = iaa.CropAndPad(px=(0, 10), pad_mode=["constant", "edge"])
  1420. Similar to the previous example, but uses zero-padding (``constant``) for
  1421. half of the images and ``edge`` padding for the other half.
  1422. >>> aug = iaa.CropAndPad(px=(0, 10), pad_mode=ia.ALL, pad_cval=(0, 255))
  1423. Similar to the previous example, but uses any available padding mode.
  1424. In case the padding mode ends up being ``constant`` or ``linear_ramp``,
  1425. and random intensity is uniformly sampled (once per image) from the
  1426. discrete interval ``[0..255]`` and used as the intensity of the new
  1427. pixels.
  1428. >>> aug = iaa.CropAndPad(px=(0, 10), sample_independently=False)
  1429. Pad each side by a random pixel value sampled uniformly once per image
  1430. from the discrete interval ``[0..10]``. Each sampled value is used
  1431. for *all* sides of the corresponding image.
  1432. >>> aug = iaa.CropAndPad(px=(0, 10), keep_size=False)
  1433. Pad each side by a random pixel value sampled uniformly per image and
  1434. side from the discrete interval ``[0..10]``. Afterwards, do **not**
  1435. resize the padded image back to the input image's size. This will increase
  1436. the image's height and width by a maximum of ``20`` pixels.
  1437. >>> aug = iaa.CropAndPad(px=((0, 10), (0, 5), (0, 10), (0, 5)))
  1438. Pad the top and bottom by a random pixel value sampled uniformly from the
  1439. discrete interval ``[0..10]``. Pad the left and right analogously by
  1440. a random value sampled from ``[0..5]``. Each value is always sampled
  1441. independently.
  1442. >>> aug = iaa.CropAndPad(percent=(0, 0.1))
  1443. Pad each side by a random fraction sampled uniformly from the continuous
  1444. interval ``[0.0, 0.10]``. The fraction is sampled once per image and
  1445. side. E.g. a sampled fraction of ``0.1`` for the top side would pad by
  1446. ``0.1*H``, where ``H`` is the height of the input image.
  1447. >>> aug = iaa.CropAndPad(
  1448. >>> percent=([0.05, 0.1], [0.05, 0.1], [0.05, 0.1], [0.05, 0.1]))
  1449. Pads each side by either ``5%`` or ``10%``. The values are sampled
  1450. once per side and image.
  1451. >>> aug = iaa.CropAndPad(px=(-10, 10))
  1452. Sample uniformly per image and side a value ``v`` from the discrete range
  1453. ``[-10..10]``. Then either crop (negative sample) or pad (positive sample)
  1454. the side by ``v`` pixels.
  1455. """
  1456. def __init__(self, px=None, percent=None, pad_mode="constant", pad_cval=0,
  1457. keep_size=True, sample_independently=True,
  1458. seed=None, name=None,
  1459. random_state="deprecated", deterministic="deprecated"):
  1460. # pylint: disable=invalid-name
  1461. super(CropAndPad, self).__init__(
  1462. seed=seed, name=name,
  1463. random_state=random_state, deterministic=deterministic)
  1464. if px is None and percent is None:
  1465. percent = (-0.1, 0.1)
  1466. self.mode, self.all_sides, self.top, self.right, self.bottom, \
  1467. self.left = self._handle_px_and_percent_args(px, percent)
  1468. self.pad_mode = _handle_pad_mode_param(pad_mode)
  1469. # TODO enable ALL here, like in e.g. Affine
  1470. self.pad_cval = iap.handle_discrete_param(
  1471. pad_cval, "pad_cval", value_range=None, tuple_to_uniform=True,
  1472. list_to_choice=True, allow_floats=True)
  1473. self.keep_size = keep_size
  1474. self.sample_independently = sample_independently
  1475. # set these to None to use the same values as sampled for the
  1476. # images (not tested)
  1477. self._pad_mode_heatmaps = "constant"
  1478. self._pad_mode_segmentation_maps = "constant"
  1479. self._pad_cval_heatmaps = 0.0
  1480. self._pad_cval_segmentation_maps = 0
  1481. @classmethod
  1482. def _handle_px_and_percent_args(cls, px, percent):
  1483. # pylint: disable=invalid-name
  1484. all_sides = None
  1485. top, right, bottom, left = None, None, None, None
  1486. if px is None and percent is None:
  1487. mode = "noop"
  1488. elif px is not None and percent is not None:
  1489. raise Exception("Can only pad by pixels or percent, not both.")
  1490. elif px is not None:
  1491. mode = "px"
  1492. all_sides, top, right, bottom, left = cls._handle_px_arg(px)
  1493. else: # = elif percent is not None:
  1494. mode = "percent"
  1495. all_sides, top, right, bottom, left = cls._handle_percent_arg(
  1496. percent)
  1497. return mode, all_sides, top, right, bottom, left
  1498. @classmethod
  1499. def _handle_px_arg(cls, px):
  1500. # pylint: disable=invalid-name
  1501. all_sides = None
  1502. top, right, bottom, left = None, None, None, None
  1503. if ia.is_single_integer(px):
  1504. all_sides = iap.Deterministic(px)
  1505. elif isinstance(px, tuple):
  1506. assert len(px) in [2, 4], (
  1507. "Expected 'px' given as a tuple to contain 2 or 4 "
  1508. "entries, got %d." % (len(px),))
  1509. def handle_param(p):
  1510. if ia.is_single_integer(p):
  1511. return iap.Deterministic(p)
  1512. if isinstance(p, tuple):
  1513. assert len(p) == 2, (
  1514. "Expected tuple of 2 values, got %d." % (len(p)))
  1515. only_ints = (
  1516. ia.is_single_integer(p[0])
  1517. and ia.is_single_integer(p[1]))
  1518. assert only_ints, (
  1519. "Expected tuple of integers, got %s and %s." % (
  1520. type(p[0]), type(p[1])))
  1521. return iap.DiscreteUniform(p[0], p[1])
  1522. if isinstance(p, list):
  1523. assert len(p) > 0, (
  1524. "Expected non-empty list, but got empty one.")
  1525. assert all([ia.is_single_integer(val) for val in p]), (
  1526. "Expected list of ints, got types %s." % (
  1527. ", ".join([str(type(v)) for v in p])))
  1528. return iap.Choice(p)
  1529. if isinstance(p, iap.StochasticParameter):
  1530. return p
  1531. raise Exception(
  1532. "Expected int, tuple of two ints, list of ints or "
  1533. "StochasticParameter, got type %s." % (type(p),))
  1534. if len(px) == 2:
  1535. all_sides = handle_param(px)
  1536. else: # len == 4
  1537. top = handle_param(px[0])
  1538. right = handle_param(px[1])
  1539. bottom = handle_param(px[2])
  1540. left = handle_param(px[3])
  1541. elif isinstance(px, iap.StochasticParameter):
  1542. top = right = bottom = left = px
  1543. else:
  1544. raise Exception(
  1545. "Expected int, tuple of 4 "
  1546. "ints/tuples/lists/StochasticParameters or "
  1547. "StochasticParameter, got type %s." % (type(px),))
  1548. return all_sides, top, right, bottom, left
  1549. @classmethod
  1550. def _handle_percent_arg(cls, percent):
  1551. all_sides = None
  1552. top, right, bottom, left = None, None, None, None
  1553. if ia.is_single_number(percent):
  1554. assert percent > -1.0, (
  1555. "Expected 'percent' to be >-1.0, got %.4f." % (percent,))
  1556. all_sides = iap.Deterministic(percent)
  1557. elif isinstance(percent, tuple):
  1558. assert len(percent) in [2, 4], (
  1559. "Expected 'percent' given as a tuple to contain 2 or 4 "
  1560. "entries, got %d." % (len(percent),))
  1561. def handle_param(p):
  1562. if ia.is_single_number(p):
  1563. return iap.Deterministic(p)
  1564. if isinstance(p, tuple):
  1565. assert len(p) == 2, (
  1566. "Expected tuple of 2 values, got %d." % (len(p),))
  1567. only_numbers = (
  1568. ia.is_single_number(p[0])
  1569. and ia.is_single_number(p[1]))
  1570. assert only_numbers, (
  1571. "Expected tuple of numbers, got %s and %s." % (
  1572. type(p[0]), type(p[1])))
  1573. assert p[0] > -1.0 and p[1] > -1.0, (
  1574. "Expected tuple of values >-1.0, got %.4f and "
  1575. "%.4f." % (p[0], p[1]))
  1576. return iap.Uniform(p[0], p[1])
  1577. if isinstance(p, list):
  1578. assert len(p) > 0, (
  1579. "Expected non-empty list, but got empty one.")
  1580. assert all([ia.is_single_number(val) for val in p]), (
  1581. "Expected list of numbers, got types %s." % (
  1582. ", ".join([str(type(v)) for v in p])))
  1583. assert all([val > -1.0 for val in p]), (
  1584. "Expected list of values >-1.0, got values %s." % (
  1585. ", ".join(["%.4f" % (v,) for v in p])))
  1586. return iap.Choice(p)
  1587. if isinstance(p, iap.StochasticParameter):
  1588. return p
  1589. raise Exception(
  1590. "Expected int, tuple of two ints, list of ints or "
  1591. "StochasticParameter, got type %s." % (type(p),))
  1592. if len(percent) == 2:
  1593. all_sides = handle_param(percent)
  1594. else: # len == 4
  1595. top = handle_param(percent[0])
  1596. right = handle_param(percent[1])
  1597. bottom = handle_param(percent[2])
  1598. left = handle_param(percent[3])
  1599. elif isinstance(percent, iap.StochasticParameter):
  1600. top = right = bottom = left = percent
  1601. else:
  1602. raise Exception(
  1603. "Expected number, tuple of 4 "
  1604. "numbers/tuples/lists/StochasticParameters or "
  1605. "StochasticParameter, got type %s." % (type(percent),))
  1606. return all_sides, top, right, bottom, left
  1607. # Added in 0.4.0.
  1608. def _augment_batch_(self, batch, random_state, parents, hooks):
  1609. shapes = batch.get_rowwise_shapes()
  1610. samples = self._draw_samples(random_state, shapes)
  1611. if batch.images is not None:
  1612. batch.images = self._augment_images_by_samples(batch.images,
  1613. samples)
  1614. if batch.heatmaps is not None:
  1615. batch.heatmaps = self._augment_maps_by_samples(
  1616. batch.heatmaps,
  1617. self._pad_mode_heatmaps, self._pad_cval_heatmaps,
  1618. samples)
  1619. if batch.segmentation_maps is not None:
  1620. batch.segmentation_maps = self._augment_maps_by_samples(
  1621. batch.segmentation_maps,
  1622. self._pad_mode_segmentation_maps,
  1623. self._pad_cval_segmentation_maps, samples)
  1624. for augm_name in ["keypoints", "bounding_boxes", "polygons",
  1625. "line_strings"]:
  1626. augm_value = getattr(batch, augm_name)
  1627. if augm_value is not None:
  1628. func = functools.partial(
  1629. self._augment_keypoints_by_samples,
  1630. samples=samples)
  1631. cbaois = self._apply_to_cbaois_as_keypoints(augm_value, func)
  1632. setattr(batch, augm_name, cbaois)
  1633. return batch
  1634. # Added in 0.4.0.
  1635. def _augment_images_by_samples(self, images, samples):
  1636. result = []
  1637. for i, image in enumerate(images):
  1638. samples_i = samples[i]
  1639. image_cr_pa = _crop_and_pad_arr(
  1640. image, samples_i.croppings, samples_i.paddings,
  1641. samples_i.pad_mode, samples_i.pad_cval, self.keep_size)
  1642. result.append(image_cr_pa)
  1643. if ia.is_np_array(images):
  1644. if self.keep_size:
  1645. result = np.array(result, dtype=images.dtype)
  1646. else:
  1647. nb_shapes = len({image.shape for image in result})
  1648. if nb_shapes == 1:
  1649. result = np.array(result, dtype=images.dtype)
  1650. return result
  1651. # Added in 0.4.0.
  1652. def _augment_maps_by_samples(self, augmentables, pad_mode, pad_cval,
  1653. samples):
  1654. result = []
  1655. for i, augmentable in enumerate(augmentables):
  1656. samples_img = samples[i]
  1657. augmentable = _crop_and_pad_hms_or_segmaps_(
  1658. augmentable,
  1659. croppings_img=samples_img.croppings,
  1660. paddings_img=samples_img.paddings,
  1661. pad_mode=(pad_mode
  1662. if pad_mode is not None
  1663. else samples_img.pad_mode),
  1664. pad_cval=(pad_cval
  1665. if pad_cval is not None
  1666. else samples_img.pad_cval),
  1667. keep_size=self.keep_size
  1668. )
  1669. result.append(augmentable)
  1670. return result
  1671. # Added in 0.4.0.
  1672. def _augment_keypoints_by_samples(self, keypoints_on_images, samples):
  1673. result = []
  1674. for i, keypoints_on_image in enumerate(keypoints_on_images):
  1675. samples_i = samples[i]
  1676. kpsoi_aug = _crop_and_pad_kpsoi_(
  1677. keypoints_on_image, croppings_img=samples_i.croppings,
  1678. paddings_img=samples_i.paddings, keep_size=self.keep_size)
  1679. result.append(kpsoi_aug)
  1680. return result
  1681. def _draw_samples(self, random_state, shapes):
  1682. nb_rows = len(shapes)
  1683. if self.mode == "noop":
  1684. top = right = bottom = left = np.full((nb_rows,), 0,
  1685. dtype=np.int32)
  1686. else:
  1687. if self.all_sides is not None:
  1688. if self.sample_independently:
  1689. samples = self.all_sides.draw_samples(
  1690. (nb_rows, 4), random_state=random_state)
  1691. top = samples[:, 0]
  1692. right = samples[:, 1]
  1693. bottom = samples[:, 2]
  1694. left = samples[:, 3]
  1695. else:
  1696. sample = self.all_sides.draw_samples(
  1697. (nb_rows,), random_state=random_state)
  1698. top = right = bottom = left = sample
  1699. else:
  1700. top = self.top.draw_samples(
  1701. (nb_rows,), random_state=random_state)
  1702. right = self.right.draw_samples(
  1703. (nb_rows,), random_state=random_state)
  1704. bottom = self.bottom.draw_samples(
  1705. (nb_rows,), random_state=random_state)
  1706. left = self.left.draw_samples(
  1707. (nb_rows,), random_state=random_state)
  1708. if self.mode == "px":
  1709. # no change necessary for pixel values
  1710. pass
  1711. elif self.mode == "percent":
  1712. # percentage values have to be transformed to pixel values
  1713. shapes_arr = np.array([shape[0:2] for shape in shapes],
  1714. dtype=np.float32)
  1715. heights = shapes_arr[:, 0]
  1716. widths = shapes_arr[:, 1]
  1717. top = np.round(heights * top).astype(np.int32)
  1718. right = np.round(widths * right).astype(np.int32)
  1719. bottom = np.round(heights * bottom).astype(np.int32)
  1720. left = np.round(widths * left).astype(np.int32)
  1721. else:
  1722. raise Exception("Invalid mode")
  1723. def _only_above_zero(arr):
  1724. arr = np.copy(arr)
  1725. mask = (arr < 0)
  1726. arr[mask] = 0
  1727. return arr
  1728. crop_top = _only_above_zero((-1) * top)
  1729. crop_right = _only_above_zero((-1) * right)
  1730. crop_bottom = _only_above_zero((-1) * bottom)
  1731. crop_left = _only_above_zero((-1) * left)
  1732. pad_top = _only_above_zero(top)
  1733. pad_right = _only_above_zero(right)
  1734. pad_bottom = _only_above_zero(bottom)
  1735. pad_left = _only_above_zero(left)
  1736. pad_mode = self.pad_mode.draw_samples((nb_rows,),
  1737. random_state=random_state)
  1738. pad_cval = self.pad_cval.draw_samples((nb_rows,),
  1739. random_state=random_state)
  1740. # TODO vectorize this part -- especially return only one instance
  1741. result = []
  1742. for i, shape in enumerate(shapes):
  1743. height, width = shape[0:2]
  1744. crop_top_i, crop_right_i, crop_bottom_i, crop_left_i = \
  1745. _crop_prevent_zero_size(
  1746. height, width,
  1747. crop_top[i], crop_right[i], crop_bottom[i], crop_left[i])
  1748. # add here any_crop_y to not warn in case of zero height/width
  1749. # images
  1750. any_crop_y = (crop_top_i > 0 or crop_bottom_i > 0)
  1751. if any_crop_y and crop_top_i + crop_bottom_i >= height:
  1752. ia.warn(
  1753. "Expected generated crop amounts in CropAndPad for top and "
  1754. "bottom image side to be less than the image's height, but "
  1755. "got %d (top) and %d (bottom) vs. image height %d. This "
  1756. "will result in an image with output height=1 (if input "
  1757. "height was >=1) or output height=0 (if input height "
  1758. "was 0)." % (crop_top_i, crop_bottom_i, height))
  1759. # add here any_crop_x to not warn in case of zero height/width
  1760. # images
  1761. any_crop_x = (crop_left_i > 0 or crop_right_i > 0)
  1762. if any_crop_x and crop_left_i + crop_right_i >= width:
  1763. ia.warn(
  1764. "Expected generated crop amounts in CropAndPad for left "
  1765. "and right image side to be less than the image's width, "
  1766. "but got %d (left) and %d (right) vs. image width %d. "
  1767. "This will result in an image with output width=1 (if "
  1768. "input width was >=1) or output width=0 (if input width "
  1769. "was 0)." % (crop_left_i, crop_right_i, width))
  1770. result.append(
  1771. _CropAndPadSamplingResult(
  1772. crop_top=crop_top_i,
  1773. crop_right=crop_right_i,
  1774. crop_bottom=crop_bottom_i,
  1775. crop_left=crop_left_i,
  1776. pad_top=pad_top[i],
  1777. pad_right=pad_right[i],
  1778. pad_bottom=pad_bottom[i],
  1779. pad_left=pad_left[i],
  1780. pad_mode=pad_mode[i],
  1781. pad_cval=pad_cval[i]))
  1782. return result
  1783. def get_parameters(self):
  1784. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  1785. return [self.all_sides, self.top, self.right, self.bottom, self.left,
  1786. self.pad_mode, self.pad_cval]
  1787. class Pad(CropAndPad):
  1788. """Pad images, i.e. adds columns/rows of pixels to them.
  1789. **Supported dtypes**:
  1790. See :class:`~imgaug.augmenters.size.CropAndPad`.
  1791. Parameters
  1792. ----------
  1793. px : None or int or imgaug.parameters.StochasticParameter or tuple, optional
  1794. The number of pixels to pad on each side of the image.
  1795. Expected value range is ``[0, inf)``.
  1796. Either this or the parameter `percent` may be set, not both at the same
  1797. time.
  1798. * If ``None``, then pixel-based padding will not be used.
  1799. * If ``int``, then that exact number of pixels will always be
  1800. padded.
  1801. * If ``StochasticParameter``, then that parameter will be used for
  1802. each image. Four samples will be drawn per image (top, right,
  1803. bottom, left), unless `sample_independently` is set to ``False``,
  1804. as then only one value will be sampled per image and used for
  1805. all sides.
  1806. * If a ``tuple`` of two ``int`` s with values ``a`` and ``b``,
  1807. then each side will be padded by a random amount sampled
  1808. uniformly per image and side from the inteval ``[a, b]``. If
  1809. however `sample_independently` is set to ``False``, only one
  1810. value will be sampled per image and used for all sides.
  1811. * If a ``tuple`` of four entries, then the entries represent top,
  1812. right, bottom, left. Each entry may be a single ``int`` (always
  1813. pad by exactly that value), a ``tuple`` of two ``int`` s
  1814. ``a`` and ``b`` (pad by an amount within ``[a, b]``), a
  1815. ``list`` of ``int`` s (pad by a random value that is
  1816. contained in the ``list``) or a ``StochasticParameter`` (sample
  1817. the amount to pad from that parameter).
  1818. percent : None or int or float or imgaug.parameters.StochasticParameter or tuple, optional
  1819. The number of pixels to pad
  1820. on each side of the image given as a *fraction* of the image
  1821. height/width. E.g. if this is set to ``0.1``, the augmenter will
  1822. always pad ``10%`` of the image's height at both the top and the
  1823. bottom (both ``10%`` each), as well as ``10%`` of the width at the
  1824. right and left.
  1825. Expected value range is ``[0.0, inf)``.
  1826. Either this or the parameter `px` may be set, not both
  1827. at the same time.
  1828. * If ``None``, then fraction-based padding will not be
  1829. used.
  1830. * If ``number``, then that fraction will always be padded.
  1831. * If ``StochasticParameter``, then that parameter will be used for
  1832. each image. Four samples will be drawn per image (top, right,
  1833. bottom, left). If however `sample_independently` is set to
  1834. ``False``, only one value will be sampled per image and used for
  1835. all sides.
  1836. * If a ``tuple`` of two ``float`` s with values ``a`` and ``b``,
  1837. then each side will be padded by a random fraction
  1838. sampled uniformly per image and side from the interval
  1839. ``[a, b]``. If however `sample_independently` is set to
  1840. ``False``, only one value will be sampled per image and used for
  1841. all sides.
  1842. * If a ``tuple`` of four entries, then the entries represent top,
  1843. right, bottom, left. Each entry may be a single ``float``
  1844. (always pad by exactly that fraction), a ``tuple`` of
  1845. two ``float`` s ``a`` and ``b`` (pad by a fraction from
  1846. ``[a, b]``), a ``list`` of ``float`` s (pad by a random
  1847. value that is contained in the list) or a ``StochasticParameter``
  1848. (sample the percentage to pad from that parameter).
  1849. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  1850. Padding mode to use. The available modes match the numpy padding modes,
  1851. i.e. ``constant``, ``edge``, ``linear_ramp``, ``maximum``, ``median``,
  1852. ``minimum``, ``reflect``, ``symmetric``, ``wrap``. The modes
  1853. ``constant`` and ``linear_ramp`` use extra values, which are provided
  1854. by ``pad_cval`` when necessary. See :func:`~imgaug.imgaug.pad` for
  1855. more details.
  1856. * If ``imgaug.ALL``, then a random mode from all available modes
  1857. will be sampled per image.
  1858. * If a ``str``, it will be used as the pad mode for all images.
  1859. * If a ``list`` of ``str``, a random one of these will be sampled
  1860. per image and used as the mode.
  1861. * If ``StochasticParameter``, a random mode will be sampled from
  1862. this parameter per image.
  1863. pad_cval : number or tuple of number list of number or imgaug.parameters.StochasticParameter, optional
  1864. The constant value to use if the pad mode is ``constant`` or the end
  1865. value to use if the mode is ``linear_ramp``.
  1866. See :func:`~imgaug.imgaug.pad` for more details.
  1867. * If ``number``, then that value will be used.
  1868. * If a ``tuple`` of two ``number`` s and at least one of them is
  1869. a ``float``, then a random number will be uniformly sampled per
  1870. image from the continuous interval ``[a, b]`` and used as the
  1871. value. If both ``number`` s are ``int`` s, the interval is
  1872. discrete.
  1873. * If a ``list`` of ``number``, then a random value will be chosen
  1874. from the elements of the ``list`` and used as the value.
  1875. * If ``StochasticParameter``, a random value will be sampled from
  1876. that parameter per image.
  1877. keep_size : bool, optional
  1878. After padding, the result image will usually have a
  1879. different height/width compared to the original input image. If this
  1880. parameter is set to ``True``, then the padded image will be
  1881. resized to the input image's size, i.e. the augmenter's output shape
  1882. is always identical to the input shape.
  1883. sample_independently : bool, optional
  1884. If ``False`` *and* the values for `px`/`percent` result in exactly
  1885. *one* probability distribution for all image sides, only one single
  1886. value will be sampled from that probability distribution and used for
  1887. all sides. I.e. the pad amount then is the same for all sides.
  1888. If ``True``, four values will be sampled independently, one per side.
  1889. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  1890. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  1891. name : None or str, optional
  1892. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  1893. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  1894. Old name for parameter `seed`.
  1895. Its usage will not yet cause a deprecation warning,
  1896. but it is still recommended to use `seed` now.
  1897. Outdated since 0.4.0.
  1898. deterministic : bool, optional
  1899. Deprecated since 0.4.0.
  1900. See method ``to_deterministic()`` for an alternative and for
  1901. details about what the "deterministic mode" actually does.
  1902. Examples
  1903. --------
  1904. >>> import imgaug.augmenters as iaa
  1905. >>> aug = iaa.Pad(px=(0, 10))
  1906. Pad each side by a random pixel value sampled uniformly per image and
  1907. side from the discrete interval ``[0..10]``. The padding happens by
  1908. zero-padding, i.e. it adds black pixels (default setting).
  1909. >>> aug = iaa.Pad(px=(0, 10), pad_mode="edge")
  1910. Pad each side by a random pixel value sampled uniformly per image and
  1911. side from the discrete interval ``[0..10]``. The padding uses the
  1912. ``edge`` mode from numpy's pad function, i.e. the pixel colors around
  1913. the image sides are repeated.
  1914. >>> aug = iaa.Pad(px=(0, 10), pad_mode=["constant", "edge"])
  1915. Similar to the previous example, but uses zero-padding (``constant``) for
  1916. half of the images and ``edge`` padding for the other half.
  1917. >>> aug = iaa.Pad(px=(0, 10), pad_mode=ia.ALL, pad_cval=(0, 255))
  1918. Similar to the previous example, but uses any available padding mode.
  1919. In case the padding mode ends up being ``constant`` or ``linear_ramp``,
  1920. and random intensity is uniformly sampled (once per image) from the
  1921. discrete interval ``[0..255]`` and used as the intensity of the new
  1922. pixels.
  1923. >>> aug = iaa.Pad(px=(0, 10), sample_independently=False)
  1924. Pad each side by a random pixel value sampled uniformly once per image
  1925. from the discrete interval ``[0..10]``. Each sampled value is used
  1926. for *all* sides of the corresponding image.
  1927. >>> aug = iaa.Pad(px=(0, 10), keep_size=False)
  1928. Pad each side by a random pixel value sampled uniformly per image and
  1929. side from the discrete interval ``[0..10]``. Afterwards, do **not**
  1930. resize the padded image back to the input image's size. This will increase
  1931. the image's height and width by a maximum of ``20`` pixels.
  1932. >>> aug = iaa.Pad(px=((0, 10), (0, 5), (0, 10), (0, 5)))
  1933. Pad the top and bottom by a random pixel value sampled uniformly from the
  1934. discrete interval ``[0..10]``. Pad the left and right analogously by
  1935. a random value sampled from ``[0..5]``. Each value is always sampled
  1936. independently.
  1937. >>> aug = iaa.Pad(percent=(0, 0.1))
  1938. Pad each side by a random fraction sampled uniformly from the continuous
  1939. interval ``[0.0, 0.10]``. The fraction is sampled once per image and
  1940. side. E.g. a sampled fraction of ``0.1`` for the top side would pad by
  1941. ``0.1*H``, where ``H`` is the height of the input image.
  1942. >>> aug = iaa.Pad(
  1943. >>> percent=([0.05, 0.1], [0.05, 0.1], [0.05, 0.1], [0.05, 0.1]))
  1944. Pads each side by either ``5%`` or ``10%``. The values are sampled
  1945. once per side and image.
  1946. """
  1947. def __init__(self, px=None, percent=None, pad_mode="constant", pad_cval=0,
  1948. keep_size=True, sample_independently=True,
  1949. seed=None, name=None,
  1950. random_state="deprecated", deterministic="deprecated"):
  1951. def recursive_validate(value):
  1952. if value is None:
  1953. return value
  1954. if ia.is_single_number(value):
  1955. assert value >= 0, "Expected value >0, got %.4f" % (value,)
  1956. return value
  1957. if isinstance(value, iap.StochasticParameter):
  1958. return value
  1959. if isinstance(value, tuple):
  1960. return tuple([recursive_validate(v_) for v_ in value])
  1961. if isinstance(value, list):
  1962. return [recursive_validate(v_) for v_ in value]
  1963. raise Exception(
  1964. "Expected None or int or float or StochasticParameter or "
  1965. "list or tuple, got %s." % (type(value),))
  1966. if px is None and percent is None:
  1967. percent = (0.0, 0.1)
  1968. px = recursive_validate(px)
  1969. percent = recursive_validate(percent)
  1970. super(Pad, self).__init__(
  1971. px=px,
  1972. percent=percent,
  1973. pad_mode=pad_mode,
  1974. pad_cval=pad_cval,
  1975. keep_size=keep_size,
  1976. sample_independently=sample_independently,
  1977. seed=seed, name=name,
  1978. random_state=random_state, deterministic=deterministic)
  1979. class Crop(CropAndPad):
  1980. """Crop images, i.e. remove columns/rows of pixels at the sides of images.
  1981. This augmenter allows to extract smaller-sized subimages from given
  1982. full-sized input images. The number of pixels to cut off may be defined
  1983. in absolute values or as fractions of the image sizes.
  1984. This augmenter will never crop images below a height or width of ``1``.
  1985. **Supported dtypes**:
  1986. See :class:`~imgaug.augmenters.size.CropAndPad`.
  1987. Parameters
  1988. ----------
  1989. px : None or int or imgaug.parameters.StochasticParameter or tuple, optional
  1990. The number of pixels to crop on each side of the image.
  1991. Expected value range is ``[0, inf)``.
  1992. Either this or the parameter `percent` may be set, not both at the same
  1993. time.
  1994. * If ``None``, then pixel-based cropping will not be used.
  1995. * If ``int``, then that exact number of pixels will always be
  1996. cropped.
  1997. * If ``StochasticParameter``, then that parameter will be used for
  1998. each image. Four samples will be drawn per image (top, right,
  1999. bottom, left), unless `sample_independently` is set to ``False``,
  2000. as then only one value will be sampled per image and used for
  2001. all sides.
  2002. * If a ``tuple`` of two ``int`` s with values ``a`` and ``b``,
  2003. then each side will be cropped by a random amount sampled
  2004. uniformly per image and side from the inteval ``[a, b]``. If
  2005. however `sample_independently` is set to ``False``, only one
  2006. value will be sampled per image and used for all sides.
  2007. * If a ``tuple`` of four entries, then the entries represent top,
  2008. right, bottom, left. Each entry may be a single ``int`` (always
  2009. crop by exactly that value), a ``tuple`` of two ``int`` s
  2010. ``a`` and ``b`` (crop by an amount within ``[a, b]``), a
  2011. ``list`` of ``int`` s (crop by a random value that is
  2012. contained in the ``list``) or a ``StochasticParameter`` (sample
  2013. the amount to crop from that parameter).
  2014. percent : None or int or float or imgaug.parameters.StochasticParameter or tuple, optional
  2015. The number of pixels to crop
  2016. on each side of the image given as a *fraction* of the image
  2017. height/width. E.g. if this is set to ``0.1``, the augmenter will
  2018. always crop ``10%`` of the image's height at both the top and the
  2019. bottom (both ``10%`` each), as well as ``10%`` of the width at the
  2020. right and left.
  2021. Expected value range is ``[0.0, 1.0)``.
  2022. Either this or the parameter `px` may be set, not both
  2023. at the same time.
  2024. * If ``None``, then fraction-based cropping will not be
  2025. used.
  2026. * If ``number``, then that fraction will always be cropped.
  2027. * If ``StochasticParameter``, then that parameter will be used for
  2028. each image. Four samples will be drawn per image (top, right,
  2029. bottom, left). If however `sample_independently` is set to
  2030. ``False``, only one value will be sampled per image and used for
  2031. all sides.
  2032. * If a ``tuple`` of two ``float`` s with values ``a`` and ``b``,
  2033. then each side will be cropped by a random fraction
  2034. sampled uniformly per image and side from the interval
  2035. ``[a, b]``. If however `sample_independently` is set to
  2036. ``False``, only one value will be sampled per image and used for
  2037. all sides.
  2038. * If a ``tuple`` of four entries, then the entries represent top,
  2039. right, bottom, left. Each entry may be a single ``float``
  2040. (always crop by exactly that fraction), a ``tuple`` of
  2041. two ``float`` s ``a`` and ``b`` (crop by a fraction from
  2042. ``[a, b]``), a ``list`` of ``float`` s (crop by a random
  2043. value that is contained in the list) or a ``StochasticParameter``
  2044. (sample the percentage to crop from that parameter).
  2045. keep_size : bool, optional
  2046. After cropping, the result image will usually have a
  2047. different height/width compared to the original input image. If this
  2048. parameter is set to ``True``, then the cropped image will be
  2049. resized to the input image's size, i.e. the augmenter's output shape
  2050. is always identical to the input shape.
  2051. sample_independently : bool, optional
  2052. If ``False`` *and* the values for `px`/`percent` result in exactly
  2053. *one* probability distribution for all image sides, only one single
  2054. value will be sampled from that probability distribution and used for
  2055. all sides. I.e. the crop amount then is the same for all sides.
  2056. If ``True``, four values will be sampled independently, one per side.
  2057. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2058. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2059. name : None or str, optional
  2060. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2061. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2062. Old name for parameter `seed`.
  2063. Its usage will not yet cause a deprecation warning,
  2064. but it is still recommended to use `seed` now.
  2065. Outdated since 0.4.0.
  2066. deterministic : bool, optional
  2067. Deprecated since 0.4.0.
  2068. See method ``to_deterministic()`` for an alternative and for
  2069. details about what the "deterministic mode" actually does.
  2070. Examples
  2071. --------
  2072. >>> import imgaug.augmenters as iaa
  2073. >>> aug = iaa.Crop(px=(0, 10))
  2074. Crop each side by a random pixel value sampled uniformly per image and
  2075. side from the discrete interval ``[0..10]``.
  2076. >>> aug = iaa.Crop(px=(0, 10), sample_independently=False)
  2077. Crop each side by a random pixel value sampled uniformly once per image
  2078. from the discrete interval ``[0..10]``. Each sampled value is used
  2079. for *all* sides of the corresponding image.
  2080. >>> aug = iaa.Crop(px=(0, 10), keep_size=False)
  2081. Crop each side by a random pixel value sampled uniformly per image and
  2082. side from the discrete interval ``[0..10]``. Afterwards, do **not**
  2083. resize the cropped image back to the input image's size. This will decrease
  2084. the image's height and width by a maximum of ``20`` pixels.
  2085. >>> aug = iaa.Crop(px=((0, 10), (0, 5), (0, 10), (0, 5)))
  2086. Crop the top and bottom by a random pixel value sampled uniformly from the
  2087. discrete interval ``[0..10]``. Crop the left and right analogously by
  2088. a random value sampled from ``[0..5]``. Each value is always sampled
  2089. independently.
  2090. >>> aug = iaa.Crop(percent=(0, 0.1))
  2091. Crop each side by a random fraction sampled uniformly from the continuous
  2092. interval ``[0.0, 0.10]``. The fraction is sampled once per image and
  2093. side. E.g. a sampled fraction of ``0.1`` for the top side would crop by
  2094. ``0.1*H``, where ``H`` is the height of the input image.
  2095. >>> aug = iaa.Crop(
  2096. >>> percent=([0.05, 0.1], [0.05, 0.1], [0.05, 0.1], [0.05, 0.1]))
  2097. Crops each side by either ``5%`` or ``10%``. The values are sampled
  2098. once per side and image.
  2099. """
  2100. def __init__(self, px=None, percent=None, keep_size=True,
  2101. sample_independently=True,
  2102. seed=None, name=None,
  2103. random_state="deprecated", deterministic="deprecated"):
  2104. def recursive_negate(value):
  2105. if value is None:
  2106. return value
  2107. if ia.is_single_number(value):
  2108. assert value >= 0, "Expected value >0, got %.4f." % (value,)
  2109. return -value
  2110. if isinstance(value, iap.StochasticParameter):
  2111. return iap.Multiply(value, -1)
  2112. if isinstance(value, tuple):
  2113. return tuple([recursive_negate(v_) for v_ in value])
  2114. if isinstance(value, list):
  2115. return [recursive_negate(v_) for v_ in value]
  2116. raise Exception(
  2117. "Expected None or int or float or StochasticParameter or "
  2118. "list or tuple, got %s." % (type(value),))
  2119. if px is None and percent is None:
  2120. percent = (0.0, 0.1)
  2121. px = recursive_negate(px)
  2122. percent = recursive_negate(percent)
  2123. super(Crop, self).__init__(
  2124. px=px,
  2125. percent=percent,
  2126. keep_size=keep_size,
  2127. sample_independently=sample_independently,
  2128. seed=seed, name=name,
  2129. random_state=random_state, deterministic=deterministic)
  2130. # TODO maybe rename this to PadToMinimumSize?
  2131. # TODO this is very similar to CropAndPad, maybe add a way to generate crop
  2132. # values imagewise via a callback in in CropAndPad?
  2133. # TODO why is padding mode and cval here called pad_mode, pad_cval but in other
  2134. # cases mode/cval?
  2135. class PadToFixedSize(meta.Augmenter):
  2136. """Pad images to a predefined minimum width and/or height.
  2137. If images are already at the minimum width/height or are larger, they will
  2138. not be padded. Note that this also means that images will not be cropped if
  2139. they exceed the required width/height.
  2140. The augmenter randomly decides per image how to distribute the required
  2141. padding amounts over the image axis. E.g. if 2px have to be padded on the
  2142. left or right to reach the required width, the augmenter will sometimes
  2143. add 2px to the left and 0px to the right, sometimes add 2px to the right
  2144. and 0px to the left and sometimes add 1px to both sides. Set `position`
  2145. to ``center`` to prevent that.
  2146. **Supported dtypes**:
  2147. See :func:`~imgaug.augmenters.size.pad`.
  2148. Parameters
  2149. ----------
  2150. width : int or None
  2151. Pad images up to this minimum width.
  2152. If ``None``, image widths will not be altered.
  2153. height : int or None
  2154. Pad images up to this minimum height.
  2155. If ``None``, image heights will not be altered.
  2156. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  2157. See :func:`~imgaug.augmenters.size.CropAndPad.__init__`.
  2158. pad_cval : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  2159. See :func:`~imgaug.augmenters.size.CropAndPad.__init__`.
  2160. position : {'uniform', 'normal', 'center', 'left-top', 'left-center', 'left-bottom', 'center-top', 'center-center', 'center-bottom', 'right-top', 'right-center', 'right-bottom'} or tuple of float or StochasticParameter or tuple of StochasticParameter, optional
  2161. Sets the center point of the padding, which determines how the
  2162. required padding amounts are distributed to each side. For a ``tuple``
  2163. ``(a, b)``, both ``a`` and ``b`` are expected to be in range
  2164. ``[0.0, 1.0]`` and describe the fraction of padding applied to the
  2165. left/right (low/high values for ``a``) and the fraction of padding
  2166. applied to the top/bottom (low/high values for ``b``). A padding
  2167. position at ``(0.5, 0.5)`` would be the center of the image and
  2168. distribute the padding equally to all sides. A padding position at
  2169. ``(0.0, 1.0)`` would be the left-bottom and would apply 100% of the
  2170. required padding to the bottom and left sides of the image so that
  2171. the bottom left corner becomes more and more the new image
  2172. center (depending on how much is padded).
  2173. * If string ``uniform`` then the share of padding is randomly and
  2174. uniformly distributed over each side.
  2175. Equivalent to ``(Uniform(0.0, 1.0), Uniform(0.0, 1.0))``.
  2176. * If string ``normal`` then the share of padding is distributed
  2177. based on a normal distribution, leading to a focus on the
  2178. center of the images.
  2179. Equivalent to
  2180. ``(Clip(Normal(0.5, 0.45/2), 0, 1),
  2181. Clip(Normal(0.5, 0.45/2), 0, 1))``.
  2182. * If string ``center`` then center point of the padding is
  2183. identical to the image center.
  2184. Equivalent to ``(0.5, 0.5)``.
  2185. * If a string matching regex
  2186. ``^(left|center|right)-(top|center|bottom)$``, e.g. ``left-top``
  2187. or ``center-bottom`` then sets the center point of the padding
  2188. to the X-Y position matching that description.
  2189. * If a tuple of float, then expected to have exactly two entries
  2190. between ``0.0`` and ``1.0``, which will always be used as the
  2191. combination the position matching (x, y) form.
  2192. * If a ``StochasticParameter``, then that parameter will be queried
  2193. once per call to ``augment_*()`` to get ``Nx2`` center positions
  2194. in ``(x, y)`` form (with ``N`` the number of images).
  2195. * If a ``tuple`` of ``StochasticParameter``, then expected to have
  2196. exactly two entries that will both be queried per call to
  2197. ``augment_*()``, each for ``(N,)`` values, to get the center
  2198. positions. First parameter is used for ``x`` coordinates,
  2199. second for ``y`` coordinates.
  2200. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2201. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2202. name : None or str, optional
  2203. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2204. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2205. Old name for parameter `seed`.
  2206. Its usage will not yet cause a deprecation warning,
  2207. but it is still recommended to use `seed` now.
  2208. Outdated since 0.4.0.
  2209. deterministic : bool, optional
  2210. Deprecated since 0.4.0.
  2211. See method ``to_deterministic()`` for an alternative and for
  2212. details about what the "deterministic mode" actually does.
  2213. Examples
  2214. --------
  2215. >>> import imgaug.augmenters as iaa
  2216. >>> aug = iaa.PadToFixedSize(width=100, height=100)
  2217. For image sides smaller than ``100`` pixels, pad to ``100`` pixels. Do
  2218. nothing for the other edges. The padding is randomly (uniformly)
  2219. distributed over the sides, so that e.g. sometimes most of the required
  2220. padding is applied to the left, sometimes to the right (analogous
  2221. top/bottom).
  2222. >>> aug = iaa.PadToFixedSize(width=100, height=100, position="center")
  2223. For image sides smaller than ``100`` pixels, pad to ``100`` pixels. Do
  2224. nothing for the other image sides. The padding is always equally
  2225. distributed over the left/right and top/bottom sides.
  2226. >>> aug = iaa.PadToFixedSize(width=100, height=100, pad_mode=ia.ALL)
  2227. For image sides smaller than ``100`` pixels, pad to ``100`` pixels and
  2228. use any possible padding mode for that. Do nothing for the other image
  2229. sides. The padding is always equally distributed over the left/right and
  2230. top/bottom sides.
  2231. >>> aug = iaa.Sequential([
  2232. >>> iaa.PadToFixedSize(width=100, height=100),
  2233. >>> iaa.CropToFixedSize(width=100, height=100)
  2234. >>> ])
  2235. Pad images smaller than ``100x100`` until they reach ``100x100``.
  2236. Analogously, crop images larger than ``100x100`` until they reach
  2237. ``100x100``. The output images therefore have a fixed size of ``100x100``.
  2238. """
  2239. def __init__(self, width, height, pad_mode="constant", pad_cval=0,
  2240. position="uniform",
  2241. seed=None, name=None,
  2242. random_state="deprecated", deterministic="deprecated"):
  2243. super(PadToFixedSize, self).__init__(
  2244. seed=seed, name=name,
  2245. random_state=random_state, deterministic=deterministic)
  2246. self.size = (width, height)
  2247. # Position of where to pad. The further to the top left this is, the
  2248. # larger the share of pixels that will be added to the top and left
  2249. # sides. I.e. set to (Deterministic(0.0), Deterministic(0.0)) to only
  2250. # add at the top and left, (Deterministic(1.0), Deterministic(1.0))
  2251. # to only add at the bottom right. Analogously (0.5, 0.5) pads equally
  2252. # on both axis, (0.0, 1.0) pads left and bottom, (1.0, 0.0) pads right
  2253. # and top.
  2254. self.position = _handle_position_parameter(position)
  2255. self.pad_mode = _handle_pad_mode_param(pad_mode)
  2256. # TODO enable ALL here like in eg Affine
  2257. self.pad_cval = iap.handle_discrete_param(
  2258. pad_cval, "pad_cval", value_range=None, tuple_to_uniform=True,
  2259. list_to_choice=True, allow_floats=True)
  2260. # set these to None to use the same values as sampled for the
  2261. # images (not tested)
  2262. self._pad_mode_heatmaps = "constant"
  2263. self._pad_mode_segmentation_maps = "constant"
  2264. self._pad_cval_heatmaps = 0.0
  2265. self._pad_cval_segmentation_maps = 0
  2266. # Added in 0.4.0.
  2267. def _augment_batch_(self, batch, random_state, parents, hooks):
  2268. # Providing the whole batch to _draw_samples() would not be necessary
  2269. # for this augmenter. The number of rows would be sufficient. This
  2270. # formulation however enables derived augmenters to use rowwise shapes
  2271. # without having to compute them here for this augmenter.
  2272. samples = self._draw_samples(batch, random_state)
  2273. if batch.images is not None:
  2274. batch.images = self._augment_images_by_samples(batch.images,
  2275. samples)
  2276. if batch.heatmaps is not None:
  2277. batch.heatmaps = self._augment_maps_by_samples(
  2278. batch.heatmaps, samples, self._pad_mode_heatmaps,
  2279. self._pad_cval_heatmaps)
  2280. if batch.segmentation_maps is not None:
  2281. batch.segmentation_maps = self._augment_maps_by_samples(
  2282. batch.segmentation_maps, samples, self._pad_mode_heatmaps,
  2283. self._pad_cval_heatmaps)
  2284. for augm_name in ["keypoints", "bounding_boxes", "polygons",
  2285. "line_strings"]:
  2286. augm_value = getattr(batch, augm_name)
  2287. if augm_value is not None:
  2288. func = functools.partial(
  2289. self._augment_keypoints_by_samples,
  2290. samples=samples)
  2291. cbaois = self._apply_to_cbaois_as_keypoints(augm_value, func)
  2292. setattr(batch, augm_name, cbaois)
  2293. return batch
  2294. # Added in 0.4.0.
  2295. def _augment_images_by_samples(self, images, samples):
  2296. result = []
  2297. sizes, pad_xs, pad_ys, pad_modes, pad_cvals = samples
  2298. for i, (image, size) in enumerate(zip(images, sizes)):
  2299. width_min, height_min = size
  2300. height_image, width_image = image.shape[:2]
  2301. paddings = self._calculate_paddings(height_image, width_image,
  2302. height_min, width_min,
  2303. pad_xs[i], pad_ys[i])
  2304. image = _crop_and_pad_arr(
  2305. image, (0, 0, 0, 0), paddings, pad_modes[i], pad_cvals[i],
  2306. keep_size=False)
  2307. result.append(image)
  2308. # TODO result is always a list. Should this be converted to an array
  2309. # if possible (not guaranteed that all images have same size,
  2310. # some might have been larger than desired height/width)
  2311. return result
  2312. # Added in 0.4.0.
  2313. def _augment_keypoints_by_samples(self, keypoints_on_images, samples):
  2314. result = []
  2315. sizes, pad_xs, pad_ys, _, _ = samples
  2316. for i, (kpsoi, size) in enumerate(zip(keypoints_on_images, sizes)):
  2317. width_min, height_min = size
  2318. height_image, width_image = kpsoi.shape[:2]
  2319. paddings_img = self._calculate_paddings(height_image, width_image,
  2320. height_min, width_min,
  2321. pad_xs[i], pad_ys[i])
  2322. keypoints_padded = _crop_and_pad_kpsoi_(
  2323. kpsoi, (0, 0, 0, 0), paddings_img,
  2324. keep_size=False)
  2325. result.append(keypoints_padded)
  2326. return result
  2327. # Added in 0.4.0.
  2328. def _augment_maps_by_samples(self, augmentables, samples, pad_mode,
  2329. pad_cval):
  2330. sizes, pad_xs, pad_ys, pad_modes, pad_cvals = samples
  2331. for i, (augmentable, size) in enumerate(zip(augmentables, sizes)):
  2332. width_min, height_min = size
  2333. height_img, width_img = augmentable.shape[:2]
  2334. paddings_img = self._calculate_paddings(
  2335. height_img, width_img, height_min, width_min,
  2336. pad_xs[i], pad_ys[i])
  2337. # TODO for the previous method (and likely the new/current one
  2338. # too):
  2339. # for 30x30 padded to 32x32 with 15x15 heatmaps this results
  2340. # in paddings of 1 on each side (assuming
  2341. # position=(0.5, 0.5)) giving 17x17 heatmaps when they should
  2342. # be 16x16. Error is due to each side getting projected 0.5
  2343. # padding which is rounded to 1. This doesn't seem right.
  2344. augmentables[i] = _crop_and_pad_hms_or_segmaps_(
  2345. augmentables[i],
  2346. (0, 0, 0, 0),
  2347. paddings_img,
  2348. pad_mode=pad_mode if pad_mode is not None else pad_modes[i],
  2349. pad_cval=pad_cval if pad_cval is not None else pad_cvals[i],
  2350. keep_size=False)
  2351. return augmentables
  2352. def _draw_samples(self, batch, random_state):
  2353. nb_images = batch.nb_rows
  2354. rngs = random_state.duplicate(4)
  2355. if isinstance(self.position, tuple):
  2356. pad_xs = self.position[0].draw_samples(nb_images,
  2357. random_state=rngs[0])
  2358. pad_ys = self.position[1].draw_samples(nb_images,
  2359. random_state=rngs[1])
  2360. else:
  2361. pads = self.position.draw_samples((nb_images, 2),
  2362. random_state=rngs[0])
  2363. pad_xs = pads[:, 0]
  2364. pad_ys = pads[:, 1]
  2365. pad_modes = self.pad_mode.draw_samples(nb_images,
  2366. random_state=rngs[2])
  2367. pad_cvals = self.pad_cval.draw_samples(nb_images,
  2368. random_state=rngs[3])
  2369. # We return here the sizes even though they are static as it allows
  2370. # derived augmenters to define image-specific heights/widths.
  2371. return [self.size] * nb_images, pad_xs, pad_ys, pad_modes, pad_cvals
  2372. @classmethod
  2373. def _calculate_paddings(cls, height_image, width_image,
  2374. height_min, width_min, pad_xs_i, pad_ys_i):
  2375. pad_top = 0
  2376. pad_right = 0
  2377. pad_bottom = 0
  2378. pad_left = 0
  2379. if width_min is not None and width_image < width_min:
  2380. pad_total_x = width_min - width_image
  2381. pad_left = int((1-pad_xs_i) * pad_total_x)
  2382. pad_right = pad_total_x - pad_left
  2383. if height_min is not None and height_image < height_min:
  2384. pad_total_y = height_min - height_image
  2385. pad_top = int((1-pad_ys_i) * pad_total_y)
  2386. pad_bottom = pad_total_y - pad_top
  2387. return pad_top, pad_right, pad_bottom, pad_left
  2388. def get_parameters(self):
  2389. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  2390. return [self.size[0], self.size[1], self.pad_mode, self.pad_cval,
  2391. self.position]
  2392. class CenterPadToFixedSize(PadToFixedSize):
  2393. """Pad images equally on all sides up to given minimum heights/widths.
  2394. This is an alias for :class:`~imgaug.augmenters.size.PadToFixedSize`
  2395. with ``position="center"``. It spreads the pad amounts equally over
  2396. all image sides, while :class:`~imgaug.augmenters.size.PadToFixedSize`
  2397. by defaults spreads them randomly.
  2398. Added in 0.4.0.
  2399. **Supported dtypes**:
  2400. See :class:`~imgaug.augmenters.size.PadToFixedSize`.
  2401. Parameters
  2402. ----------
  2403. width : int or None
  2404. See :func:`PadToFixedSize.__init__`.
  2405. height : int or None
  2406. See :func:`PadToFixedSize.__init__`.
  2407. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  2408. See :func:`PadToFixedSize.__init__`.
  2409. pad_cval : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  2410. See :func:`PadToFixedSize.__init__`.
  2411. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2412. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2413. name : None or str, optional
  2414. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2415. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2416. Old name for parameter `seed`.
  2417. Its usage will not yet cause a deprecation warning,
  2418. but it is still recommended to use `seed` now.
  2419. Outdated since 0.4.0.
  2420. deterministic : bool, optional
  2421. Deprecated since 0.4.0.
  2422. See method ``to_deterministic()`` for an alternative and for
  2423. details about what the "deterministic mode" actually does.
  2424. Examples
  2425. --------
  2426. >>> import imgaug.augmenters as iaa
  2427. >>> aug = iaa.CenterPadToFixedSize(height=20, width=30)
  2428. Create an augmenter that pads images up to ``20x30``, with the padded
  2429. rows added *equally* on the top and bottom (analogous for the padded
  2430. columns).
  2431. """
  2432. # Added in 0.4.0.
  2433. def __init__(self, width, height, pad_mode="constant", pad_cval=0,
  2434. seed=None, name=None,
  2435. random_state="deprecated", deterministic="deprecated"):
  2436. super(CenterPadToFixedSize, self).__init__(
  2437. width=width, height=height, pad_mode=pad_mode, pad_cval=pad_cval,
  2438. position="center",
  2439. seed=seed, name=name,
  2440. random_state=random_state, deterministic=deterministic)
  2441. # TODO maybe rename this to CropToMaximumSize ?
  2442. # TODO this is very similar to CropAndPad, maybe add a way to generate crop
  2443. # values imagewise via a callback in in CropAndPad?
  2444. # TODO add crop() function in imgaug, similar to pad
  2445. class CropToFixedSize(meta.Augmenter):
  2446. """Crop images down to a predefined maximum width and/or height.
  2447. If images are already at the maximum width/height or are smaller, they
  2448. will not be cropped. Note that this also means that images will not be
  2449. padded if they are below the required width/height.
  2450. The augmenter randomly decides per image how to distribute the required
  2451. cropping amounts over the image axis. E.g. if 2px have to be cropped on
  2452. the left or right to reach the required width, the augmenter will
  2453. sometimes remove 2px from the left and 0px from the right, sometimes
  2454. remove 2px from the right and 0px from the left and sometimes remove 1px
  2455. from both sides. Set `position` to ``center`` to prevent that.
  2456. **Supported dtypes**:
  2457. * ``uint8``: yes; fully tested
  2458. * ``uint16``: yes; tested
  2459. * ``uint32``: yes; tested
  2460. * ``uint64``: yes; tested
  2461. * ``int8``: yes; tested
  2462. * ``int16``: yes; tested
  2463. * ``int32``: yes; tested
  2464. * ``int64``: yes; tested
  2465. * ``float16``: yes; tested
  2466. * ``float32``: yes; tested
  2467. * ``float64``: yes; tested
  2468. * ``float128``: yes; tested
  2469. * ``bool``: yes; tested
  2470. Parameters
  2471. ----------
  2472. width : int or None
  2473. Crop images down to this maximum width.
  2474. If ``None``, image widths will not be altered.
  2475. height : int or None
  2476. Crop images down to this maximum height.
  2477. If ``None``, image heights will not be altered.
  2478. position : {'uniform', 'normal', 'center', 'left-top', 'left-center', 'left-bottom', 'center-top', 'center-center', 'center-bottom', 'right-top', 'right-center', 'right-bottom'} or tuple of float or StochasticParameter or tuple of StochasticParameter, optional
  2479. Sets the center point of the cropping, which determines how the
  2480. required cropping amounts are distributed to each side. For a
  2481. ``tuple`` ``(a, b)``, both ``a`` and ``b`` are expected to be in
  2482. range ``[0.0, 1.0]`` and describe the fraction of cropping applied
  2483. to the left/right (low/high values for ``a``) and the fraction
  2484. of cropping applied to the top/bottom (low/high values for ``b``).
  2485. A cropping position at ``(0.5, 0.5)`` would be the center of the
  2486. image and distribute the cropping equally over all sides. A cropping
  2487. position at ``(1.0, 0.0)`` would be the right-top and would apply
  2488. 100% of the required cropping to the right and top sides of the image.
  2489. * If string ``uniform`` then the share of cropping is randomly
  2490. and uniformly distributed over each side.
  2491. Equivalent to ``(Uniform(0.0, 1.0), Uniform(0.0, 1.0))``.
  2492. * If string ``normal`` then the share of cropping is distributed
  2493. based on a normal distribution, leading to a focus on the center
  2494. of the images.
  2495. Equivalent to
  2496. ``(Clip(Normal(0.5, 0.45/2), 0, 1),
  2497. Clip(Normal(0.5, 0.45/2), 0, 1))``.
  2498. * If string ``center`` then center point of the cropping is
  2499. identical to the image center.
  2500. Equivalent to ``(0.5, 0.5)``.
  2501. * If a string matching regex
  2502. ``^(left|center|right)-(top|center|bottom)$``, e.g.
  2503. ``left-top`` or ``center-bottom`` then sets the center point of
  2504. the cropping to the X-Y position matching that description.
  2505. * If a tuple of float, then expected to have exactly two entries
  2506. between ``0.0`` and ``1.0``, which will always be used as the
  2507. combination the position matching (x, y) form.
  2508. * If a ``StochasticParameter``, then that parameter will be queried
  2509. once per call to ``augment_*()`` to get ``Nx2`` center positions
  2510. in ``(x, y)`` form (with ``N`` the number of images).
  2511. * If a ``tuple`` of ``StochasticParameter``, then expected to have
  2512. exactly two entries that will both be queried per call to
  2513. ``augment_*()``, each for ``(N,)`` values, to get the center
  2514. positions. First parameter is used for ``x`` coordinates,
  2515. second for ``y`` coordinates.
  2516. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2517. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2518. name : None or str, optional
  2519. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2520. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2521. Old name for parameter `seed`.
  2522. Its usage will not yet cause a deprecation warning,
  2523. but it is still recommended to use `seed` now.
  2524. Outdated since 0.4.0.
  2525. deterministic : bool, optional
  2526. Deprecated since 0.4.0.
  2527. See method ``to_deterministic()`` for an alternative and for
  2528. details about what the "deterministic mode" actually does.
  2529. Examples
  2530. --------
  2531. >>> import imgaug.augmenters as iaa
  2532. >>> aug = iaa.CropToFixedSize(width=100, height=100)
  2533. For image sides larger than ``100`` pixels, crop to ``100`` pixels. Do
  2534. nothing for the other sides. The cropping amounts are randomly (and
  2535. uniformly) distributed over the sides of the image.
  2536. >>> aug = iaa.CropToFixedSize(width=100, height=100, position="center")
  2537. For sides larger than ``100`` pixels, crop to ``100`` pixels. Do nothing
  2538. for the other sides. The cropping amounts are always equally distributed
  2539. over the left/right sides of the image (and analogously for top/bottom).
  2540. >>> aug = iaa.Sequential([
  2541. >>> iaa.PadToFixedSize(width=100, height=100),
  2542. >>> iaa.CropToFixedSize(width=100, height=100)
  2543. >>> ])
  2544. Pad images smaller than ``100x100`` until they reach ``100x100``.
  2545. Analogously, crop images larger than ``100x100`` until they reach
  2546. ``100x100``. The output images therefore have a fixed size of ``100x100``.
  2547. """
  2548. def __init__(self, width, height, position="uniform",
  2549. seed=None, name=None,
  2550. random_state="deprecated", deterministic="deprecated"):
  2551. super(CropToFixedSize, self).__init__(
  2552. seed=seed, name=name,
  2553. random_state=random_state, deterministic=deterministic)
  2554. self.size = (width, height)
  2555. # Position of where to crop. The further to the top left this is,
  2556. # the larger the share of pixels that will be cropped from the top
  2557. # and left sides. I.e. set to (Deterministic(0.0), Deterministic(0.0))
  2558. # to only crop at the top and left,
  2559. # (Deterministic(1.0), Deterministic(1.0)) to only crop at the bottom
  2560. # right. Analogously (0.5, 0.5) crops equally on both axis,
  2561. # (0.0, 1.0) crops left and bottom, (1.0, 0.0) crops right and top.
  2562. self.position = _handle_position_parameter(position)
  2563. # Added in 0.4.0.
  2564. def _augment_batch_(self, batch, random_state, parents, hooks):
  2565. # Providing the whole batch to _draw_samples() would not be necessary
  2566. # for this augmenter. The number of rows would be sufficient. This
  2567. # formulation however enables derived augmenters to use rowwise shapes
  2568. # without having to compute them here for this augmenter.
  2569. samples = self._draw_samples(batch, random_state)
  2570. if batch.images is not None:
  2571. batch.images = self._augment_images_by_samples(batch.images,
  2572. samples)
  2573. if batch.heatmaps is not None:
  2574. batch.heatmaps = self._augment_maps_by_samples(
  2575. batch.heatmaps, samples)
  2576. if batch.segmentation_maps is not None:
  2577. batch.segmentation_maps = self._augment_maps_by_samples(
  2578. batch.segmentation_maps, samples)
  2579. for augm_name in ["keypoints", "bounding_boxes", "polygons",
  2580. "line_strings"]:
  2581. augm_value = getattr(batch, augm_name)
  2582. if augm_value is not None:
  2583. func = functools.partial(
  2584. self._augment_keypoints_by_samples,
  2585. samples=samples)
  2586. cbaois = self._apply_to_cbaois_as_keypoints(augm_value, func)
  2587. setattr(batch, augm_name, cbaois)
  2588. return batch
  2589. # Added in 0.4.0.
  2590. def _augment_images_by_samples(self, images, samples):
  2591. result = []
  2592. sizes, offset_xs, offset_ys = samples
  2593. for i, (image, size) in enumerate(zip(images, sizes)):
  2594. w, h = size
  2595. height_image, width_image = image.shape[0:2]
  2596. croppings = self._calculate_crop_amounts(
  2597. height_image, width_image, h, w, offset_ys[i], offset_xs[i])
  2598. image_cropped = _crop_and_pad_arr(image, croppings, (0, 0, 0, 0),
  2599. keep_size=False)
  2600. result.append(image_cropped)
  2601. return result
  2602. # Added in 0.4.0.
  2603. def _augment_keypoints_by_samples(self, kpsois, samples):
  2604. result = []
  2605. sizes, offset_xs, offset_ys = samples
  2606. for i, (kpsoi, size) in enumerate(zip(kpsois, sizes)):
  2607. w, h = size
  2608. height_image, width_image = kpsoi.shape[0:2]
  2609. croppings_img = self._calculate_crop_amounts(
  2610. height_image, width_image, h, w, offset_ys[i], offset_xs[i])
  2611. kpsoi_cropped = _crop_and_pad_kpsoi_(
  2612. kpsoi, croppings_img, (0, 0, 0, 0), keep_size=False)
  2613. result.append(kpsoi_cropped)
  2614. return result
  2615. # Added in 0.4.0.
  2616. def _augment_maps_by_samples(self, augmentables, samples):
  2617. sizes, offset_xs, offset_ys = samples
  2618. for i, (augmentable, size) in enumerate(zip(augmentables, sizes)):
  2619. w, h = size
  2620. height_image, width_image = augmentable.shape[0:2]
  2621. croppings_img = self._calculate_crop_amounts(
  2622. height_image, width_image, h, w, offset_ys[i], offset_xs[i])
  2623. augmentables[i] = _crop_and_pad_hms_or_segmaps_(
  2624. augmentable, croppings_img, (0, 0, 0, 0), keep_size=False)
  2625. return augmentables
  2626. @classmethod
  2627. def _calculate_crop_amounts(cls, height_image, width_image,
  2628. height_max, width_max,
  2629. offset_y, offset_x):
  2630. crop_top = 0
  2631. crop_right = 0
  2632. crop_bottom = 0
  2633. crop_left = 0
  2634. if height_max is not None and height_image > height_max:
  2635. crop_top = int(offset_y * (height_image - height_max))
  2636. crop_bottom = height_image - height_max - crop_top
  2637. if width_max is not None and width_image > width_max:
  2638. crop_left = int(offset_x * (width_image - width_max))
  2639. crop_right = width_image - width_max - crop_left
  2640. return crop_top, crop_right, crop_bottom, crop_left
  2641. def _draw_samples(self, batch, random_state):
  2642. nb_images = batch.nb_rows
  2643. rngs = random_state.duplicate(2)
  2644. if isinstance(self.position, tuple):
  2645. offset_xs = self.position[0].draw_samples(nb_images,
  2646. random_state=rngs[0])
  2647. offset_ys = self.position[1].draw_samples(nb_images,
  2648. random_state=rngs[1])
  2649. else:
  2650. offsets = self.position.draw_samples((nb_images, 2),
  2651. random_state=rngs[0])
  2652. offset_xs = offsets[:, 0]
  2653. offset_ys = offsets[:, 1]
  2654. offset_xs = 1.0 - offset_xs
  2655. offset_ys = 1.0 - offset_ys
  2656. # We return here the sizes even though they are static as it allows
  2657. # derived augmenters to define image-specific heights/widths.
  2658. return [self.size] * nb_images, offset_xs, offset_ys
  2659. def get_parameters(self):
  2660. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  2661. return [self.size[0], self.size[1], self.position]
  2662. class CenterCropToFixedSize(CropToFixedSize):
  2663. """Take a crop from the center of each image.
  2664. This is an alias for :class:`~imgaug.augmenters.size.CropToFixedSize` with
  2665. ``position="center"``.
  2666. .. note::
  2667. If images already have a width and/or height below the provided
  2668. width and/or height then this augmenter will do nothing for the
  2669. respective axis. Hence, resulting images can be smaller than the
  2670. provided axis sizes.
  2671. Added in 0.4.0.
  2672. **Supported dtypes**:
  2673. See :class:`~imgaug.augmenters.size.CropToFixedSize`.
  2674. Parameters
  2675. ----------
  2676. width : int or None
  2677. See :func:`CropToFixedSize.__init__`.
  2678. height : int or None
  2679. See :func:`CropToFixedSize.__init__`.
  2680. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2681. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2682. name : None or str, optional
  2683. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2684. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2685. Old name for parameter `seed`.
  2686. Its usage will not yet cause a deprecation warning,
  2687. but it is still recommended to use `seed` now.
  2688. Outdated since 0.4.0.
  2689. deterministic : bool, optional
  2690. Deprecated since 0.4.0.
  2691. See method ``to_deterministic()`` for an alternative and for
  2692. details about what the "deterministic mode" actually does.
  2693. Examples
  2694. --------
  2695. >>> import imgaug.augmenters as iaa
  2696. >>> crop = iaa.CenterCropToFixedSize(height=20, width=10)
  2697. Create an augmenter that takes ``20x10`` sized crops from the center of
  2698. images.
  2699. """
  2700. # Added in 0.4.0.
  2701. def __init__(self, width, height,
  2702. seed=None, name=None,
  2703. random_state="deprecated", deterministic="deprecated"):
  2704. super(CenterCropToFixedSize, self).__init__(
  2705. width=width, height=height, position="center",
  2706. seed=seed, name=name,
  2707. random_state=random_state, deterministic=deterministic)
  2708. class CropToMultiplesOf(CropToFixedSize):
  2709. """Crop images down until their height/width is a multiple of a value.
  2710. .. note::
  2711. For a given axis size ``A`` and multiple ``M``, if ``A`` is in the
  2712. interval ``[0 .. M]``, the axis will not be changed.
  2713. As a result, this augmenter can still produce axis sizes that are
  2714. not multiples of the given values.
  2715. Added in 0.4.0.
  2716. **Supported dtypes**:
  2717. See :class:`~imgaug.augmenters.size.CropToFixedSize`.
  2718. Parameters
  2719. ----------
  2720. width_multiple : int or None
  2721. Multiple for the width. Images will be cropped down until their
  2722. width is a multiple of this value.
  2723. If ``None``, image widths will not be altered.
  2724. height_multiple : int or None
  2725. Multiple for the height. Images will be cropped down until their
  2726. height is a multiple of this value.
  2727. If ``None``, image heights will not be altered.
  2728. position : {'uniform', 'normal', 'center', 'left-top', 'left-center', 'left-bottom', 'center-top', 'center-center', 'center-bottom', 'right-top', 'right-center', 'right-bottom'} or tuple of float or StochasticParameter or tuple of StochasticParameter, optional
  2729. See :func:`CropToFixedSize.__init__`.
  2730. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2731. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2732. name : None or str, optional
  2733. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2734. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2735. Old name for parameter `seed`.
  2736. Its usage will not yet cause a deprecation warning,
  2737. but it is still recommended to use `seed` now.
  2738. Outdated since 0.4.0.
  2739. deterministic : bool, optional
  2740. Deprecated since 0.4.0.
  2741. See method ``to_deterministic()`` for an alternative and for
  2742. details about what the "deterministic mode" actually does.
  2743. Examples
  2744. --------
  2745. >>> import imgaug.augmenters as iaa
  2746. >>> aug = iaa.CropToMultiplesOf(height_multiple=10, width_multiple=6)
  2747. Create an augmenter that crops images to multiples of ``10`` along
  2748. the y-axis (i.e. 10, 20, 30, ...) and to multiples of ``6`` along the
  2749. x-axis (i.e. 6, 12, 18, ...).
  2750. The rows to be cropped will be spread *randomly* over the top and bottom
  2751. sides (analogous for the left/right sides).
  2752. """
  2753. # Added in 0.4.0.
  2754. def __init__(self, width_multiple, height_multiple, position="uniform",
  2755. seed=None, name=None,
  2756. random_state="deprecated", deterministic="deprecated"):
  2757. super(CropToMultiplesOf, self).__init__(
  2758. width=None, height=None, position=position,
  2759. seed=seed, name=name,
  2760. random_state=random_state, deterministic=deterministic)
  2761. self.width_multiple = width_multiple
  2762. self.height_multiple = height_multiple
  2763. # Added in 0.4.0.
  2764. def _draw_samples(self, batch, random_state):
  2765. _sizes, offset_xs, offset_ys = super(
  2766. CropToMultiplesOf, self
  2767. )._draw_samples(batch, random_state)
  2768. shapes = batch.get_rowwise_shapes()
  2769. sizes = []
  2770. for shape in shapes:
  2771. height, width = shape[0:2]
  2772. croppings = compute_croppings_to_reach_multiples_of(
  2773. shape,
  2774. height_multiple=self.height_multiple,
  2775. width_multiple=self.width_multiple)
  2776. # TODO change that
  2777. # note that these are not in the same order as shape tuples
  2778. # in CropToFixedSize
  2779. new_size = (
  2780. width - croppings[1] - croppings[3],
  2781. height - croppings[0] - croppings[2]
  2782. )
  2783. sizes.append(new_size)
  2784. return sizes, offset_xs, offset_ys
  2785. # Added in 0.4.0.
  2786. def get_parameters(self):
  2787. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  2788. return [self.width_multiple, self.height_multiple, self.position]
  2789. class CenterCropToMultiplesOf(CropToMultiplesOf):
  2790. """Crop images equally on all sides until H/W are multiples of given values.
  2791. This is the same as :class:`~imgaug.augmenters.size.CropToMultiplesOf`,
  2792. but uses ``position="center"`` by default, which spreads the crop amounts
  2793. equally over all image sides, while
  2794. :class:`~imgaug.augmenters.size.CropToMultiplesOf` by default spreads
  2795. them randomly.
  2796. Added in 0.4.0.
  2797. **Supported dtypes**:
  2798. See :class:`~imgaug.augmenters.size.CropToFixedSize`.
  2799. Parameters
  2800. ----------
  2801. width_multiple : int or None
  2802. See :func:`CropToMultiplesOf.__init__`.
  2803. height_multiple : int or None
  2804. See :func:`CropToMultiplesOf.__init__`.
  2805. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2806. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2807. name : None or str, optional
  2808. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2809. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2810. Old name for parameter `seed`.
  2811. Its usage will not yet cause a deprecation warning,
  2812. but it is still recommended to use `seed` now.
  2813. Outdated since 0.4.0.
  2814. deterministic : bool, optional
  2815. Deprecated since 0.4.0.
  2816. See method ``to_deterministic()`` for an alternative and for
  2817. details about what the "deterministic mode" actually does.
  2818. Examples
  2819. --------
  2820. >>> import imgaug.augmenters as iaa
  2821. >>> aug = iaa.CenterCropToMultiplesOf(height_multiple=10, width_multiple=6)
  2822. Create an augmenter that crops images to multiples of ``10`` along
  2823. the y-axis (i.e. 10, 20, 30, ...) and to multiples of ``6`` along the
  2824. x-axis (i.e. 6, 12, 18, ...).
  2825. The rows to be cropped will be spread *equally* over the top and bottom
  2826. sides (analogous for the left/right sides).
  2827. """
  2828. # Added in 0.4.0.
  2829. def __init__(self, width_multiple, height_multiple,
  2830. seed=None, name=None,
  2831. random_state="deprecated", deterministic="deprecated"):
  2832. super(CenterCropToMultiplesOf, self).__init__(
  2833. width_multiple=width_multiple,
  2834. height_multiple=height_multiple,
  2835. position="center",
  2836. seed=seed, name=name,
  2837. random_state=random_state, deterministic=deterministic)
  2838. class PadToMultiplesOf(PadToFixedSize):
  2839. """Pad images until their height/width is a multiple of a value.
  2840. Added in 0.4.0.
  2841. **Supported dtypes**:
  2842. See :class:`~imgaug.augmenters.size.PadToFixedSize`.
  2843. Parameters
  2844. ----------
  2845. width_multiple : int or None
  2846. Multiple for the width. Images will be padded until their
  2847. width is a multiple of this value.
  2848. If ``None``, image widths will not be altered.
  2849. height_multiple : int or None
  2850. Multiple for the height. Images will be padded until their
  2851. height is a multiple of this value.
  2852. If ``None``, image heights will not be altered.
  2853. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  2854. See :func:`~imgaug.augmenters.size.PadToFixedSize.__init__`.
  2855. pad_cval : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  2856. See :func:`~imgaug.augmenters.size.PadToFixedSize.__init__`.
  2857. position : {'uniform', 'normal', 'center', 'left-top', 'left-center', 'left-bottom', 'center-top', 'center-center', 'center-bottom', 'right-top', 'right-center', 'right-bottom'} or tuple of float or StochasticParameter or tuple of StochasticParameter, optional
  2858. See :func:`PadToFixedSize.__init__`.
  2859. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2860. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2861. name : None or str, optional
  2862. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2863. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2864. Old name for parameter `seed`.
  2865. Its usage will not yet cause a deprecation warning,
  2866. but it is still recommended to use `seed` now.
  2867. Outdated since 0.4.0.
  2868. deterministic : bool, optional
  2869. Deprecated since 0.4.0.
  2870. See method ``to_deterministic()`` for an alternative and for
  2871. details about what the "deterministic mode" actually does.
  2872. Examples
  2873. --------
  2874. >>> import imgaug.augmenters as iaa
  2875. >>> aug = iaa.PadToMultiplesOf(height_multiple=10, width_multiple=6)
  2876. Create an augmenter that pads images to multiples of ``10`` along
  2877. the y-axis (i.e. 10, 20, 30, ...) and to multiples of ``6`` along the
  2878. x-axis (i.e. 6, 12, 18, ...).
  2879. The rows to be padded will be spread *randomly* over the top and bottom
  2880. sides (analogous for the left/right sides).
  2881. """
  2882. # Added in 0.4.0.
  2883. def __init__(self, width_multiple, height_multiple,
  2884. pad_mode="constant", pad_cval=0,
  2885. position="uniform",
  2886. seed=None, name=None,
  2887. random_state="deprecated", deterministic="deprecated"):
  2888. super(PadToMultiplesOf, self).__init__(
  2889. width=None, height=None, pad_mode=pad_mode, pad_cval=pad_cval,
  2890. position=position,
  2891. seed=seed, name=name,
  2892. random_state=random_state, deterministic=deterministic)
  2893. self.width_multiple = width_multiple
  2894. self.height_multiple = height_multiple
  2895. # Added in 0.4.0.
  2896. def _draw_samples(self, batch, random_state):
  2897. _sizes, pad_xs, pad_ys, pad_modes, pad_cvals = super(
  2898. PadToMultiplesOf, self
  2899. )._draw_samples(batch, random_state)
  2900. shapes = batch.get_rowwise_shapes()
  2901. sizes = []
  2902. for shape in shapes:
  2903. height, width = shape[0:2]
  2904. paddings = compute_paddings_to_reach_multiples_of(
  2905. shape,
  2906. height_multiple=self.height_multiple,
  2907. width_multiple=self.width_multiple)
  2908. # TODO change that
  2909. # note that these are not in the same order as shape tuples
  2910. # in PadToFixedSize
  2911. new_size = (
  2912. width + paddings[1] + paddings[3],
  2913. height + paddings[0] + paddings[2]
  2914. )
  2915. sizes.append(new_size)
  2916. return sizes, pad_xs, pad_ys, pad_modes, pad_cvals
  2917. # Added in 0.4.0.
  2918. def get_parameters(self):
  2919. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  2920. return [self.width_multiple, self.height_multiple,
  2921. self.pad_mode, self.pad_cval,
  2922. self.position]
  2923. class CenterPadToMultiplesOf(PadToMultiplesOf):
  2924. """Pad images equally on all sides until H/W are multiples of given values.
  2925. This is the same as :class:`~imgaug.augmenters.size.PadToMultiplesOf`, but
  2926. uses ``position="center"`` by default, which spreads the pad amounts
  2927. equally over all image sides, while
  2928. :class:`~imgaug.augmenters.size.PadToMultiplesOf` by default spreads them
  2929. randomly.
  2930. Added in 0.4.0.
  2931. **Supported dtypes**:
  2932. See :class:`~imgaug.augmenters.size.PadToFixedSize`.
  2933. Parameters
  2934. ----------
  2935. width_multiple : int or None
  2936. See :func:`PadToMultiplesOf.__init__`.
  2937. height_multiple : int or None
  2938. See :func:`PadToMultiplesOf.__init__`.
  2939. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  2940. See :func:`~imgaug.augmenters.size.PadToMultiplesOf.__init__`.
  2941. pad_cval : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  2942. See :func:`~imgaug.augmenters.size.PadToMultiplesOf.__init__`.
  2943. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2944. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2945. name : None or str, optional
  2946. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  2947. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  2948. Old name for parameter `seed`.
  2949. Its usage will not yet cause a deprecation warning,
  2950. but it is still recommended to use `seed` now.
  2951. Outdated since 0.4.0.
  2952. deterministic : bool, optional
  2953. Deprecated since 0.4.0.
  2954. See method ``to_deterministic()`` for an alternative and for
  2955. details about what the "deterministic mode" actually does.
  2956. Examples
  2957. --------
  2958. >>> import imgaug.augmenters as iaa
  2959. >>> aug = iaa.CenterPadToMultiplesOf(height_multiple=10, width_multiple=6)
  2960. Create an augmenter that pads images to multiples of ``10`` along
  2961. the y-axis (i.e. 10, 20, 30, ...) and to multiples of ``6`` along the
  2962. x-axis (i.e. 6, 12, 18, ...).
  2963. The rows to be padded will be spread *equally* over the top and bottom
  2964. sides (analogous for the left/right sides).
  2965. """
  2966. # Added in 0.4.0.
  2967. def __init__(self, width_multiple, height_multiple,
  2968. pad_mode="constant", pad_cval=0,
  2969. seed=None, name=None,
  2970. random_state="deprecated", deterministic="deprecated"):
  2971. super(CenterPadToMultiplesOf, self).__init__(
  2972. width_multiple=width_multiple,
  2973. height_multiple=height_multiple,
  2974. pad_mode=pad_mode,
  2975. pad_cval=pad_cval,
  2976. position="center",
  2977. seed=seed, name=name,
  2978. random_state=random_state, deterministic=deterministic)
  2979. class CropToPowersOf(CropToFixedSize):
  2980. """Crop images until their height/width is a power of a base.
  2981. This augmenter removes pixels from an axis with size ``S`` leading to the
  2982. new size ``S'`` until ``S' = B^E`` is fulfilled, where ``B`` is a
  2983. provided base (e.g. ``2``) and ``E`` is an exponent from the discrete
  2984. interval ``[1 .. inf)``.
  2985. .. note::
  2986. This augmenter does nothing for axes with size less than ``B^1 = B``.
  2987. If you have images with ``S < B^1``, it is recommended
  2988. to combine this augmenter with a padding augmenter that pads each
  2989. axis up to ``B``.
  2990. Added in 0.4.0.
  2991. **Supported dtypes**:
  2992. See :class:`~imgaug.augmenters.size.CropToFixedSize`.
  2993. Parameters
  2994. ----------
  2995. width_base : int or None
  2996. Base for the width. Images will be cropped down until their
  2997. width fulfills ``width' = width_base ^ E`` with ``E`` being any
  2998. natural number.
  2999. If ``None``, image widths will not be altered.
  3000. height_base : int or None
  3001. Base for the height. Images will be cropped down until their
  3002. height fulfills ``height' = height_base ^ E`` with ``E`` being any
  3003. natural number.
  3004. If ``None``, image heights will not be altered.
  3005. position : {'uniform', 'normal', 'center', 'left-top', 'left-center', 'left-bottom', 'center-top', 'center-center', 'center-bottom', 'right-top', 'right-center', 'right-bottom'} or tuple of float or StochasticParameter or tuple of StochasticParameter, optional
  3006. See :func:`CropToFixedSize.__init__`.
  3007. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3008. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3009. name : None or str, optional
  3010. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3011. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3012. Old name for parameter `seed`.
  3013. Its usage will not yet cause a deprecation warning,
  3014. but it is still recommended to use `seed` now.
  3015. Outdated since 0.4.0.
  3016. deterministic : bool, optional
  3017. Deprecated since 0.4.0.
  3018. See method ``to_deterministic()`` for an alternative and for
  3019. details about what the "deterministic mode" actually does.
  3020. Examples
  3021. --------
  3022. >>> import imgaug.augmenters as iaa
  3023. >>> aug = iaa.CropToPowersOf(height_base=3, width_base=2)
  3024. Create an augmenter that crops each image down to powers of ``3`` along
  3025. the y-axis (i.e. 3, 9, 27, ...) and powers of ``2`` along the x-axis (i.e.
  3026. 2, 4, 8, 16, ...).
  3027. The rows to be cropped will be spread *randomly* over the top and bottom
  3028. sides (analogous for the left/right sides).
  3029. """
  3030. # Added in 0.4.0.
  3031. def __init__(self, width_base, height_base, position="uniform",
  3032. seed=None, name=None,
  3033. random_state="deprecated", deterministic="deprecated"):
  3034. super(CropToPowersOf, self).__init__(
  3035. width=None, height=None, position=position,
  3036. seed=seed, name=name,
  3037. random_state=random_state, deterministic=deterministic)
  3038. self.width_base = width_base
  3039. self.height_base = height_base
  3040. # Added in 0.4.0.
  3041. def _draw_samples(self, batch, random_state):
  3042. _sizes, offset_xs, offset_ys = super(
  3043. CropToPowersOf, self
  3044. )._draw_samples(batch, random_state)
  3045. shapes = batch.get_rowwise_shapes()
  3046. sizes = []
  3047. for shape in shapes:
  3048. height, width = shape[0:2]
  3049. croppings = compute_croppings_to_reach_powers_of(
  3050. shape,
  3051. height_base=self.height_base,
  3052. width_base=self.width_base)
  3053. # TODO change that
  3054. # note that these are not in the same order as shape tuples
  3055. # in CropToFixedSize
  3056. new_size = (
  3057. width - croppings[1] - croppings[3],
  3058. height - croppings[0] - croppings[2]
  3059. )
  3060. sizes.append(new_size)
  3061. return sizes, offset_xs, offset_ys
  3062. # Added in 0.4.0.
  3063. def get_parameters(self):
  3064. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  3065. return [self.width_base, self.height_base, self.position]
  3066. class CenterCropToPowersOf(CropToPowersOf):
  3067. """Crop images equally on all sides until H/W is a power of a base.
  3068. This is the same as :class:`~imgaug.augmenters.size.CropToPowersOf`, but
  3069. uses ``position="center"`` by default, which spreads the crop amounts
  3070. equally over all image sides, while
  3071. :class:`~imgaug.augmenters.size.CropToPowersOf` by default spreads them
  3072. randomly.
  3073. Added in 0.4.0.
  3074. **Supported dtypes**:
  3075. See :class:`~imgaug.augmenters.size.CropToFixedSize`.
  3076. Parameters
  3077. ----------
  3078. width_base : int or None
  3079. See :func:`CropToPowersOf.__init__`.
  3080. height_base : int or None
  3081. See :func:`CropToPowersOf.__init__`.
  3082. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3083. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3084. name : None or str, optional
  3085. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3086. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3087. Old name for parameter `seed`.
  3088. Its usage will not yet cause a deprecation warning,
  3089. but it is still recommended to use `seed` now.
  3090. Outdated since 0.4.0.
  3091. deterministic : bool, optional
  3092. Deprecated since 0.4.0.
  3093. See method ``to_deterministic()`` for an alternative and for
  3094. details about what the "deterministic mode" actually does.
  3095. Examples
  3096. --------
  3097. >>> import imgaug.augmenters as iaa
  3098. >>> aug = iaa.CropToPowersOf(height_base=3, width_base=2)
  3099. Create an augmenter that crops each image down to powers of ``3`` along
  3100. the y-axis (i.e. 3, 9, 27, ...) and powers of ``2`` along the x-axis (i.e.
  3101. 2, 4, 8, 16, ...).
  3102. The rows to be cropped will be spread *equally* over the top and bottom
  3103. sides (analogous for the left/right sides).
  3104. """
  3105. # Added in 0.4.0.
  3106. def __init__(self, width_base, height_base,
  3107. seed=None, name=None,
  3108. random_state="deprecated", deterministic="deprecated"):
  3109. super(CenterCropToPowersOf, self).__init__(
  3110. width_base=width_base, height_base=height_base, position="center",
  3111. seed=seed, name=name,
  3112. random_state=random_state, deterministic=deterministic)
  3113. class PadToPowersOf(PadToFixedSize):
  3114. """Pad images until their height/width is a power of a base.
  3115. This augmenter adds pixels to an axis with size ``S`` leading to the
  3116. new size ``S'`` until ``S' = B^E`` is fulfilled, where ``B`` is a
  3117. provided base (e.g. ``2``) and ``E`` is an exponent from the discrete
  3118. interval ``[1 .. inf)``.
  3119. Added in 0.4.0.
  3120. **Supported dtypes**:
  3121. See :class:`~imgaug.augmenters.size.PadToFixedSize`.
  3122. Parameters
  3123. ----------
  3124. width_base : int or None
  3125. Base for the width. Images will be padded down until their
  3126. width fulfills ``width' = width_base ^ E`` with ``E`` being any
  3127. natural number.
  3128. If ``None``, image widths will not be altered.
  3129. height_base : int or None
  3130. Base for the height. Images will be padded until their
  3131. height fulfills ``height' = height_base ^ E`` with ``E`` being any
  3132. natural number.
  3133. If ``None``, image heights will not be altered.
  3134. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  3135. See :func:`~imgaug.augmenters.size.PadToFixedSize.__init__`.
  3136. pad_cval : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  3137. See :func:`~imgaug.augmenters.size.PadToFixedSize.__init__`.
  3138. position : {'uniform', 'normal', 'center', 'left-top', 'left-center', 'left-bottom', 'center-top', 'center-center', 'center-bottom', 'right-top', 'right-center', 'right-bottom'} or tuple of float or StochasticParameter or tuple of StochasticParameter, optional
  3139. See :func:`PadToFixedSize.__init__`.
  3140. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3141. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3142. name : None or str, optional
  3143. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3144. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3145. Old name for parameter `seed`.
  3146. Its usage will not yet cause a deprecation warning,
  3147. but it is still recommended to use `seed` now.
  3148. Outdated since 0.4.0.
  3149. deterministic : bool, optional
  3150. Deprecated since 0.4.0.
  3151. See method ``to_deterministic()`` for an alternative and for
  3152. details about what the "deterministic mode" actually does.
  3153. Examples
  3154. --------
  3155. >>> import imgaug.augmenters as iaa
  3156. >>> aug = iaa.PadToPowersOf(height_base=3, width_base=2)
  3157. Create an augmenter that pads each image to powers of ``3`` along the
  3158. y-axis (i.e. 3, 9, 27, ...) and powers of ``2`` along the x-axis (i.e. 2,
  3159. 4, 8, 16, ...).
  3160. The rows to be padded will be spread *randomly* over the top and bottom
  3161. sides (analogous for the left/right sides).
  3162. """
  3163. # Added in 0.4.0.
  3164. def __init__(self, width_base, height_base,
  3165. pad_mode="constant", pad_cval=0,
  3166. position="uniform",
  3167. seed=None, name=None,
  3168. random_state="deprecated", deterministic="deprecated"):
  3169. super(PadToPowersOf, self).__init__(
  3170. width=None, height=None, pad_mode=pad_mode, pad_cval=pad_cval,
  3171. position=position,
  3172. seed=seed, name=name,
  3173. random_state=random_state, deterministic=deterministic)
  3174. self.width_base = width_base
  3175. self.height_base = height_base
  3176. # Added in 0.4.0.
  3177. def _draw_samples(self, batch, random_state):
  3178. _sizes, pad_xs, pad_ys, pad_modes, pad_cvals = super(
  3179. PadToPowersOf, self
  3180. )._draw_samples(batch, random_state)
  3181. shapes = batch.get_rowwise_shapes()
  3182. sizes = []
  3183. for shape in shapes:
  3184. height, width = shape[0:2]
  3185. paddings = compute_paddings_to_reach_powers_of(
  3186. shape,
  3187. height_base=self.height_base,
  3188. width_base=self.width_base)
  3189. # TODO change that
  3190. # note that these are not in the same order as shape tuples
  3191. # in PadToFixedSize
  3192. new_size = (
  3193. width + paddings[1] + paddings[3],
  3194. height + paddings[0] + paddings[2]
  3195. )
  3196. sizes.append(new_size)
  3197. return sizes, pad_xs, pad_ys, pad_modes, pad_cvals
  3198. # Added in 0.4.0.
  3199. def get_parameters(self):
  3200. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  3201. return [self.width_base, self.height_base,
  3202. self.pad_mode, self.pad_cval,
  3203. self.position]
  3204. class CenterPadToPowersOf(PadToPowersOf):
  3205. """Pad images equally on all sides until H/W is a power of a base.
  3206. This is the same as :class:`~imgaug.augmenters.size.PadToPowersOf`, but uses
  3207. ``position="center"`` by default, which spreads the pad amounts equally
  3208. over all image sides, while :class:`~imgaug.augmenters.size.PadToPowersOf`
  3209. by default spreads them randomly.
  3210. Added in 0.4.0.
  3211. **Supported dtypes**:
  3212. See :class:`~imgaug.augmenters.size.PadToFixedSize`.
  3213. Parameters
  3214. ----------
  3215. width_base : int or None
  3216. See :func:`PadToPowersOf.__init__`.
  3217. height_base : int or None
  3218. See :func:`PadToPowersOf.__init__`.
  3219. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  3220. See :func:`~imgaug.augmenters.size.PadToPowersOf.__init__`.
  3221. pad_cval : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  3222. See :func:`~imgaug.augmenters.size.PadToPowersOf.__init__`.
  3223. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3224. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3225. name : None or str, optional
  3226. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3227. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3228. Old name for parameter `seed`.
  3229. Its usage will not yet cause a deprecation warning,
  3230. but it is still recommended to use `seed` now.
  3231. Outdated since 0.4.0.
  3232. deterministic : bool, optional
  3233. Deprecated since 0.4.0.
  3234. See method ``to_deterministic()`` for an alternative and for
  3235. details about what the "deterministic mode" actually does.
  3236. Examples
  3237. --------
  3238. >>> import imgaug.augmenters as iaa
  3239. >>> aug = iaa.CenterPadToPowersOf(height_base=5, width_base=2)
  3240. Create an augmenter that pads each image to powers of ``3`` along the
  3241. y-axis (i.e. 3, 9, 27, ...) and powers of ``2`` along the x-axis (i.e. 2,
  3242. 4, 8, 16, ...).
  3243. The rows to be padded will be spread *equally* over the top and bottom
  3244. sides (analogous for the left/right sides).
  3245. """
  3246. # Added in 0.4.0.
  3247. def __init__(self, width_base, height_base,
  3248. pad_mode="constant", pad_cval=0,
  3249. seed=None, name=None,
  3250. random_state="deprecated", deterministic="deprecated"):
  3251. super(CenterPadToPowersOf, self).__init__(
  3252. width_base=width_base, height_base=height_base,
  3253. pad_mode=pad_mode, pad_cval=pad_cval,
  3254. position="center",
  3255. seed=seed, name=name,
  3256. random_state=random_state, deterministic=deterministic)
  3257. class CropToAspectRatio(CropToFixedSize):
  3258. """Crop images until their width/height matches an aspect ratio.
  3259. This augmenter removes either rows or columns until the image reaches
  3260. the desired aspect ratio given in ``width / height``. The cropping
  3261. operation is stopped once the desired aspect ratio is reached or the image
  3262. side to crop reaches a size of ``1``. If any side of the image starts
  3263. with a size of ``0``, the image will not be changed.
  3264. Added in 0.4.0.
  3265. **Supported dtypes**:
  3266. See :class:`~imgaug.augmenters.size.CropToFixedSize`.
  3267. Parameters
  3268. ----------
  3269. aspect_ratio : number
  3270. The desired aspect ratio, given as ``width/height``. E.g. a ratio
  3271. of ``2.0`` denotes an image that is twice as wide as it is high.
  3272. position : {'uniform', 'normal', 'center', 'left-top', 'left-center', 'left-bottom', 'center-top', 'center-center', 'center-bottom', 'right-top', 'right-center', 'right-bottom'} or tuple of float or StochasticParameter or tuple of StochasticParameter, optional
  3273. See :func:`CropToFixedSize.__init__`.
  3274. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3275. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3276. name : None or str, optional
  3277. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3278. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3279. Old name for parameter `seed`.
  3280. Its usage will not yet cause a deprecation warning,
  3281. but it is still recommended to use `seed` now.
  3282. Outdated since 0.4.0.
  3283. deterministic : bool, optional
  3284. Deprecated since 0.4.0.
  3285. See method ``to_deterministic()`` for an alternative and for
  3286. details about what the "deterministic mode" actually does.
  3287. Examples
  3288. --------
  3289. >>> import imgaug.augmenters as iaa
  3290. >>> aug = iaa.CropToAspectRatio(2.0)
  3291. Create an augmenter that crops each image until its aspect ratio is as
  3292. close as possible to ``2.0`` (i.e. two times as many pixels along the
  3293. x-axis than the y-axis).
  3294. The rows to be cropped will be spread *randomly* over the top and bottom
  3295. sides (analogous for the left/right sides).
  3296. """
  3297. # Added in 0.4.0.
  3298. def __init__(self, aspect_ratio, position="uniform",
  3299. seed=None, name=None,
  3300. random_state="deprecated", deterministic="deprecated"):
  3301. super(CropToAspectRatio, self).__init__(
  3302. width=None, height=None, position=position,
  3303. seed=seed, name=name,
  3304. random_state=random_state, deterministic=deterministic)
  3305. self.aspect_ratio = aspect_ratio
  3306. # Added in 0.4.0.
  3307. def _draw_samples(self, batch, random_state):
  3308. _sizes, offset_xs, offset_ys = super(
  3309. CropToAspectRatio, self
  3310. )._draw_samples(batch, random_state)
  3311. shapes = batch.get_rowwise_shapes()
  3312. sizes = []
  3313. for shape in shapes:
  3314. height, width = shape[0:2]
  3315. if height == 0 or width == 0:
  3316. croppings = (0, 0, 0, 0)
  3317. else:
  3318. croppings = compute_croppings_to_reach_aspect_ratio(
  3319. shape,
  3320. aspect_ratio=self.aspect_ratio)
  3321. # TODO change that
  3322. # note that these are not in the same order as shape tuples
  3323. # in CropToFixedSize
  3324. new_size = (
  3325. width - croppings[1] - croppings[3],
  3326. height - croppings[0] - croppings[2]
  3327. )
  3328. sizes.append(new_size)
  3329. return sizes, offset_xs, offset_ys
  3330. # Added in 0.4.0.
  3331. def get_parameters(self):
  3332. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  3333. return [self.aspect_ratio, self.position]
  3334. class CenterCropToAspectRatio(CropToAspectRatio):
  3335. """Crop images equally on all sides until they reach an aspect ratio.
  3336. This is the same as :class:`~imgaug.augmenters.size.CropToAspectRatio`, but
  3337. uses ``position="center"`` by default, which spreads the crop amounts
  3338. equally over all image sides, while
  3339. :class:`~imgaug.augmenters.size.CropToAspectRatio` by default spreads
  3340. them randomly.
  3341. Added in 0.4.0.
  3342. **Supported dtypes**:
  3343. See :class:`~imgaug.augmenters.size.CropToFixedSize`.
  3344. Parameters
  3345. ----------
  3346. aspect_ratio : number
  3347. See :func:`CropToAspectRatio.__init__`.
  3348. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3349. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3350. name : None or str, optional
  3351. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3352. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3353. Old name for parameter `seed`.
  3354. Its usage will not yet cause a deprecation warning,
  3355. but it is still recommended to use `seed` now.
  3356. Outdated since 0.4.0.
  3357. deterministic : bool, optional
  3358. Deprecated since 0.4.0.
  3359. See method ``to_deterministic()`` for an alternative and for
  3360. details about what the "deterministic mode" actually does.
  3361. Examples
  3362. --------
  3363. >>> import imgaug.augmenters as iaa
  3364. >>> aug = iaa.CenterCropToAspectRatio(2.0)
  3365. Create an augmenter that crops each image until its aspect ratio is as
  3366. close as possible to ``2.0`` (i.e. two times as many pixels along the
  3367. x-axis than the y-axis).
  3368. The rows to be cropped will be spread *equally* over the top and bottom
  3369. sides (analogous for the left/right sides).
  3370. """
  3371. # Added in 0.4.0.
  3372. def __init__(self, aspect_ratio,
  3373. seed=None, name=None,
  3374. random_state="deprecated", deterministic="deprecated"):
  3375. super(CenterCropToAspectRatio, self).__init__(
  3376. aspect_ratio=aspect_ratio, position="center",
  3377. seed=seed, name=name,
  3378. random_state=random_state, deterministic=deterministic)
  3379. class PadToAspectRatio(PadToFixedSize):
  3380. """Pad images until their width/height matches an aspect ratio.
  3381. This augmenter adds either rows or columns until the image reaches
  3382. the desired aspect ratio given in ``width / height``.
  3383. Added in 0.4.0.
  3384. **Supported dtypes**:
  3385. See :class:`~imgaug.augmenters.size.PadToFixedSize`.
  3386. Parameters
  3387. ----------
  3388. aspect_ratio : number
  3389. The desired aspect ratio, given as ``width/height``. E.g. a ratio
  3390. of ``2.0`` denotes an image that is twice as wide as it is high.
  3391. position : {'uniform', 'normal', 'center', 'left-top', 'left-center', 'left-bottom', 'center-top', 'center-center', 'center-bottom', 'right-top', 'right-center', 'right-bottom'} or tuple of float or StochasticParameter or tuple of StochasticParameter, optional
  3392. See :func:`PadToFixedSize.__init__`.
  3393. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  3394. See :func:`~imgaug.augmenters.size.PadToFixedSize.__init__`.
  3395. pad_cval : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  3396. See :func:`~imgaug.augmenters.size.PadToFixedSize.__init__`.
  3397. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3398. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3399. name : None or str, optional
  3400. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3401. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3402. Old name for parameter `seed`.
  3403. Its usage will not yet cause a deprecation warning,
  3404. but it is still recommended to use `seed` now.
  3405. Outdated since 0.4.0.
  3406. deterministic : bool, optional
  3407. Deprecated since 0.4.0.
  3408. See method ``to_deterministic()`` for an alternative and for
  3409. details about what the "deterministic mode" actually does.
  3410. Examples
  3411. --------
  3412. >>> import imgaug.augmenters as iaa
  3413. >>> aug = iaa.PadToAspectRatio(2.0)
  3414. Create an augmenter that pads each image until its aspect ratio is as
  3415. close as possible to ``2.0`` (i.e. two times as many pixels along the
  3416. x-axis than the y-axis).
  3417. The rows to be padded will be spread *randomly* over the top and bottom
  3418. sides (analogous for the left/right sides).
  3419. """
  3420. # Added in 0.4.0.
  3421. def __init__(self, aspect_ratio, pad_mode="constant", pad_cval=0,
  3422. position="uniform",
  3423. seed=None, name=None,
  3424. random_state="deprecated", deterministic="deprecated"):
  3425. super(PadToAspectRatio, self).__init__(
  3426. width=None, height=None, pad_mode=pad_mode, pad_cval=pad_cval,
  3427. position=position,
  3428. seed=seed, name=name,
  3429. random_state=random_state, deterministic=deterministic)
  3430. self.aspect_ratio = aspect_ratio
  3431. # Added in 0.4.0.
  3432. def _draw_samples(self, batch, random_state):
  3433. _sizes, pad_xs, pad_ys, pad_modes, pad_cvals = super(
  3434. PadToAspectRatio, self
  3435. )._draw_samples(batch, random_state)
  3436. shapes = batch.get_rowwise_shapes()
  3437. sizes = []
  3438. for shape in shapes:
  3439. height, width = shape[0:2]
  3440. paddings = compute_paddings_to_reach_aspect_ratio(
  3441. shape,
  3442. aspect_ratio=self.aspect_ratio)
  3443. # TODO change that
  3444. # note that these are not in the same order as shape tuples
  3445. # in PadToFixedSize
  3446. new_size = (
  3447. width + paddings[1] + paddings[3],
  3448. height + paddings[0] + paddings[2]
  3449. )
  3450. sizes.append(new_size)
  3451. return sizes, pad_xs, pad_ys, pad_modes, pad_cvals
  3452. # Added in 0.4.0.
  3453. def get_parameters(self):
  3454. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  3455. return [self.aspect_ratio, self.pad_mode, self.pad_cval,
  3456. self.position]
  3457. class CenterPadToAspectRatio(PadToAspectRatio):
  3458. """Pad images equally on all sides until H/W matches an aspect ratio.
  3459. This is the same as :class:`~imgaug.augmenters.size.PadToAspectRatio`, but
  3460. uses ``position="center"`` by default, which spreads the pad amounts
  3461. equally over all image sides, while
  3462. :class:`~imgaug.augmenters.size.PadToAspectRatio` by default spreads them
  3463. randomly.
  3464. Added in 0.4.0.
  3465. **Supported dtypes**:
  3466. See :class:`~imgaug.augmenters.size.PadToFixedSize`.
  3467. Parameters
  3468. ----------
  3469. aspect_ratio : number
  3470. See :func:`PadToAspectRatio.__init__`.
  3471. name : None or str, optional
  3472. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3473. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  3474. See :func:`~imgaug.augmenters.size.PadToAspectRatio.__init__`.
  3475. pad_cval : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  3476. See :func:`~imgaug.augmenters.size.PadToAspectRatio.__init__`.
  3477. deterministic : bool, optional
  3478. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3479. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3480. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3481. Examples
  3482. --------
  3483. >>> import imgaug.augmenters as iaa
  3484. >>> aug = iaa.PadToAspectRatio(2.0)
  3485. Create am augmenter that pads each image until its aspect ratio is as
  3486. close as possible to ``2.0`` (i.e. two times as many pixels along the
  3487. x-axis than the y-axis).
  3488. The rows to be padded will be spread *equally* over the top and bottom
  3489. sides (analogous for the left/right sides).
  3490. """
  3491. # Added in 0.4.0.
  3492. def __init__(self, aspect_ratio, pad_mode="constant", pad_cval=0,
  3493. seed=None, name=None,
  3494. random_state="deprecated", deterministic="deprecated"):
  3495. super(CenterPadToAspectRatio, self).__init__(
  3496. aspect_ratio=aspect_ratio, position="center",
  3497. pad_mode=pad_mode, pad_cval=pad_cval,
  3498. seed=seed, name=name,
  3499. random_state=random_state, deterministic=deterministic)
  3500. class CropToSquare(CropToAspectRatio):
  3501. """Crop images until their width and height are identical.
  3502. This is identical to :class:`~imgaug.augmenters.size.CropToAspectRatio`
  3503. with ``aspect_ratio=1.0``.
  3504. Images with axis sizes of ``0`` will not be altered.
  3505. Added in 0.4.0.
  3506. **Supported dtypes**:
  3507. See :class:`~imgaug.augmenters.size.CropToFixedSize`.
  3508. Parameters
  3509. ----------
  3510. position : {'uniform', 'normal', 'center', 'left-top', 'left-center', 'left-bottom', 'center-top', 'center-center', 'center-bottom', 'right-top', 'right-center', 'right-bottom'} or tuple of float or StochasticParameter or tuple of StochasticParameter, optional
  3511. See :func:`CropToFixedSize.__init__`.
  3512. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3513. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3514. name : None or str, optional
  3515. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3516. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3517. Old name for parameter `seed`.
  3518. Its usage will not yet cause a deprecation warning,
  3519. but it is still recommended to use `seed` now.
  3520. Outdated since 0.4.0.
  3521. deterministic : bool, optional
  3522. Deprecated since 0.4.0.
  3523. See method ``to_deterministic()`` for an alternative and for
  3524. details about what the "deterministic mode" actually does.
  3525. Examples
  3526. --------
  3527. >>> import imgaug.augmenters as iaa
  3528. >>> aug = iaa.CropToSquare()
  3529. Create an augmenter that crops each image until its square, i.e. height
  3530. and width match.
  3531. The rows to be cropped will be spread *randomly* over the top and bottom
  3532. sides (analogous for the left/right sides).
  3533. """
  3534. # Added in 0.4.0.
  3535. def __init__(self, position="uniform",
  3536. seed=None, name=None,
  3537. random_state="deprecated", deterministic="deprecated"):
  3538. super(CropToSquare, self).__init__(
  3539. aspect_ratio=1.0, position=position,
  3540. seed=seed, name=name,
  3541. random_state=random_state, deterministic=deterministic)
  3542. class CenterCropToSquare(CropToSquare):
  3543. """Crop images equally on all sides until their height/width are identical.
  3544. In contrast to :class:`~imgaug.augmenters.size.CropToSquare`, this
  3545. augmenter always tries to spread the columns/rows to remove equally over
  3546. both sides of the respective axis to be cropped.
  3547. :class:`~imgaug.augmenters.size.CropToAspectRatio` by default spreads the
  3548. croppings randomly.
  3549. This augmenter is identical to :class:`~imgaug.augmenters.size.CropToSquare`
  3550. with ``position="center"``, and thereby the same as
  3551. :class:`~imgaug.augmenters.size.CropToAspectRatio` with
  3552. ``aspect_ratio=1.0, position="center"``.
  3553. Images with axis sizes of ``0`` will not be altered.
  3554. Added in 0.4.0.
  3555. **Supported dtypes**:
  3556. See :class:`~imgaug.augmenters.size.CropToFixedSize`.
  3557. Parameters
  3558. ----------
  3559. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3560. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3561. name : None or str, optional
  3562. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3563. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3564. Old name for parameter `seed`.
  3565. Its usage will not yet cause a deprecation warning,
  3566. but it is still recommended to use `seed` now.
  3567. Outdated since 0.4.0.
  3568. deterministic : bool, optional
  3569. Deprecated since 0.4.0.
  3570. See method ``to_deterministic()`` for an alternative and for
  3571. details about what the "deterministic mode" actually does.
  3572. Examples
  3573. --------
  3574. >>> import imgaug.augmenters as iaa
  3575. >>> aug = iaa.CenterCropToSquare()
  3576. Create an augmenter that crops each image until its square, i.e. height
  3577. and width match.
  3578. The rows to be cropped will be spread *equally* over the top and bottom
  3579. sides (analogous for the left/right sides).
  3580. """
  3581. # Added in 0.4.0.
  3582. def __init__(self, seed=None, name=None,
  3583. random_state="deprecated", deterministic="deprecated"):
  3584. super(CenterCropToSquare, self).__init__(
  3585. position="center",
  3586. seed=seed, name=name,
  3587. random_state=random_state, deterministic=deterministic)
  3588. class PadToSquare(PadToAspectRatio):
  3589. """Pad images until their height and width are identical.
  3590. This augmenter is identical to
  3591. :class:`~imgaug.augmenters.size.PadToAspectRatio` with ``aspect_ratio=1.0``.
  3592. Added in 0.4.0.
  3593. **Supported dtypes**:
  3594. See :class:`~imgaug.augmenters.size.PadToFixedSize`.
  3595. Parameters
  3596. ----------
  3597. position : {'uniform', 'normal', 'center', 'left-top', 'left-center', 'left-bottom', 'center-top', 'center-center', 'center-bottom', 'right-top', 'right-center', 'right-bottom'} or tuple of float or StochasticParameter or tuple of StochasticParameter, optional
  3598. See :func:`PadToFixedSize.__init__`.
  3599. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  3600. See :func:`~imgaug.augmenters.size.PadToFixedSize.__init__`.
  3601. pad_cval : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  3602. See :func:`~imgaug.augmenters.size.PadToFixedSize.__init__`.
  3603. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3604. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3605. name : None or str, optional
  3606. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3607. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3608. Old name for parameter `seed`.
  3609. Its usage will not yet cause a deprecation warning,
  3610. but it is still recommended to use `seed` now.
  3611. Outdated since 0.4.0.
  3612. deterministic : bool, optional
  3613. Deprecated since 0.4.0.
  3614. See method ``to_deterministic()`` for an alternative and for
  3615. details about what the "deterministic mode" actually does.
  3616. Examples
  3617. --------
  3618. >>> import imgaug.augmenters as iaa
  3619. >>> aug = iaa.PadToSquare()
  3620. Create an augmenter that pads each image until its square, i.e. height
  3621. and width match.
  3622. The rows to be padded will be spread *randomly* over the top and bottom
  3623. sides (analogous for the left/right sides).
  3624. """
  3625. # Added in 0.4.0.
  3626. def __init__(self, pad_mode="constant", pad_cval=0, position="uniform",
  3627. seed=None, name=None,
  3628. random_state="deprecated", deterministic="deprecated"):
  3629. super(PadToSquare, self).__init__(
  3630. aspect_ratio=1.0, pad_mode=pad_mode, pad_cval=pad_cval,
  3631. position=position,
  3632. seed=seed, name=name,
  3633. random_state=random_state, deterministic=deterministic)
  3634. class CenterPadToSquare(PadToSquare):
  3635. """Pad images equally on all sides until their height & width are identical.
  3636. This is the same as :class:`~imgaug.augmenters.size.PadToSquare`, but uses
  3637. ``position="center"`` by default, which spreads the pad amounts equally
  3638. over all image sides, while :class:`~imgaug.augmenters.size.PadToSquare`
  3639. by default spreads them randomly. This augmenter is thus also identical to
  3640. :class:`~imgaug.augmenters.size.PadToAspectRatio` with
  3641. ``aspect_ratio=1.0, position="center"``.
  3642. Added in 0.4.0.
  3643. **Supported dtypes**:
  3644. See :class:`~imgaug.augmenters.size.PadToFixedSize`.
  3645. Parameters
  3646. ----------
  3647. name : None or str, optional
  3648. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3649. pad_mode : imgaug.ALL or str or list of str or imgaug.parameters.StochasticParameter, optional
  3650. See :func:`~imgaug.augmenters.size.PadToAspectRatio.__init__`.
  3651. pad_cval : number or tuple of number or list of number or imgaug.parameters.StochasticParameter, optional
  3652. See :func:`~imgaug.augmenters.size.PadToAspectRatio.__init__`.
  3653. deterministic : bool, optional
  3654. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3655. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3656. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3657. Examples
  3658. --------
  3659. >>> import imgaug.augmenters as iaa
  3660. >>> aug = iaa.CenterPadToSquare()
  3661. Create an augmenter that pads each image until its square, i.e. height
  3662. and width match.
  3663. The rows to be padded will be spread *equally* over the top and bottom
  3664. sides (analogous for the left/right sides).
  3665. """
  3666. # Added in 0.4.0.
  3667. def __init__(self, pad_mode="constant", pad_cval=0,
  3668. seed=None, name=None,
  3669. random_state="deprecated", deterministic="deprecated"):
  3670. super(CenterPadToSquare, self).__init__(
  3671. pad_mode=pad_mode, pad_cval=pad_cval, position="center",
  3672. seed=seed, name=name,
  3673. random_state=random_state, deterministic=deterministic)
  3674. class KeepSizeByResize(meta.Augmenter):
  3675. """Resize images back to their input sizes after applying child augmenters.
  3676. Combining this with e.g. a cropping augmenter as the child will lead to
  3677. images being resized back to the input size after the crop operation was
  3678. applied. Some augmenters have a ``keep_size`` argument that achieves the
  3679. same goal (if set to ``True``), though this augmenter offers control over
  3680. the interpolation mode and which augmentables to resize (images, heatmaps,
  3681. segmentation maps).
  3682. **Supported dtypes**:
  3683. See :func:`~imgaug.imgaug.imresize_many_images`.
  3684. Parameters
  3685. ----------
  3686. children : Augmenter or list of imgaug.augmenters.meta.Augmenter or None, optional
  3687. One or more augmenters to apply to images. These augmenters may change
  3688. the image size.
  3689. interpolation : KeepSizeByResize.NO_RESIZE or {'nearest', 'linear', 'area', 'cubic'} or {cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_AREA, cv2.INTER_CUBIC} or list of str or list of int or StochasticParameter, optional
  3690. The interpolation mode to use when resizing images.
  3691. Can take any value that :func:`~imgaug.imgaug.imresize_single_image`
  3692. accepts, e.g. ``cubic``.
  3693. * If this is ``KeepSizeByResize.NO_RESIZE`` then images will not
  3694. be resized.
  3695. * If this is a single ``str``, it is expected to have one of the
  3696. following values: ``nearest``, ``linear``, ``area``, ``cubic``.
  3697. * If this is a single integer, it is expected to have a value
  3698. identical to one of: ``cv2.INTER_NEAREST``,
  3699. ``cv2.INTER_LINEAR``, ``cv2.INTER_AREA``, ``cv2.INTER_CUBIC``.
  3700. * If this is a ``list`` of ``str`` or ``int``, it is expected that
  3701. each ``str``/``int`` is one of the above mentioned valid ones.
  3702. A random one of these values will be sampled per image.
  3703. * If this is a ``StochasticParameter``, it will be queried once per
  3704. call to ``_augment_images()`` and must return ``N`` ``str`` s or
  3705. ``int`` s (matching the above mentioned ones) for ``N`` images.
  3706. interpolation_heatmaps : KeepSizeByResize.SAME_AS_IMAGES or KeepSizeByResize.NO_RESIZE or {'nearest', 'linear', 'area', 'cubic'} or {cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_AREA, cv2.INTER_CUBIC} or list of str or list of int or StochasticParameter, optional
  3707. The interpolation mode to use when resizing heatmaps.
  3708. Meaning and valid values are similar to `interpolation`. This
  3709. parameter may also take the value ``KeepSizeByResize.SAME_AS_IMAGES``,
  3710. which will lead to copying the interpolation modes used for the
  3711. corresponding images. The value may also be returned on a per-image
  3712. basis if `interpolation_heatmaps` is provided as a
  3713. ``StochasticParameter`` or may be one possible value if it is
  3714. provided as a ``list`` of ``str``.
  3715. interpolation_segmaps : KeepSizeByResize.SAME_AS_IMAGES or KeepSizeByResize.NO_RESIZE or {'nearest', 'linear', 'area', 'cubic'} or {cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_AREA, cv2.INTER_CUBIC} or list of str or list of int or StochasticParameter, optional
  3716. The interpolation mode to use when resizing segmentation maps.
  3717. Similar to `interpolation_heatmaps`.
  3718. **Note**: For segmentation maps, only ``NO_RESIZE`` or nearest
  3719. neighbour interpolation (i.e. ``nearest``) make sense in the vast
  3720. majority of all cases.
  3721. seed : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3722. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3723. name : None or str, optional
  3724. See :func:`~imgaug.augmenters.meta.Augmenter.__init__`.
  3725. random_state : None or int or imgaug.random.RNG or numpy.random.Generator or numpy.random.BitGenerator or numpy.random.SeedSequence or numpy.random.RandomState, optional
  3726. Old name for parameter `seed`.
  3727. Its usage will not yet cause a deprecation warning,
  3728. but it is still recommended to use `seed` now.
  3729. Outdated since 0.4.0.
  3730. deterministic : bool, optional
  3731. Deprecated since 0.4.0.
  3732. See method ``to_deterministic()`` for an alternative and for
  3733. details about what the "deterministic mode" actually does.
  3734. Examples
  3735. --------
  3736. >>> import imgaug.augmenters as iaa
  3737. >>> aug = iaa.KeepSizeByResize(
  3738. >>> iaa.Crop((20, 40), keep_size=False)
  3739. >>> )
  3740. Apply random cropping to input images, then resize them back to their
  3741. original input sizes. The resizing is done using this augmenter instead
  3742. of the corresponding internal resizing operation in ``Crop``.
  3743. >>> aug = iaa.KeepSizeByResize(
  3744. >>> iaa.Crop((20, 40), keep_size=False),
  3745. >>> interpolation="nearest"
  3746. >>> )
  3747. Same as in the previous example, but images are now always resized using
  3748. nearest neighbour interpolation.
  3749. >>> aug = iaa.KeepSizeByResize(
  3750. >>> iaa.Crop((20, 40), keep_size=False),
  3751. >>> interpolation=["nearest", "cubic"],
  3752. >>> interpolation_heatmaps=iaa.KeepSizeByResize.SAME_AS_IMAGES,
  3753. >>> interpolation_segmaps=iaa.KeepSizeByResize.NO_RESIZE
  3754. >>> )
  3755. Similar to the previous example, but images are now sometimes resized
  3756. using linear interpolation and sometimes using nearest neighbour
  3757. interpolation. Heatmaps are resized using the same interpolation as was
  3758. used for the corresponding image. Segmentation maps are not resized and
  3759. will therefore remain at their size after cropping.
  3760. """
  3761. NO_RESIZE = "NO_RESIZE"
  3762. SAME_AS_IMAGES = "SAME_AS_IMAGES"
  3763. def __init__(self, children,
  3764. interpolation="cubic",
  3765. interpolation_heatmaps=SAME_AS_IMAGES,
  3766. interpolation_segmaps="nearest",
  3767. seed=None, name=None,
  3768. random_state="deprecated", deterministic="deprecated"):
  3769. super(KeepSizeByResize, self).__init__(
  3770. seed=seed, name=name,
  3771. random_state=random_state, deterministic=deterministic)
  3772. self.children = children
  3773. def _validate_param(val, allow_same_as_images):
  3774. valid_ips_and_resize = ia.IMRESIZE_VALID_INTERPOLATIONS \
  3775. + [KeepSizeByResize.NO_RESIZE]
  3776. if allow_same_as_images and val == self.SAME_AS_IMAGES:
  3777. return self.SAME_AS_IMAGES
  3778. if val in valid_ips_and_resize:
  3779. return iap.Deterministic(val)
  3780. if isinstance(val, list):
  3781. assert len(val) > 0, (
  3782. "Expected a list of at least one interpolation method. "
  3783. "Got an empty list.")
  3784. valid_ips_here = valid_ips_and_resize
  3785. if allow_same_as_images:
  3786. valid_ips_here = valid_ips_here \
  3787. + [KeepSizeByResize.SAME_AS_IMAGES]
  3788. only_valid_ips = all([ip in valid_ips_here for ip in val])
  3789. assert only_valid_ips, (
  3790. "Expected each interpolations to be one of '%s', got "
  3791. "'%s'." % (str(valid_ips_here), str(val)))
  3792. return iap.Choice(val)
  3793. if isinstance(val, iap.StochasticParameter):
  3794. return val
  3795. raise Exception(
  3796. "Expected interpolation to be one of '%s' or a list of "
  3797. "these values or a StochasticParameter. Got type %s." % (
  3798. str(ia.IMRESIZE_VALID_INTERPOLATIONS), type(val)))
  3799. self.children = meta.handle_children_list(children, self.name, "then")
  3800. self.interpolation = _validate_param(interpolation, False)
  3801. self.interpolation_heatmaps = _validate_param(interpolation_heatmaps,
  3802. True)
  3803. self.interpolation_segmaps = _validate_param(interpolation_segmaps,
  3804. True)
  3805. # Added in 0.4.0.
  3806. def _augment_batch_(self, batch, random_state, parents, hooks):
  3807. with batch.propagation_hooks_ctx(self, hooks, parents):
  3808. images_were_array = None
  3809. if batch.images is not None:
  3810. images_were_array = ia.is_np_array(batch.images)
  3811. shapes_orig = self._get_shapes(batch)
  3812. samples = self._draw_samples(batch.nb_rows, random_state)
  3813. batch = self.children.augment_batch_(
  3814. batch, parents=parents + [self], hooks=hooks)
  3815. if batch.images is not None:
  3816. batch.images = self._keep_size_images(
  3817. batch.images, shapes_orig["images"], images_were_array,
  3818. samples)
  3819. if batch.heatmaps is not None:
  3820. # dont use shapes_orig["images"] because they might be None
  3821. batch.heatmaps = self._keep_size_maps(
  3822. batch.heatmaps, shapes_orig["heatmaps"],
  3823. shapes_orig["heatmaps_arr"], samples[1])
  3824. if batch.segmentation_maps is not None:
  3825. # dont use shapes_orig["images"] because they might be None
  3826. batch.segmentation_maps = self._keep_size_maps(
  3827. batch.segmentation_maps, shapes_orig["segmentation_maps"],
  3828. shapes_orig["segmentation_maps_arr"], samples[2])
  3829. for augm_name in ["keypoints", "bounding_boxes", "polygons",
  3830. "line_strings"]:
  3831. augm_value = getattr(batch, augm_name)
  3832. if augm_value is not None:
  3833. func = functools.partial(
  3834. self._keep_size_keypoints,
  3835. shapes_orig=shapes_orig[augm_name],
  3836. interpolations=samples[0])
  3837. cbaois = self._apply_to_cbaois_as_keypoints(augm_value,
  3838. func)
  3839. setattr(batch, augm_name, cbaois)
  3840. return batch
  3841. # Added in 0.4.0.
  3842. @classmethod
  3843. def _keep_size_images(cls, images, shapes_orig, images_were_array,
  3844. samples):
  3845. interpolations, _, _ = samples
  3846. gen = zip(images, interpolations, shapes_orig)
  3847. result = []
  3848. for image, interpolation, input_shape in gen:
  3849. if interpolation == KeepSizeByResize.NO_RESIZE:
  3850. result.append(image)
  3851. else:
  3852. result.append(
  3853. ia.imresize_single_image(image, input_shape[0:2],
  3854. interpolation))
  3855. if images_were_array:
  3856. # note here that NO_RESIZE can have led to different shapes
  3857. nb_shapes = len({image.shape for image in result})
  3858. if nb_shapes == 1:
  3859. # images.dtype does not necessarily work anymore, children
  3860. # might have turned 'images' into list
  3861. result = np.array(result, dtype=result[0].dtype)
  3862. return result
  3863. # Added in 0.4.0.
  3864. @classmethod
  3865. def _keep_size_maps(cls, augmentables, shapes_orig_images,
  3866. shapes_orig_arrs, interpolations):
  3867. result = []
  3868. gen = zip(augmentables, interpolations,
  3869. shapes_orig_arrs, shapes_orig_images)
  3870. for augmentable, interpolation, arr_shape_orig, img_shape_orig in gen:
  3871. if interpolation == "NO_RESIZE":
  3872. result.append(augmentable)
  3873. else:
  3874. augmentable = augmentable.resize(
  3875. arr_shape_orig[0:2], interpolation=interpolation)
  3876. augmentable.shape = img_shape_orig
  3877. result.append(augmentable)
  3878. return result
  3879. # Added in 0.4.0.
  3880. @classmethod
  3881. def _keep_size_keypoints(cls, kpsois_aug, shapes_orig, interpolations):
  3882. result = []
  3883. gen = zip(kpsois_aug, interpolations, shapes_orig)
  3884. for kpsoi_aug, interpolation, input_shape in gen:
  3885. if interpolation == KeepSizeByResize.NO_RESIZE:
  3886. result.append(kpsoi_aug)
  3887. else:
  3888. result.append(kpsoi_aug.on_(input_shape))
  3889. return result
  3890. # Added in 0.4.0.
  3891. @classmethod
  3892. def _get_shapes(cls, batch):
  3893. result = dict()
  3894. for column in batch.columns:
  3895. result[column.name] = [cell.shape for cell in column.value]
  3896. if batch.heatmaps is not None:
  3897. result["heatmaps_arr"] = [
  3898. cell.arr_0to1.shape for cell in batch.heatmaps]
  3899. if batch.segmentation_maps is not None:
  3900. result["segmentation_maps_arr"] = [
  3901. cell.arr.shape for cell in batch.segmentation_maps]
  3902. return result
  3903. def _draw_samples(self, nb_images, random_state):
  3904. rngs = random_state.duplicate(3)
  3905. interpolations = self.interpolation.draw_samples((nb_images,),
  3906. random_state=rngs[0])
  3907. if self.interpolation_heatmaps == KeepSizeByResize.SAME_AS_IMAGES:
  3908. interpolations_heatmaps = np.copy(interpolations)
  3909. else:
  3910. interpolations_heatmaps = self.interpolation_heatmaps.draw_samples(
  3911. (nb_images,), random_state=rngs[1]
  3912. )
  3913. # Note that `interpolations_heatmaps == self.SAME_AS_IMAGES`
  3914. # works here only if the datatype of the array is such that it
  3915. # may contain strings. It does not work properly for e.g.
  3916. # integer arrays and will produce a single bool output, even
  3917. # for arrays with more than one entry.
  3918. same_as_imgs_idx = [ip == self.SAME_AS_IMAGES
  3919. for ip in interpolations_heatmaps]
  3920. interpolations_heatmaps[same_as_imgs_idx] = \
  3921. interpolations[same_as_imgs_idx]
  3922. if self.interpolation_segmaps == KeepSizeByResize.SAME_AS_IMAGES:
  3923. interpolations_segmaps = np.copy(interpolations)
  3924. else:
  3925. # TODO This used previously the same seed as the heatmaps part
  3926. # leading to the same sampled values. Was that intentional?
  3927. # Doesn't look like it should be that way.
  3928. interpolations_segmaps = self.interpolation_segmaps.draw_samples(
  3929. (nb_images,), random_state=rngs[2]
  3930. )
  3931. # Note that `interpolations_heatmaps == self.SAME_AS_IMAGES`
  3932. # works here only if the datatype of the array is such that it
  3933. # may contain strings. It does not work properly for e.g.
  3934. # integer arrays and will produce a single bool output, even
  3935. # for arrays with more than one entry.
  3936. same_as_imgs_idx = [ip == self.SAME_AS_IMAGES
  3937. for ip in interpolations_segmaps]
  3938. interpolations_segmaps[same_as_imgs_idx] = \
  3939. interpolations[same_as_imgs_idx]
  3940. return interpolations, interpolations_heatmaps, interpolations_segmaps
  3941. def _to_deterministic(self):
  3942. aug = self.copy()
  3943. aug.children = aug.children.to_deterministic()
  3944. aug.deterministic = True
  3945. aug.random_state = self.random_state.derive_rng_()
  3946. return aug
  3947. def get_parameters(self):
  3948. """See :func:`~imgaug.augmenters.meta.Augmenter.get_parameters`."""
  3949. return [self.interpolation, self.interpolation_heatmaps]
  3950. def get_children_lists(self):
  3951. """See :func:`~imgaug.augmenters.meta.Augmenter.get_children_lists`."""
  3952. return [self.children]
  3953. def __str__(self):
  3954. pattern = (
  3955. "%s("
  3956. "interpolation=%s, "
  3957. "interpolation_heatmaps=%s, "
  3958. "name=%s, "
  3959. "children=%s, "
  3960. "deterministic=%s"
  3961. ")")
  3962. return pattern % (
  3963. self.__class__.__name__, self.interpolation,
  3964. self.interpolation_heatmaps, self.name, self.children,
  3965. self.deterministic)