geoai-py 0.18.1__tar.gz → 0.18.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. {geoai_py-0.18.1 → geoai_py-0.18.2}/.gitignore +2 -0
  2. {geoai_py-0.18.1 → geoai_py-0.18.2}/.pre-commit-config.yaml +1 -1
  3. {geoai_py-0.18.1 → geoai_py-0.18.2}/PKG-INFO +1 -1
  4. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/__init__.py +1 -1
  5. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/train.py +22 -0
  6. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/utils.py +243 -41
  7. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai_py.egg-info/PKG-INFO +1 -1
  8. {geoai_py-0.18.1 → geoai_py-0.18.2}/mkdocs.yml +2 -0
  9. {geoai_py-0.18.1 → geoai_py-0.18.2}/pyproject.toml +2 -2
  10. {geoai_py-0.18.1 → geoai_py-0.18.2}/.dockerignore +0 -0
  11. {geoai_py-0.18.1 → geoai_py-0.18.2}/.editorconfig +0 -0
  12. {geoai_py-0.18.1 → geoai_py-0.18.2}/CITATION.cff +0 -0
  13. {geoai_py-0.18.1 → geoai_py-0.18.2}/Dockerfile +0 -0
  14. {geoai_py-0.18.1 → geoai_py-0.18.2}/LICENSE +0 -0
  15. {geoai_py-0.18.1 → geoai_py-0.18.2}/MANIFEST.in +0 -0
  16. {geoai_py-0.18.1 → geoai_py-0.18.2}/README.md +0 -0
  17. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/agents/__init__.py +0 -0
  18. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/agents/catalog_models.py +0 -0
  19. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/agents/catalog_tools.py +0 -0
  20. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/agents/geo_agents.py +0 -0
  21. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/agents/map_tools.py +0 -0
  22. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/agents/stac_models.py +0 -0
  23. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/agents/stac_tools.py +0 -0
  24. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/change_detection.py +0 -0
  25. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/classify.py +0 -0
  26. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/detectron2.py +0 -0
  27. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/dinov3.py +0 -0
  28. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/download.py +0 -0
  29. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/extract.py +0 -0
  30. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/geoai.py +0 -0
  31. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/hf.py +0 -0
  32. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/map_widgets.py +0 -0
  33. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/sam.py +0 -0
  34. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/segment.py +0 -0
  35. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/segmentation.py +0 -0
  36. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/timm_segment.py +0 -0
  37. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/timm_train.py +0 -0
  38. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/tools/__init__.py +0 -0
  39. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/tools/cloudmask.py +0 -0
  40. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai/tools/multiclean.py +0 -0
  41. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai_py.egg-info/SOURCES.txt +0 -0
  42. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai_py.egg-info/dependency_links.txt +0 -0
  43. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai_py.egg-info/entry_points.txt +0 -0
  44. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai_py.egg-info/requires.txt +0 -0
  45. {geoai_py-0.18.1 → geoai_py-0.18.2}/geoai_py.egg-info/top_level.txt +0 -0
  46. {geoai_py-0.18.1 → geoai_py-0.18.2}/pytest.ini +0 -0
  47. {geoai_py-0.18.1 → geoai_py-0.18.2}/requirements.txt +0 -0
  48. {geoai_py-0.18.1 → geoai_py-0.18.2}/requirements_docs.txt +0 -0
  49. {geoai_py-0.18.1 → geoai_py-0.18.2}/setup.cfg +0 -0
  50. {geoai_py-0.18.1 → geoai_py-0.18.2}/tests/__init__.py +0 -0
  51. {geoai_py-0.18.1 → geoai_py-0.18.2}/tests/create_test_data.py +0 -0
  52. {geoai_py-0.18.1 → geoai_py-0.18.2}/tests/test_classify.py +0 -0
  53. {geoai_py-0.18.1 → geoai_py-0.18.2}/tests/test_download.py +0 -0
  54. {geoai_py-0.18.1 → geoai_py-0.18.2}/tests/test_extract.py +0 -0
  55. {geoai_py-0.18.1 → geoai_py-0.18.2}/tests/test_fixtures.py +0 -0
  56. {geoai_py-0.18.1 → geoai_py-0.18.2}/tests/test_geoai.py +0 -0
  57. {geoai_py-0.18.1 → geoai_py-0.18.2}/tests/test_segment.py +0 -0
  58. {geoai_py-0.18.1 → geoai_py-0.18.2}/tests/test_utils.py +0 -0
@@ -49,6 +49,8 @@ wheels/
49
49
  *.egg-info/
50
50
  .installed.cfg
51
51
  *.egg
52
+ docs/examples/**/*.txt
53
+ docs/examples/**/*.pth
52
54
 
53
55
  # PyInstaller
54
56
  # Usually these files are written by a python script from a template
@@ -12,7 +12,7 @@ repos:
12
12
  args: ["--maxkb=500"]
13
13
 
14
14
  - repo: https://github.com/psf/black-pre-commit-mirror
15
- rev: 25.9.0
15
+ rev: 25.11.0
16
16
  hooks:
17
17
  - id: black-jupyter
18
18
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geoai-py
3
- Version: 0.18.1
3
+ Version: 0.18.2
4
4
  Summary: A Python package for using Artificial Intelligence (AI) with geospatial data
5
5
  Author-email: Qiusheng Wu <giswqs@gmail.com>
6
6
  License: MIT License
@@ -2,7 +2,7 @@
2
2
 
3
3
  __author__ = """Qiusheng Wu"""
4
4
  __email__ = "giswqs@gmail.com"
5
- __version__ = "0.18.1"
5
+ __version__ = "0.18.2"
6
6
 
7
7
 
8
8
  import os
@@ -2015,17 +2015,39 @@ def get_semantic_transform(train: bool) -> Any:
2015
2015
  """
2016
2016
  Get transforms for semantic segmentation data augmentation.
2017
2017
 
2018
+ This function returns default data augmentation transforms for training
2019
+ semantic segmentation models. The transforms include geometric transformations
2020
+ (horizontal/vertical flips, rotations) and photometric adjustments (brightness,
2021
+ contrast) that are commonly used in remote sensing tasks.
2022
+
2018
2023
  Args:
2019
2024
  train (bool): Whether to include training-specific transforms.
2025
+ If True, applies augmentations (flips, rotations, brightness/contrast adjustments).
2026
+ If False, only converts to tensor (for validation).
2020
2027
 
2021
2028
  Returns:
2022
2029
  SemanticTransforms: Composed transforms.
2030
+
2031
+ Example:
2032
+ >>> train_transform = get_semantic_transform(train=True)
2033
+ >>> val_transform = get_semantic_transform(train=False)
2023
2034
  """
2024
2035
  transforms = []
2025
2036
  transforms.append(SemanticToTensor())
2026
2037
 
2027
2038
  if train:
2039
+ # Geometric transforms - preserve spatial structure
2028
2040
  transforms.append(SemanticRandomHorizontalFlip(0.5))
2041
+ transforms.append(SemanticRandomVerticalFlip(0.5))
2042
+ transforms.append(SemanticRandomRotation90(0.5))
2043
+
2044
+ # Photometric transforms - improve model robustness
2045
+ transforms.append(
2046
+ SemanticBrightnessAdjustment(brightness_range=(0.8, 1.2), prob=0.5)
2047
+ )
2048
+ transforms.append(
2049
+ SemanticContrastAdjustment(contrast_range=(0.8, 1.2), prob=0.5)
2050
+ )
2029
2051
 
2030
2052
  return SemanticTransforms(transforms)
2031
2053
 
@@ -3004,6 +3004,82 @@ def batch_vector_to_raster(
3004
3004
  return output_files
3005
3005
 
3006
3006
 
3007
+ def get_default_augmentation_transforms(
3008
+ tile_size: int = 256,
3009
+ include_normalize: bool = False,
3010
+ mean: Tuple[float, float, float] = (0.485, 0.456, 0.406),
3011
+ std: Tuple[float, float, float] = (0.229, 0.224, 0.225),
3012
+ ) -> Any:
3013
+ """
3014
+ Get default data augmentation transforms for geospatial imagery using albumentations.
3015
+
3016
+ This function returns a composition of augmentation transforms commonly used
3017
+ for remote sensing and geospatial data. The transforms include geometric
3018
+ transformations (flips, rotations) and photometric adjustments (brightness,
3019
+ contrast, saturation).
3020
+
3021
+ Args:
3022
+ tile_size (int): Target size for tiles. Defaults to 256.
3023
+ include_normalize (bool): Whether to include normalization transform.
3024
+ Defaults to False. Set to True if using for training with pretrained models.
3025
+ mean (tuple): Mean values for normalization (RGB). Defaults to ImageNet values.
3026
+ std (tuple): Standard deviation for normalization (RGB). Defaults to ImageNet values.
3027
+
3028
+ Returns:
3029
+ albumentations.Compose: A composition of augmentation transforms.
3030
+
3031
+ Example:
3032
+ >>> import albumentations as A
3033
+ >>> # Get default transforms
3034
+ >>> transform = get_default_augmentation_transforms()
3035
+ >>> # Apply to image and mask
3036
+ >>> augmented = transform(image=image, mask=mask)
3037
+ >>> aug_image = augmented['image']
3038
+ >>> aug_mask = augmented['mask']
3039
+ """
3040
+ try:
3041
+ import albumentations as A
3042
+ except ImportError:
3043
+ raise ImportError(
3044
+ "albumentations is required for data augmentation. "
3045
+ "Install it with: pip install albumentations"
3046
+ )
3047
+
3048
+ transforms_list = [
3049
+ # Geometric transforms
3050
+ A.HorizontalFlip(p=0.5),
3051
+ A.VerticalFlip(p=0.5),
3052
+ A.RandomRotate90(p=0.5),
3053
+ A.ShiftScaleRotate(
3054
+ shift_limit=0.1,
3055
+ scale_limit=0.1,
3056
+ rotate_limit=45,
3057
+ border_mode=0,
3058
+ p=0.5,
3059
+ ),
3060
+ # Photometric transforms
3061
+ A.RandomBrightnessContrast(
3062
+ brightness_limit=0.2,
3063
+ contrast_limit=0.2,
3064
+ p=0.5,
3065
+ ),
3066
+ A.HueSaturationValue(
3067
+ hue_shift_limit=10,
3068
+ sat_shift_limit=20,
3069
+ val_shift_limit=10,
3070
+ p=0.3,
3071
+ ),
3072
+ A.GaussNoise(var_limit=(10.0, 50.0), p=0.2),
3073
+ A.GaussianBlur(blur_limit=(3, 5), p=0.2),
3074
+ ]
3075
+
3076
+ # Add normalization if requested
3077
+ if include_normalize:
3078
+ transforms_list.append(A.Normalize(mean=mean, std=std))
3079
+
3080
+ return A.Compose(transforms_list)
3081
+
3082
+
3007
3083
  def export_geotiff_tiles(
3008
3084
  in_raster,
3009
3085
  out_folder,
@@ -3018,6 +3094,9 @@ def export_geotiff_tiles(
3018
3094
  create_overview=False,
3019
3095
  skip_empty_tiles=False,
3020
3096
  metadata_format="PASCAL_VOC",
3097
+ apply_augmentation=False,
3098
+ augmentation_count=3,
3099
+ augmentation_transforms=None,
3021
3100
  ):
3022
3101
  """
3023
3102
  Export georeferenced GeoTIFF tiles and labels from raster and classification data.
@@ -3037,12 +3116,54 @@ def export_geotiff_tiles(
3037
3116
  create_overview (bool): Whether to create an overview image of all tiles
3038
3117
  skip_empty_tiles (bool): If True, skip tiles with no features
3039
3118
  metadata_format (str): Output metadata format (PASCAL_VOC, COCO, YOLO). Default: PASCAL_VOC
3119
+ apply_augmentation (bool): If True, generate augmented versions of each tile.
3120
+ This will create multiple variants of each tile using data augmentation techniques.
3121
+ Defaults to False.
3122
+ augmentation_count (int): Number of augmented versions to generate per tile
3123
+ (only used if apply_augmentation=True). Defaults to 3.
3124
+ augmentation_transforms (albumentations.Compose, optional): Custom augmentation transforms.
3125
+ If None and apply_augmentation=True, uses default transforms from
3126
+ get_default_augmentation_transforms(). Should be an albumentations.Compose object.
3127
+ Defaults to None.
3128
+
3129
+ Returns:
3130
+ None: Tiles and labels are saved to out_folder.
3131
+
3132
+ Example:
3133
+ >>> # Export tiles without augmentation
3134
+ >>> export_geotiff_tiles('image.tif', 'output/', 'labels.tif')
3135
+ >>>
3136
+ >>> # Export tiles with default augmentation (3 augmented versions per tile)
3137
+ >>> export_geotiff_tiles('image.tif', 'output/', 'labels.tif',
3138
+ ... apply_augmentation=True)
3139
+ >>>
3140
+ >>> # Export with custom augmentation
3141
+ >>> import albumentations as A
3142
+ >>> custom_transform = A.Compose([
3143
+ ... A.HorizontalFlip(p=0.5),
3144
+ ... A.RandomBrightnessContrast(p=0.5),
3145
+ ... ])
3146
+ >>> export_geotiff_tiles('image.tif', 'output/', 'labels.tif',
3147
+ ... apply_augmentation=True,
3148
+ ... augmentation_count=5,
3149
+ ... augmentation_transforms=custom_transform)
3040
3150
  """
3041
3151
 
3042
3152
  import logging
3043
3153
 
3044
3154
  logging.getLogger("rasterio").setLevel(logging.ERROR)
3045
3155
 
3156
+ # Initialize augmentation transforms if needed
3157
+ if apply_augmentation:
3158
+ if augmentation_transforms is None:
3159
+ augmentation_transforms = get_default_augmentation_transforms(
3160
+ tile_size=tile_size
3161
+ )
3162
+ if not quiet:
3163
+ print(
3164
+ f"Data augmentation enabled: generating {augmentation_count} augmented versions per tile"
3165
+ )
3166
+
3046
3167
  # Create output directories
3047
3168
  os.makedirs(out_folder, exist_ok=True)
3048
3169
  image_dir = os.path.join(out_folder, "images")
@@ -3374,53 +3495,134 @@ def export_geotiff_tiles(
3374
3495
  # Read image data
3375
3496
  image_data = src.read(window=window)
3376
3497
 
3377
- # Export image as GeoTIFF
3378
- image_path = os.path.join(image_dir, f"tile_{tile_index:06d}.tif")
3498
+ # Helper function to save a single tile (original or augmented)
3499
+ def save_tile(
3500
+ img_data,
3501
+ lbl_mask,
3502
+ tile_id,
3503
+ img_profile,
3504
+ window_trans,
3505
+ is_augmented=False,
3506
+ ):
3507
+ """Save a single image and label tile."""
3508
+ # Export image as GeoTIFF
3509
+ image_path = os.path.join(image_dir, f"tile_{tile_id:06d}.tif")
3379
3510
 
3380
- # Create profile for image GeoTIFF
3381
- image_profile = src.profile.copy()
3382
- image_profile.update(
3383
- {
3384
- "height": tile_size,
3385
- "width": tile_size,
3386
- "count": image_data.shape[0],
3387
- "transform": window_transform,
3388
- }
3511
+ # Update profile
3512
+ img_profile_copy = img_profile.copy()
3513
+ img_profile_copy.update(
3514
+ {
3515
+ "height": tile_size,
3516
+ "width": tile_size,
3517
+ "count": img_data.shape[0],
3518
+ "transform": window_trans,
3519
+ }
3520
+ )
3521
+
3522
+ # Save image as GeoTIFF
3523
+ try:
3524
+ with rasterio.open(image_path, "w", **img_profile_copy) as dst:
3525
+ dst.write(img_data)
3526
+ stats["total_tiles"] += 1
3527
+ except Exception as e:
3528
+ pbar.write(f"ERROR saving image GeoTIFF: {e}")
3529
+ stats["errors"] += 1
3530
+ return
3531
+
3532
+ # Export label as GeoTIFF (only if class data provided)
3533
+ if in_class_data is not None:
3534
+ # Create profile for label GeoTIFF
3535
+ label_profile = {
3536
+ "driver": "GTiff",
3537
+ "height": tile_size,
3538
+ "width": tile_size,
3539
+ "count": 1,
3540
+ "dtype": "uint8",
3541
+ "crs": src.crs,
3542
+ "transform": window_trans,
3543
+ }
3544
+
3545
+ label_path = os.path.join(label_dir, f"tile_{tile_id:06d}.tif")
3546
+ try:
3547
+ with rasterio.open(label_path, "w", **label_profile) as dst:
3548
+ dst.write(lbl_mask.astype(np.uint8), 1)
3549
+
3550
+ if not is_augmented and np.any(lbl_mask > 0):
3551
+ stats["tiles_with_features"] += 1
3552
+ stats["feature_pixels"] += np.count_nonzero(lbl_mask)
3553
+ except Exception as e:
3554
+ pbar.write(f"ERROR saving label GeoTIFF: {e}")
3555
+ stats["errors"] += 1
3556
+
3557
+ # Save original tile
3558
+ save_tile(
3559
+ image_data,
3560
+ label_mask,
3561
+ tile_index,
3562
+ src.profile,
3563
+ window_transform,
3564
+ is_augmented=False,
3389
3565
  )
3390
3566
 
3391
- # Save image as GeoTIFF
3392
- try:
3393
- with rasterio.open(image_path, "w", **image_profile) as dst:
3394
- dst.write(image_data)
3395
- stats["total_tiles"] += 1
3396
- except Exception as e:
3397
- pbar.write(f"ERROR saving image GeoTIFF: {e}")
3398
- stats["errors"] += 1
3567
+ # Generate and save augmented tiles if enabled
3568
+ if apply_augmentation:
3569
+ for aug_idx in range(augmentation_count):
3570
+ # Prepare image for augmentation (convert from CHW to HWC)
3571
+ img_for_aug = np.transpose(image_data, (1, 2, 0))
3572
+
3573
+ # Ensure uint8 data type for albumentations
3574
+ # Albumentations expects uint8 for most transforms
3575
+ if not np.issubdtype(img_for_aug.dtype, np.uint8):
3576
+ # If image is float, scale to 0-255 and convert to uint8
3577
+ if np.issubdtype(img_for_aug.dtype, np.floating):
3578
+ img_for_aug = (
3579
+ (img_for_aug * 255).clip(0, 255).astype(np.uint8)
3580
+ )
3581
+ else:
3582
+ img_for_aug = img_for_aug.astype(np.uint8)
3399
3583
 
3400
- # Export label as GeoTIFF (only if class data provided)
3401
- if in_class_data is not None:
3402
- # Create profile for label GeoTIFF
3403
- label_profile = {
3404
- "driver": "GTiff",
3405
- "height": tile_size,
3406
- "width": tile_size,
3407
- "count": 1,
3408
- "dtype": "uint8",
3409
- "crs": src.crs,
3410
- "transform": window_transform,
3411
- }
3584
+ # Apply augmentation
3585
+ try:
3586
+ if in_class_data is not None:
3587
+ # Augment both image and mask
3588
+ augmented = augmentation_transforms(
3589
+ image=img_for_aug, mask=label_mask
3590
+ )
3591
+ aug_image = augmented["image"]
3592
+ aug_mask = augmented["mask"]
3593
+ else:
3594
+ # Augment only image
3595
+ augmented = augmentation_transforms(image=img_for_aug)
3596
+ aug_image = augmented["image"]
3597
+ aug_mask = label_mask
3412
3598
 
3413
- label_path = os.path.join(label_dir, f"tile_{tile_index:06d}.tif")
3414
- try:
3415
- with rasterio.open(label_path, "w", **label_profile) as dst:
3416
- dst.write(label_mask.astype(np.uint8), 1)
3599
+ # Convert back from HWC to CHW
3600
+ aug_image = np.transpose(aug_image, (2, 0, 1))
3417
3601
 
3418
- if has_features:
3419
- stats["tiles_with_features"] += 1
3420
- stats["feature_pixels"] += np.count_nonzero(label_mask)
3421
- except Exception as e:
3422
- pbar.write(f"ERROR saving label GeoTIFF: {e}")
3423
- stats["errors"] += 1
3602
+ # Ensure correct dtype for saving
3603
+ aug_image = aug_image.astype(image_data.dtype)
3604
+
3605
+ # Generate unique tile ID for augmented version
3606
+ # Use a collision-free numbering scheme: (tile_index * (augmentation_count + 1)) + aug_idx + 1
3607
+ aug_tile_id = (
3608
+ (tile_index * (augmentation_count + 1)) + aug_idx + 1
3609
+ )
3610
+
3611
+ # Save augmented tile
3612
+ save_tile(
3613
+ aug_image,
3614
+ aug_mask,
3615
+ aug_tile_id,
3616
+ src.profile,
3617
+ window_transform,
3618
+ is_augmented=True,
3619
+ )
3620
+
3621
+ except Exception as e:
3622
+ pbar.write(
3623
+ f"ERROR applying augmentation {aug_idx} to tile {tile_index}: {e}"
3624
+ )
3625
+ stats["errors"] += 1
3424
3626
 
3425
3627
  # Create annotations for object detection if using vector class data
3426
3628
  if (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geoai-py
3
- Version: 0.18.1
3
+ Version: 0.18.2
4
4
  Summary: A Python package for using Artificial Intelligence (AI) with geospatial data
5
5
  Author-email: Qiusheng Wu <giswqs@gmail.com>
6
6
  License: MIT License
@@ -60,6 +60,7 @@ plugins:
60
60
  "examples/*_detection.ipynb",
61
61
  "examples/building_footprints_*.ipynb",
62
62
  "examples/data_visualization.ipynb",
63
+ "examples/data_augmentation.ipynb",
63
64
  "examples/train_*.ipynb",
64
65
  "examples/water_dynamics.ipynb",
65
66
  "examples/wetland_mapping.ipynb",
@@ -110,6 +111,7 @@ nav:
110
111
  - examples/image_tiling.ipynb
111
112
  - examples/create_training_data.ipynb
112
113
  - examples/export_training_data_formats.ipynb
114
+ - examples/data_augmentation.ipynb
113
115
  - examples/building_footprints_usa.ipynb
114
116
  - examples/building_footprints_africa.ipynb
115
117
  - examples/building_footprints_china.ipynb
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "geoai-py"
3
- version = "0.18.1"
3
+ version = "0.18.2"
4
4
  dynamic = [
5
5
  "dependencies",
6
6
  ]
@@ -44,7 +44,7 @@ universal = true
44
44
 
45
45
 
46
46
  [tool.bumpversion]
47
- current_version = "0.18.1"
47
+ current_version = "0.18.2"
48
48
  commit = true
49
49
  tag = true
50
50
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes