geowatch.heuristics module¶
In the interest of development speed we can’t always be perfect about correctly passing the right metadata to functions that need it. This module serves as a place to store hard-coded heuristics so we are explicit about where we are cutting corners or using magic numbers. The idea is that this will make it easier for us to go back and make the code robust.
References
https://gitlab.kitware.com/smart/annotations-wiki/-/blob/main/Annotation-Status-Types.md
- geowatch.heuristics.DEFAULT_QA_ENCODING = 'ARA-4'¶
Status Data Info¶
The following is a long-form table, where list-items are rows and keys are columns to describe how to interpret IARPA annotation status labels in different cases. More information on status labels can be found in [TEAnnotStatus] and in our internal fork [KWAnnotStatus].
- Column Info:
- status:
the name of the site status label
- color:
what color to use for this status in visualizations. These are mostly taken from [EvalMetricColors], but in cases where they are undefined we make them up.
- kwcoco_catname:
what category to map this status to in the kwcoco dataset (and thus what will be learned), Note: a status is different than a phase label, and annotations with phase labels may overwrite the kwcoco category defined here. This is used in geowatch reproject.
- positive_match_confusion
This is the label the truth is given when it has some match in our set of positive predictions. Denote what type of confusion a truth status incurs when it is matched.
The following code prints a concice version of this table and shows a legend with colors.
from geowatch.heuristics import * # NOQA import pandas as pd import rich df = pd.DataFrame(HUERISTIC_STATUS_DATA) rich.print(df.to_string()) import kwplot kwplot.autompl() status_to_color = {r['status']: r['color'] for r in HUERISTIC_STATUS_DATA} img = kwplot.make_legend_img(status_to_color, dpi=300) kwplot.imshow(img, fnum=1)
References
- geowatch.heuristics.IARPA_REAL_STATUS = {'ignore': 'ignore', 'negative': ['positive_excluded', 'negative', 'negative_unbounded'], 'positive': ['positive_annotated', 'positive_annotated_static', 'positive_partial', 'positive_pending']}¶
For official color definitions see:
iarpa_smart_metrics.evaluation.Evaluation.get_sm_color()andiarpa_smart_metrics.evaluation.Evaluation.get_gt_color()
- geowatch.heuristics.iarpa_assign_truth_confusion(truth_status, has_positive_match)[source]¶
Example
>>> from geowatch.heuristics import * # NOQA >>> import pandas as pd >>> rows = [] >>> for truth_status in IARPA_STATUS_TO_INFO.keys(): >>> for has_positive_match in [0, 1]: >>> gt_cfsn = iarpa_assign_truth_confusion(truth_status, has_positive_match) >>> rows.append({ >>> 'truth_status': truth_status, >>> 'has_positive_match': has_positive_match, >>> 'confusion': gt_cfsn, >>> }) >>> print(pd.DataFrame(rows).to_string())
- geowatch.heuristics.iarpa_assign_pred_confusion(truth_match_statuses)[source]¶
Example
>>> from geowatch.heuristics import * # NOQA >>> import itertools as it >>> truth_match_statuses = {'positive_partial', 'positive_excluded'} >>> for combo in it.combinations(IARPA_STATUS_TO_INFO, 2): >>> truth_match_statuses = combo >>> pred_cfsn = iarpa_assign_pred_confusion(truth_match_statuses) >>> print(f'{pred_cfsn=} for {truth_match_statuses}')
- geowatch.heuristics.hack_track_categories(track_catnames, task)[source]¶
-
Example
>>> from geowatch.heuristics import * # NOQA >>> basis = { >>> #'task': ['class', 'saliency'], >>> 'task': ['class'], >>> 'track_catnames': [ >>> ['No Activity'], >>> ['Post Construction'], >>> ['Post Construction', 'Post Construction', ], >>> ['Post Construction', 'Post Construction', 'Post Construction', ], >>> ['No Activity', 'ignore', 'ignore'], >>> ['No Activity', 'Post Construction'], >>> ['No Activity', 'Site Preparation', 'Post Construction'], >>> ], >>> } >>> for kw in ub.named_product(basis): >>> task = kw['task'] >>> track_catnames = kw['track_catnames'] >>> kw['new_catnames'] = hack_track_categories(track_catnames, task) >>> print('kw = {}'.format(ub.urepr(kw, nl=1)))
Example
>>> from geowatch.heuristics import * # NOQA >>> track_catnames = ['negative', 'negative'] >>> task = 'saliency' >>> result = hack_track_categories(track_catnames, task) >>> print(result) ['negative', 'negative']
- geowatch.heuristics.ensure_heuristic_coco_colors(coco_dset, force=False)[source]¶
- Parameters:
coco_dset (kwcoco.CocoDataset) – object to modify
force (bool) – if True, overwrites existing colors if needed
Todo
- [ ] Move this non-heuristic functionality to
kwcoco.CocoDataset.ensure_class_colors()
Example
>>> from geowatch.heuristics import * # NOQA >>> import kwcoco >>> coco_dset = kwcoco.CocoDataset.demo() >>> ensure_heuristic_coco_colors(coco_dset) >>> assert all(c['color'] for c in coco_dset.cats.values())
- geowatch.heuristics.ensure_heuristic_category_tree_colors(classes, force=False)[source]¶
- Parameters:
classes (kwcoco.CategoryTree) – object to modify
force (bool) – if True, overwrites existing colors if needed
Todo
- [ ] Move this non-heuristic functionality to
kwcoco.CategoryTree.ensure_colors()
[ ] Consolidate with ~/code/watch/geowatch/tasks/fusion/utils :: category_tree_ensure_color
[ ] Consolidate with ~/code/watch/geowatch/utils/kwcoco_extensions :: category_category_colors
[ ] Consolidate with ~/code/watch/geowatch/heuristics.py :: ensure_heuristic_category_tree_colors
[ ] Consolidate with ~/code/watch/geowatch/heuristics.py :: ensure_heuristic_coco_colors
Example
>>> from geowatch import heuristics >>> import kwcoco >>> classes = kwcoco.CategoryTree.coerce(['ignore', 'positive', 'Active Construction', 'foobar', 'Unknown', 'baz']) >>> heuristics.ensure_heuristic_category_tree_colors(classes) >>> assert all(d['color'] for n, d in classes.graph.nodes(data=True))
- geowatch.heuristics.build_image_header_text(**kwargs)[source]¶
A heuristic for what sort of info is useful to plot on the header of an image.
- Kwargs:
img coco_dset vidname, _header_extra
gid, frame_index, dset_idstr, name, sensor_coarse, date_captured
Example
>>> from geowatch.heuristics import * # NOQA >>> img = { >>> 'id': 1, >>> 'frame_index': 0, >>> 'date_captured': '2020-01-01', >>> 'name': 'BLARG', >>> 'sensor_coarse': 'Sensor1', >>> } >>> kwargs = { >>> 'img': img, >>> 'dset_idstr': '', >>> 'name': '', >>> '_header_extra': None, >>> } >>> header_lines = build_image_header_text(**kwargs) >>> print('header_lines = {}'.format(ub.urepr(header_lines, nl=1)))
- geowatch.heuristics.normalize_sensors(coco_dset, sensor_warnings=True, format='te')[source]¶
Convert to / from internal representations or IAPRA sensor standards
- geowatch.heuristics.extract_region_id(fname)[source]¶
Example
>>> fname = 'foobar_KR_R001_otherstuff' >>> extract_region_id(fname)
- geowatch.heuristics.register_known_fsspec_s3_buckets()[source]¶
A workaround to handle requester pays information for particular s3 endpoints. Ideally the user would be able to specify this mapping via the CLI, but for now lets just hack it in.
We are not specifying the profile here, assuming that instead the user will use the
AWS_DEFAULT_PROFILEenviron.Note: the
AWS_REQUEST_PAYERenviron is only repsected by gdal, and this function does not impact gdal at all, so this environ needs to be set as well as calling this workaround.