- Fix possible crash in
blend.blend_alpha()
if dtype numpy.float128 does not exist. - Fixed a crash in
ChangeColorspace
whencv2.COLOR_Lab2RGB
was actually calledcv2.COLOR_LAB2RGB
in the local OpenCV installation (analogous for BGR). (PR #263) - Fixed
ReplaceElementwise
always sampling replacement per channel. - Re-allowed numpy 1.16 in
requirements.txt
. - Fixed an error in
draw_text()
due to arrays that could not be set to writeable after drawing the text via PIL. - Fixed errors in docstring of
parameters.Subtract
. - Improved docstring of
multicore.Pool
. - Reordered classes in
parameters.py
. - Add
_ConcavePolygonRecoverer
toimgaug.py
. - Fixed a division by zero bug in
angle_between_vectors()
. - Add
PolygonsOnImage
toimgaug.py
. - Fixed
Polygon.clip_out_of_image(image)
not handlingimage
being a tuple. Augmenter
offers now methods for polygon augmentation.- Added
augment_polygons()
toAugmenter
. - Added
_augment_polygons()
toAugmenter
. - Added
_augment_polygons_as_keypoints()
toAugmenter
. - Added argument
polygons
toimgaug.Batch
. - Added attributes
polygons_aug
andpolygons_unaug
toimgaug.Batch
. - Added polygon handling to
Augmenter.augment_batches()
.
- Added
- Fixed
Rot90
not changingKeypointsOnImage.shape
if.keypoints
was empty. - Fixed
Affine
not changingKeypointsOnImage.shape
if.keypoints
was empty. - Fixed
PerspectiveTransform
not changingKeypointsOnImage.shape
if.keypoints
was empty. - Fixed
Resize
not changingKeypointsOnImage.shape
if.keypoints
was empty. - Fixed
CropAndPad
not changingKeypointsOnImage.shape
if.keypoints
was empty. (Same forCrop
,Pad
.) - Fixed
PadToFixedSize
not changingKeypointsOnImage.shape
if.keypoints
was empty. - Fixed
CropToFixedSize
not changingKeypointsOnImage.shape
if.keypoints
was empty. - Fixed
KeepSizeByResize
not changingKeypointsOnImage.shape
if.keypoints
was empty. - Added method
Polygon.to_keypoints()
. - Added optional arguments
keypoints
andshape
toKeypointsOnImage.deepcopy()
. - Added optional arguments
keypoints
andshape
toKeypointsOnImage.copy()
. - Added method
Keypoint.copy()
. - Added method
Keypoint.deepcopy()
.- Refactored methods in
Keypoint
to usedeepcopy()
to create copies of itself (instead of instantiating new instances viaKeypoint(...)
).
- Refactored methods in
KeypointsOnImage.deepcopy()
now usesKeypoint.deepcopy()
to create Keypoint copies, making it more flexible.- Refactored
KeypointsOnImage
to useKeypointsOnImage.deepcopy()
in as many methods as possible to create copies of itself. - Refactored
Affine
to useKeypointsOnImage.deepcopy()
andKeypoint.deepcopy()
during keypoint augmentation. - Refactored
AffineCv2
to useKeypointsOnImage.deepcopy()
andKeypoint.deepcopy()
during keypoint augmentation. - Refactored
PiecewiseAffine
to useKeypointsOnImage.deepcopy()
andKeypoint.deepcopy()
during keypoint augmentation. - Refactored
PerspectiveTransform
to useKeypointsOnImage.deepcopy()
andKeypoint.deepcopy()
during keypoint augmentation. - Refactored
ElasticTransformation
to useKeypointsOnImage.deepcopy()
andKeypoint.deepcopy()
during keypoint augmentation. - Refactored
Rot90
to useKeypointsOnImage.deepcopy()
andKeypoint.deepcopy()
during keypoint augmentation. - Changed
Keypoint.project()
to raise an exception iffrom_shape[0:2]
contains zeros. - Changed
Keypoint.project()
to raise a warning ifto_shape[0:2]
contains zeros. - Changed
PerspectiveTransform
to ensure minimum height and width of output images (by default2x2
). This prevents errors in polygon augmentation (possibly also in keypoint augmentation). - Changed
Polygon.exterior_almost_equals()
to accept lists of tuples as argumentother_polygon
. - Added optional drawing of corner points to
Polygon.draw_on_image()
andPolygonsOnImage.draw_on_image()
. - Changed arguments
color
andalpha
inPolygon.draw_on_image()
andPolygonsOnImage.draw_on_image()
to represent the general color and alpha of the polygon. The colors/alphas of the inner area, perimeter and points are derived fromcolor
andalpha
(unlesscolor_inner
,color_perimeter
orcolor_points
are set (analogous for alpha)). - Added
imgaug.quokka_polygons()
function to generate example polygon data. - [mildly breaking] Added an
alpha
argument toKeypointsOnImage.draw_on_image()
. This can break code that relied on the order of arguments of the method (though will usually only have visual consequences). - Added argument
raise_if_too_far_away=True
toPolygon.change_first_point_by_coords()
. - Added property
Polygon.height
. - Added property
Polygon.width
. - [mildly breaking] Changed the output of
Polygon.clip_out_of_image()
fromMultiPolygon
tolist
ofPolygon
. This breaks for anybody who has already usedPolygon.clip_out_of_image()
. - Fixed
Affine
heatmap augmentation producing arrays with values outside the range[0.0, 1.0]
whenorder
was set to3
. - Changed
Affine
to always useorder=3
for heatmap augmentation. - Fixed
PiecewiseAffine
heatmap augmentation producing arrays with values outside the range[0.0, 1.0]
whenorder
was set to3
. - Changed
PiecewiseAffine
to always useorder=3
for heatmap augmentation. - Changed
ElasticTransformation
to always useorder=3
for heatmap augmentation. - Changed check in
HeatmapsOnImage
that validates whether the input array is within the desired value range[min_value, max_value]
from a hard exception to a soft warning (with clipping). Also improved the error message a bit. - Fixed assert in
SegmentationMapOnImage
falsely checking if max class index is<= nb_classes
instead of< nb_classes
. - Moved
Keypoint
,KeypointsOnImage
andimgaug.imgaug.compute_geometric_median
toaugmentables/kps.py
. - Moved
BoundingBox
,BoundingBoxesOnImage
toaugmentables/bbs.py
. - Moved
Polygon
,PolygonsOnImage
and related classes/functions toaugmentables/polys.py
. - Moved
HeatmapsOnImage
toaugmentables/heatmaps.py
. - Moved
SegmentationMapOnImage
toaugmentables/segmaps.py
. - Moved
Batch
toaugmentables/batches.py
. - Added
imgaug.augmentables.batches.UnnormalizedBatch
. - Added module
imgaug.augmentables.normalization
for data normalization routines. - Changed
augment_batches()
:- Accepts now
UnnormalizedBatch
as input. It is automatically normalized before augmentation and unnormalized afterwards. This allows to useBatch
instances with non-standard datatypes. - Accepts now single instances of
Batch
(andUnnormalizedBatch
). - The input may now also be a generator.
- The input may now be any iterable instead of just list (arrays or strings are not allowed).
- Accepts now
- Marked support for non-
Batch
(and non-UnnormalizedBatch
) inputs toaugment_batches()
as deprecated. - Added
Augmenter.augment()
method. - Added
Augmenter.augment_batch()
method.- This method is now called by
Augmenter.augment_batches()
and multicore routines.
- This method is now called by
- Added
dtypes.clip_()
function. - Fixed an issue in
dtypes.clip_to_value_range_()
anddtypes.restore_dtypes_()
causing errors when clip value range exceeded array dtype's value range. - Fixed an issue in
dtypes.clip_to_value_range_()
anddtypes.restore_dtypes_()
when the input array was scalar, i.e. had shape()
. - Refactored
Batch.deepcopy()
- Does not longer verify attribute datatypes.
- Allows now to directly change attributes of created copies, e.g. via
batch.deepcopy(images_aug=...)
.
- Added
imgaug.imgaug.DeprecationWarning
. The builtin pythonDeprecationWarning
is silent since 2.7, which is why now a separate deprecation warning is used. - Added
imgaug.imgaug.warn_deprecated()
.- Refactored deprecation warnings to use this function.
- Added
imgaug.imgaug.deprecated
decorator.- Refactored deprecation warnings to use this decorator.
This update focused on extending and documenting the library's dtype support, improving the performance and reworking multicore augmentation.
Previous versions of imgaug
were primarily geared towards uint8
.
In this version, all augmenters and helper functions were refactored to be more tolerant towards non-uint8 dtypes.
Additionally all augmenters were tested with non-uint8 dtypes and an overview of the expected support-level
is now listed in the documentation on page dtype support.
Further details are listed in the docstrings of each individual augmenter or helper function.
Below are some numbers for the achieved performance improvements compared to 0.2.7. The measurements were taken using realistic 224x224x3 uint8 images and batch size 128. The percentage values denote the increase in bandwidth (i.e. mbyte/sec) of the respective augmenter given the described input. Improvements for smaller images, smaller batch sizes and non-uint8 dtypes may differ. Augmenters with less than roughly 10% improvement are not listed. While the numbers here are exact, there is some measurement error involved as they were calculated based on a rather low number of 100 repetitions.
- Sequential (with 2x Noop as children) +184% to +276%
- SomeOf (with 3x Noop as children) +24% to +49%
- OneOf (with 3x Noop as children) +21%
- Sometimes (with Noop as child) +23%
- WithChannels +32%
- Add +216%
- AddElementwise +49%
- AdditiveGaussianNoise +26%
- AdditiveLaplaceNoise +20%
- AdditivePoissonNoise +18%
- Multiply +206%
- MultiplyElementwise +74%
- Dropout +154%
- CoarseDropout +246%
- ReplaceElementwise +119%
- ImpulseNoise +333%
- SaltAndPepper +184%
- CoarseSaltAndPepper +227%
- Salt +204%
- CoarseSalt +260%
- Pepper +208%
- CoarsePepper +276%
- Invert +1192%
- GaussianBlur +885%
- AddToHueAndSaturation +48%
- GammaContrast +2988%
- SigmoidContrast +519%
- LogContrast +1048%
- LinearContrast +448%
- Convolve +47%
- Sharpen +29%
- Emboss +18%
- EdgeDetect +41%
- DirectedEdgeDetect +53%
- Fliplr +75%
- Flipud +25%
- Affine +7% to +33%
- ElasticTransformation +650 to +680%
- CropAndPad +30% to +77% (from improved padding)
- Pad +40 to +140%
- PadToFixedSize +288%
- KeepSizeByResize (with CropToFixedSize as child) +58%
- Snowflakes +44%
- SnowflakesLayer +42%
The implementation for multicore augmentation was completely rewritten and is now a wrapper around python's multiprocessing.Pool
. Compared to the old version, it is by far less fragile and faster. It is also easier to use. Every augmenter now offers a simple pool()
method, which can be used to quickly spawn a pool of child workers on multiple CPU cores. Example:
aug = iaa.PiecewiseAffine(0.2)
with aug.pool(processes=-1, seed=123) as pool:
batches_aug = pool.imap_batches(batches_generator, chunksize=32)
for batch_aug in batches_aug:
# do something
Here, batches_generator
is a generator that yields instances of imgaug.Batch
, e.g. something like imgaug.Batch(images=<numpy array>, keypoints=[imgaug.KeypointsOnImage(...), imgaug.KeypointsOnImage(...), ...])
. The arguement processes=-1
spawns N-1
workers, where N
is the number of CPU cores (includes hyperthreads).
Note that Augmenter.augment_batches(batches, background=True)
still works and now uses the above pool()
method.
- Added constants that control the min/max values for seed generation
- Improved performance of
pad()
- this change also improves the performance of:
imgaug.imgaug.pad_to_aspect_ratio()
,imgaug.imgaug.HeatmapsOnImage.pad()
,imgaug.imgaug.HeatmapsOnImage.pad_to_aspect_ratio()
,imgaug.imgaug.SegmentationMapOnImage.pad()
,imgaug.imgaug.SegmentationMapOnImage.pad_to_aspect_ratio()
,imgaug.augmenters.size.PadToFixedSize
,imgaug.augmenters.size.Pad
,imgaug.augmenters.size.CropAndPad
- this change also improves the performance of:
- Changed
imshow()
to explicitly make the plot figure size dependent on the input image size. - Refactored
SegmentationMapOnImage
to have simplified dtype handling in__init__
- Fixed an issue with
SEED_MAX_VALUE
exceeding theint32
maximum on some systems, causing crashes related to RandomState. - Moved BatchLoader to
multicore.py
and replaced the class with an alias pointing toimgaug.multicore.BatchLoader
. - Moved BackgroundAugmenter to
multicore.py
and replaced the class with an alias pointing toimgaug.multicore.BatchLoader
. - Renamed
HeatmapsOnImage.scale()
toHeatmapsOnImage.resize()
. - Marked
HeatmapsOnImage.scale()
as deprecated. - Renamed
SegmentationMapOnImage.scale()
toSegmentationMapOnImage.resize()
. - Marked
SegmentationMapOnImage.scale()
as deprecated. - Renamed
BoundingBox.cut_out_of_image()
toBoundingBox.clip_out_of_image()
. - Marked
BoundingBox.cut_out_of_image()
as deprecated. - Renamed
BoundingBoxesOnImage.cut_out_of_image()
toBoundingBoxesOnImage.clip_out_of_image()
. - Marked
BoundingBoxesOnImage.cut_out_of_image()
as deprecated. - Marked
Polygon.cut_out_of_image()
as deprecated. (The analogous clip function existed already.) - Renamed in
imgaug.Batch
the attributes storing input data<attribute>_unaug
, e.g.imgaug.Batch.images
toimgaug.Batch.images_unaug
orimgaug.Batch.keypoints
toimgaug.Batch.keypoints_unaug
. The old attributes are still accessible, but will raise a DeprecatedWarning.
- Created this file.
- Moved
BatchLoader
here fromimgaug.py
. - Moved
BackgroudAugmenter
here fromimgaug.py
. - Marked
BatchLoader
as deprecated. - Marked
BackgroundAugmenter
as deprecated. - Added class
Pool
. This is the new recommended way for multicore augmentation.BatchLoader
/BackgroundAugmenter
should not be used anymore. Example:The example starts a pool with N-1 workers (N=number of CPU cores) and augments 100 batches using these workers. Useimport imgaug as ia from imgaug import augmenters as iaa from imgaug import multicore import numpy as np aug = iaa.Add(1) images = np.zeros((16, 128, 128, 3), dtype=np.uint8) batches = [ia.Batch(images=np.copy(images)) for _ in range(100)] with multicore.Pool(aug, processes=-1, seed=2) as pool: batches_aug = pool.map_batches(batches, chunksize=8) print(np.sum(batches_aug[0].images_aug[0]))
imap_batches()
to feed in and get out a generator.
- Added
TruncatedNormal
- Added
handle_discrete_kernel_size_param()
- Improved dtype-related interplay of
FromLowerResolution
andimresize_many_images()
- Improved performance for sampling from
Deterministic
by about 2x - Improved performance for sampling from
Uniform
witha == b
- Improved performance for sampling from
DiscreteUniform
witha == b
- Improved performance for sampling from
Laplace
withscale=0
- Improved performance for sampling from
Normal
withscale=0
- Improved performance of
Clip
and improved code style - Refactored
float check in force_np_float_dtype()
- Refactored
RandomSign
- Refactored various unittests to be more flexible with regards to returned dtypes
- Refactored
StochasticParameter.draw_distribution_graph()
to use internally tempfile-based drawing. Should result in higher-quality outputs. - Refactored unittest for
draw_distributions_grid()
to improve performance - Fixed in
draw_distributions_grid()
a possible error from arrays with unequal shapes being combined to one array - Fixed a problem with
Sigmoid
not returning floats - Fixed noise produced by
SimplexNoise
having values below 0.0 or above 1.0 - Fixed noise produced by
SimplexNoise
being more biased towards 0 than it should be
- Added new file
imgaug/dtypes.py
and respective test filetest_dtypes.py
. - Added
clip_to_dtype_value_range_()
- Added
get_value_range_of_dtype()
- Added
promote_array_dtypes_()
- Added
get_minimal_dtype()
- Added
get_minimal_dtypes_for_values()
- Added
get_minimal_dtype_by_value_range()
- Added
restore_dtypes_()
- Added
gate_dtypes()
- Added
increase_array_resolutions()
- Added
copy_dtypes_for_restore()
- Added
estimate_max_number_of_channels()
- Added
copy_arrays()
- Added an optional parameter
default
tohandle_children_lists()
- Enabled
None
as arguments forLambda
and made all arguments optional - Enabled
None
as arguments forAssertLambda
and made all arguments optional - Improved dtype support of
AssertShape
- Improved dtype support of
AssertLambda
- Improved dtype support of
Lambda
- Improved dtype support of
ChannelShuffle
- Improved dtype support of
WithChannels
- Improved dtype support of
Sometimes
- Improved dtype support of
SomeOf
- Improved dtype support of
Sequential
- Improved dtype support of
Noop
- [breaking, mostly internal] Removed
restore_augmented_images_dtypes()
- [breaking, mostly internal] Removed
restore_augmented_images_dtypes_()
- [breaking, mostly internal] Removed
restore_augmented_images_dtype()
- [breaking, mostly internal] Removed
restore_augmented_images_dtype_()
- [breaking, mostly internal] Refactored
Augmenter.augment_images()
andAugmenter._augment_images()
to defaulthooks
toNone
- This will affect any custom implemented augmenters that try to access the hooks argument.
- [breaking, mostly internal] Refactored
Augmenter.augment_heatmaps()
andAugmenter._augment_heatmaps()
to defaulthooks
toNone
- Same as above for images.
- [breaking, mostly internal] Refactored
Augmenter.augment_keypoints()
andAugmenter._augment_keypoints()
to defaulthooks
to None- Same as above for images.
- [breaking, mostly internal] Improved performance of image augmentation for augmenters with children
- For calls to
augment_image()
, the validation, normalization and copying steps are skipped if the call is a child call (e.g. aSequential
callingaugment_images()
on a childAdd
). Hence, such child calls augment now fully in-place (the top-most call still creates a copy though, so from the user perspective nothing changes). Custom implemented augmenters that rely on child calls toaugment_images()
creating copies will break from this change. For an exampleSequential
containing twoNoop
augmenters, this change improves the performance by roughly 2x
- For calls to
- [breaking, mostly internal] Improved performance of heatmap augmentation for augmenters with children
- Same as above for images.
- Speedup is around 2-3x for an exemplary
Sequential
containing twoNoop
s. - This will similarly affect segmentation map augmentation too.
- [breaking, mostly internal] Improved performance of keypoint augmentation for augmenters with children
- Same as above for images.
- Speedup is around 1.5-2x for an exemplary
Sequential
containing two Noops. - This will similarly affect bounding box augmentation.
- [critical] Fixed a bug in the augmentation of empty
KeypointsOnImage
instances that would lead image and keypoint augmentation to be un-aligned within a batch after the first emptyKeypointsOnImage
instance. (#231) - Added
pool()
toAugmenter
. This is a helper to start aimgaug.multicore.Pool
viawith augmenter.pool() as pool: ...
. - Refactored
Augmenter.augment_batches(..., background=True)
to useimgaug.multicore.Pool
. - Changed
to_deterministic()
inAugmenter
and various child classes to derive its new random state from the augmenter's local random state instead of the global random state. - Enabled support for non-list
HeatmapsOnImage
inputs inAugmenter.augment_heatmaps()
. (Before, only lists were supported.) - Enabled support for non-list
SegmentationMapOnImage
inputs inAugmenter.augment_segmentation_maps()
. (Before, only lists were supported.) - Enabled support for non-list
KeypointsOnImage
inputs inAugmenter.augment_keypoints()
. (Before, only lists were supported.) - Enabled support for non-list
BoundingBoxesOnImage
inputs inAugmenter.augment_bounding_boxes()
. (Before, only lists were supported.)
ContrastNormalization
is now an alias forLinearContrast
- Restricted
JpegCompression
to uint8 inputs. Other dtypes will now produce errors early on. - Changed in
Add
the parametervalue
to be continuous and removed itsvalue_range
- Renamed
imgaug.augmenters.overlay
toimgaug.augmenters.blend
. Functions and classes inimgaug.augmenters.overlay
are still accessible, but will now raise a DeprecatedWarning. - Added
blend_alpha()
. - Refactored
Alpha
to be simpler and useblend_alpha()
. - Fixed
Alpha
not having its own__str__
method. - Improved dtype support of
AlphaElementwise
.
- Added function
blur_gaussian()
- Added
Lab2RGB
andLab2BGR
toChangeColorspace
- Refactored the main loop in
AddToHueAndSaturation
to make it simpler and faster - Fixed
ChangeColorspace
not being able to convert from RGB/BGR to Lab/Luv
- Added
AllChannelsCLAHE
- Added
CLAHE
- Added
AllChannelsHistogramEqualization
- Added
HistogramEqualization
- Added
_IntensityChannelBasedApplier
- Added function
adjust_contrast_gamma()
- Added function
adjust_contrast_sigmoid()
- Added function
adjust_contrast_log()
- Refactored random state handling in
_ContrastFuncWrapper
- [breaking, internal] Removed
_PreserveDtype
- [breaking, internal] Renamed
_adjust_linear
toadjust_contrast_linear()
- Refactored
AverageBlur
to have improved random state handling - Refactored
GaussianBlur
to only overwrite input images when that is necessary - Refactored
GaussianBlur
to have a simplified main loop - Refactored
AverageBlur
to have a simplified main loop - Refactored
MedianBlur
to have a simplified main loop - Refactored
BilateralBlur
to have a simplified main loop - Improved dtype support of
GaussianBlur
- Improved dtype support of
AverageBlur
- Improved dtype support of
Convolve
- Improved dtype support of
Fliplr
- Improved dtype support of
Flipud
- Refactored
Fliplr
main loop to be more elegant and tolerant - Refactored
Flipud
main loop to be more elegant and tolerant - Added alias
HorizontalFlip
forFliplr
. - Added alias
VerticalFlip
forFlipud
.
ElasticTransformation
- [breaking, mostly internal]
generate_indices()
now returns only the pixelwise shift as a tuple of x and y - [breaking, mostly internal]
generate_indices()
has no longer areshape
argument - [breaking, mostly internal]
renamed generate_indices()
togenerate_shift_maps()
- [breaking, mostly internal]
map_coordinates()
now expects to get the pixelwise shift as its input, instead of the target coordinates
- [breaking, mostly internal]
- Improved dtype support of
Superpixels
- Removed the restriction to
uint8
inScale
. The augmenter now supports the same dtypes asimresize_many_images()
. - Fixed missing pad mode
mean
inPad
andCropAndPad
. - Improved error messages related to pad mode.
- Improved and fixed docstrings of
CropAndPad
,Crop
,Pad
. - Renamed
Scale
toResize
. - Marked
Scale
as deprecated.
- Improved descriptions of the library in
setup.py
matplotlib
is now an optional dependency of the library and loaded lazily when neededShapely
is now an optional dependency of the library and loaded lazily when neededopencv-python
is now a dependency of the librarysetup.py
no longer enforcescv2
to be installed (to allow installing libraries in random order)- Minimum required
numpy
version is now 1.15