From 5b360b9ac5a55f0ae64be1dd2427a200c9c0a345 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 21:39:49 +0000 Subject: [PATCH 1/3] Initial plan From d2fd7ca18544af1f81c4a7b7735aca7c394eff30 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 21:42:14 +0000 Subject: [PATCH 2/3] Return shapes and deviation statistics instead of centroids and mean Co-authored-by: calebrob6 <1088078+calebrob6@users.noreply.github.com> --- generate_interesting_points.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/generate_interesting_points.py b/generate_interesting_points.py index bf24c8f..250aa06 100644 --- a/generate_interesting_points.py +++ b/generate_interesting_points.py @@ -253,9 +253,11 @@ def main(args): ) ) - # Calculate the mean deviation for each feature and check for all-zero pixels + # Calculate deviation statistics for each feature and check for all-zero pixels # We use memory files for speed - all_vals = [] + all_means = [] + all_maxes = [] + all_stds = [] has_zero_pixels = [] base_profile = { @@ -277,7 +279,9 @@ def main(args): for geom, val in tqdm(outputs): if val == 1: feature_devs, _ = rasterio.mask.mask(dev_f, [geom], crop=True, filled=False) - all_vals.append(float(feature_devs.mean())) + all_means.append(float(feature_devs.mean())) + all_maxes.append(float(feature_devs.max())) + all_stds.append(float(feature_devs.std())) # Check original imagery for all-zero pixels (only within the geometry) feature_data, _ = rasterio.mask.mask(src, [geom], crop=True, indexes=band_indices, filled=False) @@ -285,15 +289,23 @@ def main(args): all_zeros = np.all(feature_data.data == 0, axis=0) has_zero_pixels.append(np.any(all_zeros & valid_mask)) else: - all_vals.append(float("inf")) + all_means.append(float("inf")) + all_maxes.append(float("inf")) + all_stds.append(float("inf")) has_zero_pixels.append(True) print(f"Found {len(outputs)} features in {time.time() - tic} seconds\n") print("Writing output") tic = time.time() schema = { - "geometry": "Point", - "properties": {"id": "int", "area": "float", "deviation": "float"}, + "geometry": "Polygon", + "properties": { + "id": "int", + "area": "float", + "deviation_mean": "float", + "deviation_max": "float", + "deviation_std": "float", + }, } count = 0 @@ -311,11 +323,13 @@ def main(args): if val == 1 and area > args.area_threshold and area <= max_area and not has_zero_pixels[i]: row = { "type": "Feature", - "geometry": shapely.geometry.mapping(shape.centroid), + "geometry": shapely.geometry.mapping(shape), "properties": { "id": i, "area": area, - "deviation": all_vals[i], + "deviation_mean": all_means[i], + "deviation_max": all_maxes[i], + "deviation_std": all_stds[i], }, } f.write(row) From 94e3d98540eba5e42bee354e3715a7629e3f1c5b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 2 Mar 2026 21:46:52 +0000 Subject: [PATCH 3/3] Add --return-full-shapes flag to control output geometry and statistics Co-authored-by: calebrob6 <1088078+calebrob6@users.noreply.github.com> --- generate_interesting_points.py | 65 +++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 21 deletions(-) diff --git a/generate_interesting_points.py b/generate_interesting_points.py index 250aa06..0666975 100644 --- a/generate_interesting_points.py +++ b/generate_interesting_points.py @@ -99,6 +99,12 @@ def set_up_parser(): help="Comma-separated list of band indices (1-based) to use, e.g., '1,2,3' for RGB. " "If not specified, all bands are used.", ) + parser.add_argument( + "--return-full-shapes", + action="store_true", + help="Output full polygon shapes with deviation statistics (mean, max, std) instead of " + "centroid points with mean deviation only", + ) return parser @@ -297,16 +303,22 @@ def main(args): print("Writing output") tic = time.time() - schema = { - "geometry": "Polygon", - "properties": { - "id": "int", - "area": "float", - "deviation_mean": "float", - "deviation_max": "float", - "deviation_std": "float", - }, - } + if args.return_full_shapes: + schema = { + "geometry": "Polygon", + "properties": { + "id": "int", + "area": "float", + "deviation_mean": "float", + "deviation_max": "float", + "deviation_std": "float", + }, + } + else: + schema = { + "geometry": "Point", + "properties": {"id": "int", "area": "float", "deviation": "float"}, + } count = 0 max_area = args.area_threshold * 5 @@ -321,17 +333,28 @@ def main(args): shape = shapely.geometry.shape(geom) area = shape.area if val == 1 and area > args.area_threshold and area <= max_area and not has_zero_pixels[i]: - row = { - "type": "Feature", - "geometry": shapely.geometry.mapping(shape), - "properties": { - "id": i, - "area": area, - "deviation_mean": all_means[i], - "deviation_max": all_maxes[i], - "deviation_std": all_stds[i], - }, - } + if args.return_full_shapes: + row = { + "type": "Feature", + "geometry": shapely.geometry.mapping(shape), + "properties": { + "id": i, + "area": area, + "deviation_mean": all_means[i], + "deviation_max": all_maxes[i], + "deviation_std": all_stds[i], + }, + } + else: + row = { + "type": "Feature", + "geometry": shapely.geometry.mapping(shape.centroid), + "properties": { + "id": i, + "area": area, + "deviation": all_means[i], + }, + } f.write(row) count += 1