Salvando logs do visual e weed worker durante operacao

This commit is contained in:
Diego Freitas 2026-06-10 15:47:10 -03:00
parent 386520716e
commit 3aae33cc50
15 changed files with 978 additions and 548 deletions

View File

@ -48,6 +48,7 @@
this.nudTemposalvarlog = new System.Windows.Forms.NumericUpDown();
this.lblTemposalvarlog = new System.Windows.Forms.Label();
this.gpbP_Atu = new System.Windows.Forms.GroupBox();
this.cmbAgitadorModo = new System.Windows.Forms.ComboBox();
this.chbPulverizadorAutomatico = new System.Windows.Forms.CheckBox();
this.nudAtuarem = new System.Windows.Forms.NumericUpDown();
this.lblAtuarem = new System.Windows.Forms.Label();
@ -93,7 +94,7 @@
this.nudCapacidadereservatorio = new System.Windows.Forms.NumericUpDown();
this.lblUnCapcaidadereservatorio = new System.Windows.Forms.Label();
this.lblCapacidadereservatorio = new System.Windows.Forms.Label();
this.cmbAgitadorModo = new System.Windows.Forms.ComboBox();
this.chbGravarDadosPosProcessamento = new System.Windows.Forms.CheckBox();
this.gpbModulos.SuspendLayout();
this.gpbP_Knt.SuspendLayout();
this.gpbP_Sen.SuspendLayout();
@ -363,6 +364,17 @@
this.gpbP_Atu.TabStop = false;
this.gpbP_Atu.Text = "Ajustes";
//
// cmbAgitadorModo
//
this.cmbAgitadorModo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbAgitadorModo.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.cmbAgitadorModo.FormattingEnabled = true;
this.cmbAgitadorModo.Location = new System.Drawing.Point(9, 132);
this.cmbAgitadorModo.Margin = new System.Windows.Forms.Padding(6);
this.cmbAgitadorModo.Name = "cmbAgitadorModo";
this.cmbAgitadorModo.Size = new System.Drawing.Size(175, 32);
this.cmbAgitadorModo.TabIndex = 9;
//
// chbPulverizadorAutomatico
//
this.chbPulverizadorAutomatico.AutoSize = true;
@ -802,6 +814,7 @@
//
// gpbConfiguracoesgerais
//
this.gpbConfiguracoesgerais.Controls.Add(this.chbGravarDadosPosProcessamento);
this.gpbConfiguracoesgerais.Controls.Add(this.txtDensidadeherbicida);
this.gpbConfiguracoesgerais.Controls.Add(this.lblUnDensidadeherbicida);
this.gpbConfiguracoesgerais.Controls.Add(this.label2);
@ -872,16 +885,16 @@
this.lblCapacidadereservatorio.TabIndex = 9;
this.lblCapacidadereservatorio.Text = "Capacidade reservatório";
//
// cmbAgitadorModo
// chbGravarDadosPosProcessamento
//
this.cmbAgitadorModo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cmbAgitadorModo.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.cmbAgitadorModo.FormattingEnabled = true;
this.cmbAgitadorModo.Location = new System.Drawing.Point(9, 132);
this.cmbAgitadorModo.Margin = new System.Windows.Forms.Padding(6);
this.cmbAgitadorModo.Name = "cmbAgitadorModo";
this.cmbAgitadorModo.Size = new System.Drawing.Size(175, 32);
this.cmbAgitadorModo.TabIndex = 9;
this.chbGravarDadosPosProcessamento.AutoSize = true;
this.chbGravarDadosPosProcessamento.Location = new System.Drawing.Point(14, 219);
this.chbGravarDadosPosProcessamento.Margin = new System.Windows.Forms.Padding(6);
this.chbGravarDadosPosProcessamento.Name = "chbGravarDadosPosProcessamento";
this.chbGravarDadosPosProcessamento.Size = new System.Drawing.Size(354, 28);
this.chbGravarDadosPosProcessamento.TabIndex = 15;
this.chbGravarDadosPosProcessamento.Text = "Gravar dados para pós processamento";
this.chbGravarDadosPosProcessamento.UseVisualStyleBackColor = true;
//
// frmParametrizacaoOperacao
//
@ -998,5 +1011,6 @@
private System.Windows.Forms.CheckBox chbFrenagem;
private System.Windows.Forms.CheckBox chbMovAuxilioSonar;
private System.Windows.Forms.ComboBox cmbAgitadorModo;
private System.Windows.Forms.CheckBox chbGravarDadosPosProcessamento;
}
}

View File

@ -88,6 +88,8 @@ namespace AgroBase.Forms.Operacoes
txtAnteciparManobraM.Text = _Parametros.Controle.AnteciparManobraCorredorM.ToString();
cmbAgitadorModo.SelectedIndex = (int)_Parametros.Controle.AtuAgitadorModo;
chbGravarDadosPosProcessamento.Checked = _Parametros.Controle.RegistrarDadosPosProcessamento;
}
private void chbD_CheckedChanged(object sender, EventArgs e)
@ -148,6 +150,7 @@ namespace AgroBase.Forms.Operacoes
Variaveis.OperacaoEmAndamento.Parametros.Controle.MovAuxilioSonar = chbMovAuxilioSonar.Checked;
Variaveis.OperacaoEmAndamento.Parametros.Controle.FrenagemAutomaticaAoParar = chbFrenagem.Checked;
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuAgitadorModo = (ModoAgitadorCalda)cmbAgitadorModo.SelectedIndex;
Variaveis.OperacaoEmAndamento.Parametros.Controle.RegistrarDadosPosProcessamento = chbGravarDadosPosProcessamento.Checked;
Variaveis.OperacaoEmAndamento.Parametros.ModulosMandatorios = ModulosMandatorios.Where(x => x.Utilizar).ToList();
Variaveis.OperacaoEmAndamento.Parametros.Controle.PulverizadorAutomatico = chbPulverizadorAutomatico.Checked;

View File

