2025-07-30 11:54:39 +08:00

83 lines
2.2 KiB
Python

import cv2
from numpy import ones, uint8, concatenate
from ...robot.controller import SensorsController
from ...robot.sensor import Sensor
class Blob(Sensor):
registers = Sensor.registers + ['center', 'radius']
def __init__(self, x, y, radius):
self.center = x, y
self.radius = radius
def draw(self, img, color=(255, 0, 0), thickness=3):
cv2.circle(img, self.center, self.radius, color, thickness)
@property
def json(self):
return {"center": self.center, "radius": self.radius}
class BlobDetector(SensorsController):
channels = {
'R': 2, 'G': 1, 'B': 0,
'H': 0, 'S': 1, 'V': 2
}
def __init__(self, robot, name, cameras, freq, filters):
SensorsController.__init__(self, None, [], freq)
self.name = name
self._robot = robot
self._names = cameras
self._blobs = []
self.filters = filters
def detect_blob(self, img, filters):
"""
"filters" must be something similar to:
filters = {
'R': (150, 255), # (min, max)
'S': (150, 255),
}
"""
acc_mask = ones(img.shape[:2], dtype=uint8) * 255
rgb = img.copy()
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
for c, (min, max) in filters.items():
img = rgb if c in 'RGB' else hsv
mask = img[:, :, self.channels[c]]
mask[mask < min] = 0
mask[mask > max] = 0
acc_mask &= mask
kernel = ones((5, 5), uint8)
acc_mask = cv2.dilate(cv2.erode(acc_mask, kernel), kernel)
circles = cv2.HoughCircles(acc_mask, cv2.HOUGH_GRADIENT, 3, img.shape[0] / 5.)
return circles.reshape(-1, 3) if circles is not None else []
def update(self):
if not hasattr(self, 'cameras'):
self.cameras = [getattr(self._robot, c) for c in self._names]
self._blobs = concatenate([self.detect_blob(c.frame, self.filters)
for c in self.cameras])
@property
def blobs(self):
return [Blob(*b) for b in self._blobs]
@property
def registers(self):
return ['blobs']