adicionado ia de deteccao de objetos ao visual worker
This commit is contained in:
parent
c43e1daab8
commit
6853d3f264
Binary file not shown.
|
|
@ -7,9 +7,10 @@ from shared.enums import StatusModulo, T_Code
|
|||
from shared.contexto_global_redis import ContextoGlobalRedis, CtxKey
|
||||
|
||||
class CameraOak:
|
||||
def __init__(self, mostrar_log, mx_id, modelo_ia_onboard=None):
|
||||
def __init__(self, mostrar_log, mx_id, modelo_ia_seg=None, modelo_ia_det=None):
|
||||
self.mostrar_log = mostrar_log
|
||||
self.modelo_ia_onboard = modelo_ia_onboard
|
||||
self.modelo_ia_seg = modelo_ia_seg
|
||||
self.modelo_ia_det = modelo_ia_det
|
||||
|
||||
disp_list = dai.Device.getAllAvailableDevices()
|
||||
disp_info = next((d for d in disp_list if d.getMxId() == mx_id), None)
|
||||
|
|
@ -81,8 +82,11 @@ class CameraOak:
|
|||
self.q_imu = self.device.getOutputQueue(name="imu", maxSize=50, blocking=False)
|
||||
self.imu = IMUCamera(self.q_imu, freq=100, angulo_inicial=26.3)
|
||||
|
||||
if self.modelo_ia_onboard is not None:
|
||||
self.q_nn = self.device.getOutputQueue(name="nn", maxSize=1, blocking=False)
|
||||
if self.modelo_ia_seg is not None:
|
||||
self.q_seg = self.device.getOutputQueue(name="seg", maxSize=1, blocking=False)
|
||||
|
||||
if self.modelo_ia_det is not None:
|
||||
self.q_det = self.device.getOutputQueue(name="det", maxSize=4, blocking=False)
|
||||
|
||||
if self.dispositivo == T_Code.Snr:
|
||||
dadosSnr = ContextoGlobalRedis.get_operacao().get("Snr", {})
|
||||
|
|
@ -195,18 +199,36 @@ class CameraOak:
|
|||
except Exception as e:
|
||||
self.mostrar_log(f"[WARN] Falha ao montar pipeline imu: {e}")
|
||||
|
||||
if self.modelo_ia_onboard is not None:
|
||||
if self.modelo_ia_seg is not None or self.modelo_ia_det is not None:
|
||||
N_seg = self.modelo_ia_seg["det_every_n"]
|
||||
N_det = self.modelo_ia_det["det_every_n"]
|
||||
script = pipeline.create(dai.node.Script)
|
||||
script.setProcessor(dai.ProcessorType.LEON_CSS)
|
||||
script.setScript(f"""
|
||||
from time import monotonic
|
||||
i = 0
|
||||
while True:
|
||||
f = node.io['in'].get()
|
||||
if i % {N_seg} == 0:
|
||||
node.io['toSeg'].send(f)
|
||||
if i % {N_det} == 0:
|
||||
node.io['toDet'].send(f)
|
||||
i += 1
|
||||
""")
|
||||
cam.video.link(script.inputs['in'])
|
||||
|
||||
if self.modelo_ia_seg is not None:
|
||||
try:
|
||||
from shared.utils import carregar_labelmap_completo
|
||||
|
||||
# Carregar mapa de cores
|
||||
labelmap_path = self.modelo_ia_onboard["ia_labelmap_path"]
|
||||
self.cor_para_id, self.colormap_rgb, self.classes, self.ignore_rgb = carregar_labelmap_completo(labelmap_path)
|
||||
labelmap_path = self.modelo_ia_seg["ia_labelmap_path"]
|
||||
self.modelo_ia_seg["cor_para_id"], self.modelo_ia_seg["colormap_rgb"], self.modelo_ia_seg["classes"], self.modelo_ia_seg["ignore_rgb"] = carregar_labelmap_completo(labelmap_path)
|
||||
|
||||
RESOLUCAO = self.modelo_ia_onboard["ia_resolution"]
|
||||
ROI_INICIO = self.modelo_ia_onboard["ia_roi_begin"]
|
||||
ROI_TAMANHO = self.modelo_ia_onboard["ia_roi_size"]
|
||||
blob_path = self.modelo_ia_onboard["ia_model_path"]
|
||||
RESOLUCAO = self.modelo_ia_seg["ia_resolution"]
|
||||
ROI_INICIO = self.modelo_ia_seg["ia_roi_begin"]
|
||||
ROI_TAMANHO = self.modelo_ia_seg["ia_roi_size"]
|
||||
blob_path = self.modelo_ia_seg["ia_model_path"]
|
||||
|
||||
y1 = 1.0 - (ROI_INICIO + ROI_TAMANHO)
|
||||
y2 = 1.0 - ROI_INICIO
|
||||
|
|
@ -216,20 +238,66 @@ class CameraOak:
|
|||
manip.initialConfig.setResize(RESOLUCAO[0], RESOLUCAO[1])
|
||||
manip.initialConfig.setFrameType(dai.RawImgFrame.Type.RGB888p)
|
||||
manip.initialConfig.setKeepAspectRatio(False)
|
||||
cam.video.link(manip.inputImage)
|
||||
#cam.video.link(manip.inputImage)
|
||||
|
||||
nn = pipeline.createNeuralNetwork()
|
||||
nn.setBlobPath(blob_path)
|
||||
manip.out.link(nn.input)
|
||||
|
||||
xout_nn = pipeline.createXLinkOut()
|
||||
xout_nn.setStreamName("nn")
|
||||
xout_nn.setStreamName("seg")
|
||||
nn.out.link(xout_nn.input)
|
||||
|
||||
script.outputs['toSeg'].link(manip.inputImage)
|
||||
|
||||
self.mostrar_log("Pipeline de segmentação onboard criado")
|
||||
except Exception as e:
|
||||
self.mostrar_log(f"[WARN] Falha ao montar pipeline IA Onboard: {e}")
|
||||
|
||||
if self.modelo_ia_det is not None:
|
||||
try:
|
||||
RESOLUCAO = self.modelo_ia_det["ia_resolution"]
|
||||
ROI_INICIO = self.modelo_ia_det["ia_roi_begin"]
|
||||
ROI_TAMANHO = self.modelo_ia_det["ia_roi_size"]
|
||||
CONF = self.modelo_ia_det["ia_conf"]
|
||||
blob_path = self.modelo_ia_det["ia_model_path"]
|
||||
|
||||
y1 = 1.0 - (ROI_INICIO + ROI_TAMANHO)
|
||||
y2 = 1.0 - ROI_INICIO
|
||||
|
||||
if blob_path:
|
||||
manip_det = pipeline.createImageManip()
|
||||
manip_det.initialConfig.setCropRect(0.0, y1, 1.0, y2)
|
||||
manip_det.initialConfig.setResize(RESOLUCAO[0], RESOLUCAO[1])
|
||||
manip_det.initialConfig.setKeepAspectRatio(True)
|
||||
manip_det.initialConfig.setFrameType(dai.RawImgFrame.Type.RGB888p)
|
||||
|
||||
det = pipeline.createMobileNetDetectionNetwork()
|
||||
det.setBlobPath(blob_path)
|
||||
det.setConfidenceThreshold(CONF)
|
||||
det.setNumInferenceThreads(2)
|
||||
det.input.setBlocking(False)
|
||||
det.input.setQueueSize(2)
|
||||
manip_det.out.link(det.input)
|
||||
|
||||
xout_det = pipeline.createXLinkOut()
|
||||
xout_det.setStreamName("det")
|
||||
det.out.link(xout_det.input)
|
||||
|
||||
script.outputs['toDet'].link(manip_det.inputImage)
|
||||
|
||||
# (opcional) passthrough para sincronizar timestamp/frame com a detecção
|
||||
# xout_det_img = pipeline.createXLinkOut()
|
||||
# xout_det_img.setStreamName("det_img")
|
||||
# det.passthrough.link(xout_det_img.input)
|
||||
|
||||
self.mostrar_log("Pipeline de detecção leve (MobileNet-SSD) criado")
|
||||
else:
|
||||
self.mostrar_log("[INFO] Detector não configurado (detector_blob_path ausente). Pulando.")
|
||||
except Exception as e:
|
||||
self.mostrar_log(f"[WARN] Falha ao montar pipeline detecção: {e}")
|
||||
|
||||
|
||||
return pipeline
|
||||
|
||||
def _set_calib(self):
|
||||
|
|
@ -297,15 +365,15 @@ class CameraOak:
|
|||
}
|
||||
|
||||
def requisitar_segmentacao(self):
|
||||
if not hasattr(self, "q_nn"):
|
||||
return None, {"erro": "Segmentação não disponível", "duracao": 0, "frame_valido": False}
|
||||
if not hasattr(self, "q_seg"):
|
||||
return None, {"erro": "Segmentacao nao disponivel", "duracao": 0, "frame_valido": False}
|
||||
start = time.time()
|
||||
try:
|
||||
w, h = self.modelo_ia_onboard["ia_resolution"]
|
||||
in_nn = self.q_nn.get()
|
||||
out_raw = in_nn.getFirstLayerFp16()
|
||||
w, h = self.modelo_ia_seg["ia_resolution"]
|
||||
in_seg = self.q_seg.get()
|
||||
out_raw = in_seg.getFirstLayerFp16()
|
||||
arr16 = np.frombuffer(np.asarray(out_raw, dtype=np.float16), dtype=np.float16)
|
||||
arr16 = arr16.reshape(len(self.classes), h, w)
|
||||
arr16 = arr16.reshape(len(self.modelo_ia_seg["classes"]), h, w)
|
||||
pred_ids = arr16.argmax(axis=0).astype(np.uint8, copy=False)
|
||||
dur = time.time() - start
|
||||
self.timestamp_ultima_segmentacao = time.time()
|
||||
|
|
@ -313,6 +381,103 @@ class CameraOak:
|
|||
except Exception as e:
|
||||
dur = time.time() - start
|
||||
return None, {"erro": str(e), "duracao": dur, "frame_valido": False}
|
||||
|
||||
def requisitar_deteccao(self, mapear_para_fullframe: bool = False):
|
||||
"""
|
||||
Lê uma predição do detector leve (MobileNet-SSD/YOLO).
|
||||
Retorna (lista_de_deteccoes, meta).
|
||||
|
||||
Cada detecção:
|
||||
{
|
||||
"label_id": int,
|
||||
"label": str|None,
|
||||
"conf": float,
|
||||
"bbox_norm": [x0, y0, x1, y1], # 0..1, relativo ao input do detector (ROI)
|
||||
"bbox_px": [x0, y0, x1, y1], # em pixels do input do detector (ex.: 300x300)
|
||||
"bbox_full": [x0, y0, x1, y1], # opcional, só se mapear_para_fullframe=True e houver ROI/size salvos
|
||||
"xyz_m": [x,y,z] # opcional, se for SpatialDetectionNetwork
|
||||
}
|
||||
"""
|
||||
if not hasattr(self, "q_det"):
|
||||
return [], {"erro": "Deteccao não disponivel", "duracao": 0, "frame_valido": False}
|
||||
|
||||
# defaults caso você não tenha setado antes
|
||||
det_W, det_H = self.modelo_ia_det["ia_resolution"]
|
||||
|
||||
def _clamp01(v):
|
||||
return float(min(1.0, max(0.0, v)))
|
||||
|
||||
def _map_bbox_to_full(bn):
|
||||
# precisa: self.det_roi_frac = (rx1, ry1, rx2, ry2) em 0..1 no frame FULL
|
||||
# self.frame_size = (W_full, H_full)
|
||||
if not (hasattr(self, "det_roi_frac") and hasattr(self, "frame_size")):
|
||||
return None
|
||||
rx1, ry1, rx2, ry2 = self.det_roi_frac
|
||||
Wf, Hf = self.frame_size
|
||||
sx = (rx2 - rx1)
|
||||
sy = (ry2 - ry1)
|
||||
x0n, y0n, x1n, y1n = bn
|
||||
fx0 = (rx1 + x0n * sx) * Wf
|
||||
fy0 = (ry1 + y0n * sy) * Hf
|
||||
fx1 = (rx1 + x1n * sx) * Wf
|
||||
fy1 = (ry1 + y1n * sy) * Hf
|
||||
return [int(round(fx0)), int(round(fy0)), int(round(fx1)), int(round(fy1))]
|
||||
|
||||
start = time.time()
|
||||
try:
|
||||
pkt = self.q_det.get() # ImgDetections
|
||||
raw_dets = getattr(pkt, "detections", [])
|
||||
dets = []
|
||||
|
||||
for d in raw_dets:
|
||||
# normalizados 0..1 (clamp por segurança)
|
||||
x0n = _clamp01(getattr(d, "xmin", 0.0))
|
||||
y0n = _clamp01(getattr(d, "ymin", 0.0))
|
||||
x1n = _clamp01(getattr(d, "xmax", 0.0))
|
||||
y1n = _clamp01(getattr(d, "ymax", 0.0))
|
||||
|
||||
# em pixels do input do detector (ex.: 300x300)
|
||||
x0p = int(round(x0n * det_W)); y0p = int(round(y0n * det_H))
|
||||
x1p = int(round(x1n * det_W)); y1p = int(round(y1n * det_H))
|
||||
|
||||
label_id = int(getattr(d, "label", -1))
|
||||
conf = float(getattr(d, "confidence", 0.0))
|
||||
label = None
|
||||
labels = self.modelo_ia_det.get("classes", [])
|
||||
if 0 <= label_id < len(labels):
|
||||
if label_id != 0: # 0 = background
|
||||
label = labels[label_id]
|
||||
else:
|
||||
label = None
|
||||
|
||||
item = {
|
||||
"label_id": label_id,
|
||||
"label": label,
|
||||
"conf": conf,
|
||||
"bbox_norm": [x0n, y0n, x1n, y1n],
|
||||
"bbox_px": [x0p, y0p, x1p, y1p],
|
||||
}
|
||||
|
||||
# Se for SpatialDetectionNetwork, adiciona XYZ (em metros)
|
||||
if hasattr(d, "spatialCoordinates"):
|
||||
sc = d.spatialCoordinates
|
||||
item["xyz_m"] = [float(sc.x) / 1000.0, float(sc.y) / 1000.0, float(sc.z) / 1000.0]
|
||||
|
||||
# Opcional: mapear para o frame completo (leva em conta ROI da detecção)
|
||||
if mapear_para_fullframe:
|
||||
bf = _map_bbox_to_full(item["bbox_norm"])
|
||||
if bf is not None:
|
||||
item["bbox_full"] = bf
|
||||
|
||||
dets.append(item)
|
||||
|
||||
dur = time.time() - start
|
||||
self.timestamp_ultima_deteccao = time.time()
|
||||
return dets, {"erro": None, "duracao": dur, "frame_valido": True}
|
||||
|
||||
except Exception as e:
|
||||
dur = time.time() - start
|
||||
return [], {"erro": str(e), "duracao": dur, "frame_valido": False}
|
||||
|
||||
def atualizar_saude(self):
|
||||
#self.mostrar_log(f"[{self.mx_id}] Atualizando saude {self.dispositivo.name}...")
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -33,11 +33,13 @@ class CameraManager:
|
|||
self._ultima_analise_solo = {}
|
||||
self._ultima_analise_radar = {}
|
||||
self._ultima_analise_segmentacao = {}
|
||||
self._ultima_analise_deteccao = {}
|
||||
self._ultima_analise_matriz_confianca = {}
|
||||
self._ultima_analise_matriz_custo = {}
|
||||
self._ultimo_rgb_frame = None
|
||||
self._ultimo_depth_frame = None
|
||||
self._ts_segmentacao_anterior = 0
|
||||
self._ts_deteccao_anterior = 0
|
||||
self._pool = ThreadPoolExecutor(max_workers=6)
|
||||
|
||||
def inicializar(self, mx_id):
|
||||
|
|
@ -56,11 +58,12 @@ class CameraManager:
|
|||
|
||||
self.mx_id = mx_id
|
||||
|
||||
from visual_worker.config import load_config
|
||||
camera_config = load_config()
|
||||
from visual_worker.config import load_seg_config, load_det_config
|
||||
seg_config = load_seg_config()
|
||||
det_config = load_det_config()
|
||||
|
||||
try:
|
||||
nova = CameraOak(self.mostrar_log, mx_id, modelo_ia_onboard=camera_config)
|
||||
nova = CameraOak(self.mostrar_log, mx_id, modelo_ia_seg=seg_config, modelo_ia_det=det_config)
|
||||
if nova.iniciado:
|
||||
self.camera = nova
|
||||
except Exception as e:
|
||||
|
|
@ -78,7 +81,7 @@ class CameraManager:
|
|||
self.setores_referencia = None
|
||||
self.anomalias_manager = AnaliseAnomaliasManager()
|
||||
self.solo_manager = AnaliseSoloManager()
|
||||
self.segmentacao_manager = SegmentacaoManager(self.camera.colormap_rgb, self.camera.classes)
|
||||
self.segmentacao_manager = SegmentacaoManager(self.camera.modelo_ia_seg.get("colormap_rgb"), self.camera.modelo_ia_seg.get("classes"))
|
||||
self.radar_manager = Radar2DManager()
|
||||
self.data_fuser = CostmapFuser(grid_shape=self.grid_ref_shape, K=3, M=2, fuse_method="q0.7", block_thr=0.7, central_cols=None, y_range_m=(0.5,5.0), near_is_bottom=True, fov_h_rad=np.radians(self.camera.parametros["fov_h"]), robot_width=self.largura_robo_m)
|
||||
self.operante = True
|
||||
|
|
@ -88,12 +91,16 @@ class CameraManager:
|
|||
self._ultima_analise_solo = {}
|
||||
self._ultima_analise_radar = {}
|
||||
self._ultima_analise_segmentacao = {}
|
||||
self._ultima_analise_deteccao = {}
|
||||
self._ultima_analise_matriz_confianca = {}
|
||||
self._ultima_analise_matriz_custo = {}
|
||||
self._ts_segmentacao_anterior = 0
|
||||
self._ts_deteccao_anterior = 0
|
||||
self._ultimo_rgb_frame = None
|
||||
self._depth_frame_necessario = True
|
||||
self._rgb_frame_necessario = True
|
||||
self._nova_segmentacao_disponivel = False
|
||||
self._nova_deteccao_disponivel = False
|
||||
self._nova_grid_conf_disponivel = False
|
||||
|
||||
self._analisando_anomalias = False
|
||||
|
|
@ -102,6 +109,7 @@ class CameraManager:
|
|||
self._analisando_matriz_custo = False
|
||||
self._analisando_matriz_confianca = False
|
||||
self._analisando_segmentacao = False
|
||||
self._analisando_deteccao = False
|
||||
|
||||
self._iniciar_loop_analise_continua(15.0)
|
||||
self.iniciando = False
|
||||
|
|
@ -178,7 +186,6 @@ class CameraManager:
|
|||
try:
|
||||
predictions, res = self.camera.requisitar_segmentacao()
|
||||
if predictions is not None:
|
||||
self._ultimo_predictions = predictions
|
||||
return predictions, self.camera.timestamp_ultima_segmentacao, res
|
||||
elif "X_LINK_ERROR" in res["erro"]:
|
||||
self.reiniciar_status()
|
||||
|
|
@ -189,6 +196,23 @@ class CameraManager:
|
|||
|
||||
return None, None, None
|
||||
|
||||
def get_detections(self):
|
||||
if self.camera is None:
|
||||
return None, None, None
|
||||
|
||||
try:
|
||||
detections, res = self.camera.requisitar_deteccao()
|
||||
if detections is not None:
|
||||
return detections, self.camera.timestamp_ultima_deteccao, res
|
||||
elif "X_LINK_ERROR" in res["erro"]:
|
||||
self.reiniciar_status()
|
||||
except Exception as e:
|
||||
self.mostrar_log("Erro ao requisitar detections:", e)
|
||||
if "X_LINK_ERROR" in str(e):
|
||||
self.reiniciar_status()
|
||||
|
||||
return None, None, None
|
||||
|
||||
def get_select_frame(self, tipo: CameraFrameType):
|
||||
f = None
|
||||
t = None
|
||||
|
|
@ -273,18 +297,18 @@ class CameraManager:
|
|||
|
||||
|
||||
def _realizar_analises(self):
|
||||
self._analise_segmentacao()
|
||||
|
||||
if self._depth_frame_necessario:
|
||||
depth_frame_np, depth_timestamp, depth_res = self.get_depth_frame()
|
||||
else:
|
||||
depth_frame_np = self._ultimo_depth_frame
|
||||
self._analise_segmentacao()
|
||||
parametros_camera = self.camera.parametros
|
||||
fov_h = parametros_camera["fov_h"]
|
||||
distancia_max_m = parametros_camera["distancia_maxima"] / 1000.0
|
||||
self._analise_matriz_confianca(depth_frame_np, distancia_max_m, fov_h)
|
||||
#key, vis = self.debug_show_costmap(rgb_frame=self._ultimo_rgb_frame, grid_dict=self._ultima_analise_matriz_confianca, grid_shape=self.grid_ref_shape, window_name="viz MPC", wait=1, text_mode="mini")
|
||||
#key, vis = self.debug_show_visualworker(frame_bgr=self._ultimo_rgb_frame, grid=self._ultima_analise_matriz_confianca, wait=1, text_mode="full", draw_grid=True, draw_cells=True, draw_legend=True)
|
||||
self.segmentacao_manager.display_segmentation_debug(self._ultimo_rgb_frame, 150)
|
||||
|
||||
self._analise_deteccao()
|
||||
|
||||
def _realizar_analises_async(self):
|
||||
executor = self._pool
|
||||
|
|
@ -351,6 +375,12 @@ class CameraManager:
|
|||
)
|
||||
self._nova_segmentacao_disponivel = True
|
||||
|
||||
from visual_worker.config import load_seg_config
|
||||
if load_seg_config().get("debug_visual", False):
|
||||
#key, vis = self.debug_show_costmap(rgb_frame=self._ultimo_rgb_frame, grid_dict=self._ultima_analise_matriz_confianca, grid_shape=self.grid_ref_shape, window_name="viz MPC", wait=1, text_mode="mini")
|
||||
#key, vis = self.debug_show_visualworker(frame_bgr=self._ultimo_rgb_frame, grid=self._ultima_analise_matriz_confianca, wait=1, text_mode="full", draw_grid=True, draw_cells=True, draw_legend=True)
|
||||
self.segmentacao_manager.display_segmentation_debug(self._ultimo_rgb_frame, 150)
|
||||
|
||||
# Enviar comando para atualizar os dados de controle sempre que um novo dado de segmentacao seja processado e a operacao seja do tipo MapeamentoVisual
|
||||
#op_modo = ContextoGlobalRedis.get_operacao().get("modo", ModoOperacao.NaoDefinido.value)
|
||||
#movimento_automatico = ContextoGlobalRedis.get_controle().get("movimento_automatico", False)
|
||||
|
|
@ -375,7 +405,7 @@ class CameraManager:
|
|||
|
||||
t0 = time.time()
|
||||
#grid_conf = self._gerar_grid_confianca(depth_frame_np, segmentacao, dist_max)
|
||||
grid_conf = self._construir_grid_confianca(depth_frame_np, segmentacao, self.grid_ref, self.grid_ref_shape, self.camera.classes)
|
||||
grid_conf = self._construir_grid_confianca(depth_frame_np, segmentacao, self.grid_ref, self.grid_ref_shape, self.camera.modelo_ia_seg.get("classes"))
|
||||
#self.mostrar_log(grid_conf)
|
||||
t1 = time.time()
|
||||
grid_conf["ultima_chamada"] = self._ultima_analise_matriz_confianca.get("ultima_chamada", t0)
|
||||
|
|
@ -401,6 +431,38 @@ class CameraManager:
|
|||
self._analisando_matriz_confianca = False
|
||||
#self.mostrar_log("Matriz de confianca concluida")
|
||||
|
||||
def _analise_deteccao(self):
|
||||
if self._analisando_deteccao or self.camera.modelo_ia_det is None: return
|
||||
self._analisando_deteccao = True
|
||||
try:
|
||||
t0 = time.time()
|
||||
dets, ts, meta = self.get_detections()
|
||||
if ts == self._ts_deteccao_anterior: return
|
||||
self._ts_deteccao_anterior = ts
|
||||
if dets is not None:
|
||||
t1 = time.time()
|
||||
analise_deteccoes = {
|
||||
"bboxes": dets
|
||||
}
|
||||
self._calcular_performance(t0, t1, analise_deteccoes)
|
||||
self._ultima_analise_deteccao = analise_deteccoes
|
||||
ContextoGlobalRedis.atualizar_ctx_dict(
|
||||
CtxKey.DadosVisualWorker,
|
||||
ts_analise=t1,
|
||||
deteccao=converter_valores_numpy(dets)
|
||||
)
|
||||
self._nova_deteccao_disponivel = True
|
||||
|
||||
from visual_worker.config import load_det_config
|
||||
if load_det_config().get("debug_visual", False):
|
||||
self._overlay_deteccoes(self._ultimo_rgb_frame, dets)
|
||||
|
||||
except Exception as e:
|
||||
self.mostrar_log(f"❌ Erro na deteccao de objetos: {e}")
|
||||
finally:
|
||||
self._analisando_deteccao = False
|
||||
#self.mostrar_log(f"Deteccao concluida em {self._ultima_analise_deteccao['latencia']:.4f} s, a {fps:.4f} FPS")
|
||||
|
||||
def _analise_anomalias(self, grid_conf, limiar_delta, limiar_conf, dist_max, largura_min, altura_min):
|
||||
if self._analisando_anomalias:
|
||||
return
|
||||
|
|
@ -1399,4 +1461,122 @@ class CameraManager:
|
|||
cv2.imshow(win_name, vis)
|
||||
cv2.waitKey(1)
|
||||
return vis, metrics
|
||||
|
||||
|
||||
def _overlay_deteccoes(
|
||||
self,
|
||||
rgb_frame,
|
||||
dets,
|
||||
conf_thr=0.5, # limiar de confiança pra desenhar
|
||||
roi_frac=None, # (rx1,ry1,rx2,ry2) normalizado da ROI usada no detector (ex.: (0.0,y1,1.0,y2))
|
||||
show=True, # se True, faz cv2.imshow
|
||||
janela="det", # nome da janela
|
||||
fps_state=None, # dict estado do FPS (persistido fora), ex.: {}
|
||||
):
|
||||
"""
|
||||
dets: lista de dicts no formato:
|
||||
{
|
||||
"label_id": int,
|
||||
"label": str|None,
|
||||
"conf": float,
|
||||
"bbox_norm": [x0,y0,x1,y1] # 0..1 relativo ao input do detector (na ROI)
|
||||
# opcional: "bbox_full": [x0,y0,x1,y1] em px do frame completo
|
||||
}
|
||||
Retorna: (frame_com_overlay, fps_state, keep_loop_bool)
|
||||
"""
|
||||
img = cv2.resize(rgb_frame.copy(), (1280, 720))
|
||||
H, W = img.shape[:2]
|
||||
|
||||
# paleta simples por classe
|
||||
palette = [
|
||||
(255, 56, 56), (255, 157, 151), (72, 249, 10), (0, 255, 0), (0, 0, 255),
|
||||
(255, 0, 255), (0, 255, 255), (255, 191, 0), (52, 148, 230), (147, 112, 219)
|
||||
]
|
||||
|
||||
def _map_bbox_norm_to_full(bn):
|
||||
# bn é [x0n,y0n,x1n,y1n] relativo ao input da ROI (0..1)
|
||||
x0n, y0n, x1n, y1n = bn
|
||||
if roi_frac is not None:
|
||||
rx1, ry1, rx2, ry2 = roi_frac
|
||||
sx, sy = (rx2 - rx1), (ry2 - ry1)
|
||||
x0 = int(round((rx1 + x0n * sx) * W))
|
||||
y0 = int(round((ry1 + y0n * sy) * H))
|
||||
x1 = int(round((rx1 + x1n * sx) * W))
|
||||
y1 = int(round((ry1 + y1n * sy) * H))
|
||||
else:
|
||||
x0 = int(round(x0n * W))
|
||||
y0 = int(round(y0n * H))
|
||||
x1 = int(round(x1n * W))
|
||||
y1 = int(round(y1n * H))
|
||||
# clamp
|
||||
x0 = max(0, min(W - 1, x0)); x1 = max(0, min(W - 1, x1))
|
||||
y0 = max(0, min(H - 1, y0)); y1 = max(0, min(H - 1, y1))
|
||||
return x0, y0, x1, y1
|
||||
|
||||
def _put_label(img, text, x, y, bg):
|
||||
(tw, th), _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
|
||||
cv2.rectangle(img, (x, max(0, y - th - 6)), (x + tw + 6, y), bg, -1)
|
||||
cv2.putText(img, text, (x + 3, y - 4), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 1, cv2.LINE_AA)
|
||||
|
||||
# desenhar ROI (opcional, ajuda debug)
|
||||
if roi_frac is not None:
|
||||
rx1, ry1, rx2, ry2 = roi_frac
|
||||
x0r, y0r = int(rx1 * W), int(ry1 * H)
|
||||
x1r, y1r = int(rx2 * W), int(ry2 * H)
|
||||
cv2.rectangle(img, (x0r, y0r), (x1r, y1r), (60, 60, 60), 1)
|
||||
|
||||
# desenhar detecções
|
||||
for d in dets:
|
||||
if d.get("conf", 0.0) < conf_thr:
|
||||
continue
|
||||
|
||||
# bbox em px do frame
|
||||
if "bbox_full" in d and d["bbox_full"]:
|
||||
x0, y0, x1, y1 = d["bbox_full"]
|
||||
# clamp se necessário
|
||||
x0 = max(0, min(W - 1, int(x0))); x1 = max(0, min(W - 1, int(x1)))
|
||||
y0 = max(0, min(H - 1, int(y0))); y1 = max(0, min(H - 1, int(y1)))
|
||||
else:
|
||||
bn = d.get("bbox_norm", None)
|
||||
if not bn:
|
||||
continue
|
||||
x0, y0, x1, y1 = _map_bbox_norm_to_full(bn)
|
||||
|
||||
if x1 <= x0 or y1 <= y0:
|
||||
continue
|
||||
|
||||
lid = int(d.get("label_id", -1))
|
||||
color = palette[lid % len(palette)] if lid >= 0 else (0, 255, 0)
|
||||
|
||||
cv2.rectangle(img, (x0, y0), (x1, y1), color, 2)
|
||||
|
||||
name = d.get("label", None)
|
||||
txt = f"{name or f'id:{lid}'} {d.get('conf', 0.0):.2f}"
|
||||
_put_label(img, txt, x0, y0, color)
|
||||
|
||||
# FPS (EMA)
|
||||
now = time.monotonic()
|
||||
if fps_state is None:
|
||||
fps_state = {}
|
||||
t_prev = fps_state.get("t_prev")
|
||||
fps_ema = fps_state.get("fps_ema")
|
||||
if t_prev is not None:
|
||||
dt = now - t_prev
|
||||
if dt > 0:
|
||||
fps_inst = 1.0 / dt
|
||||
alpha = 0.90
|
||||
fps_ema = fps_inst if fps_ema is None else (alpha * fps_ema + (1 - alpha) * fps_inst)
|
||||
fps_state["t_prev"] = now
|
||||
fps_state["fps_ema"] = fps_ema
|
||||
|
||||
if fps_ema:
|
||||
cv2.putText(img, f"FPS: {fps_ema:.1f}", (10, 22), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (50, 220, 50), 2, cv2.LINE_AA)
|
||||
|
||||
keep = True
|
||||
if show:
|
||||
cv2.imshow(janela, img)
|
||||
k = cv2.waitKey(1) & 0xFF
|
||||
keep = (k != 27) # ESC para sair
|
||||
|
||||
return img, fps_state, keep
|
||||
|
||||
|
|
@ -37,7 +37,7 @@ _CONFIG_CACHE = None
|
|||
_CONFIG_MTIME = None
|
||||
_CONFIG_LOCK = threading.Lock()
|
||||
|
||||
def load_config(force_reload=False):
|
||||
def load_seg_config(force_reload=False):
|
||||
global _CONFIG_CACHE, _CONFIG_MTIME
|
||||
with _CONFIG_LOCK:
|
||||
#try:
|
||||
|
|
@ -72,15 +72,36 @@ def load_config(force_reload=False):
|
|||
# "kernel_morf": 3
|
||||
# }
|
||||
_CONFIG_CACHE = {
|
||||
"debug_visual": True,
|
||||
"debug_visual": False,
|
||||
"ia_roi_begin": 0.0,
|
||||
"ia_roi_size": 1.0,
|
||||
"ia_resolution": [512,288]
|
||||
"ia_resolution": [512,288],
|
||||
"det_every_n": 1,
|
||||
}
|
||||
_CONFIG_CACHE["ia_model_path"] = ContextoGlobalRedis.get_equipamento().get("path_ia_model_ruas", "C:/AgroBaseModels/Ruas/model-1_1.blob")
|
||||
_CONFIG_CACHE["ia_labelmap_path"] = ContextoGlobalRedis.get_equipamento().get("path_ia_labelmap_ruas", "C:/AgroBaseModels/Ruas/model-1_1.txt")
|
||||
|
||||
return _CONFIG_CACHE
|
||||
|
||||
def reload_config():
|
||||
return load_config(force_reload=True)
|
||||
def reload_seg_config():
|
||||
return load_seg_config(force_reload=True)
|
||||
|
||||
def load_det_config():
|
||||
_CONFIG_DET = {
|
||||
"debug_visual": False,
|
||||
"ia_roi_begin": 0.0,
|
||||
"ia_roi_size": 1.0,
|
||||
"ia_resolution": [300,300],
|
||||
"det_every_n": 3,
|
||||
"ia_conf": 0.5,
|
||||
"ia_model_path": "C:\\AgroBaseModels\\Ruas\\det_3.blob",
|
||||
"classes": [
|
||||
"background",
|
||||
"aeroplane","bicycle","bird","boat","bottle",
|
||||
"bus","car","cat","chair","cow",
|
||||
"diningtable","dog","horse","motorbike","person",
|
||||
"pottedplant","sheep","sofa","train","tvmonitor",
|
||||
]
|
||||
}
|
||||
return _CONFIG_DET
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -15,8 +15,8 @@ class ClassesSegmentacao(IntEnum):
|
|||
|
||||
class SegmentacaoManager:
|
||||
def __init__(self, color_map, classes):
|
||||
from visual_worker.config import load_config
|
||||
config = load_config()
|
||||
from visual_worker.config import load_seg_config
|
||||
config = load_seg_config()
|
||||
resolucao = config.get("ia_resolution")
|
||||
self.color_map = color_map
|
||||
self.classes = classes
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -42,8 +42,8 @@ class CameraManager:
|
|||
|
||||
self.mx_id = mx_id
|
||||
|
||||
from weed_worker.config import load_config
|
||||
camera_config = load_config()
|
||||
from weed_worker.config import load_seg_config
|
||||
camera_config = load_seg_config()
|
||||
|
||||
try:
|
||||
nova = CameraOak(self.mostrar_log, mx_id, modelo_ia_onboard=camera_config)
|
||||
|
|
@ -62,7 +62,7 @@ class CameraManager:
|
|||
self._ultimo_rgb_frame = None
|
||||
self._ultimo_predictions = None
|
||||
|
||||
self.weed_detector = WeedDetector(self.camera.colormap_rgb, self.camera.classes)
|
||||
self.weed_detector = WeedDetector(self.camera.modelo_ia_seg.get("colormap_rgb"), self.camera.modelo_ia_seg.get("classes"))
|
||||
|
||||
self._iniciar_loop_analise_continua(20.0)
|
||||
self.iniciando = False
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ _CONFIG_CACHE = None
|
|||
_CONFIG_MTIME = None
|
||||
_CONFIG_LOCK = threading.Lock()
|
||||
|
||||
def load_config(force_reload=False):
|
||||
def load_seg_config(force_reload=False):
|
||||
global _CONFIG_CACHE, _CONFIG_MTIME
|
||||
with _CONFIG_LOCK:
|
||||
#try:
|
||||
|
|
@ -104,5 +104,5 @@ def load_config(force_reload=False):
|
|||
_CONFIG_CACHE["faixa_atuacao_bicos"] = dadosAtu.get("percent_vertical_deteccao", 0.3)
|
||||
return _CONFIG_CACHE
|
||||
|
||||
def reload_config():
|
||||
return load_config(force_reload=True)
|
||||
def reload_seg_config():
|
||||
return load_seg_config(force_reload=True)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ class ClassesSegmentacao(IntEnum):
|
|||
|
||||
class WeedDetector:
|
||||
def __init__(self, color_map, classes):
|
||||
from weed_worker.config import load_config
|
||||
config = load_config()
|
||||
from weed_worker.config import load_seg_config
|
||||
config = load_seg_config()
|
||||
resolucao = config.get("ia_resolution")
|
||||
self.color_map = color_map
|
||||
self.classes = classes
|
||||
|
|
@ -40,8 +40,8 @@ class WeedDetector:
|
|||
self._seg_fps_ema = None # opcional: chame quando terminar a segmentação
|
||||
|
||||
def _reiniciar_deteccoes(self):
|
||||
from weed_worker.config import load_config
|
||||
config = load_config()
|
||||
from weed_worker.config import load_seg_config
|
||||
config = load_seg_config()
|
||||
qtd_bicos = config.get("qtd_bicos")
|
||||
self.ervas_ativas_radar = []
|
||||
self.ervas_ativas_filtradas = []
|
||||
|
|
@ -99,8 +99,8 @@ class WeedDetector:
|
|||
print("[Erro] Máscara de classes não encontrada no resultado")
|
||||
return None
|
||||
|
||||
from weed_worker.config import load_config
|
||||
config = load_config()
|
||||
from weed_worker.config import load_seg_config
|
||||
config = load_seg_config()
|
||||
|
||||
# vel_norm pode vir do contexto (0..1 da sua Vmax). Se não tiver, manda 0.0
|
||||
vel_norm = float(config.get("velocidade_robo", 0.0))
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ MODELO = config["camera"]
|
|||
MODEL_NAME = config["model_name"]
|
||||
RESOLUCAO = config["resolucao"]
|
||||
MAIN_CLASS_NAME = config["main_class_name"]
|
||||
N_SHAVES = config["shaves"]
|
||||
use_main_class = config["use_main_class"]
|
||||
model_path = os.path.join(MODELO, "backup", config["modelo"], MODEL_NAME)
|
||||
labelmap_path = os.path.join(MODELO, "dataset", "labelmap.txt")
|
||||
|
|
@ -55,7 +56,7 @@ blob_path = blobconverter.from_openvino(
|
|||
xml=os.path.join(model_path, model_name + ".xml"),
|
||||
bin=os.path.join(model_path, model_name + ".bin"),
|
||||
data_type="FP16",
|
||||
shaves=6,
|
||||
shaves=N_SHAVES,
|
||||
output_dir=model_path,
|
||||
#compile_params=[
|
||||
# "-ip U8", # entrada em bytes; compila a conversão interna p/ FP16
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@
|
|||
"use_main_class": false,
|
||||
"resolucao": [512, 288],
|
||||
"roi_inicio": 0.0,
|
||||
"roi_tamanho": 1.0
|
||||
"roi_tamanho": 1.0,
|
||||
"shaves": 3
|
||||
}
|
||||
Loading…
Reference in New Issue