Skip to content

Commit 2d2ac06

Browse files
authored
Merge pull request #1960 from AdeelH/backport
[BACKPORT] Backport changes to the 0.21 branch for v0.21.3 release
2 parents 63c672d + 781d9d2 commit 2d2ac06

File tree

24 files changed

+153
-41
lines changed

24 files changed

+153
-41
lines changed

.github/workflows/continuous_integration.yml

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ jobs:
1818

1919
- run: df -hT
2020

21+
- run: rm -rf /opt/hostedtoolcache
22+
23+
- run: df -hT
24+
2125
- run: ./scripts/cibuild
2226

2327
- run: df -hT

.github/workflows/release.yml

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ jobs:
2323
steps:
2424
- uses: actions/checkout@v4
2525

26+
- run: rm -rf /opt/hostedtoolcache
27+
2628
- run: ./scripts/cibuild
2729

2830
- run: docker system prune -f

docs/release.rst

+21-6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ Minor or Major Version Release
6060
docker push quay.io/azavea/raster-vision:pytorch-<version>
6161
6262
#. Make a GitHub `tag <https://github.com/azavea/raster-vision/tags>`_ and `release <https://github.com/azavea/raster-vision/releases>`_ using the previous release as a template.
63+
#. Remove artifacts from previous builds. From the repo root:
64+
65+
.. code-block:: console
66+
67+
rm -rf build/ dist/ *.egg-info
68+
rm -rf rastervision_*/build rastervision_*/dist rastervision_*/*.egg-info
69+
6370
#. Publish all packages to PyPI. This step requires `twine <https://twine.readthedocs.io/en/stable/>`__ which you can install with
6471

6572
.. code-block:: console
@@ -105,12 +112,20 @@ Minor or Major Version Release
105112
#. Announce the new release in our `forum <https://github.com/azavea/raster-vision/discussions>`_, and with a blog post if it's a big release.
106113
#. Make a PR to the master branch that updates the version number to the next development version, ``X.Y.Z-dev``. For example, if the last release was ``0.20.1``, update the version to ``0.20.2-dev``.
107114

108-
Bug Fix Release
115+
Patch Release
109116
-----------------
110117

111-
This describes how to create a new bug fix release, using incrementing from 0.8.0 to 0.8.1 as an example. This assumes that there is already a branch for a minor release called ``0.8``.
118+
This describes how to create a new patch release (AKA a bug-fix release), using an increment from 0.8.0 to 0.8.1 as an example. This assumes that there is already a branch for a minor release called ``0.8``.
119+
120+
#. Backport changes to the ``0.8`` branch. To create a patch release (version 0.8.1), we need to backport all the commits on the ``master`` branch that have been added since the last patch release onto the ``0.8`` branch. To do this:
121+
122+
#. Create a new branch from the ``0.8`` branch. Let's call it ``backport``.
123+
#. Cherry-pick each commit that we want to include from the ``master`` branch onto the ``backport`` branch.
124+
#. Make a PR against the ``0.8`` branch from the ``backport`` branch. The title of the PR should start with ``[BACKPORT]``.
125+
#. Update changelog and version on the ``0.8`` branch. Make and merge a PR against ``0.8`` (but not ``master``) that adds a changelog for the new release and increments the version to ``0.8.1`` throughout the repo. Wait for the ``0.8`` branch to be built by GitHub Actions and the ``0.8`` Docker images to be published to Quay. If that is successful, we can proceed to the next steps of actually publishing a release.
126+
#. Publish the new version to PyPI. Follow the same instructions for PyPI as listed above for minor/major version releases.
127+
#. Using the GitHub UI, make a new release. Use ``v0.8.1`` as the tag, and the ``0.8`` branch as the target.
128+
#. Update changelog and version on the ``master`` branch. Make and merge a PR against ``master`` that
112129

113-
#. To create a bug fix release (version 0.8.1), we need to backport all the bug fix commits on the ``master`` branch that have been added since the last bug fix release onto the ``0.8`` branch. For each bug fix PR on ``master``, we need to create a PR against the ``0.8`` branch based on a branch of ``0.8`` that has cherry-picked the commits from the original PR. The title of the PR should start with [BACKPORT].
114-
#. Make and merge a PR against ``0.8`` (but not ``master``) that increments the version in each ``setup.py`` file to ``0.8.1``. Then wait for the ``0.8`` branch to be built by GitHub Actions and the ``0.8`` Docker images to be published to Quay. If that is successful, we can proceed to the next steps of actually publishing a release.
115-
#. Using the GitHub UI, make a new release. Use ``0.8.1`` as the tag, and the ``0.8`` branch as the target.
116-
#. Publish the new version to PyPI. Follow the same instructions for PyPI that are listed above for minor/major version releases.
130+
* includes the cherry-picked commit that updates the changelog for ``0.8.1`` and
131+
* increments the version to ``0.8.2-dev`` throughout the repo.

rastervision_core/rastervision/core/data/label/chip_classification_labels.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -155,20 +155,26 @@ def extend(self, labels: 'ChipClassificationLabels') -> None:
155155
for cell in labels.get_cells():
156156
self.set_cell(cell, *labels[cell])
157157

158-
def save(self, uri: str, class_config: 'ClassConfig',
159-
crs_transformer: 'CRSTransformer') -> None:
158+
def save(self,
159+
uri: str,
160+
class_config: 'ClassConfig',
161+
crs_transformer: 'CRSTransformer',
162+
bbox: Optional[Box] = None) -> None:
160163
"""Save labels as a GeoJSON file.
161164
162165
Args:
163166
uri (str): URI of the output file.
164167
class_config (ClassConfig): ClassConfig to map class IDs to names.
165168
crs_transformer (CRSTransformer): CRSTransformer to convert from
166169
pixel-coords to map-coords before saving.
170+
bbox (Optional[Box]): User-specified crop of the extent. Must be
171+
provided if the corresponding RasterSource has bbox != extent.
167172
"""
168173
from rastervision.core.data import ChipClassificationGeoJSONStore
169174

170175
label_store = ChipClassificationGeoJSONStore(
171176
uri=uri,
172177
class_config=class_config,
173-
crs_transformer=crs_transformer)
178+
crs_transformer=crs_transformer,
179+
bbox=bbox)
174180
label_store.save(self)

rastervision_core/rastervision/core/data/label/object_detection_labels.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -294,20 +294,26 @@ def prune_duplicates(
294294
score_threshold=score_thresh)
295295
return ObjectDetectionLabels.from_boxlist(pruned_boxlist)
296296

297-
def save(self, uri: str, class_config: 'ClassConfig',
298-
crs_transformer: 'CRSTransformer') -> None:
297+
def save(self,
298+
uri: str,
299+
class_config: 'ClassConfig',
300+
crs_transformer: 'CRSTransformer',
301+
bbox: Optional[Box] = None) -> None:
299302
"""Save labels as a GeoJSON file.
300303
301304
Args:
302305
uri (str): URI of the output file.
303306
class_config (ClassConfig): ClassConfig to map class IDs to names.
304307
crs_transformer (CRSTransformer): CRSTransformer to convert from
305308
pixel-coords to map-coords before saving.
309+
bbox (Optional[Box]): User-specified crop of the extent. Must be
310+
provided if the corresponding RasterSource has bbox != extent.
306311
"""
307312
from rastervision.core.data import ObjectDetectionGeoJSONStore
308313

309314
label_store = ObjectDetectionGeoJSONStore(
310315
uri=uri,
311316
class_config=class_config,
312-
crs_transformer=crs_transformer)
317+
crs_transformer=crs_transformer,
318+
bbox=bbox)
313319
label_store.save(self)

rastervision_core/rastervision/core/data/label/semantic_segmentation_labels.py

+8
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ def save(self,
357357
uri: str,
358358
crs_transformer: 'CRSTransformer',
359359
class_config: 'ClassConfig',
360+
bbox: Optional[Box] = None,
360361
tmp_dir: Optional[str] = None,
361362
save_as_rgb: bool = False,
362363
raster_output: bool = True,
@@ -373,6 +374,8 @@ def save(self,
373374
crs_transformer (CRSTransformer): CRSTransformer to configure CRS
374375
and affine transform of the output GeoTiff.
375376
class_config (ClassConfig): The ClassConfig.
377+
bbox (Optional[Box]): User-specified crop of the extent. Must be
378+
provided if the corresponding RasterSource has bbox != extent.
376379
tmp_dir (Optional[str], optional): Temporary directory to use. If
377380
None, will be auto-generated. Defaults to None.
378381
save_as_rgb (bool, optional): If True, Saves labels as an RGB
@@ -397,6 +400,7 @@ def save(self,
397400
uri=uri,
398401
crs_transformer=crs_transformer,
399402
class_config=class_config,
403+
bbox=bbox,
400404
tmp_dir=tmp_dir,
401405
save_as_rgb=save_as_rgb,
402406
discrete_output=raster_output,
@@ -529,6 +533,7 @@ def save(self,
529533
uri: str,
530534
crs_transformer: 'CRSTransformer',
531535
class_config: 'ClassConfig',
536+
bbox: Optional[Box] = None,
532537
tmp_dir: Optional[str] = None,
533538
save_as_rgb: bool = False,
534539
discrete_output: bool = True,
@@ -547,6 +552,8 @@ def save(self,
547552
crs_transformer (CRSTransformer): CRSTransformer to configure CRS
548553
and affine transform of the output GeoTiff(s).
549554
class_config (ClassConfig): The ClassConfig.
555+
bbox (Optional[Box]): User-specified crop of the extent. Must be
556+
provided if the corresponding RasterSource has bbox != extent.
550557
tmp_dir (Optional[str], optional): Temporary directory to use. If
551558
None, will be auto-generated. Defaults to None.
552559
save_as_rgb (bool, optional): If True, saves labels as an RGB
@@ -577,6 +584,7 @@ def save(self,
577584
uri=uri,
578585
crs_transformer=crs_transformer,
579586
class_config=class_config,
587+
bbox=bbox,
580588
tmp_dir=tmp_dir,
581589
save_as_rgb=save_as_rgb,
582590
discrete_output=discrete_output,

rastervision_core/rastervision/core/data/label_store/chip_classification_geojson_store.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ def __init__(self,
3030
in GeoJSON file to pixel coords.
3131
bbox (Optional[Box], optional): User-specified crop of the extent.
3232
If provided, only labels falling inside it are returned by
33-
:meth:`.ChipClassificationGeoJSONStore.get_labels`.
33+
:meth:`.ChipClassificationGeoJSONStore.get_labels`. Must be
34+
provided if the corresponding RasterSource has bbox != extent.
3435
"""
3536
self.uri = uri
3637
self.class_config = class_config
@@ -51,7 +52,8 @@ def save(self, labels: ChipClassificationLabels) -> None:
5152
class_ids,
5253
self.crs_transformer,
5354
self.class_config,
54-
scores=scores)
55+
scores=scores,
56+
bbox=self.bbox)
5557
json_to_file(geojson, self.uri)
5658

5759
def get_labels(self) -> ChipClassificationLabels:

rastervision_core/rastervision/core/data/label_store/object_detection_geojson_store.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ def __init__(self,
3232
in GeoJSON file to pixel coords.
3333
bbox (Optional[Box], optional): User-specified crop of the extent.
3434
If provided, only labels falling inside it are returned by
35-
:meth:`.ObjectDetectionGeoJSONStore.get_labels`.
35+
:meth:`.ObjectDetectionGeoJSONStore.get_labels`. Must be
36+
provided if the corresponding RasterSource has bbox != extent.
3637
"""
3738
self.uri = uri
3839
self.class_config = class_config

rastervision_core/rastervision/core/data/label_store/semantic_segmentation_label_store.py

+15-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import numpy as np
66
import rasterio as rio
7+
import rasterio.windows as rio_windows
78
from tqdm.auto import tqdm
89

910
from rastervision.pipeline.file_system import (
@@ -58,7 +59,8 @@ def __init__(
5859
class_config (ClassConfig): Class config.
5960
bbox (Optional[Box], optional): User-specified crop of the extent.
6061
If provided, only labels falling inside it are returned by
61-
:meth:`.SemanticSegmentationLabelStore.get_labels`.
62+
:meth:`.SemanticSegmentationLabelStore.get_labels`. Must be
63+
provided if the corresponding RasterSource has bbox != extent.
6264
tmp_dir (Optional[str], optional): Temporary directory to use. If
6365
None, will be auto-generated. Defaults to None.
6466
vector_outputs (Optional[Sequence[VectorOutputConfig]], optional):
@@ -207,11 +209,17 @@ def save(self,
207209
make_dir(local_root)
208210

209211
height, width = labels.extent.size
212+
if self.bbox is not None:
213+
bbox_rio_window = self.bbox.rasterio_format()
214+
transform = rio_windows.transform(bbox_rio_window,
215+
self.crs_transformer.transform)
216+
else:
217+
transform = self.crs_transformer.transform
210218
out_profile = dict(
211219
driver='GTiff',
212220
height=height,
213221
width=width,
214-
transform=self.crs_transformer.transform,
222+
transform=transform,
215223
crs=self.crs_transformer.image_crs,
216224
blockxsize=min(self.rasterio_block_size, width),
217225
blockysize=min(self.rasterio_block_size, height))
@@ -257,6 +265,7 @@ def write_smooth_raster_output(
257265
out_profile.update(dict(count=num_bands, dtype=dtype))
258266

259267
extent = labels.extent
268+
260269
with rio.open(scores_path, 'w', **out_profile) as ds:
261270
windows = [Box.from_rasterio(w) for _, w in ds.block_windows(1)]
262271
with tqdm(windows, desc='Saving pixel scores') as bar:
@@ -310,7 +319,10 @@ def write_vector_outputs(self, labels: SemanticSegmentationLabels,
310319
bar.set_postfix(vo.dict())
311320
class_mask = (label_arr == vo.class_id).astype(np.uint8)
312321
polys = vo.vectorize(class_mask)
313-
polys = [self.crs_transformer.pixel_to_map(p) for p in polys]
322+
polys = [
323+
self.crs_transformer.pixel_to_map(p, bbox=self.bbox)
324+
for p in polys
325+
]
314326
geojson = geoms_to_geojson(polys)
315327
out_uri = vo.get_uri(vector_output_dir, self.class_config)
316328
json_to_file(geojson, out_uri)

rastervision_core/rastervision/core/data/label_store/utils.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ def boxes_to_geojson(
1616
class_ids: Sequence[int],
1717
crs_transformer: 'CRSTransformer',
1818
class_config: 'ClassConfig',
19-
scores: Optional[Sequence[Union[float, Sequence[float]]]] = None
20-
) -> dict:
19+
scores: Optional[Sequence[Union[float, Sequence[float]]]] = None,
20+
bbox: Optional['Box'] = None) -> dict:
2121
"""Convert boxes and associated data into a GeoJSON dict.
2222
2323
Args:
@@ -30,6 +30,8 @@ def boxes_to_geojson(
3030
Optional list of score or scores. If floats (one for each box),
3131
property name will be "score". If lists of floats, property name
3232
will be "scores". Defaults to None.
33+
bbox (Optional[Box]): User-specified crop of the extent. Must be
34+
provided if the corresponding RasterSource has bbox != extent.
3335
3436
Returns:
3537
dict: Serialized GeoJSON.
@@ -46,7 +48,10 @@ def boxes_to_geojson(
4648
boxes,
4749
desc='Transforming boxes to map coords',
4850
delay=PROGRESSBAR_DELAY_SEC) as bar:
49-
geoms = [crs_transformer.pixel_to_map(box.to_shapely()) for box in bar]
51+
geoms = [
52+
crs_transformer.pixel_to_map(box.to_shapely(), bbox=bbox)
53+
for box in bar
54+
]
5055

5156
# add box properties (ID and name of predicted class)
5257
with tqdm(

rastervision_core/rastervision/core/data/raster_transformer/stats_transformer.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ def transform(self,
9797
def from_raster_sources(cls,
9898
raster_sources: List['RasterSource'],
9999
sample_prob: Optional[float] = 0.1,
100-
max_stds: float = 3.) -> 'StatsTransformer':
100+
max_stds: float = 3.,
101+
chip_sz: int = 300) -> 'StatsTransformer':
101102
"""Build with stats from the given raster sources.
102103
103104
Args:
@@ -113,7 +114,10 @@ def from_raster_sources(cls,
113114
StatsTransformer: A StatsTransformer.
114115
"""
115116
stats = RasterStats()
116-
stats.compute(raster_sources=raster_sources, sample_prob=sample_prob)
117+
stats.compute(
118+
raster_sources=raster_sources,
119+
sample_prob=sample_prob,
120+
chip_sz=chip_sz)
117121
stats_transformer = StatsTransformer.from_raster_stats(
118122
stats, max_stds=max_stds)
119123
return stats_transformer
@@ -162,4 +166,4 @@ def stats(self) -> RasterStats:
162166

163167
def __repr__(self) -> str:
164168
return repr_with_args(
165-
self, means=self.means, std=self.stds, max_stds=self.max_stds)
169+
self, means=self.means, stds=self.stds, max_stds=self.max_stds)

rastervision_core/rastervision/core/rv_pipeline/rv_pipeline.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from rastervision.core.rv_pipeline import TRAIN, VALIDATION
1818
from rastervision.pipeline.file_system.utils import (
1919
download_if_needed, zipdir, get_local_path, upload_or_copy, make_dir,
20-
sync_to_dir, file_exists)
20+
sync_from_dir, file_exists)
2121

2222
log = logging.getLogger(__name__)
2323

@@ -252,8 +252,8 @@ def bundle(self):
252252
shutil.copy(path, join(bundle_dir, fn))
253253

254254
if file_exists(self.config.analyze_uri, include_dir=True):
255-
sync_to_dir(self.config.analyze_uri, join(
256-
bundle_dir, 'analyze'))
255+
analyze_dst = join(bundle_dir, 'analyze')
256+
sync_from_dir(self.config.analyze_uri, analyze_dst)
257257

258258
path = download_if_needed(self.config.get_config_uri(), tmp_dir)
259259
shutil.copy(path, join(bundle_dir, 'pipeline-config.json'))

rastervision_core/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ rastervision_pipeline==0.21.2
22
shapely==2.0.1
33
geopandas==0.13.2
44
numpy==1.25.0
5-
pillow==9.3.0
5+
pillow==10.0.1
66
pyproj==3.4.0
77
rasterio==1.3.7
88
pystac==1.6.1

rastervision_pytorch_backend/rastervision/pytorch_backend/examples/semantic_segmentation/spacenet_vegas.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ def build_scene(spacenet_cfg: SpacenetConfig,
9898
label_uri = spacenet_cfg.get_geojson_uri(id)
9999

100100
raster_source = RasterioSourceConfig(
101-
uris=[image_uri], channel_order=channel_order)
101+
uris=[image_uri],
102+
channel_order=channel_order,
103+
transformers=[StatsTransformerConfig()])
102104

103105
# Set a line buffer to convert line strings to polygons.
104106
vector_source = GeoJSONVectorSourceConfig(

rastervision_pytorch_backend/rastervision/pytorch_backend/examples/test.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
file_to_json, sync_from_dir, upload_or_copy, download_or_copy, file_exists,
1212
sync_to_dir, NotReadableError, download_if_needed)
1313

14-
NEW_VERSION = '0.21'
14+
NEW_VERSION_FULL = '0.21.2'
1515
NEW_VERSION_MAJOR_MINOR = '0.21'
1616

1717
EXAMPLES_MODULE_ROOT = 'rastervision.pytorch_backend.examples'
1818
EXAMPLES_PATH_ROOT = '/opt/src/rastervision_pytorch_backend/rastervision/pytorch_backend/examples' # noqa
19-
REMOTE_PROCESSED_ROOT = f's3://raster-vision/examples/{NEW_VERSION}/processed-data'
20-
REMOTE_OUTPUT_ROOT = f's3://raster-vision/examples/{NEW_VERSION}/output'
19+
REMOTE_PROCESSED_ROOT = f's3://raster-vision/examples/{NEW_VERSION_FULL}/processed-data'
20+
REMOTE_OUTPUT_ROOT = f's3://raster-vision/examples/{NEW_VERSION_FULL}/output'
2121
LOCAL_RAW_ROOT = '/opt/data/raw-data'
2222
LOCAL_PROCESSED_ROOT = '/opt/data/examples/processed-data'
2323
LOCAL_OUTPUT_ROOT = '/opt/data/examples/output'

rastervision_pytorch_learner/rastervision/pytorch_learner/dataset/transform.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,8 @@ def semantic_segmentation_transformer(
227227
y = np.array(y)
228228
out = apply_transform(transform, image=x, mask=y)
229229
x, y = out['image'], out['mask']
230-
y = y.astype(int)
230+
if y is not None:
231+
y = y.astype(int)
231232
return x, y
232233

233234

0 commit comments

Comments
 (0)