geoai-py 0.3.2__py2.py3-none-any.whl → 0.3.3__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/__init__.py +1 -1
- geoai/extract.py +38 -17
- geoai/geoai.py +0 -1
- geoai/preprocess.py +20 -6
- geoai/utils.py +3788 -13
- {geoai_py-0.3.2.dist-info → geoai_py-0.3.3.dist-info}/METADATA +11 -4
- geoai_py-0.3.3.dist-info/RECORD +13 -0
- geoai_py-0.3.2.dist-info/RECORD +0 -13
- {geoai_py-0.3.2.dist-info → geoai_py-0.3.3.dist-info}/LICENSE +0 -0
- {geoai_py-0.3.2.dist-info → geoai_py-0.3.3.dist-info}/WHEEL +0 -0
- {geoai_py-0.3.2.dist-info → geoai_py-0.3.3.dist-info}/entry_points.txt +0 -0
- {geoai_py-0.3.2.dist-info → geoai_py-0.3.3.dist-info}/top_level.txt +0 -0
geoai/__init__.py
CHANGED
geoai/extract.py
CHANGED
|
@@ -13,7 +13,7 @@ import rasterio
|
|
|
13
13
|
from rasterio.windows import Window
|
|
14
14
|
from rasterio.features import shapes
|
|
15
15
|
from huggingface_hub import hf_hub_download
|
|
16
|
-
from .
|
|
16
|
+
from .utils import get_raster_stats
|
|
17
17
|
|
|
18
18
|
try:
|
|
19
19
|
from torchgeo.datasets import NonGeoDataset
|
|
@@ -196,7 +196,8 @@ class ObjectDetector:
|
|
|
196
196
|
self.overlap = 0.25 # Default overlap between tiles
|
|
197
197
|
self.confidence_threshold = 0.5 # Default confidence threshold
|
|
198
198
|
self.nms_iou_threshold = 0.5 # IoU threshold for non-maximum suppression
|
|
199
|
-
self.
|
|
199
|
+
self.min_object_area = 100 # Minimum area in pixels to keep an object
|
|
200
|
+
self.max_object_area = None # Maximum area in pixels to keep an object
|
|
200
201
|
self.mask_threshold = 0.5 # Threshold for mask binarization
|
|
201
202
|
self.simplify_tolerance = 1.0 # Tolerance for polygon simplification
|
|
202
203
|
|
|
@@ -326,7 +327,8 @@ class ObjectDetector:
|
|
|
326
327
|
**kwargs: Optional parameters:
|
|
327
328
|
simplify_tolerance: Tolerance for polygon simplification
|
|
328
329
|
mask_threshold: Threshold for mask binarization
|
|
329
|
-
|
|
330
|
+
min_object_area: Minimum area in pixels to keep an object
|
|
331
|
+
max_object_area: Maximum area in pixels to keep an object
|
|
330
332
|
|
|
331
333
|
Returns:
|
|
332
334
|
List of polygons as lists of (x, y) coordinates
|
|
@@ -335,7 +337,8 @@ class ObjectDetector:
|
|
|
335
337
|
# Get parameters from kwargs or use instance defaults
|
|
336
338
|
simplify_tolerance = kwargs.get("simplify_tolerance", self.simplify_tolerance)
|
|
337
339
|
mask_threshold = kwargs.get("mask_threshold", self.mask_threshold)
|
|
338
|
-
|
|
340
|
+
min_object_area = kwargs.get("min_object_area", self.min_object_area)
|
|
341
|
+
max_object_area = kwargs.get("max_object_area", self.max_object_area)
|
|
339
342
|
|
|
340
343
|
# Ensure binary mask
|
|
341
344
|
mask = (mask > mask_threshold).astype(np.uint8)
|
|
@@ -351,7 +354,14 @@ class ObjectDetector:
|
|
|
351
354
|
polygons = []
|
|
352
355
|
for contour in contours:
|
|
353
356
|
# Filter out too small contours
|
|
354
|
-
if contour.shape[0] < 3 or cv2.contourArea(contour) <
|
|
357
|
+
if contour.shape[0] < 3 or cv2.contourArea(contour) < min_object_area:
|
|
358
|
+
continue
|
|
359
|
+
|
|
360
|
+
# Filter out too large contours
|
|
361
|
+
if (
|
|
362
|
+
max_object_area is not None
|
|
363
|
+
and cv2.contourArea(contour) > max_object_area
|
|
364
|
+
):
|
|
355
365
|
continue
|
|
356
366
|
|
|
357
367
|
# Simplify contour if it has many points
|
|
@@ -491,7 +501,8 @@ class ObjectDetector:
|
|
|
491
501
|
output_path=None,
|
|
492
502
|
simplify_tolerance=None,
|
|
493
503
|
mask_threshold=None,
|
|
494
|
-
|
|
504
|
+
min_object_area=None,
|
|
505
|
+
max_object_area=None,
|
|
495
506
|
nms_iou_threshold=None,
|
|
496
507
|
regularize=True,
|
|
497
508
|
angle_threshold=15,
|
|
@@ -505,7 +516,8 @@ class ObjectDetector:
|
|
|
505
516
|
output_path: Path to save the output GeoJSON (default: mask_path with .geojson extension)
|
|
506
517
|
simplify_tolerance: Tolerance for polygon simplification (default: self.simplify_tolerance)
|
|
507
518
|
mask_threshold: Threshold for mask binarization (default: self.mask_threshold)
|
|
508
|
-
|
|
519
|
+
min_object_area: Minimum area in pixels to keep an object (default: self.min_object_area)
|
|
520
|
+
max_object_area: Minimum area in pixels to keep an object (default: self.max_object_area)
|
|
509
521
|
nms_iou_threshold: IoU threshold for non-maximum suppression (default: self.nms_iou_threshold)
|
|
510
522
|
regularize: Whether to regularize objects to right angles (default: True)
|
|
511
523
|
angle_threshold: Maximum deviation from 90 degrees for regularization (default: 15)
|
|
@@ -523,10 +535,11 @@ class ObjectDetector:
|
|
|
523
535
|
mask_threshold = (
|
|
524
536
|
mask_threshold if mask_threshold is not None else self.mask_threshold
|
|
525
537
|
)
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
538
|
+
min_object_area = (
|
|
539
|
+
min_object_area if min_object_area is not None else self.min_object_area
|
|
540
|
+
)
|
|
541
|
+
max_object_area = (
|
|
542
|
+
max_object_area if max_object_area is not None else self.max_object_area
|
|
530
543
|
)
|
|
531
544
|
nms_iou_threshold = (
|
|
532
545
|
nms_iou_threshold
|
|
@@ -540,7 +553,8 @@ class ObjectDetector:
|
|
|
540
553
|
|
|
541
554
|
print(f"Converting mask to GeoJSON with parameters:")
|
|
542
555
|
print(f"- Mask threshold: {mask_threshold}")
|
|
543
|
-
print(f"- Min object area: {
|
|
556
|
+
print(f"- Min object area: {min_object_area}")
|
|
557
|
+
print(f"- Max object area: {max_object_area}")
|
|
544
558
|
print(f"- Simplify tolerance: {simplify_tolerance}")
|
|
545
559
|
print(f"- NMS IoU threshold: {nms_iou_threshold}")
|
|
546
560
|
print(f"- Regularize objects: {regularize}")
|
|
@@ -586,7 +600,11 @@ class ObjectDetector:
|
|
|
586
600
|
area = stats[i, cv2.CC_STAT_AREA]
|
|
587
601
|
|
|
588
602
|
# Skip if too small
|
|
589
|
-
if area <
|
|
603
|
+
if area < min_object_area:
|
|
604
|
+
continue
|
|
605
|
+
|
|
606
|
+
# Skip if too large
|
|
607
|
+
if max_object_area is not None and area > max_object_area:
|
|
590
608
|
continue
|
|
591
609
|
|
|
592
610
|
# Create a mask for this object
|
|
@@ -710,7 +728,7 @@ class ObjectDetector:
|
|
|
710
728
|
chip_size: Size of image chips for processing (height, width)
|
|
711
729
|
nms_iou_threshold: IoU threshold for non-maximum suppression (0.0-1.0)
|
|
712
730
|
mask_threshold: Threshold for mask binarization (0.0-1.0)
|
|
713
|
-
|
|
731
|
+
min_object_area: Minimum area in pixels to keep an object
|
|
714
732
|
simplify_tolerance: Tolerance for polygon simplification
|
|
715
733
|
|
|
716
734
|
Returns:
|
|
@@ -724,7 +742,8 @@ class ObjectDetector:
|
|
|
724
742
|
chip_size = kwargs.get("chip_size", self.chip_size)
|
|
725
743
|
nms_iou_threshold = kwargs.get("nms_iou_threshold", self.nms_iou_threshold)
|
|
726
744
|
mask_threshold = kwargs.get("mask_threshold", self.mask_threshold)
|
|
727
|
-
|
|
745
|
+
min_object_area = kwargs.get("min_object_area", self.min_object_area)
|
|
746
|
+
max_object_area = kwargs.get("max_object_area", self.max_object_area)
|
|
728
747
|
simplify_tolerance = kwargs.get("simplify_tolerance", self.simplify_tolerance)
|
|
729
748
|
|
|
730
749
|
# Print parameters being used
|
|
@@ -734,7 +753,8 @@ class ObjectDetector:
|
|
|
734
753
|
print(f"- Chip size: {chip_size}")
|
|
735
754
|
print(f"- NMS IoU threshold: {nms_iou_threshold}")
|
|
736
755
|
print(f"- Mask threshold: {mask_threshold}")
|
|
737
|
-
print(f"- Min object area: {
|
|
756
|
+
print(f"- Min object area: {min_object_area}")
|
|
757
|
+
print(f"- Max object area: {max_object_area}")
|
|
738
758
|
print(f"- Simplify tolerance: {simplify_tolerance}")
|
|
739
759
|
print(f"- Filter edge objects: {filter_edges}")
|
|
740
760
|
if filter_edges:
|
|
@@ -865,7 +885,8 @@ class ObjectDetector:
|
|
|
865
885
|
binary_mask,
|
|
866
886
|
simplify_tolerance=simplify_tolerance,
|
|
867
887
|
mask_threshold=mask_threshold,
|
|
868
|
-
|
|
888
|
+
min_object_area=min_object_area,
|
|
889
|
+
max_object_area=max_object_area,
|
|
869
890
|
)
|
|
870
891
|
|
|
871
892
|
# Skip if no valid polygons
|
geoai/geoai.py
CHANGED
geoai/preprocess.py
CHANGED
|
@@ -288,7 +288,11 @@ def get_vector_info(vector_path):
|
|
|
288
288
|
dict: Dictionary containing the basic information about the vector dataset
|
|
289
289
|
"""
|
|
290
290
|
# Open the vector dataset
|
|
291
|
-
gdf =
|
|
291
|
+
gdf = (
|
|
292
|
+
gpd.read_parquet(vector_path)
|
|
293
|
+
if vector_path.endswith(".parquet")
|
|
294
|
+
else gpd.read_file(vector_path)
|
|
295
|
+
)
|
|
292
296
|
|
|
293
297
|
# Get basic metadata
|
|
294
298
|
info = {
|
|
@@ -359,7 +363,11 @@ def print_vector_info(vector_path, show_preview=True, figsize=(10, 8)):
|
|
|
359
363
|
|
|
360
364
|
# Show a preview if requested
|
|
361
365
|
if show_preview:
|
|
362
|
-
gdf =
|
|
366
|
+
gdf = (
|
|
367
|
+
gpd.read_parquet(vector_path)
|
|
368
|
+
if vector_path.endswith(".parquet")
|
|
369
|
+
else gpd.read_file(vector_path)
|
|
370
|
+
)
|
|
363
371
|
fig, ax = plt.subplots(figsize=figsize)
|
|
364
372
|
gdf.plot(ax=ax, cmap="viridis")
|
|
365
373
|
ax.set_title(f"Preview: {vector_path}")
|
|
@@ -2813,7 +2821,8 @@ def masks_to_vector(
|
|
|
2813
2821
|
output_path=None,
|
|
2814
2822
|
simplify_tolerance=1.0,
|
|
2815
2823
|
mask_threshold=0.5,
|
|
2816
|
-
|
|
2824
|
+
min_object_area=100,
|
|
2825
|
+
max_object_area=None,
|
|
2817
2826
|
nms_iou_threshold=0.5,
|
|
2818
2827
|
):
|
|
2819
2828
|
"""
|
|
@@ -2824,7 +2833,8 @@ def masks_to_vector(
|
|
|
2824
2833
|
output_path: Path to save the output GeoJSON (default: mask_path with .geojson extension)
|
|
2825
2834
|
simplify_tolerance: Tolerance for polygon simplification (default: self.simplify_tolerance)
|
|
2826
2835
|
mask_threshold: Threshold for mask binarization (default: self.mask_threshold)
|
|
2827
|
-
|
|
2836
|
+
min_object_area: Minimum area in pixels to keep a building (default: self.min_object_area)
|
|
2837
|
+
max_object_area: Maximum area in pixels to keep a building (default: self.max_object_area)
|
|
2828
2838
|
nms_iou_threshold: IoU threshold for non-maximum suppression (default: self.nms_iou_threshold)
|
|
2829
2839
|
|
|
2830
2840
|
Returns:
|
|
@@ -2836,7 +2846,7 @@ def masks_to_vector(
|
|
|
2836
2846
|
|
|
2837
2847
|
print(f"Converting mask to GeoJSON with parameters:")
|
|
2838
2848
|
print(f"- Mask threshold: {mask_threshold}")
|
|
2839
|
-
print(f"- Min building area: {
|
|
2849
|
+
print(f"- Min building area: {min_object_area}")
|
|
2840
2850
|
print(f"- Simplify tolerance: {simplify_tolerance}")
|
|
2841
2851
|
print(f"- NMS IoU threshold: {nms_iou_threshold}")
|
|
2842
2852
|
|
|
@@ -2876,7 +2886,11 @@ def masks_to_vector(
|
|
|
2876
2886
|
area = stats[i, cv2.CC_STAT_AREA]
|
|
2877
2887
|
|
|
2878
2888
|
# Skip if too small
|
|
2879
|
-
if area <
|
|
2889
|
+
if area < min_object_area:
|
|
2890
|
+
continue
|
|
2891
|
+
|
|
2892
|
+
# Skip if too large
|
|
2893
|
+
if max_object_area is not None and area > max_object_area:
|
|
2880
2894
|
continue
|
|
2881
2895
|
|
|
2882
2896
|
# Create a mask for this building
|