ajsutado salvamento para pós processamento

This commit is contained in:
Diego Freitas 2026-06-11 20:10:47 -03:00
parent 3b15a2473c
commit 405903d5da
4 changed files with 167 additions and 14 deletions

View File

@ -105,6 +105,11 @@ class CameraManager:
self.perf = VisualPerfMonitor(janela=180)
self.gpu_controller = None
self._ultimo_posproc_save_ts = 0.0
self._posproc_save_lock = threading.Lock()
self._posproc_salvando = False
self.posproc_intervalo_min_s = 5.0
self._reset_runtime_state()
# ============================================================
@ -197,6 +202,8 @@ class CameraManager:
self.seg_config = load_seg_config()
self.det_config = load_det_config()
self.posproc_intervalo_min_s = float(self.seg_config.get("posproc_intervalo_min_s", 5.0))
self.debug_visual = bool(self.seg_config.get("debug_visual", False))
self.debug_perf = bool(self.seg_config.get("debug_perf", False))
@ -1252,6 +1259,8 @@ class CameraManager:
if agora - self._ultimo_perf_publish >= 1.0:
self._ultimo_perf_publish = agora
self._atualizar_config_dinamica_visual(intervalo_s=1.0)
ctrl = self.gpu_controller
if ctrl is not None:
ctrl.update_from_redis()
@ -1291,6 +1300,33 @@ class CameraManager:
except Exception as e:
self.mostrar_log(f"[saude] erro: {e}")
def _atualizar_config_dinamica_visual(self, intervalo_s=1.0):
agora = time.time()
if not hasattr(self, "_ultimo_config_update_ts"):
self._ultimo_config_update_ts = 0.0
if (agora - self._ultimo_config_update_ts) < intervalo_s:
return
try:
from visual_worker.config import load_seg_config
cfg = load_seg_config() or {}
self.seg_config = cfg
self.debug_visual = bool(cfg.get("debug_visual", self.debug_visual))
self.debug_perf = bool(cfg.get("debug_perf", self.debug_perf))
self.posproc_intervalo_min_s = float(
cfg.get("posproc_intervalo_min_s", self.posproc_intervalo_min_s)
)
self._ultimo_config_update_ts = agora
except Exception as e:
self.mostrar_log(f"[visual] erro ao atualizar config dinâmica: {e}")
def _verificar_desconexao_camera(self):
if self.iniciando or self._em_warmup or time.time() < self._startup_grace_until:
return
@ -1441,7 +1477,6 @@ class CameraManager:
frame_name = nome.strip() if nome else datetime.datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3]
replay_jpeg_quality = 70
pos_jpeg_quality = 100
for frame_type in tipos:
try:
@ -1463,13 +1498,48 @@ class CameraManager:
# No Visual Worker, o dado científico é só a imagem limpa.
# Salva com qualidade máxima.
if tipo_enum == TipoFrameCamera.PosProcessamento:
caminho = os.path.join(pasta, f"{nome_base}.png")
pode_salvar, motivo = self._pode_salvar_posprocessamento()
ok = cv2.imwrite(caminho, frame)
if not pode_salvar:
self.mostrar_log(
f"[visual][SAVE_PP] pulado | motivo={motivo} "
f"intervalo_min={self.posproc_intervalo_min_s:.1f}s "
f"nome={nome_base}"
)
continue
if ok:
frames_salvos.append(caminho)
frame_pp = frame.copy()
def salvar_pp_async(nome_base_async, pasta_async, frame_async):
try:
t_pp0 = time.perf_counter()
caminho = os.path.join(pasta_async, f"{nome_base_async}.png")
ok = cv2.imwrite(caminho, frame_async)
t_pp1 = time.perf_counter()
self.mostrar_log(
f"[visual][SAVE_PP] salvo async | "
f"nome={nome_base_async} "
f"ok={ok} "
f"tempo_ms={(t_pp1 - t_pp0) * 1000.0:.1f}"
)
except Exception as e:
self.mostrar_log(f"❌ Erro no visual SAVE_PP async: {e}")
finally:
self._finalizar_salvamento_posprocessamento()
threading.Thread(
target=salvar_pp_async,
args=(nome_base, pasta, frame_pp),
daemon=True
).start()
frames_salvos.append(f"ASYNC_STARTED:{nome_base}")
continue
# ====================================================
@ -1493,6 +1563,26 @@ class CameraManager:
self.mostrar_log(f"❌ Erro ao salvar frames visual: {e}")
return []
def _pode_salvar_posprocessamento(self):
agora = time.time()
with self._posproc_save_lock:
if self._posproc_salvando:
return False, "busy"
dt = agora - self._ultimo_posproc_save_ts
if dt < self.posproc_intervalo_min_s:
return False, f"cooldown_{dt:.2f}s"
self._posproc_salvando = True
self._ultimo_posproc_save_ts = agora
return True, "ok"
def _finalizar_salvamento_posprocessamento(self):
with self._posproc_save_lock:
self._posproc_salvando = False
def _visual_disponivel_para_frame(self) -> bool:
"""
Indica se o Visual Worker tem o mínimo necessário para gerar/salvar frames.

View File

@ -115,6 +115,7 @@ VISUAL_DEFAULT_CONFIG = {
# ============================================================
# Mostra janelas OpenCV/debug visual. Não usar em runtime de campo.
"debug_visual": False,
"posproc_intervalo_min_s": 5.0,
# Publica logs de performance no console.
"debug_perf": False,

View File

@ -82,6 +82,11 @@ class CameraManager:
self.perf = VisualPerfMonitor(janela=180)
self._ultimo_posproc_save_ts = 0.0
self._posproc_save_lock = threading.Lock()
self._posproc_salvando = False
self.posproc_intervalo_min_s = 5.0
self._reset_runtime_state()
# ============================================================
@ -188,6 +193,8 @@ class CameraManager:
from weed_worker.config import load_seg_config
self.seg_config = load_seg_config()
self.posproc_intervalo_min_s = float(self.seg_config.get("posproc_intervalo_min_s", 5.0))
self._inicializar_camera(mx_id, self.seg_config)
if self.camera is None:
@ -526,6 +533,7 @@ class CameraManager:
cfg = load_seg_config()
self.seg_config = cfg
self.qtd_bicos = int(cfg.get("qtd_bicos", self.qtd_bicos or 7) or 7)
self.posproc_intervalo_min_s = float(cfg.get("posproc_intervalo_min_s", self.posproc_intervalo_min_s))
if self.weed_detector is not None:
self.weed_detector.atualizar_config(cfg)
@ -1533,17 +1541,49 @@ class CameraManager:
nome_frame = f"{frame_name}_{tipo_nome}"
if tipo_enum == TipoFrameCamera.PosProcessamento:
caminhos = self._salvar_bruto_multiespectral(
nome_base=nome_frame,
pasta=pasta
)
pode_salvar, motivo = self._pode_salvar_posprocessamento()
if caminhos:
if isinstance(caminhos, list):
frames_salvos.extend(caminhos)
else:
frames_salvos.append(caminhos)
if not pode_salvar:
self.mostrar_log(
f"[weed][SAVE_PP] pulado | motivo={motivo} "
f"intervalo_min={self.posproc_intervalo_min_s:.1f}s "
f"nome={nome_frame}"
)
continue
def salvar_pp_async(nome_frame_async, pasta_async):
try:
t_pp0 = time.perf_counter()
caminhos = self._salvar_bruto_multiespectral(
nome_base=nome_frame_async,
pasta=pasta_async
)
t_pp1 = time.perf_counter()
qtd = len(caminhos) if isinstance(caminhos, list) else 1 if caminhos else 0
self.mostrar_log(
f"[weed][SAVE_PP] salvo async | "
f"nome={nome_frame_async} "
f"arquivos={qtd} "
f"tempo_ms={(t_pp1 - t_pp0) * 1000.0:.1f}"
)
except Exception as e:
self.mostrar_log(f"❌ Erro no SAVE_PP async: {e}")
finally:
self._finalizar_salvamento_posprocessamento()
threading.Thread(
target=salvar_pp_async,
args=(nome_frame, pasta),
daemon=True
).start()
frames_salvos.append(f"{nome_frame}_PosProcessamento_ASYNC_STARTED")
continue
# ====================================================
@ -1635,3 +1675,24 @@ class CameraManager:
except Exception as e:
self.mostrar_log(f"❌ Erro ao salvar bruto multiespectral: {e}")
return []
def _pode_salvar_posprocessamento(self):
agora = time.time()
with self._posproc_save_lock:
if self._posproc_salvando:
return False, "busy"
dt = agora - self._ultimo_posproc_save_ts
if dt < self.posproc_intervalo_min_s:
return False, f"cooldown_{dt:.2f}s"
self._posproc_salvando = True
self._ultimo_posproc_save_ts = agora
return True, "ok"
def _finalizar_salvamento_posprocessamento(self):
with self._posproc_save_lock:
self._posproc_salvando = False

View File

@ -41,6 +41,7 @@ WEED_DEFAULT_CONFIG = {
# ============================================================
# Mostra janela OpenCV/debug visual. Não usar em runtime de campo.
"debug_visual": False,
"posproc_intervalo_min_s": 5.0,
# Publica logs de performance no console.
"debug_perf": False,