|
@@ -7,11 +7,56 @@ from collections import namedtuple
|
|
|
from skimage import filters
|
|
|
|
|
|
# the coordinates are relative!
|
|
|
-BBox = namedtuple("BBox", "x0 y0 x1 y1")
|
|
|
BBoxInfo = namedtuple("BBoxInfo", "area ratio mean std selected", defaults=[-1, -1, -1, -1, False])
|
|
|
Detection = namedtuple("Detection", "bbox info")
|
|
|
|
|
|
+class BBox(namedtuple("BBox", "x0 y0 x1 y1")):
|
|
|
+ __slots__ = ()
|
|
|
|
|
|
+ @property
|
|
|
+ def w(self):
|
|
|
+ return abs(self.x1 - self.x0)
|
|
|
+
|
|
|
+ @property
|
|
|
+ def h(self):
|
|
|
+ return abs(self.y1 - self.y0)
|
|
|
+
|
|
|
+
|
|
|
+ @property
|
|
|
+ def area(self):
|
|
|
+ return self.h * self.w
|
|
|
+
|
|
|
+ @property
|
|
|
+ def ratio(self):
|
|
|
+ return min(self.h, self.w) / max(self.h, self.w)
|
|
|
+
|
|
|
+ def crop(self, im: np.ndarray, enlarge: bool = True):
|
|
|
+
|
|
|
+ x0, y0, x1, y1 = self
|
|
|
+ H, W, *_ = im.shape
|
|
|
+
|
|
|
+ # translate from relative coordinates to pixel
|
|
|
+ # coordinates for the given image
|
|
|
+
|
|
|
+ x0, x1 = int(x0 * W), int(x1 * W)
|
|
|
+ y0, y1 = int(y0 * H), int(y1 * H)
|
|
|
+
|
|
|
+ # enlarge to a square extent
|
|
|
+ if enlarge:
|
|
|
+ h, w = int(self.h * H), int(self.h * W)
|
|
|
+ size = max(h, w)
|
|
|
+ dw, dh = (size - w) / 2, (size - h) / 2
|
|
|
+ x0, x1 = max(int(x0 - dw), 0), int(x0 - dw + size)
|
|
|
+ y0, y1 = max(int(y0 - dh), 0), int(y0 - dh + size)
|
|
|
+
|
|
|
+ if im.ndim == 2:
|
|
|
+ return im[y0:y1, x0:x1]
|
|
|
+
|
|
|
+ elif im.ndim == 3:
|
|
|
+ return im[y0:y1, x0:x1, :]
|
|
|
+
|
|
|
+ else:
|
|
|
+ ValueError(f"Unsupported ndims: {im.ndims=}")
|
|
|
|
|
|
|
|
|
class Detector(object):
|
|
@@ -116,7 +161,7 @@ class Detector(object):
|
|
|
for i in inds.squeeze():
|
|
|
bbox, _ = detections[i]
|
|
|
mean, std, n = _im_mean_std(integral, integral_sq, bbox)
|
|
|
- area, ratio = _area(bbox), _ratio(bbox)
|
|
|
+ area, ratio = bbox.area, bbox.ratio
|
|
|
selected = self.is_selected(mean, std, ratio, area)
|
|
|
info = BBoxInfo(mean, std, area, ratio, selected)
|
|
|
detections[i] = Detection(bbox, info)
|
|
@@ -139,17 +184,6 @@ def _contour2bbox(contour: np.ndarray, shape: T.Tuple[int, int]) -> BBox:
|
|
|
return BBox(x0/w, y0/h, x1/w, y1/h)
|
|
|
|
|
|
|
|
|
-def _ratio(bbox: BBox) -> float:
|
|
|
- x0, y0, x1, y1 = bbox
|
|
|
- h, w = y1-y0, x1-x0
|
|
|
- return min(h, w) / max(h, w)
|
|
|
-
|
|
|
-
|
|
|
-def _area(bbox: BBox) -> float:
|
|
|
- x0, y0, x1, y1 = bbox
|
|
|
- h, w = y1-y0, x1-x0
|
|
|
- return h * w
|
|
|
-
|
|
|
def _im_mean_std(integral: np.ndarray,
|
|
|
integral_sq: np.ndarray,
|
|
|
bbox: T.Optional[BBox] = None
|