{"id":13738513,"url":"https://github.com/mjkvaak/ImageDataAugmentor","last_synced_at":"2025-05-08T16:34:27.388Z","repository":{"id":55623322,"uuid":"199986268","full_name":"mjkvaak/ImageDataAugmentor","owner":"mjkvaak","description":"Custom image data generator for TF Keras that supports the modern augmentation module albumentations","archived":false,"fork":false,"pushed_at":"2022-06-20T07:33:54.000Z","size":2637,"stargazers_count":86,"open_issues_count":1,"forks_count":27,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-15T07:34:40.042Z","etag":null,"topics":["augmentation","augmentations","data-generation","deep-learning","image-augmentation","image-classification","machine-learning","python","tensorflow2"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mjkvaak.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-01T05:55:41.000Z","updated_at":"2024-05-14T15:30:35.000Z","dependencies_parsed_at":"2022-08-15T04:40:55.043Z","dependency_job_id":null,"html_url":"https://github.com/mjkvaak/ImageDataAugmentor","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjkvaak%2FImageDataAugmentor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjkvaak%2FImageDataAugmentor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjkvaak%2FImageDataAugmentor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjkvaak%2FImageDataAugmentor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mjkvaak","download_url":"https://codeload.github.com/mjkvaak/ImageDataAugmentor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253105640,"owners_count":21855070,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["augmentation","augmentations","data-generation","deep-learning","image-augmentation","image-classification","machine-learning","python","tensorflow2"],"created_at":"2024-08-03T03:02:24.704Z","updated_at":"2025-05-08T16:34:26.724Z","avatar_url":"https://github.com/mjkvaak.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"\u003e**NOTICE!**\n\u003e * Support has moved from `keras` to `tensorflow.keras` framework. \n\u003e * There were large updates in Dec 2020, see in [Changelog](CHANGELOG.md) what has changed.\n\n# ImageDataAugmentor\n`ImageDataAugmentor` is a custom image data generator for `tensorflow.keras` \nthat supports `albumentations`.\n\nTo learn more about:\n* `ImageDataGenerator`, see:\n  https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/ImageDataGenerator\n* `albumentations`, see:\n  https://github.com/albumentations-team/albumentations\n\n\n### Installation \n\u003e For the installation of the prerequisites, see these two gists: [NVIDIA-driver installation](https://gist.github.com/mjkvaak/5769ebdfbf6598b3fd0ece66b3c12a3c) and [TF2.x installation](https://gist.github.com/mjkvaak/ad0fea057d5a733dc76524825f21dee2)\n\n```shell\n$ pip install git+https://github.com/mjkvaak/ImageDataAugmentor\n```\n\n### How to use\nThe usage is analogous to `tensorflow.keras.ImageDataGenerator` with\nthe exception that the image transformations will be generated using\nexternal augmentations library `albumentations`.\n\u003e Tip: Complete list of `albumentations.transforms` can be \n\u003e found [here](https://albumentations.ai/docs/api_reference/augmentations/transforms/). \n\u003e See also [this](https://albumentations-demo.herokuapp.com/) handy tool for testing\n\u003e the different transforms.\n\nThe most notable added features are:\n* Augmentations are passed to `ImageDataAugmentor` as a single `albumentations` transform\n  (e.g. `albumentations.HorizontalFlip()`) or a composition of multiple transforms as\n  `albumentations.Compose` object\n* `albumentations` can transform various types of data, e.g. imagery, segmentation mask, \n  bounding box and keypoints. \n  `input_augment_mode` (resp. `label_augment_mode`) can be used to select which type\n  of transforms to apply to the (model) inputs (resp. model labels) \n* `.show_data()` can be used to visualize a random bunch of images \n  generated by `ImageDataAugmentor`\n\nBelow are a few examples of some commonly encountered use cases.\nMore complete examples can be found in [`./examples`](./examples) folder.\n\n**Example of using `.flow_from_directory(directory)` with `albumentations`**:\n```python\nimport tensorflow as tf\nfrom ImageDataAugmentor.image_data_augmentor import *\nimport albumentations\n...\n    \nAUGMENTATIONS = albumentations.Compose([\n    albumentations.Transpose(p=0.5),\n    albumentations.Flip(p=0.5),\n    albumentations.OneOf([\n        albumentations.RandomBrightnessContrast(brightness_limit=0.3, contrast_limit=0.3),\n        albumentations.RandomBrightnessContrast(brightness_limit=0.1, contrast_limit=0.1)\n    ],p=1),\n    albumentations.GaussianBlur(p=0.05),\n    albumentations.HueSaturationValue(p=0.5),\n    albumentations.RGBShift(p=0.5),\n])\n\n# dataloaders\ntrain_datagen = ImageDataAugmentor(\n        rescale=1./255,\n        augment=AUGMENTATIONS,\n        preprocess_input=None)\ntrain_generator = train_datagen.flow_from_directory(\n        'data/train',\n        target_size=(224, 224),\n        batch_size=32,\n        class_mode='binary')\nval_datagen = ImageDataAugmentor(rescale=1./255)\nvalidation_generator = val_datagen.flow_from_directory(\n        'data/validation',\n        target_size=(224, 224),\n        batch_size=32,\n        class_mode='binary')\n#train_generator.show_data() #\u003c- visualize a bunch of augmented data\n\n# train the model with real-time data augmentations\nmodel.fit(\n        train_generator,\n        steps_per_epoch=len(train_generator),\n        epochs=50,\n        validation_data=validation_generator,\n        validation_steps=len(validation_generator))\n...\n```\n\n**Example of using `.flow(x, y)` with `albumentations`:**\n```python\nimport tensorflow as tf\nfrom ImageDataAugmentor.image_data_augmentor import *\nimport albumentations\n...\n\nAUGMENTATIONS = albumentations.Compose([\n    albumentations.HorizontalFlip(p=0.5), # horizontally flip 50% of all images\n    albumentations.VerticalFlip(p=0.2), # vertically flip 20% of all images\n    albumentations.ShiftScaleRotate(p=0.5)\n],)  \n\n# fetch data\n(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()\nnum_classes = len(np.unique(y_train))\ny_train = tf.keras.utils.to_categorical(y_train, num_classes)\ny_test = tf.keras.utils.to_categorical(y_test, num_classes)\n\n# dataloaders\ndatagen = ImageDataAugmentor(\n    featurewise_center=True,\n    featurewise_std_normalization=True,\n    augment=AUGMENTATIONS, \n    validation_split=0.2\n)\n# compute quantities required for featurewise normalization\ndatagen.fit(x_train, augment=True)\ntrain_generator = datagen.flow(x_train, y_train, batch_size=32, subset='training')\nvalidation_generator = datagen.flow(x_train, y_train, batch_size=32, subset='validation')\n# train_generator.show_data()\n\n# train the model with real-time data augmentations\nmodel.fit(\n  train_generator,\n  steps_per_epoch=len(train_generator),\n  epochs=50,\n  validation_data=validation_generator,\n  validation_steps=len(validation_generator)\n)\n\n# evaluate the model with test data\ntest_datagen = ImageDataAugmentor(\n    featurewise_center=True,\n    featurewise_std_normalization=True,\n    augment=albumentations.HorizontalFlip(p=0.5), \n)\ntest_datagen.mean = datagen.mean #\u003c- stats from training dataset \ntest_datagen.std = datagen.std #\u003c- stats training dataset\ntest_generator = test_datagen.flow(x_test, y_test, batch_size=32)\nmodel.evaluate(test_generator)\n```    \n\n**Example of using `.flow_from_directory()` with masks for segmentation with `albumentations`:**\n```python\nimport tensorflow as tf\nfrom ImageDataAugmentor.image_data_augmentor import *\nimport albumentations\n...\n\nSEED = 123\nAUGMENTATIONS = albumentations.Compose([\n  albumentations.HorizontalFlip(p=0.5),\n  albumentations.ElasticTransform(),\n])\n\n# Assume that DATA_DIR has subdirs \"images\" and \"masks\", \n# where masks have been saved as grayscale images with pixel value\n# denoting the segmentation label\nDATA_DIR = ... \nN_CLASSES = ... # number of segmentation classes in masks\n\ndef one_hot_encode_masks(y:np.array, classes=range(N_CLASSES)):\n    ''' One hot encodes target masks for segmentation '''\n    y = y.squeeze()\n    masks = [(y == v) for v in classes]\n    mask = np.stack(masks, axis=-1).astype('float')\n    # add background if the mask is not binary\n    if mask.shape[-1] != 1:\n        background = 1 - mask.sum(axis=-1, keepdims=True)\n        mask = np.concatenate((mask, background), axis=-1)\n    return mask\n\nimg_data_gen = ImageDataAugmentor(\n    augment=AUGMENTATIONS, \n    input_augment_mode='image', \n    validation_split=0.2,\n    seed=SEED,\n)\nmask_data_gen = ImageDataAugmentor(\n    augment=AUGMENTATIONS, \n    input_augment_mode='mask', #\u003c- notice the different augment mode\n    preprocess_input=one_hot_encode_masks,\n    validation_split=0.2,\n    seed=SEED,\n)\nprint(\"training:\")\ntr_img_gen = img_data_gen.flow_from_directory(DATA_DIR, \n                                              classes=['images'], \n                                              class_mode=None,\n                                              subset=\"training\", \n                                              shuffle=True)\ntr_mask_gen = mask_data_gen.flow_from_directory(DATA_DIR, \n                                                classes=['masks'],\n                                                class_mode=None, \n                                                color_mode='gray', #\u003c- notice the color mode\n                                                subset=\"training\",\n                                                shuffle=True)\nprint(\"validation:\")\nval_img_gen = img_data_gen.flow_from_directory(DATA_DIR, \n                                               classes=['images'],\n                                               class_mode=None,\n                                               subset=\"validation\", \n                                               shuffle=True)\nval_mask_gen = mask_data_gen.flow_from_directory(DATA_DIR, \n                                                 classes=['masks'], \n                                                 class_mode=None, \n                                                 color_mode='gray', #\u003c- notice the color mode\n                                                 subset=\"validation\",\n                                                 shuffle=True)\n#tr_img_gen.show_data()\n#tr_mask_gen.show_data()\n\ntrain_generator = zip(tr_img_gen, tr_mask_gen)\nvalidation_generator = zip(tr_img_gen, tr_mask_gen)\n\n# visualize images\nrows = 5\nimage_batch, mask_batch = next(train_generator)\nfix, ax = plt.subplots(rows,2, figsize=(4,rows*2))\nfor i, (img,mask) in enumerate(zip(image_batch, mask_batch)):\n    if i\u003erows-1:\n        break\n    ax[i,0].imshow(np.uint8(img))\n    ax[i,1].imshow(mask.argmax(-1))\n    \nplt.show()\n\n# train the model with real-time data augmentations\nmodel.fit(\n  train_generator,\n  steps_per_epoch=len(train_generator),\n  epochs=50,\n  validation_data=validation_generator,\n  validation_steps=len(validation_generator)\n)\n...\n\n```\n\n\n## Citing (BibTex):\u003cbr /\u003e\n```\n@misc{Tukiainen:2019,\n  author = {Tukiainen, M.},\n  title = {ImageDataAugmentor},\n  year = {2019},\n  publisher = {GitHub},\n  journal = {GitHub repository},\n  howpublished = {https://github.com/mjkvaak/ImageDataAugmentor/} \n}\n```\n\n## License\nThis project is distributed under [MIT license](LICENSE). \nThe code is heavily adapted from\nhttps://github.com/keras-team/keras-preprocessing/blob/master/keras_preprocessing/ (also MIT licensed)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmjkvaak%2FImageDataAugmentor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmjkvaak%2FImageDataAugmentor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmjkvaak%2FImageDataAugmentor/lists"}