Feature detection and regularization#
When you have imagery but no inventory, rAPIdtools can discover assets itself. SAM 3 scans a raster for a text concept and returns polygons, and the regularizers turn those raw masks into clean building footprints or road centrelines.
Finding assets in a raster#
SAM3OrthoFeatureExtractor tiles a raster into
square patches of a real-world size, runs SAM 3 on each batch with your
prompt, and maps the resulting masks back to WGS84 polygons.
from rapidtools import SAM3OrthoFeatureExtractor
extractor = SAM3OrthoFeatureExtractor(
prompt='building roof',
patch_size=50, unit='meters', # tile size on the ground
overlap_ratio=0.25, # overlap between tiles to avoid edge cuts
batch_size=4,
threshold=0.5, # detection confidence
mask_threshold=0.4, # mask binarization
)
buildings = extractor('eaton_bing.tiff')
buildings.to_geojson('buildings_preliminary.geojson')
Smaller patches keep texture visible for small objects; larger ones are
faster and suit roads and vegetation. Because neighbouring tiles overlap,
the same object is often detected more than once. By default touching
detections dissolve into one polygon, which is right for roofs, roads and
vegetation. For countable objects such as vehicles, pass
merge_overlaps=False to keep one asset per instance with its SAM 3
confidence, and only remove duplicates seen from overlapping tiles.
Segmenting attached images#
SAM3ImageSegmenter runs the same model on the
images already attached to assets, batching across the whole collection, and
stores the masks and boxes in each asset’s attributes under sam3_masks
and sam3_bounding_boxes.
Regularizing building footprints#
Raw masks from a basemap are jagged, sometimes merged with a neighbour, and
occasionally hallucinated. BuildingRegularizer
crops high-resolution imagery around each preliminary footprint, runs SAM 3
again at the higher resolution, and keeps a mask only when it agrees with
its seed (by intersection-over-union or recall). Merged seeds are split,
fragments closer than max_gap_bridge_ft are bridged, and dropped assets
get a second, lower-threshold pass to rescue buildings in shadow.
from rapidtools import AerialImageryExtractor, BuildingRegularizer
with_crops = AerialImageryExtractor(
'eaton_bing.tiff', save_directory='output/crops',
buffer_asset='20 m', force_square_image=True,
)(buildings)
final = BuildingRegularizer(prompt='building roof', batch_size=8)(with_crops)
Every image the regularizer reads must carry georeferencing in its
properties, which AerialImageryExtractor
writes automatically: native_georef (the crop’s affine transform and
CRS, used to vectorize masks in the raster’s own grid before reprojecting to
WGS84) and wgs84_bounds. Crops from older runs that only have
wgs84_bounds still work, but their polygons are mapped through the
lon/lat envelope, which is exact only for north-up WGS84 rasters.
Regularizing roads#
RoadwayRegularizer extracts a Voronoi
skeleton from raw road polygons, heals the graph, merges collinear segments,
samples widths statistically and drops disconnected stubs shorter than
min_network_length_ft. It returns both centrelines and rebuilt polygons.
from rapidtools import RoadwayRegularizer, SAM3OrthoFeatureExtractor
raw = SAM3OrthoFeatureExtractor(
prompt='paved road, street', patch_size=100, unit='meters',
threshold=0.25, mask_threshold=0.25,
)('eaton_patch_20250214.tiff')
centerlines, polygons = RoadwayRegularizer(min_width_ft=22)(raw)
centerlines[0].attributes
# {'asset_type': 'road_centerline', 'width_ft': 24.5, 'azimuth_deg': 91.2}