-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handling a ROI when loading raster data #642
base: main
Are you sure you want to change the base?
Conversation
3e25dec
to
33fbbac
Compare
Great addition, thanks @vschaffn! 🙂 I have a main remark about the As it happens, the
In short, doing: rst = Raster("file.tif")
rst_cropped = rst.crop(my_roi) worked without loading the full dataset. We had been debating about adding the windowed reading of Maybe this is the occasion to merge things together? |
Additionally, by merging like this, all the existing tests we have for |
@rhugonnet I had not noticed that the crop() method already worked with the data not loaded on disk. After studying _crop() function, I think the simplest thing is to restore _load_rio() without ROI, and to use crop, as it is, before _load_rio() if a ROI is passed when the raster is initialised. This will effectively mean that there is only one function dealing with the ROI, and therefore simplified code maintenance 😃 |
@vschaffn Yes that's true, this would work as well 🙂. The difference would be only internal to make |
Okay for me, we can open an issue for the |
# Check if ROI is georeferenced or pixel_based and convert to crs | ||
if roi_georef.issubset(roi.keys()): | ||
crs_roi = roi.get("crs", "EPSG:4326") | ||
transformer = Transformer.from_crs(crs_roi, crs, always_xy=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that we have a function to convert points from one CRS to another, which saves a few lines: https://github.com/GlacioHack/geoutils/blob/main/geoutils/projtools.py#L246
@@ -303,6 +312,41 @@ def test_load(self) -> None: | |||
r.filename = None | |||
r.load() | |||
|
|||
@pytest.mark.parametrize("example", [landsat_b4_path, aster_dem_path, landsat_rgb_path]) # type: ignore | |||
def test_raster_with_roi(self, example: str) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great test! But you also need to include tests that could fail, like e.g. with ROI that are out of bounds etc, to make sure that these are caught correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typically, we check that errors are raised properly, such as the ones raised at L 1075 in raster.py.
Hi all, I'm slowly trying to catch up, and sorry if some of it should have come up earlier during the conception... One more thing to consider. We should make sure that crop and ROI (if kept separate) behave the same way when the ROI is partially or fully out of the raster bounds. I had to check with crop, but it looks like it does not raise any warning or error if the bound is larger (but silently crops to the maximum extent) and raises an error if there is no intersection at all between the two. See example below. Maybe we should raise a warning when the requested crop partially overlap and an error when it does not overlap at all?
|
I agree, we should make the naming and behaviour fully consistent between |
Resolves GlacioHack/xdem#602
Description
This PR introduces the functionality for handling a Region of Interest (ROI) when loading raster data. Specifically, it ensures that rasters can be loaded with a specific subset of their data, as defined by a ROI. This functionality is available during the raster initialization. The ROI can be either pixel-based or georeferenced.
Changes
roi
parameter in theRaster
class constructor:roi
parameter is introduced to specify the region of interest when loading a raster. It is a dictionary with the keys:x
,y
,w
, andh
if pixel-based (where (x
,y
) top-left corner coordinates and (w
,h
) the dimensions (width, height) in pixels).left
,bottom
,right
,top
and optionalcrs
(defaults to EPSG:4326) if georeferenced, representing the bounding box of the region to load.Raster
class to crop the raster data during initialization. If provided, the data will be sliced accordingly, while also adjusting the transform and metadata to match the cropped area.convert_roi
method:_load_rio
function modification:_load_rio
function now supports the roi parameter to load a specific subset of raster data directly from the disk.Window
for reading the data in the specified region, ensuring that only the relevant part of the raster is loaded into memory.from_array
method now supports an optionalroi
parameter. This allows users to define a ROI when creating a raster from an in-memory numpy array.Tests
test_raster_with_roi
: This test verifies the correct behavior when loading raster data with a specified ROI. It checks that the raster is properly cropped and ensures the output data matches expectations when applying either a georeferenced or pixel-based ROI. This ensures the convert_roi method functions as intended in real-world use cases.test_init
andtest_from_array
: These tests have been extended to validate behavior when a ROI is provided but the raster is initialized without a file path. The tests ensure that the ROI is correctly handled when working with arrays directly, confirming the method's compatibility with non-file-based rasters.Documentation
crop
in the raster documentation has been updated with the possibility to pass a ROI in parameter and crop the raster during initialization.Example
Test with
xDEM