r"""
Uses the building detector to validate a construction event.
Given a site model:
* search for the K highest quality images at the start of the sequences.
* search for the K highest quality images at the end of the sequence.
* run the building detector on all of the chosen images.
* test if the site boundary intersects detections in the start images.
* test if the site boundary intersects detections in the end images.
.. code::
StartTest | EndTest | Result
----------+---------+-------
T | T | Reject
----------+---------+-------
T | F | Reject
----------+---------+-------
F | T | Accept
----------+---------+-------
F | F | Reject
----------+---------+-------
? | T | Accept
----------+---------+-------
T | ? | Reject
----------+---------+-------
? | F | Reject
----------+---------+-------
F | ? | Accept
----------+---------+-------
Dataflow:
* BAS outputs a region model with candidate site summaries
* We should be given a kwcoco path that indexes all of the data we could
look at. In MLOPs this will be a region cropped kwcoco path that indexes
existant images on disk. In smartflow this will be a virtual kwcoco file
that requires network access.
"""
#!/usr/bin/env python3
import scriptconfig as scfg
import ubelt as ub
[docs]
class BuildingValidatorConfig(scfg.DataConfig):
input_kwcoco = scfg.Value(None, help='input')
input_region = scfg.Value(None)
input_sites = scfg.Value(None)
output_region_fpath = scfg.Value(None)
output_sites_dpath = scfg.Value(None)
output_site_manifest_fpath = scfg.Value(None)
box_isect_threshold = scfg.Value(0.1, help='This fraction of the a detected building box must intersect the proposed polygon')
box_score_threshold = scfg.Value(0.01, help='The detected building boxes must have a score higher than this')
start_max_score = scfg.Value(1.0, help='The max building score needed in the start sequence')
end_min_score = scfg.Value(0.1, help='The min building score needed in the end sequence')
IGNORE_CLASS_NAMES = ub.codeblock(
'''
Fixed-wing Aircraft
Small Aircraft
Cargo Plane
Helicopter
Passenger Vehicle
Small Car
Bus
Pickup Truck
Utility Truck
Truck
Cargo Truck
Truck w/Box
Truck Tractor
Trailer
Truck w/Flatbed
Truck w/Liquid
Crane Truck
Railway Vehicle
Passenger Car
Cargo Car
Flat Car
Tank car
Locomotive
Maritime Vessel
Motorboat
Sailboat
Tugboat
Barge
Fishing Vessel
Ferry
Yacht
Container Ship
Oil Tanker
Engineering Vehicle
Tower crane
Container Crane
Reach Stacker
Straddle Carrier
Mobile Crane
Dump Truck
Haul Truck
Scraper/Tractor
Front loader/Bulldozer
Excavator
Cement Mixer
Ground Grader
''').split('\n')
DONT_IGNORE_CLASSNAMES = ub.codeblock(
'''
Aircraft Hangar
Helipad
Storage Tank
Hut/Tent
Shipping container lot
Shipping Container
Pylon
Tower
Shed
Building
Damaged Building
Facility
Construction Site
Vehicle Lot
''').split('\n')
[docs]
def main(cmdline=1, **kwargs):
"""
Ignore:
from geowatch.tasks.dino_detector.building_validator import * # NOQA
NODE_DPATH = '/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/buildings/buildings_id_fd298dba'
from geowatch.utils.partial_format import fsubtemplate
coco_fpath = fsubtemplate('$NODE_DPATH/pred_boxes.kwcoco.zip')
from kwutil.util_path import coerce_patterned_paths
site_summary = ub.Path(fsubtemplate('$NODE_DPATH/.pred/sv_crop/*/.pred/bas_poly/*/site_summaries_manifest.json'))
site_summary = ub.Path(fsubtemplate('$NODE_DPATH/.pred/valicrop/*/.pred/bas_poly/*/site_summaries_manifest.json'))
site_summary = coerce_patterned_paths(site_summary)[0]
output_region_fpath = ub.Path(fsubtemplate('$NODE_DPATH/filtered_site_summaries.geojson'))
kwargs = {
'input_kwcoco': coco_fpath,
'input_region': site_summary,
'input_sites': (site_summary.parent / 'sites'),
'output_region_fpath': output_region_fpath,
}
cmdline = 0
Ignore:
>>> import geowatch
>>> dvc_data_dpath = geowatch.find_dvc_dpath(tags='phase2_data', hardware='auto')
>>> coco_fpath = dvc_data_dpath / 'Drop6/imgonly-KR_R001.kwcoco.json'
>>> region_fpath = dvc_data_dpath / 'annotations/drop6_hard_v1/region_models/KR_R001.geojson'
Example:
>>> # xdoctest: +SKIP
>>> cmdline = 0
>>> kwargs = dict()
>>> main(cmdline=cmdline, **kwargs)
"""
config = BuildingValidatorConfig.cli(cmdline=cmdline, data=kwargs, strict=True)
import rich
rich.print('config = ' + ub.urepr(config, nl=1))
from geowatch.geoannots import geomodels
from kwgis.utils import util_gis
import kwcoco
from geowatch.cli import reproject_annotations
from kwcoco.util import util_json
from geowatch.utils import process_context
import os
import safer
import json
# Args will be serailized in kwcoco, so make sure it can be coerced to json
jsonified_config = util_json.ensure_json_serializable(config.asdict())
walker = ub.IndexableWalker(jsonified_config)
for problem in util_json.find_json_unserializable(jsonified_config):
bad_data = problem['data']
walker[problem['loc']] = str(bad_data)
filter_output = {
'type': 'tracking_result',
'info': [],
'files': [],
}
# Track process info
proc_context = process_context.ProcessContext(
name='geowatch.tasks.dino_detector.building_validator', type='process',
config=jsonified_config,
track_emissions=False,
)
proc_context.start()
filter_output['info'].append(proc_context.obj)
input_coco = kwcoco.CocoDataset(config.input_kwcoco)
region_model = geomodels.RegionModel.coerce(config.input_region)
output_region_fpath = ub.Path(config.output_region_fpath)
input_site_fpaths = util_gis.coerce_geojson_paths(config.input_sites)
# set(input_coco.annots().lookup('track_id', None))
site_to_site_fpath = ub.udict({
p.stem: p for p in input_site_fpaths
})
input_sites = list(geomodels.SiteModel.coerce_multiple(site_to_site_fpath.values()))
site_id_to_summary = ub.udict()
for summary in region_model.site_summaries():
assert summary.site_id not in site_id_to_summary
site_id_to_summary[summary.site_id] = summary
##
# Ensure caches
for summary in site_id_to_summary.values():
summary['properties'].setdefault('cache', {})
for site in input_sites:
site.header['properties'].setdefault('cache', {})
output_kwcoco = reproject_annotations.main(
cmdline=0, src=input_coco.copy(),
dst='return',
region_models=config.input_region,
status_to_catname={'system_confirmed': 'positive'},
role='pred_poly',
validate_checks=False,
clear_existing=False,
)
if 0:
from geowatch.utils import util_framework
region_models = [region_model]
site_models = input_sites
util_framework.check_region_and_site_models_agree(region_models, site_models)
site_to_decisions = make_decisions(output_kwcoco, site_id_to_summary, config)
num_accept = sum(d['accept'] for s, d in site_to_decisions.items())
print(f'Filter to {num_accept} / {len(site_id_to_summary)} sites')
# Enrich each site summary with the decision reason and update status
for site_id, decision in site_to_decisions.items():
sitesum = site_id_to_summary[site_id]
# Change the status of sites to "system_rejected" instead of droping them
if not decision['accept']:
sitesum['properties']['status'] = 'system_rejected'
if 'cache' not in sitesum['properties']:
sitesum['properties']['cache'] = {}
sitesum['properties']['cache']['dino_decision'] = decision
# Copy the site models and update their header with new summary
# information.
output_sites_dpath = ub.Path(config.output_sites_dpath)
output_sites_dpath.ensuredir()
out_site_fpaths = []
for old_site in input_sites:
site_id = old_site.site_id
old_fpath = site_to_site_fpath[site_id]
new_fpath = output_sites_dpath / old_fpath.name
new_summary = site_id_to_summary[site_id]
old_site.header['properties']['status'] = new_summary['properties']['status']
if 'cache' not in old_site.header['properties']:
old_site.header['properties']['cache'] = {}
old_site.header['properties']['cache'].update(new_summary['properties']['cache'])
new_fpath.write_text(old_site.dumps())
out_site_fpaths.append(new_fpath)
# Write the updated site summaries in a new region model
new_summaries = list(site_id_to_summary.values())
new_region_model = geomodels.RegionModel.from_features(
[region_model.header] + list(new_summaries))
output_region_fpath.parent.ensuredir()
if 1:
from geowatch.utils import util_framework
region_models = [region_model]
site_models = input_sites
util_framework.check_region_and_site_models_agree([new_region_model], site_models)
print(f'Write filtered region model to: {output_region_fpath}')
with safer.open(output_region_fpath, 'w', temp_file=not ub.WIN32) as file:
json.dump(new_region_model, file, indent=4)
# from kwutil.util_json import debug_json_unserializable
# debug_json_unserializable(new_region_model)
proc_context.stop()
if config.output_site_manifest_fpath is not None:
filter_output['files'] = [os.fspath(p) for p in out_site_fpaths]
print(f'Write filtered site result to {config.output_site_manifest_fpath}')
with safer.open(config.output_site_manifest_fpath, 'w', temp_file=not ub.WIN32) as file:
json.dump(filter_output, file, indent=4)
[docs]
def make_decisions(output_kwcoco, site_id_to_summary, config):
"""
Make yes/no decision about sites with dino predictions in the kwcoco file.
Returns:
Dict: mapping from site-ids to the decision made for it
"""
from kwcoco.util import util_json
from kwutil import util_time
# Enrich all sites with features (evidence) and decisions.
site_to_decisions = {
s: {
'type': 'dino_decision',
'accept': True,
'why': None,
'features': None,
}
for s in site_id_to_summary.keys()
}
for video_id in ub.ProgIter(output_kwcoco.videos(), desc='validate sites'):
video = output_kwcoco.index.videos[video_id]
video_name = video['name'] # the vide name should be the site id
summary = site_id_to_summary[video_name]
site_id = summary.site_id
video_images = output_kwcoco.images(video_id=video_id)
start_date = summary.start_date
end_date = summary.end_date
# Get the starting and ending observations
start_images = []
end_images = []
for coco_img in video_images.coco_images:
img_time = util_time.coerce_datetime(coco_img['date_captured'])
dist_start = abs(img_time - start_date)
dist_end = abs(img_time - end_date)
if dist_end < dist_start:
end_images.append(coco_img)
else:
start_images.append(coco_img)
start_features = []
end_features = []
try:
for coco_img in start_images:
feat = building_in_image_features(coco_img, site_id, config)
feat['datetime'] = coco_img['date_captured']
feat['type'] = 'start_feature'
start_features.append(feat)
for coco_img in end_images:
feat = building_in_image_features(coco_img, site_id, config)
feat['datetime'] = coco_img['date_captured']
feat['type'] = 'end_feature'
end_features.append(feat)
if len(start_features) and len(end_features):
max_start_score = max(f['max_score'] for f in start_features)
max_end_score = max(f['max_score'] for f in end_features)
accept = bool(
max_start_score <= config.start_max_score and
max_end_score >= config.end_min_score
)
why = 'threshold'
else:
# Unobservable case, automatically accept
accept = True
why = 'unobservable'
except CouldNotValidate:
accept = True
why = 'CouldNotValidate'
decision = site_to_decisions[site_id]
decision['accept'] = accept
decision['why'] = why
decision['features'] = start_features + end_features
decision = util_json.ensure_json_serializable(decision)
site_to_decisions[site_id] = decision
return site_to_decisions
[docs]
def building_in_image_features(coco_img, site_id, config):
import numpy as np
import kwimage
import geopandas as gpd
import warnings
annots = coco_img.annots()
flags = np.array([r == 'pred_poly' for r in annots.lookup('role', None)], dtype=bool)
box_annots = annots.compress(~flags)
poly_annots = annots.compress(flags)
is_main_poly = [t == site_id for t in poly_annots.lookup('track_id')]
main_poly_annots = poly_annots.compress(is_main_poly)
if len(main_poly_annots) > 1:
warnings.warn('FIXME: Len of "main-poly-annots" is not 1.')
elif len(main_poly_annots) == 0:
raise CouldNotValidate('We dont expect to be here')
flags = [cname not in IGNORE_CLASS_NAMES for cname in box_annots.category_names]
box_annots = box_annots.compress(flags)
iooa_thresh = config.box_isect_threshold
score_thresh = config.box_score_threshold
box_gdf = gpd.GeoDataFrame({
'geometry': box_annots.boxes.to_shapely(),
'class': box_annots.category_names,
'score': box_annots.lookup('score'),
})
box_gdf = box_gdf[box_gdf.score > score_thresh]
proposal_gdf = gpd.GeoDataFrame({
'geometry': [
kwimage.MultiPolygon.coerce(p).to_shapely()
for p in main_poly_annots.lookup('segmentation')
],
})
proposal_geom = proposal_gdf.iloc[0]['geometry']
with warnings.catch_warnings():
warnings.filterwarnings('ignore', 'invalid value encountered in intersection')
intersections = box_gdf.intersection(proposal_geom)
bad_flags = (intersections.isnull() | intersections.is_empty)
isect_flags = (~bad_flags) & (intersections.is_valid)
feat = {
'max_iou': 0,
'max_iooa': 0,
'max_score': 0,
'num_cands': 0,
}
if isect_flags.any():
cand_boxes = box_gdf[isect_flags]
cand_isects = intersections[isect_flags]
cand_iooa1 = cand_isects.area / cand_boxes.area
ioaa_flags = cand_iooa1 > iooa_thresh
if ioaa_flags.any():
cand_boxes = cand_boxes[ioaa_flags]
cand_unions = cand_boxes.union(proposal_geom)
cand_ious = cand_isects.area / cand_unions.area
feat['max_iou'] = cand_ious.max()
feat['max_iooa'] = cand_iooa1.max()
feat['max_score'] = cand_boxes['score'].max()
feat['num_cands'] = len(cand_boxes)
return feat
[docs]
class CouldNotValidate(Exception):
...
if __name__ == '__main__':
"""
CommandLine:
python ~/code/watch/geowatch/tasks/dino_detector/building_validator.py
python -m geowatch.tasks.dino_detector.building_validator
"""
main()
"""
Ignore:
DVC_DATA_DPATH=$(geowatch_dvc --tags='phase2_data' --hardware=auto)
DVC_EXPT_DPATH=$(geowatch_dvc --tags='phase2_expt' --hardware=auto)
geowatch schedule --params="
matrix:
bas_pxl.package_fpath:
- $DVC_EXPT_DPATH/models/fusion/Drop6-MeanYear10GSD/packages/Drop6_TCombo1Year_BAS_10GSD_split6_V42_cont2/Drop6_TCombo1Year_BAS_10GSD_split6_V42_cont2_epoch3_step941.pt
bas_pxl.test_dataset:
- $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-KR_R002.kwcoco.zip
- $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-BR_R002.kwcoco.zip
- $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-CH_R001.kwcoco.zip
- $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-NZ_R001.kwcoco.zip
- $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-KR_R001.kwcoco.zip
- $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-AE_R001.kwcoco.zip
bas_pxl.chip_overlap: 0.3
bas_pxl.chip_dims:
- auto
bas_pxl.time_span:
- auto
bas_pxl.time_sampling:
# - auto
# - soft5
- soft4
bas_poly.thresh:
- 0.33
#- 0.38
#- 0.4
bas_poly.inner_window_size:
- 1y
#- null
bas_poly.inner_agg_fn:
- mean
bas_poly.norm_ord:
#- 1
- inf
bas_poly.polygon_simplify_tolerance:
- 1
bas_poly.agg_fn:
- probs
bas_poly.resolution:
- 10GSD
bas_poly.moving_window_size:
- null
#- 1
bas_poly.poly_merge_method:
- 'v2'
#- 'v1'
bas_poly.min_area_square_meters:
- 7200
bas_poly.max_area_square_meters:
- 8000000
bas_poly.boundary_region: $DVC_DATA_DPATH/annotations/drop6/region_models
bas_poly_eval.true_site_dpath: $DVC_DATA_DPATH/annotations/drop6/site_models
bas_poly_eval.true_region_dpath: $DVC_DATA_DPATH/annotations/drop6/region_models
bas_pxl.enabled: 1
bas_pxl_eval.enabled: 1
bas_poly.enabled: 1
bas_poly_eval.enabled: 1
bas_poly_viz.enabled: 0
sv_crop.enabled: 1
sv_crop.minimum_size: "256x256@2GSD"
sv_crop.num_start_frames: 3
sv_crop.num_end_frames: 3
sv_crop.context_factor: 1.5
sv_dino_boxes.enabled: 1
sv_dino_boxes.package_fpath: $DVC_EXPT_DPATH/models/kitware/xview_dino.pt
sv_dino_boxes.window_dims:
- 256
- 512
- 768
- 1024
# - 1536
sv_dino_boxes.window_overlap:
- "0.5"
sv_dino_boxes.fixed_resolution:
- "1GSD"
- "2GSD"
- "2.5GSD"
- "3GSD"
- "3.3GSD"
sv_dino_filter.box_isect_threshold:
- 0.1
sv_dino_filter.box_score_threshold:
- 0.01
sv_dino_filter.start_max_score:
- 1.0
- 0.8
# - 0.5
sv_dino_filter.end_min_score:
- 0.0
# - 0.05
- 0.1
- 0.15
- 0.2
- 0.25
- 0.3
# - 0.4
- 0.5
submatrices:
- bas_pxl.test_dataset: $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-KR_R001.kwcoco.zip
sv_crop.crop_src_fpath: $DVC_DATA_DPATH/Drop6/imgonly-KR_R001.kwcoco.json
- bas_pxl.test_dataset: $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-KR_R002.kwcoco.zip
sv_crop.crop_src_fpath: $DVC_DATA_DPATH/Drop6/imgonly-KR_R002.kwcoco.json
- bas_pxl.test_dataset: $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-BR_R002.kwcoco.zip
sv_crop.crop_src_fpath: $DVC_DATA_DPATH/Drop6/imgonly-BR_R002.kwcoco.json
- bas_pxl.test_dataset: $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-CH_R001.kwcoco.zip
sv_crop.crop_src_fpath: $DVC_DATA_DPATH/Drop6/imgonly-CH_R001.kwcoco.json
- bas_pxl.test_dataset: $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-NZ_R001.kwcoco.zip
sv_crop.crop_src_fpath: $DVC_DATA_DPATH/Drop6/imgonly-NZ_R001.kwcoco.json
- bas_pxl.test_dataset: $DVC_DATA_DPATH/Drop6-MeanYear10GSD-V2/imganns-AE_R001.kwcoco.zip
sv_crop.crop_src_fpath: $DVC_DATA_DPATH/Drop6/imgonly-AE_R001.kwcoco.json
" \
--root_dpath="$DVC_EXPT_DPATH/_mlops_eval10_baseline" \
--devices="0," --tmux_workers=8 \
--backend=tmux --queue_name "_mlops_eval10_baseline" \
--pipeline=bas_building_vali --skip_existing=1 \
--run=1
DVC_EXPT_DPATH=$(geowatch_dvc --tags='phase2_expt' --hardware=auto)
gwmlops aggregate \
--pipeline=bas_building_vali \
--target \
"$DVC_EXPT_DPATH/_mlops_eval10_baseline" \
--resource_report=0 \
--rois='[KR_R002,KR_R001,BR_R002,CH_R001,NZ_R001,AE_R001]' \
--stdout_report="
top_k: 5
per_group: 1
macro_analysis: 0
analyze: 0
reference_region: final
shorten: 1
" --eval_nodes="[sv_poly_eval]" \
--plot_params="
enabled: True
"
--rois='[NZ_R001,KR_R001]' \
print_models: True
geowatch align \
--src "/home/joncrall/remote/toothbrush/data/dvc-repos/smart_data_dvc-ssd/Drop6/imgonly-KR_R001.kwcoco.json" \
--dst "/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/sv_crop/valicrop_id_2e8c8dc3/sv_crop.kwcoco.zip" \
--regions="/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/bas_poly/bas_poly_id_dc32b2a6/site_summaries_manifest.json" \
--site_summary=True \
--verbose="1" \
--workers="32" \
--aux_workers="4" \
--debug_valid_regions="False" \
--visualize="False" \
--keep="img" \
--geo_preprop="auto" \
--minimum_size="256x256@2GSD" \
--num_start_frames="3" \
--num_end_frames="3" \
--context_factor="1.5" \
--include_sensors="WV" \
--force_nodata="-9999" \
--rpc_align_method="orthorectify" \
--target_gsd="2" \
--force_min_gsd="2" \
--convexify_regions="True"
geowatch visualize /home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/sv_crop/valicrop_id_2e8c8dc3/sv_crop.kwcoco.zip --smart
python ~/code/watch/dev/wip/grid_sitevali_crops.py /home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/sv_crop/valicrop_id_2e8c8dc3/_viz_*
python -m geowatch.tasks.dino_detector.predict \
--package_fpath="/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/models/kitware/xview_dino.pt" \
--coco_fpath="/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/sv_crop/valicrop_id_2e8c8dc3/sv_crop.kwcoco.zip" \
--out_coco_fpath="/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/buildings/buildings_id_61b8c2c7/pred_boxes.kwcoco.zip" \
--device="0" \
--data_workers="2" \
--fixed_resolution="1.0GSD" \
--window_dims="2048" \
--batch_size="1"
geowatch visualize /home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/buildings/buildings_id_61b8c2c7/pred_and_truth.kwcoco.zip \
--resolution=2GSD \
--smart \
--ann_score_thresh=0.3 \
--viz_dpath /home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/buildings/buildings_id_61b8c2c7/_vizme
python ~/code/watch/dev/wip/grid_sitevali_crops.py --sub=_anns \
/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/buildings/buildings_id_61b8c2c7/_vizme
NODE_DPATH=/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/buildings/buildings_id_fd298dba
DVC_DATA_DPATH=$(geowatch_dvc --tags='phase2_data' --hardware=auto)
geowatch reproject \
--src "$NODE_DPATH/pred_boxes.kwcoco.zip" \
--dst "$NODE_DPATH/pred_boxes_with_polys.kwcoco.zip" \
--region_models "$NODE_DPATH/.pred/sv_crop/*/.pred/bas_poly/*/site_summaries_manifest.json" \
--status_to_catname="{system_confirmed: positive}" \
--role=pred_poly \
--validate_checks=False \
--clear_existing=False
geowatch reproject \
--src "$NODE_DPATH/pred_boxes_with_polys.kwcoco.zip" \
--dst "$NODE_DPATH/pred_and_truth.kwcoco.zip" \
--region_models="$DVC_DATA_DPATH/annotations/drop6/region_models/*.geojson" \
--site_models="$DVC_DATA_DPATH/annotations/drop6/site_models/*.geojson" \
--status_to_catname="{system_confirmed: positive}" \
--role=truth \
--clear_existing=False
gw visualize --smart 1 \
--ann_score_thresh 0.5 \
--draw_labels False \
--alpha 0.5 \
--src $NODE_DPATH/pred_and_truth.kwcoco.zip \
--viz_dpath $NODE_DPATH/_vizme \
python ~/code/watch/dev/wip/grid_sitevali_crops.py \
--sub=_anns \
$NODE_DPATH/_vizme
python -m geowatch.tasks.dino_detector.building_validator \
--input_kwcoco "$NODE_DPATH/pred_boxes.kwcoco.zip" \
--input_region $NODE_DPATH/.pred/sv_crop/*/.pred/bas_poly/*/site_summaries_manifest.json \
--output_region_fpath "$NODE_DPATH/filtered_summaries.json" \
--box_isect_threshold 0.1 \
--box_score_threshold 0.1 \
--start_max_score 0.0 \
--end_min_score 0.3
python -m geowatch.tasks.dino_detector.building_validator \
--input_kwcoco="/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/buildings/buildings_id_663bd461/pred_boxes.kwcoco.zip" \
--input_region="/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/bas_poly/bas_poly_id_f8061df6/site_summaries_manifest.json" \
--input_sites="/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/bas_poly/bas_poly_id_f8061df6/sites_manifest.json" \
--output_region_fpath="/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/building_validate/building_validate_id_60a56eed/out_region.geojson" \
--output_sites_dpath="/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/building_validate/building_validate_id_60a56eed/out_sites" \
--output_site_manifest_fpath="/home/joncrall/remote/toothbrush/data/dvc-repos/smart_expt_dvc/_mlops_eval10_baseline/pred/flat/building_validate/building_validate_id_60a56eed/out_site_manifest.json" \
--box_isect_threshold="0.1" \
--box_score_threshold="0.1" \
--start_max_score="0.1" \
--end_min_score="0.3"
"""