geoai-py 0.4.3__py2.py3-none-any.whl → 0.5.1__py2.py3-none-any.whl

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.
geoai/utils.py CHANGED
@@ -6053,3 +6053,199 @@ def try_common_architectures(state_dict):
6053
6053
 
6054
6054
  except Exception as e:
6055
6055
  print(f"- {name}: Failed to load - {str(e)}")
6056
+
6057
+
6058
+ def mosaic_geotiffs(input_dir, output_file, mask_file=None):
6059
+ """Create a mosaic from all GeoTIFF files as a Cloud Optimized GeoTIFF (COG).
6060
+
6061
+ This function identifies all GeoTIFF files in the specified directory,
6062
+ creates a seamless mosaic with proper handling of nodata values, and saves
6063
+ as a Cloud Optimized GeoTIFF format. If a mask file is provided, the output
6064
+ will be clipped to the extent of the mask.
6065
+
6066
+ Args:
6067
+ input_dir (str): Path to the directory containing GeoTIFF files.
6068
+ output_file (str): Path to the output Cloud Optimized GeoTIFF file.
6069
+ mask_file (str, optional): Path to a mask file to clip the output.
6070
+ If provided, the output will be clipped to the extent of this mask.
6071
+ Defaults to None.
6072
+
6073
+ Returns:
6074
+ bool: True if the mosaic was created successfully, False otherwise.
6075
+
6076
+ Examples:
6077
+ >>> mosaic_geotiffs('naip', 'merged_naip.tif')
6078
+ True
6079
+ >>> mosaic_geotiffs('naip', 'merged_naip.tif', 'boundary.tif')
6080
+ True
6081
+ """
6082
+ import glob
6083
+ from osgeo import gdal
6084
+
6085
+ gdal.UseExceptions()
6086
+ # Get all tif files in the directory
6087
+ tif_files = glob.glob(os.path.join(input_dir, "*.tif"))
6088
+
6089
+ if not tif_files:
6090
+ print("No GeoTIFF files found in the specified directory.")
6091
+ return False
6092
+
6093
+ # Analyze the first input file to determine compression and nodata settings
6094
+ ds = gdal.Open(tif_files[0])
6095
+ if ds is None:
6096
+ print(f"Unable to open {tif_files[0]}")
6097
+ return False
6098
+
6099
+ # Get driver metadata from the first file
6100
+ driver = ds.GetDriver()
6101
+ creation_options = []
6102
+
6103
+ # Check compression type
6104
+ metadata = ds.GetMetadata("IMAGE_STRUCTURE")
6105
+ if "COMPRESSION" in metadata:
6106
+ compression = metadata["COMPRESSION"]
6107
+ creation_options.append(f"COMPRESS={compression}")
6108
+ else:
6109
+ # Default compression if none detected
6110
+ creation_options.append("COMPRESS=LZW")
6111
+
6112
+ # Add COG-specific creation options
6113
+ creation_options.extend(["TILED=YES", "BLOCKXSIZE=512", "BLOCKYSIZE=512"])
6114
+
6115
+ # Check for nodata value in the first band of the first file
6116
+ band = ds.GetRasterBand(1)
6117
+ has_nodata = band.GetNoDataValue() is not None
6118
+ nodata_value = band.GetNoDataValue() if has_nodata else None
6119
+
6120
+ # Close the dataset
6121
+ ds = None
6122
+
6123
+ # Create a temporary VRT (Virtual Dataset)
6124
+ vrt_path = os.path.join(input_dir, "temp_mosaic.vrt")
6125
+
6126
+ # Build VRT from input files with proper nodata handling
6127
+ vrt_options = gdal.BuildVRTOptions(
6128
+ resampleAlg="nearest",
6129
+ srcNodata=nodata_value if has_nodata else None,
6130
+ VRTNodata=nodata_value if has_nodata else None,
6131
+ )
6132
+ vrt_dataset = gdal.BuildVRT(vrt_path, tif_files, options=vrt_options)
6133
+
6134
+ # Close the VRT dataset to flush it to disk
6135
+ vrt_dataset = None
6136
+
6137
+ # Create temp mosaic
6138
+ temp_mosaic = output_file + ".temp.tif"
6139
+
6140
+ # Convert VRT to GeoTIFF with the same compression as input
6141
+ translate_options = gdal.TranslateOptions(
6142
+ format="GTiff",
6143
+ creationOptions=creation_options,
6144
+ noData=nodata_value if has_nodata else None,
6145
+ )
6146
+ gdal.Translate(temp_mosaic, vrt_path, options=translate_options)
6147
+
6148
+ # Apply mask if provided
6149
+ if mask_file and os.path.exists(mask_file):
6150
+ print(f"Clipping mosaic to mask: {mask_file}")
6151
+
6152
+ # Create a temporary clipped file
6153
+ clipped_mosaic = output_file + ".clipped.tif"
6154
+
6155
+ # Open mask file
6156
+ mask_ds = gdal.Open(mask_file)
6157
+ if mask_ds is None:
6158
+ print(f"Unable to open mask file: {mask_file}")
6159
+ # Continue without clipping
6160
+ else:
6161
+ # Get mask extent
6162
+ mask_geotransform = mask_ds.GetGeoTransform()
6163
+ mask_projection = mask_ds.GetProjection()
6164
+ mask_ulx = mask_geotransform[0]
6165
+ mask_uly = mask_geotransform[3]
6166
+ mask_lrx = mask_ulx + (mask_geotransform[1] * mask_ds.RasterXSize)
6167
+ mask_lry = mask_uly + (mask_geotransform[5] * mask_ds.RasterYSize)
6168
+
6169
+ # Close mask dataset
6170
+ mask_ds = None
6171
+
6172
+ # Use warp options to clip
6173
+ warp_options = gdal.WarpOptions(
6174
+ format="GTiff",
6175
+ outputBounds=[mask_ulx, mask_lry, mask_lrx, mask_uly],
6176
+ dstSRS=mask_projection,
6177
+ creationOptions=creation_options,
6178
+ srcNodata=nodata_value if has_nodata else None,
6179
+ dstNodata=nodata_value if has_nodata else None,
6180
+ )
6181
+
6182
+ # Apply clipping
6183
+ gdal.Warp(clipped_mosaic, temp_mosaic, options=warp_options)
6184
+
6185
+ # Remove the unclipped temp mosaic and use the clipped one
6186
+ os.remove(temp_mosaic)
6187
+ temp_mosaic = clipped_mosaic
6188
+
6189
+ # Create internal overviews for the temp mosaic
6190
+ ds = gdal.Open(temp_mosaic, gdal.GA_Update)
6191
+ overview_list = [2, 4, 8, 16, 32]
6192
+ ds.BuildOverviews("NEAREST", overview_list)
6193
+ ds = None # Close the dataset to ensure overviews are written
6194
+
6195
+ # Convert the temp mosaic to a proper COG
6196
+ cog_options = gdal.TranslateOptions(
6197
+ format="GTiff",
6198
+ creationOptions=[
6199
+ "TILED=YES",
6200
+ "COPY_SRC_OVERVIEWS=YES",
6201
+ "COMPRESS=DEFLATE",
6202
+ "PREDICTOR=2",
6203
+ "BLOCKXSIZE=512",
6204
+ "BLOCKYSIZE=512",
6205
+ ],
6206
+ noData=nodata_value if has_nodata else None,
6207
+ )
6208
+ gdal.Translate(output_file, temp_mosaic, options=cog_options)
6209
+
6210
+ # Clean up temporary files
6211
+ if os.path.exists(vrt_path):
6212
+ os.remove(vrt_path)
6213
+ if os.path.exists(temp_mosaic):
6214
+ os.remove(temp_mosaic)
6215
+
6216
+ print(f"Cloud Optimized GeoTIFF mosaic created successfully: {output_file}")
6217
+ return True
6218
+
6219
+
6220
+ def download_model_from_hf(model_path, repo_id=None):
6221
+ """
6222
+ Download the object detection model from Hugging Face.
6223
+
6224
+ Args:
6225
+ model_path: Path to the model file.
6226
+ repo_id: Hugging Face repository ID.
6227
+
6228
+ Returns:
6229
+ Path to the downloaded model file
6230
+ """
6231
+ from huggingface_hub import hf_hub_download
6232
+
6233
+ try:
6234
+
6235
+ # Define the repository ID and model filename
6236
+ if repo_id is None:
6237
+ print(
6238
+ "Repo is is not specified, using default Hugging Face repo_id: giswqs/geoai"
6239
+ )
6240
+ repo_id = "giswqs/geoai"
6241
+
6242
+ # Download the model
6243
+ model_path = hf_hub_download(repo_id=repo_id, filename=model_path)
6244
+ print(f"Model downloaded to: {model_path}")
6245
+
6246
+ return model_path
6247
+
6248
+ except Exception as e:
6249
+ print(f"Error downloading model from Hugging Face: {e}")
6250
+ print("Please specify a local model path or ensure internet connectivity.")
6251
+ raise
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: geoai-py
3
- Version: 0.4.3
3
+ Version: 0.5.1
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
@@ -25,6 +25,7 @@ Requires-Dist: jupyter-server-proxy
25
25
  Requires-Dist: leafmap
