"""Small local perception functions. A detector score is not a probability."""
import cv2

_hog = cv2.HOGDescriptor()
_hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())


def people(frame):
    if frame is None or frame.size == 0:
        raise ValueError("Camera returned an empty frame")
    height, width = frame.shape[:2]
    if height < 128 or width < 64:
        raise ValueError("Image is smaller than the detector's window")
    scale = min(1.0, 640 / width)
    small = cv2.resize(frame, (int(width * scale), int(height * scale)))
    if small.shape[0] < 128:
        raise ValueError("Resized image is too short; use a less panoramic frame")
    boxes, scores = _hog.detectMultiScale(small, winStride=(8, 8), padding=(8, 8), scale=1.05)
    return [(int(x / scale), int(y / scale), int(w / scale), int(h / scale))
            for (x, y, w, h), score in zip(boxes, scores) if float(score) > 0.5]


def marker(frame):
    """Locate a bright green marker; this rule-based function is NOT ML.

    Returns normalized (x, area) or None. Calibrate HSV bounds to the scene.
    """
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, (40, 80, 70), (85, 255, 255))
    count, _, stats, centroids = cv2.connectedComponentsWithStats(mask)
    if count <= 1:
        return None
    largest = 1 + stats[1:, cv2.CC_STAT_AREA].argmax()
    area = float(stats[largest, cv2.CC_STAT_AREA]) / (frame.shape[0] * frame.shape[1])
    if area < 0.005:
        return None
    return float(centroids[largest][0]) / frame.shape[1], area
