Spaces:
Sleeping
Sleeping
File size: 2,945 Bytes
07392e1 1f3bac1 07392e1 1f3bac1 07392e1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | """
Mouse-based region selector using OpenCV callbacks.
This module provides the low-level RegionSelector class that handles
mouse events for interactive region selection.
"""
from typing import Callable, List, Optional, Tuple
import cv2
from .models import BBox, SelectionState
# Type alias for key handler functions
KeyHandler = Callable[[SelectionState, "RegionSelector"], None]
class RegionSelector:
"""
Interactive region selector using OpenCV mouse callbacks.
Supports two selection modes:
- Two-click selection: click top-left, then click bottom-right
- Click-and-drag selection: click, drag, and release
"""
def __init__(self, window_name: str, mode: str = "two_click"):
"""Initialize the region selector."""
self.window_name = window_name
self.mode = mode
# Two-click mode state
self.points: List[Tuple[int, int]] = []
self.current_point: Optional[Tuple[int, int]] = None
# Drag mode state
self.start_point: Optional[Tuple[int, int]] = None
self.end_point: Optional[Tuple[int, int]] = None
self.drawing = False
self.selection_complete = False
def mouse_callback(self, event: int, x: int, y: int, _flags: int, _param: object) -> None:
"""Handle mouse events for region selection."""
if self.mode == "two_click":
if event == cv2.EVENT_MOUSEMOVE:
self.current_point = (x, y)
elif event == cv2.EVENT_LBUTTONDOWN:
self.points.append((x, y))
if len(self.points) >= 2:
self.selection_complete = True
else:
if event == cv2.EVENT_LBUTTONDOWN:
self.start_point = (x, y)
self.end_point = (x, y)
self.drawing = True
self.selection_complete = False
elif event == cv2.EVENT_MOUSEMOVE and self.drawing:
self.end_point = (x, y)
elif event == cv2.EVENT_LBUTTONUP:
self.end_point = (x, y)
self.drawing = False
self.selection_complete = True
def get_bbox(self) -> Optional[BBox]:
"""Get the selected bounding box."""
if self.mode == "two_click":
if len(self.points) < 2:
return None
p1, p2 = self.points[0], self.points[1]
else:
if self.start_point is None or self.end_point is None:
return None
p1, p2 = self.start_point, self.end_point
bbox = BBox.from_points(p1, p2)
if bbox.width == 0 or bbox.height == 0:
return None
return bbox
def reset(self) -> None:
"""Reset the selection state."""
self.points = []
self.current_point = None
self.start_point = None
self.end_point = None
self.drawing = False
self.selection_complete = False
|