@ -25,6 +25,8 @@ namespace AgroBase.Forms.Operacoes
List<AtuSensoriamentoLogModel> LogsAtuador = new List<AtuSensoriamentoLogModel>();
List<SensoriamentoMensagemJsonModel> LogsSensoriamento = new List<SensoriamentoMensagemJsonModel>();
List<List<CameraWorkerItemModel>> LogsCam_Solo = new List<List<CameraWorkerItemModel>>();
List<VisualWorkerModel> LogsVisualWorker = new List<VisualWorkerModel>();
List<WeedWorkerModel> LogsWeedWorker = new List<WeedWorkerModel>();
List<string> pathImagensSolo = new List<string>();
List<PictureBox> picsCamSolo = new List<PictureBox>();
List<PictureBox> picsCamSoloSeg = new List<PictureBox>();
@ -160,6 +162,8 @@ namespace AgroBase.Forms.Operacoes
LogsSensoriamento = JsonConvert.DeserializeObject<SensoriamentoMensagemJsonModel[]>(OperacaoModel.DeserializarDadosOperacao(ofd.FileName, data.sen ?? Enums.T_Code.Sen.ToString())).ToList();
pathImagensCaminho = ofd.FileName.Replace("data.lgop", data.cam_caminho + "\\");
LogsCam_Caminho = JsonConvert.DeserializeObject<List<CameraWorkerItemModel>>(OperacaoModel.DeserializarDadosOperacao(ofd.FileName, data.cam_caminho ?? Enums.T_Code.Snr.ToString())).ToList();
LogsVisualWorker = JsonConvert.DeserializeObject<List<VisualWorkerModel>>(OperacaoModel.DeserializarDadosOperacao(ofd.FileName, "VisualWorker")).ToList();
LogsWeedWorker = JsonConvert.DeserializeObject<List<WeedWorkerModel>>(OperacaoModel.DeserializarDadosOperacao(ofd.FileName, "WeedWorker")).ToList();
pathImagensSolo = new List<string>();
picsCamSolo = new List<PictureBox>();
@ -843,7 +847,7 @@ namespace AgroBase.Forms.Operacoes
{
new GraficoInterativoSerieModel()
{
Titulo = $"{camNome} RAM %",
Titulo = $"{camNome} RAM Mb",
Valores = camSolo.Select(x => (double)(x?.performance?.memoria_usada ?? 0)).ToList(),
Visivel = true,
MostrarValor = true
@ -865,7 +869,7 @@ namespace AgroBase.Forms.Operacoes
{
new GraficoInterativoSerieModel()
{
Titulo = $"{camNome} RAM %",
Titulo = $"{camNome} RAM Mb",
Valores = camCaminho.Select(x => (double)(x?.performance?.memoria_usada ?? 0)).ToList(),
Visivel = true,
MostrarValor = true
@ -895,10 +899,8 @@ namespace AgroBase.Forms.Operacoes
dtComandosDir.Columns.Add("clTipoMovimento", "Tipo Movimento");
dtComandosAtu.Columns.Clear();
dtComandosAtu.Columns.Add("clB0", "B0");
dtComandosAtu.Columns.Add("clB1", "B1");
dtComandosAtu.Columns.Add("clB2", "B2");
dtComandosAtu.Columns.Add("clB3", "B3");
for (int i = 1; i <= VariaveisEquipamento.QuantidadeBicosPulverizadores; i++)
dtComandosAtu.Columns.Add($"clB{i}", $"B{i}");
}
private void InicializarCombosBusca()
@ -1029,10 +1031,10 @@ namespace AgroBase.Forms.Operacoes
private Bitmap CarregarImagemCamera(string Caminho, string complemento = "")
{
string caminhoCompleto = Caminho + trbMomento.Value + ".jpeg";
string caminhoCompleto = Caminho + trbMomento.Value + ".jpg";
if (!string.IsNullOrEmpty(complemento))
{
caminhoCompleto = caminhoCompleto.Replace(".jpeg", $"{complemento}.jpeg");
caminhoCompleto = caminhoCompleto.Replace(".jpg", $"{complemento}.jpg");
}
Bitmap frame = new Bitmap(1, 1);
using (Graphics g = Graphics.FromImage(frame))
@ -1126,6 +1128,7 @@ namespace AgroBase.Forms.Operacoes
{
var Log = LogsOperacao[idxMomentoAtual];
var LogAtu = LogsAtuador[idxMomentoAtual];
var LogWw = LogsWeedWorker[idxMomentoAtual];
lblPercentualBateria.Text = $"Bateria {Log.Bateria.PercentualBateria.ToString("0.00")}%";
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualBateria, Log.Bateria.PercentualBateria);
@ -1145,7 +1148,7 @@ namespace AgroBase.Forms.Operacoes
txtHerbicidaPorErva.Text = LogAtu.HerbicidaPorAtuacao.ToString("0.00") + " ml";
txtDentroRua.Text = Log.Trajetoria.CorredorAtual.Dentro ? "Sim" : "Não";
txtDirecaoCarro.Text = Log.Trajetoria.DirecaoCaminho.ToString() + " (" + Log.Trajetoria.CorredorAtual.Idx + " - " + Log.Trajetoria.ProximoPonto.idxPonto + " - " + Log.Trajetoria.ProximoPonto.idxPontoCorredor + ")";
txtErvasNoRadar.Text = Log.Atuador.ErvasNoRadar.ToString() + " (" + (Log.Atuador.PercentualErvasNoRadar * 100).ToString("0.00") + "%)";
txtErvasNoRadar.Text = LogWw.Analise.ervas_no_radar + " (" + (LogWw.Analise.percentual_ervas_no_radar).ToString("0.00") + "%)";
txtErvasTerreno.Text = Log.Atuador.PercentualErvasTerreno.ToString("0.00");
txtTipoMovimento.Text = Log.Controle.TipoMovimento.ToString();
txtVelocidade.Text = (Log.Movimentacao.VelocidadeMedia * 3.6).ToString("0.00") + " km/h (" + Log.Movimentacao.VelocidadeMedia.ToString("0.00") + " m/s)";

View File

@ -155,7 +155,7 @@ namespace AgroBase.Forms
lblLeituraDebug.Text = $"Leitura em: " + (analise?.timestamp ?? DateTime.MinValue).ToString("dd/MM/yyyy HH:mm:ss");
OAKCameraFrameModel frame = VisualWorkerService.DadosLeitura.CameraFrames[TipoFrameCamera.Heatmap];
picDebug.Image?.Dispose();
picDebug.Image = analise.PlotarAnalise(frame);
//picDebug.Image = analise.PlotarAnalise(frame);
//PreencherGridAnomalias(analise.anomalias ?? new List<VisualWorkerMessageAnaliseBBoxModel>());
//PreencherGridSolo(analise.solo?.bbox_list ?? new List<VisualWorkerMessageAnaliseBBoxModel>());
@ -254,7 +254,7 @@ namespace AgroBase.Forms
chartPerfilSolo.Legends[0].Docking = Docking.Bottom;
}
void PlotarGraficoPerfilCorredor(List<VisualWorkerMessageRadar2DPerfilModel> perfilCorredor)
/*void PlotarGraficoPerfilCorredor(List<VisualWorkerMessageRadar2DPerfilModel> perfilCorredor)
{
chartCorredor.Series.Clear();
@ -303,7 +303,7 @@ namespace AgroBase.Forms
chartCorredor.ChartAreas[0].AxisX.Crossing = 0; // 🔥 Eixo X cruza no centro (0 lateral)
}
}*/
private void pnlInclinacao_Paint(object sender, PaintEventArgs e)
{

View File

@ -405,6 +405,7 @@ namespace AgroBase.Models
AtuPercentualInicioPulverizacao = 70,
AtuPressaoLinha = 85,
AtuAgitadorModo = ModoAgitadorCalda.SemAgitacao,
AtuModoControle = ModoControleBomba.OnOff
};
p.ModulosMandatorios = new List<OperacaoModulosMandatoriosModel>()
{
@ -515,7 +516,7 @@ namespace AgroBase.Models
AtuPercentualInicioPulverizacao = 70,
AtuPressaoLinha = 85,
AtuAgitadorModo = ModoAgitadorCalda.Continuo,
AtuModoControle = ModoControleBomba.PID,
AtuModoControle = ModoControleBomba.OnOff,
};
p.ModulosMandatorios = new List<OperacaoModulosMandatoriosModel>()
{
@ -2087,7 +2088,9 @@ namespace AgroBase.Models
SalvarLogLine(T_Code.Sen.ToString(), logSen);
SalvarLogCameraSolo();
SalvarLogLine("WeedWorker", Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorErvas);
SalvarLogCameraCaminho();
SalvarLogLine("VisualWorker", Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual);
string ArquivoOp = Variaveis.CaminhoOperacoes + Variaveis.OperacaoEmAndamento.ID + "/data.lgop";
if (!File.Exists(ArquivoOp))

View File

@ -1,7 +1,8 @@
using System;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Newtonsoft.Json;
using static AgroBase.Models.Enums;
namespace AgroBase.Models.Operadores
@ -13,12 +14,15 @@ namespace AgroBase.Models.Operadores
public bool Pronto { get; set; }
public DateTime ProntoEm { get; set; }
public DateTime UltimaMensagem { get; set; }
[JsonIgnore]
public Dictionary<TipoFrameCamera, OAKCameraFrameModel> CameraFrames { get; set; } = new Dictionary<TipoFrameCamera, OAKCameraFrameModel>();
public VisualWorkerMessageAnaliseModel Analises { get; set; } = new VisualWorkerMessageAnaliseModel();
public VisualWorkerMessageIMUModel Imu { get; set; } = new VisualWorkerMessageIMUModel();
public StatusModulo Status { get; set; }
public bool StatusValido => new List<StatusModulo>() { StatusModulo.Operante, StatusModulo.Alerta }.Contains(Status);
public VisualWorkerResumoModel Resumo { get; set; }
public VisualWorkerPerformanceModel Performance { get; set; } = new VisualWorkerPerformanceModel();
public VisualWorkerRedisTimestampsModel Timestamps { get; set; } = new VisualWorkerRedisTimestampsModel();
public VisualWorkerModel Clone()
{
@ -33,7 +37,9 @@ namespace AgroBase.Models.Operadores
Imu = Imu?.Clone(),
UltimaMensagem = UltimaMensagem,
Status = Status,
Resumo = Resumo?.Clone()
Resumo = Resumo?.Clone(),
Performance = Performance?.Clone() ?? new VisualWorkerPerformanceModel(),
Timestamps = Timestamps?.Clone() ?? new VisualWorkerRedisTimestampsModel(),
};
}
@ -48,6 +54,22 @@ namespace AgroBase.Models.Operadores
Imu = new VisualWorkerMessageIMUModel();
Resumo = new VisualWorkerResumoModel();
Status = StatusModulo.Desconectado;
Performance = new VisualWorkerPerformanceModel();
Timestamps = new VisualWorkerRedisTimestampsModel();
}
}
public class VisualWorkerRedisTimestampsModel
{
public double analise { get; set; }
public double segmentacao { get; set; }
public double deteccao { get; set; }
public double matriz_confianca { get; set; }
public double performance_visual { get; set; }
public VisualWorkerRedisTimestampsModel Clone()
{
return (VisualWorkerRedisTimestampsModel)MemberwiseClone();
}
}
@ -124,130 +146,48 @@ namespace AgroBase.Models.Operadores
}
}
public class VisualWorkerDadosModel
{
public bool DesvioNecessario { get; set; }
public Enums.Direcao DirecaoDesvio { get; set; }
public Obstaculo ObstaculoCritico { get; set; }
public List<Obstaculo> Obstaculos { get; set; }
public VisualWorkerDadosModel Clone()
{
return new VisualWorkerDadosModel()
{
DesvioNecessario = DesvioNecessario,
DirecaoDesvio = DirecaoDesvio,
ObstaculoCritico = ObstaculoCritico?.Clone(),
Obstaculos = new List<Obstaculo>(Obstaculos ?? new List<Obstaculo>()),
};
}
}
public class VisualWorkerMessageResponseModel
{
public VisualWorkerCommandType cmd { get; set; }
public VisualWorkerMessageResponseSaveFramesModel save_frames { get; set; }
public VisualWorkerMessageResponseModel Clone()
{
return new VisualWorkerMessageResponseModel()
{
cmd = cmd,
save_frames = save_frames.Clone()
};
}
}
public class VisualWorkerMessageResponseSaveFramesModel
{
public long timestamp { get; set; }
public List<string> frames { get; set; }
private bool _newData = false;
public bool newData
{
get
{
if (_newData)
{
_newData = false;
return true;
}
else
{
return false;
}
}
set
{
_newData = value;
}
}
public VisualWorkerMessageResponseSaveFramesModel Clone()
{
return new VisualWorkerMessageResponseSaveFramesModel()
{
timestamp = timestamp,
frames = new List<string>(frames),
newData = true
};
}
}
public class VisualWorkerMessageIMUModel
{
public long timestamp { get; set; }
public bool valido { get; set; }
public double timestamp { get; set; }
public double roll { get; set; }
public double pitch { get; set; }
public double yaw { get; set; }
public double yaw_fixed { get; set; }
public double frequencia_hz { get; set; }
public double latencia_ms { get; set; }
public double rugosidade { get; set; }
public double impacto { get; set; }
public double estabilidade { get; set; }
public bool movimento_detectado { get; set; }
[JsonExtensionData]
public IDictionary<string, JToken> Extra { get; set; } = new Dictionary<string, JToken>();
public VisualWorkerMessageIMUModel Clone()
{
return new VisualWorkerMessageIMUModel()
return new VisualWorkerMessageIMUModel
{
valido = valido,
timestamp = timestamp,
roll = roll,
pitch = pitch,
yaw = yaw,
};
}
}
public class VisualWorkerMessageSetupModel
{
public long timestamp { get; set; }
public bool status { get; set; }
private bool _newData = false;
public bool newData
{
get
{
if (_newData)
{
_newData = false;
return true;
}
else
{
return false;
}
}
set
{
_newData = value;
}
}
public VisualWorkerMessageSetupModel Clone()
{
return new VisualWorkerMessageSetupModel()
{
timestamp = timestamp,
status = status,
newData = true
yaw_fixed = yaw_fixed,
frequencia_hz = frequencia_hz,
latencia_ms = latencia_ms,
rugosidade = rugosidade,
impacto = impacto,
estabilidade = estabilidade,
movimento_detectado = movimento_detectado,
Extra = Extra?.ToDictionary(
x => x.Key,
x => x.Value?.DeepClone()
) ?? new Dictionary<string, JToken>()
};
}
}
@ -255,160 +195,20 @@ namespace AgroBase.Models.Operadores
public class VisualWorkerMessageAnaliseModel
{
public DateTime timestamp { get; set; }
//public List<VisualWorkerMessageAnaliseBBoxModel> anomalias { get; set; }
//public List<VisualWorkerMessageAnaliseBBoxModel> sombras { get; set; }
//public VisualWorkerMessageAnaliseSoloModel solo { get; set; }
//public List<VisualWorkerMessageRadar2DPerfilModel> corredor_prof { get; set; }
//public List<VisualWorkerMessageRadar2DPerfilModel> corredor_seg { get; set; }
public VisualWorkerMessageSegmentacaoSemanticaModel segmentacao { get; set; }
public VisualWorkerMessageMatrizConfiancaModel matriz_confianca { get; set; }
public List<VisualWorkerMessageDeteccaoModel> deteccao { get; set; }
public VisualWorkerMessageSegmentacaoSemanticaModel segmentacao { get; set; } = new VisualWorkerMessageSegmentacaoSemanticaModel();
public VisualWorkerMessageMatrizConfiancaModel matriz_confianca { get; set; } = new VisualWorkerMessageMatrizConfiancaModel();
public List<VisualWorkerMessageDeteccaoModel> deteccao { get; set; } = new List<VisualWorkerMessageDeteccaoModel>();
public VisualWorkerMessageAnaliseModel Clone()
{
return new VisualWorkerMessageAnaliseModel()
{
timestamp = timestamp,
//anomalias = new List<VisualWorkerMessageAnaliseBBoxModel>(anomalias ?? new List<VisualWorkerMessageAnaliseBBoxModel>()),
//sombras = new List<VisualWorkerMessageAnaliseBBoxModel>(sombras ?? new List<VisualWorkerMessageAnaliseBBoxModel>()),
//solo = solo?.Clone(),
//corredor_prof = new List<VisualWorkerMessageRadar2DPerfilModel>(corredor_prof ?? new List<VisualWorkerMessageRadar2DPerfilModel>()),
//corredor_seg = new List<VisualWorkerMessageRadar2DPerfilModel>(corredor_seg ?? new List<VisualWorkerMessageRadar2DPerfilModel>()),
segmentacao = segmentacao?.Clone() ?? new VisualWorkerMessageSegmentacaoSemanticaModel(),
matriz_confianca = matriz_confianca?.Clone() ?? new VisualWorkerMessageMatrizConfiancaModel(),
deteccao = deteccao?.Select(x => x.Clone()).ToList() ?? new List<VisualWorkerMessageDeteccaoModel>()
};
}
public Bitmap PlotarAnalise(OAKCameraFrameModel frame)
{
return null;
/*Bitmap img = frame?.image();
if (img == null) return null;
using (Graphics g = Graphics.FromImage(img))
{
Pen penObstaculo = new Pen(Color.Red, 2);
Pen penErosao = new Pen(Color.Blue, 2);
Pen penLombada = new Pen(Color.Orange, 2);
Pen penFaixaSolo = new Pen(Color.Black, 2);
Pen penGrafico = new Pen(Color.DarkGreen, 2);
Font font = new Font("Arial", 8);
Brush brush = Brushes.Black;
// 🔸 Definir brushes semi-transparentes para preenchimento
Brush brushObstaculo = new SolidBrush(Color.FromArgb(60, Color.Red));
Brush brushErosao = new SolidBrush(Color.FromArgb(60, Color.Blue));
Brush brushLombada = new SolidBrush(Color.FromArgb(60, Color.Orange));
int imgWidth = img.Width;
int imgHeight = img.Height;
// 🔸 Desenhar Bounding Boxes (Anomalias + Solo)
List<VisualWorkerMessageAnaliseBBoxModel> bboxes = new List<VisualWorkerMessageAnaliseBBoxModel>();
if (anomalias != null) bboxes.AddRange(anomalias);
//if (solo?.bbox_list != null) bboxes.AddRange(solo.bbox_list);
foreach (var bbox in bboxes)
{
Pen pen = penObstaculo;
Brush fill = brushObstaculo;
if (bbox.tipo == "erosao")
{
pen = penErosao;
fill = brushErosao;
}
if (bbox.tipo == "lombada")
{
pen = penLombada;
fill = brushLombada;
}
int x = (int)(bbox.bbox[0] * imgWidth);
int y = (int)(bbox.bbox[1] * imgHeight);
int w = (int)(bbox.bbox[2] * imgWidth);
int h = (int)(bbox.bbox[3] * imgHeight);
var rect = new Rectangle(x, y, w, h);
// 🔸 Preencher com opacidade
g.FillRectangle(fill, rect);
// 🔸 Contorno
g.DrawRectangle(pen, rect);
// 🔸 Label
string label = $"{bbox.tipo} {bbox.distancia_m}m Δ{bbox.variacao}mm";
g.DrawString(label, font, brush, rect.X, rect.Y - 12);
}
// 🔸 Linha da faixa do solo
if (solo != null)
{
int yInicio = imgHeight - (int)(solo.percent_y * imgHeight);
g.DrawLine(penFaixaSolo, 0, yInicio, imgWidth, yInicio);
}
// 🔸 Gráfico do perfil de solo
if (solo?.perfil != null && solo.perfil.Count > 1)
{
var perfil = solo.perfil;
int setores = solo.perfil.Count;
int yInicio = imgHeight - (int)(solo.percent_y * imgHeight);
int alturaRegiao = imgHeight / solo.perfil.Count;
double maxZ = perfil.Max();
double minZ = perfil.Min();
if (maxZ == minZ) maxZ += 1; // evita divisão por zero
for (int i = 0; i < perfil.Count - 1; i++)
{
float x1 = (float)(i * imgWidth / setores + imgWidth / (2.0 * setores));
float x2 = (float)((i + 1) * imgWidth / setores + imgWidth / (2.0 * setores));
float y1 = (float)(yInicio + alturaRegiao - ((perfil[i] - minZ) / (maxZ - minZ)) * alturaRegiao);
float y2 = (float)(yInicio + alturaRegiao - ((perfil[i + 1] - minZ) / (maxZ - minZ)) * alturaRegiao);
g.DrawLine(penGrafico, x1, y1, x2, y2);
g.FillEllipse(Brushes.DarkGreen, x1 - 3, y1 - 3, 6, 6);
}
// Desenha o último ponto
float xLast = (float)((perfil.Count - 1) * imgWidth / setores + imgWidth / (2.0 * setores));
float yLast = (float)(yInicio + alturaRegiao - ((perfil.Last() - minZ) / (maxZ - minZ)) * alturaRegiao);
g.FillEllipse(Brushes.DarkGreen, xLast - 3, yLast - 3, 6, 6);
}
}
return img;*/
}
}
public class VisualWorkerMessageAnaliseSoloModel
{
public List<double> perfil { get; set; }
public double percent_y { get; set; }
public double inclinacao { get; set; }
//public List<VisualWorkerMessageAnaliseBBoxModel> bbox_list { get; set; }
//public int y_inicio { get; set; }
//public int altura_regiao { get; set; }
//public int n_setores { get; set; }
public VisualWorkerMessageAnaliseSoloModel Clone()
{
return new VisualWorkerMessageAnaliseSoloModel()
{
perfil = new List<double>(perfil),
percent_y = percent_y,
inclinacao = inclinacao,
//bbox_list = new List<VisualWorkerMessageAnaliseBBoxModel>(bbox_list),
//y_inicio = y_inicio,
//altura_regiao = altura_regiao,
//n_setores = n_setores,
};
}
}
public class VisualWorkerMessageAnaliseBBoxModel
@ -423,142 +223,6 @@ namespace AgroBase.Models.Operadores
public double? variacao { get; set; } // delta Z ou null
}
public class VisualWorkerMessageRadar2DModel
{
public OAKCameraFrameModel frame { get; set; }
public VisualWorkerMessageRadar2DAnaliseModel analise { get; set; }
private bool _newData = false;
public bool newData
{
get
{
if (_newData)
{
_newData = false;
return true;
}
else
{
return false;
}
}
set
{
_newData = value;
}
}
public VisualWorkerMessageRadar2DModel Clone()
{
return new VisualWorkerMessageRadar2DModel()
{
frame = frame.Clone(),
analise = analise.Clone(),
newData = true
};
}
public Bitmap PlotarAnalsie(Bitmap img)
{
/*try
{
using (Graphics g = Graphics.FromImage(img))
{
var grid = analise.grid_info;
double cellSize = grid.cell_size;
double escala = grid.escala;
int imgSize = (int)grid.img_size;
int centerX = (int)grid.center_x;
int centerY = (int)grid.center_y;
int gridX = (int)(2 * grid.distancia_max / cellSize);
int gridZ = (int)(grid.distancia_max / cellSize);
foreach (var bbox in analise.bboxes_sombra)
{
int xGrid = bbox.bbox[0];
int zGrid = bbox.bbox[1];
int wGrid = bbox.bbox[2];
int hGrid = bbox.bbox[3];
// 🔸 Converte X (grid → metros → pixels com margem)
int pixelX = (int)(centerX + (xGrid - gridX / 2.0) * cellSize * escala);
// 🔸 Converte Z/Y (grid → metros → pixels com inversão vertical + margem)
int pixelY = (int)((centerY / 3) + zGrid * cellSize * escala);
// 🔸 Tamanho da bbox em pixels
int pixelW = (int)(wGrid * cellSize * escala);
int pixelH = (int)(hGrid * cellSize * escala);
// 🔸 Desenha a bbox
var rect = new Rectangle(pixelX, pixelY, pixelW, pixelH);
g.DrawRectangle(new Pen(Color.Red, 2), rect);
// 🔸 Desenha o centro da bbox
int centroX = pixelX + pixelW / 2;
int centroY = pixelY + pixelH / 2;
g.FillEllipse(Brushes.Red, centroX - 3, centroY - 3, 6, 6);
}
}
}
catch
{
}*/
return img;
}
}
public class VisualWorkerMessageRadar2DAnaliseModel
{
public List<VisualWorkerMessageAnaliseBBoxModel> bboxes_sombra { get; set; }
public List<VisualWorkerMessageRadar2DPerfilModel> corredor_perfil { get; set; }
public VisualWorkerMessageRadar2DGridInfoModel grid_info { get; set; }
public VisualWorkerMessageRadar2DAnaliseModel Clone()
{
return new VisualWorkerMessageRadar2DAnaliseModel()
{
bboxes_sombra = new List<VisualWorkerMessageAnaliseBBoxModel>(bboxes_sombra),
corredor_perfil = new List<VisualWorkerMessageRadar2DPerfilModel>(corredor_perfil),
grid_info = grid_info.Clone()
};
}
}
public class VisualWorkerMessageRadar2DPerfilModel
{
public double distancia_m { get; set; }
public double esquerda_m { get; set; }
public double direita_m { get; set; }
public double largura_m { get; set; }
}
public class VisualWorkerMessageRadar2DGridInfoModel
{
public double escala { get; set; }
public double img_size { get; set; }
public double center_x { get; set; }
public double center_y { get; set; }
public double cell_size { get; set; }
public double distancia_max { get; set; }
public double largura_max { get; set; }
public VisualWorkerMessageRadar2DGridInfoModel Clone()
{
return new VisualWorkerMessageRadar2DGridInfoModel()
{
escala = escala,
img_size = img_size,
center_x = center_x,
center_y = center_y,
cell_size = cell_size,
distancia_max = distancia_max,
largura_max = largura_max
};
}
}
public class VisualWorkerMessageSegmentacaoSemanticaModel
{
public double timestamp { get; set; }
@ -569,8 +233,8 @@ namespace AgroBase.Models.Operadores
public StatusCarroMapa status_corredor { get; set; }
public StatusCarroMapa status_corredor_anterior { get; set; }
public VisualWorkerMessageSegmentacaoSemanticaDebugCorredorModel status_corredor_debug { get; set; }
public List<double?[]> centros_corredor { get; set; }
public List<int> larguras_px { get; set; }
public List<double?[]> centros_corredor { get; set; } = new List<double?[]>();
public List<int> larguras_px { get; set; } = new List<int>();
public VisualWorkerMessageSegmentacaoSemanticaModel Clone()
{
@ -583,8 +247,11 @@ namespace AgroBase.Models.Operadores
erro_lateral_pct = erro_lateral_pct,
status_corredor = status_corredor,
status_corredor_anterior = status_corredor_anterior,
status_corredor_debug = status_corredor_debug,
centros_corredor = new List<double?[]>(centros_corredor ?? new List<double?[]>()),
status_corredor_debug = status_corredor_debug?.Clone(),
centros_corredor = centros_corredor?
.Select(x => x?.ToArray())
.ToList()
?? new List<double?[]>(),
larguras_px = new List<int>(larguras_px ?? new List<int>()),
};
}
@ -601,6 +268,30 @@ namespace AgroBase.Models.Operadores
public StatusCarroMapa status_heuristico { get; set; }
public string status_heuristico_nome { get; set; }
public dynamic heuristica_debug { get; set; }
public VisualWorkerMessageSegmentacaoSemanticaDebugCorredorModel Clone()
{
return new VisualWorkerMessageSegmentacaoSemanticaDebugCorredorModel
{
origem_status = origem_status,
status_modelo = status_modelo,
status_modelo_nome = status_modelo_nome,
status_modelo_label_name = status_modelo_label_name,
status_modelo_conf = status_modelo_conf,
status_modelo_probs = CloneDynamic(status_modelo_probs),
status_heuristico = status_heuristico,
status_heuristico_nome = status_heuristico_nome,
heuristica_debug = CloneDynamic(heuristica_debug)
};
}
private static object CloneDynamic(object valor)
{
if (valor is JToken token)
return token.DeepClone();
return valor;
}
}
public class VisualWorkerMessageMatrizConfiancaModel
@ -609,10 +300,10 @@ namespace AgroBase.Models.Operadores
public int seq { get; set; }
public int grid_w { get; set; }
public int grid_h { get; set; }
public List<float> y_range_m { get; set; }
public List<float> row_dist_m { get; set; }
public List<float> row_scale_x_m { get; set; }
public VisualWorkerMessageMatrizConfiancaBlockModel block { get; set; }
public List<float> y_range_m { get; set; } = new List<float>();
public List<float> row_dist_m { get; set; } = new List<float>();
public List<float> row_scale_x_m { get; set; } = new List<float>();
public VisualWorkerMessageMatrizConfiancaBlockModel block { get; set; } = new VisualWorkerMessageMatrizConfiancaBlockModel();
public VisualWorkerMessageMatrizConfiancaModel Clone()
{
@ -622,10 +313,10 @@ namespace AgroBase.Models.Operadores
seq = seq,
grid_w = grid_w,
grid_h = grid_h,
y_range_m = y_range_m,
y_range_m = new List<float>(y_range_m ?? new List<float>()),
row_dist_m = new List<float>(row_dist_m ?? new List<float>()),
row_scale_x_m = new List<float>(row_scale_x_m ?? new List<float>()),
block = block?.Clone() ?? new VisualWorkerMessageMatrizConfiancaBlockModel()
block = block?.Clone() ?? new VisualWorkerMessageMatrizConfiancaBlockModel(),
};
}
}
@ -728,9 +419,9 @@ namespace AgroBase.Models.Operadores
public string track_status { get; set; }
public bool tem_tracker { get; set; }
public List<double> xyz_m { get; set; }
public double distancia_m { get; set; }
public double lateral_m { get; set; }
public double altura_relativa_m { get; set; }
public double? distancia_m { get; set; }
public double? lateral_m { get; set; }
public double? altura_relativa_m { get; set; }
public List<double> bbox_full { get; set; }
public VisualWorkerMessageDeteccaoModel Clone()
@ -739,22 +430,158 @@ namespace AgroBase.Models.Operadores
{
label_id = label_id,
label = label,
bbox_norm = bbox_norm,
bbox_px = bbox_px,
bbox_norm = bbox_norm != null
? new List<double>(bbox_norm)
: new List<double>(),
bbox_px = bbox_px != null
? new List<double>(bbox_px)
: new List<double>(),
conf = conf,
track_id = track_id,
track_status = track_status,
tem_tracker = tem_tracker,
xyz_m = xyz_m,
xyz_m = xyz_m != null
? new List<double>(xyz_m)
: new List<double>(),
distancia_m = distancia_m,
lateral_m = lateral_m,
altura_relativa_m = altura_relativa_m,
bbox_full = bbox_full,
bbox_full = bbox_full != null
? new List<double>(bbox_full)
: new List<double>(),
};
}
}
public class VisualWorkerPerformanceModel
{
public double timestamp { get; set; }
public Dictionary<string, VisualWorkerPerformanceLoopModel> loops { get; set; }
= new Dictionary<string, VisualWorkerPerformanceLoopModel>();
public JObject sync { get; set; } = new JObject();
public JObject camera_cache { get; set; } = new JObject();
public VisualWorkerPerformanceCacheModel visual_cache { get; set; }
= new VisualWorkerPerformanceCacheModel();
public VisualWorkerPerformancePublicacaoModel pub_debug { get; set; }
= new VisualWorkerPerformancePublicacaoModel();
public JObject contadores { get; set; } = new JObject();
[JsonExtensionData]
public IDictionary<string, JToken> Extra { get; set; }
= new Dictionary<string, JToken>();
public VisualWorkerPerformanceModel Clone()
{
return new VisualWorkerPerformanceModel
{
timestamp = timestamp,
loops = loops?.ToDictionary(
x => x.Key,
x => x.Value?.Clone()
) ?? new Dictionary<string, VisualWorkerPerformanceLoopModel>(),
sync = sync != null ? (JObject)sync.DeepClone() : new JObject(),
camera_cache = camera_cache != null
? (JObject)camera_cache.DeepClone()
: new JObject(),
visual_cache = visual_cache?.Clone()
?? new VisualWorkerPerformanceCacheModel(),
pub_debug = pub_debug?.Clone()
?? new VisualWorkerPerformancePublicacaoModel(),
contadores = contadores != null
? (JObject)contadores.DeepClone()
: new JObject(),
Extra = Extra?.ToDictionary(
x => x.Key,
x => x.Value?.DeepClone()
) ?? new Dictionary<string, JToken>()
};
}
}
public class VisualWorkerPerformanceLoopModel
{
public double fps_real { get; set; }
public JObject periodo_ms { get; set; } = new JObject();
public JObject latencia_ms { get; set; } = new JObject();
public Dictionary<string, JObject> metrics_ms { get; set; }
= new Dictionary<string, JObject>();
[JsonExtensionData]
public IDictionary<string, JToken> Extra { get; set; }
= new Dictionary<string, JToken>();
public VisualWorkerPerformanceLoopModel Clone()
{
return new VisualWorkerPerformanceLoopModel
{
fps_real = fps_real,
periodo_ms = periodo_ms != null
? (JObject)periodo_ms.DeepClone()
: new JObject(),
latencia_ms = latencia_ms != null
? (JObject)latencia_ms.DeepClone()
: new JObject(),
metrics_ms = metrics_ms?.ToDictionary(
x => x.Key,
x => x.Value != null
? (JObject)x.Value.DeepClone()
: new JObject()
) ?? new Dictionary<string, JObject>(),
Extra = Extra?.ToDictionary(
x => x.Key,
x => x.Value?.DeepClone()
) ?? new Dictionary<string, JToken>()
};
}
}
public class VisualWorkerPerformanceCacheModel
{
public double seg_ts { get; set; }
public double det_ts { get; set; }
public double grid_ts { get; set; }
public bool tem_seg { get; set; }
public bool tem_grid { get; set; }
public VisualWorkerPerformanceCacheModel Clone()
{
return (VisualWorkerPerformanceCacheModel)MemberwiseClone();
}
}
public class VisualWorkerPerformancePublicacaoModel
{
public double ts { get; set; }
public int publicou { get; set; }
public int campos { get; set; }
public double redis_ms { get; set; }
public VisualWorkerPerformancePublicacaoModel Clone()
{
return (VisualWorkerPerformancePublicacaoModel)MemberwiseClone();
}
}
public enum VisualWorkerCommandType
{
ScriptCarregado = 1,

View File

@ -1,5 +1,8 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using static AgroBase.Models.Enums;
namespace AgroBase.Models.Operadores
@ -11,21 +14,35 @@ namespace AgroBase.Models.Operadores
public bool Pronto { get; set; }
public DateTime ProntoEm { get; set; }
public DateTime UltimaMensagem { get; set; }
[JsonIgnore]
public Dictionary<TipoFrameCamera, OAKCameraFrameModel> CameraFrames { get; set; } = new Dictionary<TipoFrameCamera, OAKCameraFrameModel>();
public WeedWorkerAnaliseModel Analise { get; set; } = new WeedWorkerAnaliseModel();
public WeedWorkerPerformanceModel Performance { get; set; } = new WeedWorkerPerformanceModel();
public WeedWorkerAnaliseMetricasModel MetricasAnalise { get; set; } = new WeedWorkerAnaliseMetricasModel();
public WeedWorkerRedisTimestampsModel Timestamps { get; set; } = new WeedWorkerRedisTimestampsModel();
public WeedWorkerModel Clone()
{
return new WeedWorkerModel()
return new WeedWorkerModel
{
Iniciado = Iniciado,
IniciadoEm = IniciadoEm,
Pronto = Pronto,
ProntoEm = ProntoEm,
CameraFrames = new Dictionary<TipoFrameCamera, OAKCameraFrameModel>(CameraFrames ?? new Dictionary<TipoFrameCamera, OAKCameraFrameModel>()),
Analise = Analise.Clone(),
UltimaMensagem = UltimaMensagem,
Analise = Analise?.Clone()
?? new WeedWorkerAnaliseModel(),
MetricasAnalise = MetricasAnalise?.Clone()
?? new WeedWorkerAnaliseMetricasModel(),
Performance = Performance?.Clone()
?? new WeedWorkerPerformanceModel(),
Timestamps = Timestamps?.Clone()
?? new WeedWorkerRedisTimestampsModel()
};
}
@ -33,9 +50,73 @@ namespace AgroBase.Models.Operadores
{
Iniciado = false;
IniciadoEm = DateTime.MinValue;
Pronto = false;
ProntoEm = DateTime.MinValue;
CameraFrames = new Dictionary<TipoFrameCamera, OAKCameraFrameModel>();
UltimaMensagem = DateTime.MinValue;
CameraFrames =
new Dictionary<TipoFrameCamera, OAKCameraFrameModel>();
Analise = new WeedWorkerAnaliseModel();
MetricasAnalise = new WeedWorkerAnaliseMetricasModel();
Performance = new WeedWorkerPerformanceModel();
Timestamps = new WeedWorkerRedisTimestampsModel();
}
}
public class WeedWorkerAnaliseMetricasModel
{
public double ts_analise { get; set; }
public double fps_model { get; set; }
public double fps_inferencia { get; set; }
public double infer_ms { get; set; }
public double infer_gpu_ms { get; set; }
public WeedWorkerAnaliseMetricasModel Clone()
{
return (WeedWorkerAnaliseMetricasModel)MemberwiseClone();
}
}
public class WeedWorkerAnaliseEnvelopeModel
{
public double ts_analise { get; set; }
public double fps_model { get; set; }
public double fps_inferencia { get; set; }
public double infer_ms { get; set; }
public double infer_gpu_ms { get; set; }
public WeedWorkerAnaliseModel analise { get; set; }
= new WeedWorkerAnaliseModel();
[JsonExtensionData]
public IDictionary<string, JToken> Extra { get; set; }
= new Dictionary<string, JToken>();
public WeedWorkerAnaliseEnvelopeModel Clone()
{
return new WeedWorkerAnaliseEnvelopeModel
{
ts_analise = ts_analise,
fps_model = fps_model,
fps_inferencia = fps_inferencia,
infer_ms = infer_ms,
infer_gpu_ms = infer_gpu_ms,
analise = analise?.Clone()
?? new WeedWorkerAnaliseModel(),
Extra = Extra?.ToDictionary(
x => x.Key,
x => x.Value?.DeepClone()
) ?? new Dictionary<string, JToken>()
};
}
}
@ -51,9 +132,11 @@ namespace AgroBase.Models.Operadores
public double timestamp { get; set; }
public int height { get; set; }
public int width { get; set; }
public Dictionary<int, bool> controle { get; set; }
public Dictionary<int, bool> controle { get; set; } = new Dictionary<int, bool>();
public bool ervas_no_radar { get; set; }
public WeedWorkerAnaliseEstatisticasModel estatisticas { get; set; }
public double fracao_ervas_no_radar { get; set; }
public double percentual_ervas_no_radar { get; set; }
public WeedWorkerAnaliseEstatisticasModel estatisticas { get; set; } = new WeedWorkerAnaliseEstatisticasModel();
public WeedWorkerAnaliseModel Clone()
{
@ -64,28 +147,17 @@ namespace AgroBase.Models.Operadores
height = height,
width = width,
ervas_no_radar = ervas_no_radar,
fracao_ervas_no_radar = fracao_ervas_no_radar,
percentual_ervas_no_radar = percentual_ervas_no_radar,
estatisticas = estatisticas?.Clone()
};
}
}
public class WeedWorkerAnaliseDeteccaoModel
{
public int id { get; set; }
public double[] centro { get; set; }
public double[] bbox { get; set; }
public int class_id { get; set; }
public int ultimo_frame { get; set; }
public int frames_detectada { get; set; }
public string status { get; set; }
public string descricao { get; set; }
public double confianca { get; set; }
}
public class WeedWorkerAnaliseEstatisticasModel
{
public WeedWorkerAnaliseEstatisticasErvasModel erva { get; set; }
public WeedWorkerAnaliseEstatisticasBicosModel bicos { get; set; }
public WeedWorkerAnaliseEstatisticasErvasModel erva { get; set; } = new WeedWorkerAnaliseEstatisticasErvasModel();
public WeedWorkerAnaliseEstatisticasBicosModel bicos { get; set; } = new WeedWorkerAnaliseEstatisticasBicosModel();
public WeedWorkerAnaliseEstatisticasModel Clone()
{
@ -120,19 +192,62 @@ namespace AgroBase.Models.Operadores
public class WeedWorkerAnaliseEstatisticasBicosModel
{
public List<double> larguras { get; set; }
public List<double> contagem_cana_px_por_bico { get; set; }
public List<double> contagem_cana_frac_por_bico { get; set; }
public string motivo { get; set; }
public List<double> frac_erva_por_bico { get; set; }
= new List<double>();
public List<double> ema_frac_por_bico { get; set; }
= new List<double>();
public WeedWorkerAnaliseEstatisticasBicosFaixaModel faixa { get; set; }
= new WeedWorkerAnaliseEstatisticasBicosFaixaModel();
public List<double> larguras { get; set; }
= new List<double>();
public int shift_px { get; set; }
public double thr_on_eff { get; set; }
public double thr_off_eff { get; set; }
public List<int> on_cnt { get; set; }
= new List<int>();
public List<int> off_cnt { get; set; }
= new List<int>();
public List<bool> estado_bico { get; set; }
= new List<bool>();
[JsonExtensionData]
public IDictionary<string, JToken> Extra { get; set; }
= new Dictionary<string, JToken>();
public WeedWorkerAnaliseEstatisticasBicosModel Clone()
{
return new WeedWorkerAnaliseEstatisticasBicosModel()
return new WeedWorkerAnaliseEstatisticasBicosModel
{
larguras = new List<double>(larguras),
contagem_cana_frac_por_bico = new List<double>(contagem_cana_frac_por_bico ?? new List<double>()),
contagem_cana_px_por_bico = new List<double>(contagem_cana_px_por_bico ?? new List<double>()),
motivo = motivo,
frac_erva_por_bico =
new List<double>(frac_erva_por_bico ?? new List<double>()),
ema_frac_por_bico =
new List<double>(ema_frac_por_bico ?? new List<double>()),
faixa = faixa?.Clone()
?? new WeedWorkerAnaliseEstatisticasBicosFaixaModel(),
larguras =
new List<double>(larguras ?? new List<double>()),
shift_px = shift_px,
thr_on_eff = thr_on_eff,
thr_off_eff = thr_off_eff,
on_cnt = new List<int>(on_cnt ?? new List<int>()),
off_cnt = new List<int>(off_cnt ?? new List<int>()),
estado_bico =
new List<bool>(estado_bico ?? new List<bool>()),
Extra = Extra?.ToDictionary(
x => x.Key,
x => x.Value?.DeepClone()
) ?? new Dictionary<string, JToken>()
};
}
}
@ -152,6 +267,144 @@ namespace AgroBase.Models.Operadores
}
}
public class WeedWorkerPerformanceModel
{
public double timestamp { get; set; }
public Dictionary<string, WeedWorkerPerformanceLoopModel> loops { get; set; }
= new Dictionary<string, WeedWorkerPerformanceLoopModel>();
public JObject sync { get; set; } = new JObject();
public WeedWorkerPerformanceCacheModel weed_cache { get; set; }
= new WeedWorkerPerformanceCacheModel();
public WeedWorkerPerformancePublicacaoModel pub_debug { get; set; }
= new WeedWorkerPerformancePublicacaoModel();
public JObject contadores { get; set; } = new JObject();
[JsonExtensionData]
public IDictionary<string, JToken> Extra { get; set; }
= new Dictionary<string, JToken>();
public WeedWorkerPerformanceModel Clone()
{
return new WeedWorkerPerformanceModel
{
timestamp = timestamp,
loops = loops?.ToDictionary(
x => x.Key,
x => x.Value?.Clone()
) ?? new Dictionary<string, WeedWorkerPerformanceLoopModel>(),
sync = sync != null
? (JObject)sync.DeepClone()
: new JObject(),
weed_cache = weed_cache?.Clone()
?? new WeedWorkerPerformanceCacheModel(),
pub_debug = pub_debug?.Clone()
?? new WeedWorkerPerformancePublicacaoModel(),
contadores = contadores != null
? (JObject)contadores.DeepClone()
: new JObject(),
Extra = Extra?.ToDictionary(
x => x.Key,
x => x.Value?.DeepClone()
) ?? new Dictionary<string, JToken>()
};
}
}
public class WeedWorkerPerformanceLoopModel
{
public double fps_real { get; set; }
public JObject periodo_ms { get; set; } = new JObject();
public JObject latencia_ms { get; set; } = new JObject();
public Dictionary<string, JObject> metrics_ms { get; set; }
= new Dictionary<string, JObject>();
[Newtonsoft.Json.JsonExtensionData]
public IDictionary<string, JToken> Extra { get; set; }
= new Dictionary<string, JToken>();
public WeedWorkerPerformanceLoopModel Clone()
{
return new WeedWorkerPerformanceLoopModel
{
fps_real = fps_real,
periodo_ms = periodo_ms != null
? (JObject)periodo_ms.DeepClone()
: new JObject(),
latencia_ms = latencia_ms != null
? (JObject)latencia_ms.DeepClone()
: new JObject(),
metrics_ms = metrics_ms?.ToDictionary(
x => x.Key,
x => x.Value != null
? (JObject)x.Value.DeepClone()
: new JObject()
) ?? new Dictionary<string, JObject>(),
Extra = Extra?.ToDictionary(
x => x.Key,
x => x.Value?.DeepClone()
) ?? new Dictionary<string, JToken>()
};
}
}
public class WeedWorkerPerformanceCacheModel
{
public double tensor_ts { get; set; }
public double? tensor_age_ms { get; set; }
public double tensor_consumido_ts { get; set; }
public bool tem_tensor { get; set; }
public WeedWorkerPerformanceCacheModel Clone()
{
return (WeedWorkerPerformanceCacheModel)MemberwiseClone();
}
}
public class WeedWorkerPerformancePublicacaoModel
{
public double ts { get; set; }
public int publicou { get; set; }
public int campos { get; set; }
public double redis_ms { get; set; }
public WeedWorkerPerformancePublicacaoModel Clone()
{
return (WeedWorkerPerformancePublicacaoModel)MemberwiseClone();
}
}
public class WeedWorkerRedisTimestampsModel
{
public double analise { get; set; }
public double analise_weed { get; set; }
public double performance_weed { get; set; }
public WeedWorkerRedisTimestampsModel Clone()
{
return (WeedWorkerRedisTimestampsModel)MemberwiseClone();
}
}
public enum WeedWorkerCommandType
{
ScriptCarregado = 1,

View File

@ -18,7 +18,10 @@ namespace AgroBase.Services.Operadores
private bool DebugMode = true;
static long _lastTsVW = -1;
private static double _lastTsSegmentacao = -1;
private static double _lastTsDeteccao = -1;
private static double _lastTsMatrizConfianca = -1;
private static double _lastTsPerformanceVisual = -1;
public void MostrarLog(string message, int limite = 500)
{
@ -143,92 +146,211 @@ namespace AgroBase.Services.Operadores
public static void AtualizarAnalise()
{
// IMU (simples e direto)
string imuJson = RedisService.Get(RedisService.ModKey(Enums.T_Code.Imu));
if (!string.IsNullOrWhiteSpace(imuJson))
{
try
{
DadosLeitura.Imu = JsonConvert.DeserializeObject<VisualWorkerMessageIMUModel>(imuJson);
}
catch { /* opcional: logar erro */ }
}
AtualizarImu();
DadosLeitura.Status = HealthWorkerService.ModulosSaude.FirstOrDefault(x => x.modulo == Enums.T_Code.Snr)?.status ?? Enums.StatusModulo.Desconectado;
DadosLeitura.Status =
HealthWorkerService.ModulosSaude
.FirstOrDefault(x => x.modulo == Enums.T_Code.Snr)?.status
?? Enums.StatusModulo.Desconectado;
// VisualWorker
var json = RedisService.Get(CtxKey.DadosVisualWorker);
if (string.IsNullOrWhiteSpace(json)) return;
string json = RedisService.Get(CtxKey.DadosVisualWorker);
if (string.IsNullOrWhiteSpace(json))
return;
JObject root;
try
{
root = JObject.Parse(json);
}
catch (Exception ex)
{
// Opcional: registrar payload inválido
return;
}
double tsAnalise =
root["ts_analise"]?.Value<double>() ?? 0.0;
double tsSegmentacao =
root["ts_segmentacao"]?.Value<double>() ?? 0.0;
double tsDeteccao =
root["ts_deteccao"]?.Value<double>() ?? 0.0;
double tsMatriz =
root["ts_matriz_confianca"]?.Value<double>() ?? 0.0;
double tsPerformance =
root["ts_performance_visual"]?.Value<double>() ?? 0.0;
DadosLeitura.Timestamps.analise = tsAnalise;
DadosLeitura.Timestamps.segmentacao = tsSegmentacao;
DadosLeitura.Timestamps.deteccao = tsDeteccao;
DadosLeitura.Timestamps.matriz_confianca = tsMatriz;
DadosLeitura.Timestamps.performance_visual = tsPerformance;
if (tsAnalise > 0)
{
DadosLeitura.Analises.timestamp =
FuncoesGlobais.UnixToDateTime(tsAnalise.ToString(
System.Globalization.CultureInfo.InvariantCulture
));
}
if (tsSegmentacao > 0 &&
tsSegmentacao != _lastTsSegmentacao)
{
var token = root["segmentacao"];
if (token != null &&
token.Type != JTokenType.Null)
{
try
{
var model =
token.ToObject<VisualWorkerMessageSegmentacaoSemanticaModel>();
if (model != null)
DadosLeitura.Analises.segmentacao = model;
}
catch
{
// Opcional: registrar erro de contrato
}
}
_lastTsSegmentacao = tsSegmentacao;
}
if (tsDeteccao > 0 &&
tsDeteccao != _lastTsDeteccao)
{
var token = root["deteccao"];
if (token != null &&
token.Type != JTokenType.Null)
{
try
{
var model =
token.ToObject<List<VisualWorkerMessageDeteccaoModel>>();
DadosLeitura.Analises.deteccao =
model ?? new List<VisualWorkerMessageDeteccaoModel>();
}
catch
{
// Opcional: registrar erro de contrato
}
}
_lastTsDeteccao = tsDeteccao;
}
if (tsMatriz > 0 &&
tsMatriz != _lastTsMatrizConfianca)
{
var token = root["matriz_confianca"];
if (token != null &&
token.Type != JTokenType.Null)
{
try
{
var model =
token.ToObject<VisualWorkerMessageMatrizConfiancaModel>();
if (model != null)
DadosLeitura.Analises.matriz_confianca = model;
}
catch
{
// Opcional: registrar erro de contrato
}
}
_lastTsMatrizConfianca = tsMatriz;
}
if (tsPerformance > 0 &&
tsPerformance != _lastTsPerformanceVisual)
{
var token = root["performance_visual"];
if (token != null &&
token.Type != JTokenType.Null)
{
try
{
var model =
token.ToObject<VisualWorkerPerformanceModel>();
if (model != null)
{
model.timestamp = tsPerformance;
DadosLeitura.Performance = model;
}
}
catch
{
// Opcional: registrar erro de contrato
}
}
_lastTsPerformanceVisual = tsPerformance;
}
}
private static void AtualizarImu()
{
try
{
string mxId = Variaveis.OperacaoEmAndamento?.DispSen?.Dados?.CameraCaminho?.Id;
if (string.IsNullOrWhiteSpace(mxId))
return;
string cameraJson = RedisService.Get(RedisService.CamKey(mxId));
if (string.IsNullOrWhiteSpace(cameraJson))
return;
JObject root = JObject.Parse(cameraJson);
JToken imuToken = root["imu"];
if (imuToken == null ||
imuToken.Type == JTokenType.Null)
return;
var imu = imuToken.ToObject<VisualWorkerMessageIMUModel>();
if (imu != null)
DadosLeitura.Imu = imu;
}
catch
{
return; // payload inválido
}
// ts_analise (Unix)
long tsUnix = root["ts_analise"]?.Value<long>() ?? 0;
if (tsUnix != 0)
{
// atualiza o DateTime sempre que vier um ts válido
DadosLeitura.Analises.timestamp = FuncoesGlobais.UnixToDateTime(tsUnix.ToString());
}
// Se o timestamp não mudou, evita desserializar objetos grandes
if (tsUnix != 0 && tsUnix == _lastTsVW)
return;
_lastTsVW = tsUnix;
// segmentação (sem re-serializar o token)
var segTok = root["segmentacao"];
if (segTok != null)
{
try
{
var seg = segTok.ToObject<VisualWorkerMessageSegmentacaoSemanticaModel>();
if (seg != null) DadosLeitura.Analises.segmentacao = seg;
}
catch { /* opcional: log */ }
}
// matriz de confiança
var mcTok = root["matriz_confianca"];
if (mcTok != null)
{
try
{
var mc = mcTok.ToObject<VisualWorkerMessageMatrizConfiancaModel>();
if (mc != null) DadosLeitura.Analises.matriz_confianca = mc;
}
catch { /* opcional: log */ }
}
// deteccao (sem re-serializar o token)
var detTok = root["deteccao"];
if (detTok != null)
{
try
{
var det = detTok.ToObject<List<VisualWorkerMessageDeteccaoModel>>();
if (det != null) DadosLeitura.Analises.deteccao = det;
}
catch { /* opcional: log */ }
// Mantém a última leitura válida.
}
}
public static void ReiniciarLeituraAnalise()
{
RedisService.AtualizarCampos(
CtxKey.DadosWeedWorker,
("analise.segmentacao", new VisualWorkerMessageSegmentacaoSemanticaModel()),
("analise.matriz_confianca", new VisualWorkerMessageMatrizConfiancaModel()),
("analise.deteccao", new List<VisualWorkerMessageDeteccaoModel>())
CtxKey.DadosVisualWorker,
("segmentacao", new VisualWorkerMessageSegmentacaoSemanticaModel()),
("matriz_confianca", new VisualWorkerMessageMatrizConfiancaModel()),
("deteccao", new List<VisualWorkerMessageDeteccaoModel>()),
("ts_segmentacao", 0.0),
("ts_matriz_confianca", 0.0),
("ts_deteccao", 0.0)
);
_lastTsSegmentacao = -1;
_lastTsMatrizConfianca = -1;
_lastTsDeteccao = -1;
}
}

View File

@ -18,6 +18,9 @@ namespace AgroBase.Services.Operadores
private bool DebugMode = true;
private static double _lastTsAnaliseWeed = -1;
private static double _lastTsPerformanceWeed = -1;
public void MostrarLog(string message, int limite = 500)
{
if (DebugMode)
@ -171,20 +174,106 @@ namespace AgroBase.Services.Operadores
public static void AtualizarAnalise()
{
var json = RedisService.Get(CtxKey.DadosWeedWorker);
if (string.IsNullOrWhiteSpace(json)) return;
string json = RedisService.Get(CtxKey.DadosWeedWorker);
var root = JObject.Parse(json);
var analise = root["analise"] as JObject;
if (analise == null) return;
if (string.IsNullOrWhiteSpace(json))
return;
JObject root;
try
{
DadosLeitura.Analise = JsonConvert.DeserializeObject<WeedWorkerAnaliseModel>(root["analise"].ToString());
root = JObject.Parse(json);
}
catch (Exception ex)
{
Console.WriteLine($"Erro ao deserializar analise de ervas: {ex.Message}");
Console.WriteLine(
$"Erro ao interpretar DadosWeedWorker: {ex.Message}"
);
return;
}
double tsAnalise =
root["ts_analise"]?.Value<double>() ?? 0.0;
double tsAnaliseWeed =
root["ts_analise_weed"]?.Value<double>() ?? 0.0;
double tsPerformance =
root["ts_performance_weed"]?.Value<double>() ?? 0.0;
DadosLeitura.Timestamps.analise = tsAnalise;
DadosLeitura.Timestamps.analise_weed = tsAnaliseWeed;
DadosLeitura.Timestamps.performance_weed = tsPerformance;
if (tsAnaliseWeed > 0 &&
tsAnaliseWeed != _lastTsAnaliseWeed)
{
JToken envelopeToken = root["analise"];
if (envelopeToken != null &&
envelopeToken.Type != JTokenType.Null)
{
try
{
var envelope =
envelopeToken.ToObject<WeedWorkerAnaliseEnvelopeModel>();
if (envelope != null)
{
DadosLeitura.MetricasAnalise =
new WeedWorkerAnaliseMetricasModel
{
ts_analise = envelope.ts_analise,
fps_model = envelope.fps_model,
fps_inferencia = envelope.fps_inferencia,
infer_ms = envelope.infer_ms,
infer_gpu_ms = envelope.infer_gpu_ms
};
DadosLeitura.Analise =
envelope.analise ?? new WeedWorkerAnaliseModel();
}
}
catch (Exception ex)
{
Console.WriteLine(
$"Erro ao desserializar análise de ervas: {ex.Message}"
);
}
}
_lastTsAnaliseWeed = tsAnaliseWeed;
}
if (tsPerformance > 0 &&
tsPerformance != _lastTsPerformanceWeed)
{
JToken performanceToken = root["performance_weed"];
if (performanceToken != null &&
performanceToken.Type != JTokenType.Null)
{
try
{
var performance =
performanceToken.ToObject<WeedWorkerPerformanceModel>();
if (performance != null)
{
performance.timestamp = tsPerformance;
DadosLeitura.Performance = performance;
}
}
catch (Exception ex)
{
Console.WriteLine(
$"Erro ao desserializar performance weed: {ex.Message}"
);
}
}
_lastTsPerformanceWeed = tsPerformance;
}
}
@ -192,11 +281,36 @@ namespace AgroBase.Services.Operadores
{
RedisService.AtualizarCampos(
CtxKey.DadosWeedWorker,
("analise.ervas_no_radar", false),
("analise.percentual_ervas_no_radar", 0),
("analise.controle", new Dictionary<string, bool>(Variaveis.OperacaoEmAndamento.DispAtu.Dados.BicosPulverizadores.ToDictionary(x => x.Posicao.ToString(), x => x.ComandoAtuar))),
("analise.estatisticas", new WeedWorkerAnaliseEstatisticasModel())
("analise.analise.ervas_no_radar", false),
("analise.analise.controle",
new Dictionary<string, bool>(
Variaveis.OperacaoEmAndamento
.DispAtu
.Dados
.BicosPulverizadores
.ToDictionary(
x => x.Posicao.ToString(),
x => false
)
)
),
("analise.analise.estatisticas",
new WeedWorkerAnaliseEstatisticasModel()
),
("ts_analise_weed", 0.0)
);
_lastTsAnaliseWeed = -1;
DadosLeitura.Analise =
new WeedWorkerAnaliseModel();
DadosLeitura.MetricasAnalise =
new WeedWorkerAnaliseMetricasModel();
}
}

View File

@ -8,6 +8,66 @@ class CameraManager:
def __init__(self, mostrar_log):
self.mostrar_log = mostrar_log
self._ultimo_scan = 0
self._resetar_estados_volateis_cameras()
def _resetar_estados_volateis_cameras(self):
"""
Limpa estados que pertencem à execução anterior dos workers.
Esses campos não podem ser confiados após o camera_worker reiniciar,
pois podem ter permanecido como True no Redis mesmo com os pipelines
encerrados.
"""
try:
agora = time.time()
cameras_mapeadas = ContextoGlobalRedis.get_cameras() or {}
if not cameras_mapeadas:
return
for mx_id, camera_resumo in list(cameras_mapeadas.items()):
if not isinstance(camera_resumo, dict):
camera_resumo = {}
cameras_mapeadas[mx_id] = camera_resumo
# Estado resumido dentro de DadosCameras
camera_resumo["iniciando"] = False
camera_resumo["iniciado"] = False
camera_resumo["rodando"] = False
camera_resumo["presente_scan"] = False
camera_resumo["status_scan"] = "aguardando_scan"
# Não atualizar o timestamp de heartbeat.
# Se atualizarmos, uma câmera antiga parecerá recente.
camera_resumo["manager_reset_ts"] = agora
# Estado detalhado da câmera em CamKey(mx_id)
camera_detalhada = ContextoGlobalRedis.get_camera(mx_id) or {}
camera_detalhada["iniciando"] = False
camera_detalhada["iniciado"] = False
camera_detalhada["rodando"] = False
camera_detalhada["manager_reset_ts"] = agora
ContextoGlobalRedis.set(
ContextoGlobalRedis.CamKey(mx_id),
camera_detalhada
)
ContextoGlobalRedis.set(
CtxKey.DadosCameras,
cameras_mapeadas
)
self.mostrar_log(
f"[CameraManager] Estados voláteis resetados para "
f"{len(cameras_mapeadas)} câmera(s)."
)
except Exception as e:
self.mostrar_log(
f"[CameraManager] Erro ao resetar estados das câmeras: {e}"
)
def atualizar_cameras(self):
agora = time.time()
@ -88,6 +148,9 @@ class CameraManager:
cam = ContextoGlobalRedis.get_camera(cam_id) or val
timestamp = cam.get("timestamp", val.get("timestamp", 0))
iniciando = cam.get("iniciando", val.get("iniciando", False))
iniciado = cam.get("iniciado", val.get("iniciado", False))
idade = agora - timestamp
#self.mostrar_log(f"mx_id: {cam_id}, ts: {timestamp}, idade: {idade}")
@ -114,7 +177,7 @@ class CameraManager:
val["status_scan"] = "provavelmente_em_uso"
# Se passou muito tempo sem scan e sem saúde, remove
elif not vista_no_scan and idade > TIMEOUT_CAMERA_SUMIR:
elif not vista_no_scan and idade > TIMEOUT_CAMERA_SUMIR and not iniciando and not iniciado:
ids_para_remover.append(cam_id)
# Se apareceu no scan, mantém
@ -193,7 +256,7 @@ def definir_saude_camera(mx_id: str, status: StatusModulo, saude: int, motivos:
"status": status.value,
"saude": saude,
"motivos": motivos,
"saude_idividual": []
"saude_individual": []
}
#if not conectado:
# _cameras[mx_id] = {}

View File

@ -117,7 +117,7 @@ VISUAL_DEFAULT_CONFIG = {
"debug_visual": False,
# Publica logs de performance no console.
"debug_perf": True,
"debug_perf": False,
# Tamanho dos frames de preview/debug enviados ao C#.
"preview_size": (1280, 720),

View File

@ -77,6 +77,22 @@ def main():
def inicializar():
mostrar_log("🚀 Iniciando Visual Worker...")
ContextoGlobalRedis.set(
CtxKey.DadosVisualWorker,
{
"ts_analise": time.time(),
"ts_segmentacao": 0.0,
"ts_deteccao": 0.0,
"ts_matriz_confianca": 0.0,
"ts_performance_visual": 0.0,
"segmentacao": None,
"deteccao": None,
"matriz_confianca": None,
"performance_visual": None,
}
)
ContextoGlobalRedis.ouvir_comandos(CmdKey.VisualWorkerRx, redis_callback)
ContextoGlobalRedis.publicar_comando(CmdKey.VisualWorkerTx, { "cmd": VisualWorkerCommandType.ScriptCarregado.value })
loop_ativo()

View File

@ -43,7 +43,7 @@ WEED_DEFAULT_CONFIG = {
"debug_visual": False,
# Publica logs de performance no console.
"debug_perf": True,
"debug_perf": False,
# Inclui tempos internos do WeedDetector no payload de análise.
# Barato e útil nesta fase; pode desligar na versão final final.

View File

@ -75,6 +75,16 @@ def main():
def inicializar():
mostrar_log("🚀 Iniciando Weed Worker...")
ContextoGlobalRedis.set(
CtxKey.DadosWeedWorker,
{
"ts_analise": time.time(),
"ts_analise_weed": 0.0,
"ts_performance_weed": 0.0,
"analise": None,
"performance_weed": None,
}
)
ContextoGlobalRedis.ouvir_comandos(CmdKey.WeedWorkerRx, redis_callback)
ContextoGlobalRedis.publicar_comando(CmdKey.WeedWorkerTx, { "cmd": WeedWorkerCommandType.ScriptCarregado.value })
loop_ativo()

View File

@ -196,6 +196,8 @@ class WeedDetector:
# Mantém o nome antigo para não quebrar payload/C# agora.
# Semântica atual: True se há alvo pulverizável no radar.
"ervas_no_radar": bool(target_no_radar),
"fracao_ervas_no_radar": float(estat_target.get("frac_global", 0.0)),
"percentual_ervas_no_radar": float(estat_target.get("frac_global", 0.0) * 100.0),
"estatisticas": {
# Mantém a chave "erva" para compatibilidade do payload.