refactor: make the matcher and detector safe for concurrent clients
The recognition server will classify crops from several clients at once. Two things blocked that: - OpenCV Feature2D objects were shared across calls, so parallel classify_crop() calls could corrupt each other. Each thread now gets its own extractor set; the template cache is untouched. - score_crop() is extracted from classify_crop() so callers that need every SKU score (live track aggregation) do not have to re-derive it from the top-5 list. classify_crop() output is byte-identical to before (verified against the pre-change module on 82 real crops x 4 methods). - ShelfProductDetector accepts device/imgsz so the server can pin inference. Dependencies: pin ultralytics to the version that wrote the checkpoint and that the session tracker targets (8.4.153), add lap so ultralytics never pip-installs it mid-request, and add websockets for the streaming endpoint. Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
b443e3c381
commit
0f1d46f9b3
4 changed files with 73 additions and 32 deletions
|
|
@ -99,8 +99,17 @@ from ultralytics import YOLO
|
|||
class ShelfProductDetector:
|
||||
"""Wraps the YOLO detector for supermarket shelf products."""
|
||||
|
||||
def __init__(self, weights_path: str = "runs/detect/train/weights/best.pt"):
|
||||
def __init__(
|
||||
self,
|
||||
weights_path: str = "runs/detect/train/weights/best.pt",
|
||||
device: Optional[str] = None,
|
||||
imgsz: int = 640,
|
||||
half: bool = False
|
||||
):
|
||||
self.weights_path = weights_path
|
||||
self.device = device
|
||||
self.imgsz = imgsz
|
||||
self.half = half
|
||||
if not os.path.exists(weights_path):
|
||||
raise FileNotFoundError(f"YOLO weights not found at: {weights_path}")
|
||||
|
||||
|
|
@ -129,7 +138,14 @@ class ShelfProductDetector:
|
|||
return {"status": "error", "message": "Failed to read image", "boxes": []}
|
||||
|
||||
h, w = image_bgr.shape[:2]
|
||||
results = self.model(image_bgr, conf=conf_threshold, iou=iou_threshold, verbose=False)
|
||||
predict_kwargs: Dict[str, Any] = dict(
|
||||
conf=conf_threshold, iou=iou_threshold, imgsz=self.imgsz, verbose=False
|
||||
)
|
||||
if self.device:
|
||||
predict_kwargs["device"] = self.device
|
||||
if self.half:
|
||||
predict_kwargs["half"] = True
|
||||
results = self.model(image_bgr, **predict_kwargs)
|
||||
|
||||
boxes_list = []
|
||||
if results and len(results) > 0:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue