Skip to content

GEOPY-2771: backport - high runtime and memory for GeoImage.copy_by_extent#858

Merged
sebhmg merged 2 commits intoMiraGeoscience:hotfix/gi-4.3from
sebhmg:GEOPY-2771
Mar 16, 2026
Merged

GEOPY-2771: backport - high runtime and memory for GeoImage.copy_by_extent#858
sebhmg merged 2 commits intoMiraGeoscience:hotfix/gi-4.3from
sebhmg:GEOPY-2771

Conversation

@sebhmg
Copy link
Contributor

@sebhmg sebhmg commented Mar 16, 2026

GEOPY-2771 - backport - high runtime and memory allocation for GeoImage.copy_by_extent

GEOPY-2540: Copy from extent GeoImage takes forever. (cherry picked from commit 9fb75bc)

GEOPY-2540: Copy from extent GeoImage takes forever.
(cherry picked from commit 9fb75bc)
Copilot AI review requested due to automatic review settings March 16, 2026 14:50
@sebhmg sebhmg changed the title Merge pull request #817 from MiraGeoscience/GEOPY-2540 GEOPY-2771: backport - Copy from extent GeoImage takes forever Mar 16, 2026
@sebhmg sebhmg changed the title GEOPY-2771: backport - Copy from extent GeoImage takes forever GEOPY-2771: backport - high runtime and memory for GeoImage.copy_by_extent Mar 16, 2026
@codecov
Copy link

codecov bot commented Mar 16, 2026

Codecov Report

❌ Patch coverage is 90.40000% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.12%. Comparing base (cb7137f) to head (55de7c2).
⚠️ Report is 3 commits behind head on hotfix/gi-4.3.

Files with missing lines Patch % Lines
geoh5py/shared/cut_by_extent.py 91.94% 6 Missing and 6 partials ⚠️
geoh5py/objects/geo_image.py 87.50% 5 Missing and 3 partials ⚠️
geoh5py/shared/utils.py 87.87% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@                Coverage Diff                @@
##           hotfix/gi-4.3     #858      +/-   ##
=================================================
+ Coverage          90.91%   91.12%   +0.21%     
=================================================
  Files                113      114       +1     
  Lines               9869    10067     +198     
  Branches            1836     1867      +31     
=================================================
+ Hits                8972     9174     +202     
+ Misses               485      477       -8     
- Partials             412      416       +4     
Files with missing lines Coverage Δ
geoh5py/shared/conversion/geo_image.py 82.69% <100.00%> (-0.65%) ⬇️
geoh5py/shared/utils.py 91.77% <87.87%> (-0.05%) ⬇️
geoh5py/objects/geo_image.py 95.72% <87.50%> (+6.99%) ⬆️
geoh5py/shared/cut_by_extent.py 91.94% <91.94%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Addresses GEOPY-2540 by reworking GeoImage.copy_from_extent to avoid expensive Grid2D round-trips and introducing shared geometry helpers to compute extent/plane intersections more directly.

Changes:

  • Added a new Plane model + polygon/box intersection utilities to compute crop extents in UV space.
  • Updated GeoImage.copy_from_extent to crop via PIL using the computed pixel rectangle instead of converting to Grid2D.
  • Expanded/adjusted test coverage around GeoImage extent-copying, rotations/dips, and new cut-by-extent helpers.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
geoh5py/objects/geo_image.py Reimplements copy_from_extent, adjusts tag handling, and tweaks dip/rotation logic and image loading behavior.
geoh5py/shared/cut_by_extent.py New Plane/geometry module used to compute intersections and pixel crop extents.
geoh5py/shared/utils.py Adds extent-cleaning and vector/polygon helper validators used by new geometry logic; updates mask_by_extent.
geoh5py/shared/conversion/geo_image.py Uses GeoImage-derived u_count/v_count and cell sizes for Grid2D conversion.
tests/geo_image_test.py Adds/updates tests for tags/vertices, rotation/dip, and copy-from-extent behavior.
tests/shared_utils_test.py Adjusts expectations around mask_by_extent input validation.
tests/cut_by_extent_test.py New tests for Plane validation and extent_from_vertices_and_box input checks.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


if not isinstance(extent, np.ndarray) or extent.shape not in [(2, 3), (2, 2)]:
raise ValueError(
"extent must be a numpy array of shape (2, 3)."
Comment on lines +389 to +394
old_limit = Image.MAX_IMAGE_PIXELS
Image.MAX_IMAGE_PIXELS = None
try:
im = Image.open(BytesIO(self.image_data.file_bytes))
finally:
Image.MAX_IMAGE_PIXELS = old_limit
Comment on lines 712 to 718
if len(xyz) != 4:
raise ValueError("Array of 'vertices' must be of shape (4, 3).")

self._vertices = xyz
self._tag = None

if self.on_file:
self.workspace.update_attribute(self, "vertices")
Comment on lines +918 to +919
# Create with image so we get past the image check, then remove vertices
image = Image.fromarray(np.arange(16, dtype="uint8").reshape(4, 4), "L")
Comment on lines +681 to +685
if extent.shape[1] == 2 or np.all(extent[:, 2] == 0):
z_coordinates = locations[:, 2]
z_min, z_max = float(z_coordinates.min()), float(z_coordinates.max())
z_bounds = np.array([[z_min - 1], [z_max + 1]], dtype=np.float64)
extent = np.column_stack([extent.astype(np.float64), z_bounds])
Comment on lines +456 to +462
print(geoimage3.dip, geoimage3.rotation)
np.testing.assert_array_almost_equal(geoimage3.dip, 44)

geoimage4 = GeoImage.create(
workspace, name="test_area", image=image, dip=44, rotation=66
)
print(geoimage4.dip, geoimage4.rotation)
Comment on lines +885 to +886
warn("Skipping comparison due to one method returning None")
return
ValueError, match=re.escape("Input 'extent' must be a 2D array-like.")
):
mask_by_extent(points, 1.0)
with pytest.raises(ValueError, match="Input 'extent' must be a 2D array-like."):
Comment on lines +677 to +679
raise ValueError(
"Input 'extent' must be a 2D array-like with 2 points and 2 or 3 columns"
)
Comment on lines +149 to +155
f"Got {type(vertices)} with shape {vertices.shape}."
)

if not isinstance(extent, np.ndarray) or extent.shape not in [(2, 3), (2, 2)]:
raise ValueError(
"extent must be a numpy array of shape (2, 3)."
f"Got {type(extent)} with shape {extent.shape}."
@sebhmg sebhmg merged commit a865f68 into MiraGeoscience:hotfix/gi-4.3 Mar 16, 2026
13 checks passed
@sebhmg sebhmg deleted the GEOPY-2771 branch March 16, 2026 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants