Coverage for qubalab/images/region_2d.py: 93%
30 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-31 11:24 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-31 11:24 +0000
1from __future__ import annotations
2from dataclasses import dataclass
3import shapely
6@dataclass(frozen=True)
7class Region2D:
8 """
9 Simple data class to represent the bounding box for a region in 2D.
11 :param x: the top left x-coordinate of the bounding box
12 :param y: the top left y-coordinate of the bounding box
13 :param width: the width of the bounding box
14 :param height: the height of the bounding box
15 :param z: the z-slice index of the bounding box
16 :param t: the time point index of the bounding box
17 """
18 x: int = 0
19 y: int = 0
20 width: int = -1
21 height: int = -1
22 z: int = 0
23 t: int = 0
25 @property
26 def geometry(self) -> shapely.Geometry:
27 """
28 A shapely geometry describing the x/y coordinates of the region.
29 """
30 return shapely.box(self.x, self.y, self.x+self.width, self.y+self.height)
32 def scale_region(self, scale_factor: float) -> Region2D:
33 """
34 Scale the bounding box of this region on the x and y axis.
36 :param scale_factor: the scale factor to apply to this region
37 :returns: a Region2D scaled by the provided factor
38 :raises ValueError: when scale_factor is 0
39 """
40 return self.downsample_region(1.0 / scale_factor)
42 def downsample_region(self, downsample: float) -> Region2D:
43 """
44 Downsample the bounding box of this region on the x and y axis.
46 This can be used to convert coordinates from (for example) the full image resolution
47 to a different pyramidal level.
49 :param downsample: the downsample to apply to this region
50 :returns: a Region2D downsampled by the provided factor
51 :raises ValueError: when downsample is 0
52 """
53 if downsample == 1:
54 return self
56 if downsample == 0:
57 raise ValueError('Downsample cannot be 0!')
59 x = int(self.x / downsample)
60 y = int(self.y / downsample)
62 # Handle -1 for width & height, i.e. until the full image width
63 if self.width == -1:
64 x2 = x - 1
65 else:
66 x2 = int(round(self.x + self.width) / downsample)
68 if self.height == -1:
69 y2 = y - 1
70 else:
71 y2 = int(round(self.y + self.height) / downsample)
73 return Region2D(x=x, y=y, width=x2 - x, height=y2 - y, z=self.z, t=self.t)