26
26
  Requires-Dist: localtileserver
27
27
  Requires-Dist: mapclassify
28
+ Requires-Dist: maplibre
28
29
  Requires-Dist: overturemaps
29
30
  Requires-Dist: planetary-computer
30
31
  Requires-Dist: pystac-client
@@ -143,3 +144,10 @@ We welcome contributions of all kinds! See our [contributing guide](https://geoa
143
144
  ## 📄 License
144
145
 
145
146
  GeoAI is free and open source software, licensed under the MIT License.
147
+
148
+ ## Acknowledgments
149
+
150
+ We gratefully acknowledge the support of the following organizations:
151
+
152
+ - [NASA](https://www.nasa.gov): This research is partially supported by the National Aeronautics and Space Administration (NASA) through Grant No. 80NSSC22K1742, awarded under the [Open Source Tools, Frameworks, and Libraries Program](https://bit.ly/3RVBRcQ).
153
+ - [AmericaView](https://americaview.org): This work is also partially supported by the U.S. Geological Survey through Grant/Cooperative Agreement No. G23AP00683 (GY23-GY27) in collaboration with AmericaView.
@@ -0,0 +1,16 @@
1
+ geoai/__init__.py,sha256=pJWIhWx8tlrmE1KCdmmSNJFEyvGyzOBBtYWdtQanGCU,3765
2
+ geoai/classify.py,sha256=_e-193QzAx3pIxUflPIsIs1qZevQx5ADu7i3bOL1G70,35055
3
+ geoai/download.py,sha256=lJ1GsJOZsKc2i6_dQyPV-XXIXmlADOpmSBo-wha4DEU,40892
4
+ geoai/extract.py,sha256=GocJufMmrwEWxNBL1J91EXXHL8AKcO8m_lmtUF5AKPw,119102
5
+ geoai/geoai.py,sha256=QGKDAenLPo1CgKZLsMFDzW7CLH1Ao2sYaWhFZG3eTpk,4896
6
+ geoai/hf.py,sha256=mLKGxEAS5eHkxZLwuLpYc1o7e3-7QIXdBv-QUY-RkFk,17072
7
+ geoai/segment.py,sha256=g3YW17ftr--CKq6VB32TJEPY8owGQ7uQ0sg_tUT2ooE,13681
8
+ geoai/segmentation.py,sha256=AtPzCvguHAEeuyXafa4bzMFATvltEYcah1B8ZMfkM_s,11373
9
+ geoai/train.py,sha256=mQXat2yuddT-2rME4xnX_m3SkY23E_-zdxLnBIKxw8o,44091
10
+ geoai/utils.py,sha256=5BZTL9QlJGEs9uw5w6i_aZ4s8SH_FGvb6ZFlIyEHEZI,239703
11
+ geoai_py-0.5.1.dist-info/licenses/LICENSE,sha256=vN2L5U7cZ6ZkOHFmc8WiGlsogWsZc5dllMeNxnKVOZg,1070
12
+ geoai_py-0.5.1.dist-info/METADATA,sha256=9_A_dN9Vnl5C4Q_i7N8OdgTTo1Ke4wunve3ChsUvQnA,6637
13
+ geoai_py-0.5.1.dist-info/WHEEL,sha256=MAQBAzGbXNI3bUmkDsiV_duv8i-gcdnLzw7cfUFwqhU,109
14
+ geoai_py-0.5.1.dist-info/entry_points.txt,sha256=uGp3Az3HURIsRHP9v-ys0hIbUuBBNUfXv6VbYHIXeg4,41
15
+ geoai_py-0.5.1.dist-info/top_level.txt,sha256=1YkCUWu-ii-0qIex7kbwAvfei-gos9ycyDyUCJPNWHY,6
16
+ geoai_py-0.5.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (77.0.3)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any
@@ -1,15 +0,0 @@
1
- geoai/__init__.py,sha256=b12E2HztHEPaaKMVKpk6GPjC7ElUMxOW9pYKl4VZkmE,3592
2
- geoai/download.py,sha256=BvCEpcBwZlEOWieixsdyvQDiE0CXRjU7oayLmy5_Dgs,40110
3
- geoai/extract.py,sha256=GocJufMmrwEWxNBL1J91EXXHL8AKcO8m_lmtUF5AKPw,119102
4
- geoai/geoai.py,sha256=BqKdWzNruDdGqwqoyTaJzUq4lKGj-RDBZlSO3t3-GxQ,626
5
- geoai/hf.py,sha256=mLKGxEAS5eHkxZLwuLpYc1o7e3-7QIXdBv-QUY-RkFk,17072
6
- geoai/segment.py,sha256=g3YW17ftr--CKq6VB32TJEPY8owGQ7uQ0sg_tUT2ooE,13681
7
- geoai/segmentation.py,sha256=AtPzCvguHAEeuyXafa4bzMFATvltEYcah1B8ZMfkM_s,11373
8
- geoai/train.py,sha256=-l2j1leTxDnFDLaBslu1q6CobXjm3LEdiQwUWOU8P6M,40088
9
- geoai/utils.py,sha256=Wg9jbMBKUZSGUmU8Vkp6v19QcDNg5KmcyZxuHqJvgnc,233016
10
- geoai_py-0.4.3.dist-info/licenses/LICENSE,sha256=vN2L5U7cZ6ZkOHFmc8WiGlsogWsZc5dllMeNxnKVOZg,1070
11
- geoai_py-0.4.3.dist-info/METADATA,sha256=geDmJ-1zHImsOdcj4gypgq8JqSy8MznnxAnICwh0EbA,6049
12
- geoai_py-0.4.3.dist-info/WHEEL,sha256=aoLN90hLOL0c0qxXMxWYUM3HA3WmFGZQqEJHX1V_OJE,109
13
- geoai_py-0.4.3.dist-info/entry_points.txt,sha256=uGp3Az3HURIsRHP9v-ys0hIbUuBBNUfXv6VbYHIXeg4,41
14
- geoai_py-0.4.3.dist-info/top_level.txt,sha256=1YkCUWu-ii-0qIex7kbwAvfei-gos9ycyDyUCJPNWHY,6
15
- geoai_py-0.4.3.dist-info/RECORD,,