Salvando logs do visual e weed worker durante operacao
This commit is contained in:
parent
386520716e
commit
3aae33cc50
|
|
@ -48,6 +48,7 @@
|
||||||
this.nudTemposalvarlog = new System.Windows.Forms.NumericUpDown();
|
this.nudTemposalvarlog = new System.Windows.Forms.NumericUpDown();
|
||||||
this.lblTemposalvarlog = new System.Windows.Forms.Label();
|
this.lblTemposalvarlog = new System.Windows.Forms.Label();
|
||||||
this.gpbP_Atu = new System.Windows.Forms.GroupBox();
|
this.gpbP_Atu = new System.Windows.Forms.GroupBox();
|
||||||
|
this.cmbAgitadorModo = new System.Windows.Forms.ComboBox();
|
||||||
this.chbPulverizadorAutomatico = new System.Windows.Forms.CheckBox();
|
this.chbPulverizadorAutomatico = new System.Windows.Forms.CheckBox();
|
||||||
this.nudAtuarem = new System.Windows.Forms.NumericUpDown();
|
this.nudAtuarem = new System.Windows.Forms.NumericUpDown();
|
||||||
this.lblAtuarem = new System.Windows.Forms.Label();
|
this.lblAtuarem = new System.Windows.Forms.Label();
|
||||||
|
|
@ -93,7 +94,7 @@
|
||||||
this.nudCapacidadereservatorio = new System.Windows.Forms.NumericUpDown();
|
this.nudCapacidadereservatorio = new System.Windows.Forms.NumericUpDown();
|
||||||
this.lblUnCapcaidadereservatorio = new System.Windows.Forms.Label();
|
this.lblUnCapcaidadereservatorio = new System.Windows.Forms.Label();
|
||||||
this.lblCapacidadereservatorio = 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.gpbModulos.SuspendLayout();
|
||||||
this.gpbP_Knt.SuspendLayout();
|
this.gpbP_Knt.SuspendLayout();
|
||||||
this.gpbP_Sen.SuspendLayout();
|
this.gpbP_Sen.SuspendLayout();
|
||||||
|
|
@ -363,6 +364,17 @@
|
||||||
this.gpbP_Atu.TabStop = false;
|
this.gpbP_Atu.TabStop = false;
|
||||||
this.gpbP_Atu.Text = "Ajustes";
|
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
|
// chbPulverizadorAutomatico
|
||||||
//
|
//
|
||||||
this.chbPulverizadorAutomatico.AutoSize = true;
|
this.chbPulverizadorAutomatico.AutoSize = true;
|
||||||
|
|
@ -802,6 +814,7 @@
|
||||||
//
|
//
|
||||||
// gpbConfiguracoesgerais
|
// gpbConfiguracoesgerais
|
||||||
//
|
//
|
||||||
|
this.gpbConfiguracoesgerais.Controls.Add(this.chbGravarDadosPosProcessamento);
|
||||||
this.gpbConfiguracoesgerais.Controls.Add(this.txtDensidadeherbicida);
|
this.gpbConfiguracoesgerais.Controls.Add(this.txtDensidadeherbicida);
|
||||||
this.gpbConfiguracoesgerais.Controls.Add(this.lblUnDensidadeherbicida);
|
this.gpbConfiguracoesgerais.Controls.Add(this.lblUnDensidadeherbicida);
|
||||||
this.gpbConfiguracoesgerais.Controls.Add(this.label2);
|
this.gpbConfiguracoesgerais.Controls.Add(this.label2);
|
||||||
|
|
@ -872,16 +885,16 @@
|
||||||
this.lblCapacidadereservatorio.TabIndex = 9;
|
this.lblCapacidadereservatorio.TabIndex = 9;
|
||||||
this.lblCapacidadereservatorio.Text = "Capacidade reservatório";
|
this.lblCapacidadereservatorio.Text = "Capacidade reservatório";
|
||||||
//
|
//
|
||||||
// cmbAgitadorModo
|
// chbGravarDadosPosProcessamento
|
||||||
//
|
//
|
||||||
this.cmbAgitadorModo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
this.chbGravarDadosPosProcessamento.AutoSize = true;
|
||||||
this.cmbAgitadorModo.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
this.chbGravarDadosPosProcessamento.Location = new System.Drawing.Point(14, 219);
|
||||||
this.cmbAgitadorModo.FormattingEnabled = true;
|
this.chbGravarDadosPosProcessamento.Margin = new System.Windows.Forms.Padding(6);
|
||||||
this.cmbAgitadorModo.Location = new System.Drawing.Point(9, 132);
|
this.chbGravarDadosPosProcessamento.Name = "chbGravarDadosPosProcessamento";
|
||||||
this.cmbAgitadorModo.Margin = new System.Windows.Forms.Padding(6);
|
this.chbGravarDadosPosProcessamento.Size = new System.Drawing.Size(354, 28);
|
||||||
this.cmbAgitadorModo.Name = "cmbAgitadorModo";
|
this.chbGravarDadosPosProcessamento.TabIndex = 15;
|
||||||
this.cmbAgitadorModo.Size = new System.Drawing.Size(175, 32);
|
this.chbGravarDadosPosProcessamento.Text = "Gravar dados para pós processamento";
|
||||||
this.cmbAgitadorModo.TabIndex = 9;
|
this.chbGravarDadosPosProcessamento.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// frmParametrizacaoOperacao
|
// frmParametrizacaoOperacao
|
||||||
//
|
//
|
||||||
|
|
@ -998,5 +1011,6 @@
|
||||||
private System.Windows.Forms.CheckBox chbFrenagem;
|
private System.Windows.Forms.CheckBox chbFrenagem;
|
||||||
private System.Windows.Forms.CheckBox chbMovAuxilioSonar;
|
private System.Windows.Forms.CheckBox chbMovAuxilioSonar;
|
||||||
private System.Windows.Forms.ComboBox cmbAgitadorModo;
|
private System.Windows.Forms.ComboBox cmbAgitadorModo;
|
||||||
|
private System.Windows.Forms.CheckBox chbGravarDadosPosProcessamento;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -88,6 +88,8 @@ namespace AgroBase.Forms.Operacoes
|
||||||
txtAnteciparManobraM.Text = _Parametros.Controle.AnteciparManobraCorredorM.ToString();
|
txtAnteciparManobraM.Text = _Parametros.Controle.AnteciparManobraCorredorM.ToString();
|
||||||
|
|
||||||
cmbAgitadorModo.SelectedIndex = (int)_Parametros.Controle.AtuAgitadorModo;
|
cmbAgitadorModo.SelectedIndex = (int)_Parametros.Controle.AtuAgitadorModo;
|
||||||
|
|
||||||
|
chbGravarDadosPosProcessamento.Checked = _Parametros.Controle.RegistrarDadosPosProcessamento;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void chbD_CheckedChanged(object sender, EventArgs e)
|
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.MovAuxilioSonar = chbMovAuxilioSonar.Checked;
|
||||||
Variaveis.OperacaoEmAndamento.Parametros.Controle.FrenagemAutomaticaAoParar = chbFrenagem.Checked;
|
Variaveis.OperacaoEmAndamento.Parametros.Controle.FrenagemAutomaticaAoParar = chbFrenagem.Checked;
|
||||||
Variaveis.OperacaoEmAndamento.Parametros.Controle.AtuAgitadorModo = (ModoAgitadorCalda)cmbAgitadorModo.SelectedIndex;
|
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.ModulosMandatorios = ModulosMandatorios.Where(x => x.Utilizar).ToList();
|
||||||
Variaveis.OperacaoEmAndamento.Parametros.Controle.PulverizadorAutomatico = chbPulverizadorAutomatico.Checked;
|
Variaveis.OperacaoEmAndamento.Parametros.Controle.PulverizadorAutomatico = chbPulverizadorAutomatico.Checked;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ namespace AgroBase.Forms.Operacoes
|
||||||
List<AtuSensoriamentoLogModel> LogsAtuador = new List<AtuSensoriamentoLogModel>();
|
List<AtuSensoriamentoLogModel> LogsAtuador = new List<AtuSensoriamentoLogModel>();
|
||||||
List<SensoriamentoMensagemJsonModel> LogsSensoriamento = new List<SensoriamentoMensagemJsonModel>();
|
List<SensoriamentoMensagemJsonModel> LogsSensoriamento = new List<SensoriamentoMensagemJsonModel>();
|
||||||
List<List<CameraWorkerItemModel>> LogsCam_Solo = new List<List<CameraWorkerItemModel>>();
|
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<string> pathImagensSolo = new List<string>();
|
||||||
List<PictureBox> picsCamSolo = new List<PictureBox>();
|
List<PictureBox> picsCamSolo = new List<PictureBox>();
|
||||||
List<PictureBox> picsCamSoloSeg = 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();
|
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 + "\\");
|
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();
|
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>();
|
pathImagensSolo = new List<string>();
|
||||||
picsCamSolo = new List<PictureBox>();
|
picsCamSolo = new List<PictureBox>();
|
||||||
|
|
@ -843,7 +847,7 @@ namespace AgroBase.Forms.Operacoes
|
||||||
{
|
{
|
||||||
new GraficoInterativoSerieModel()
|
new GraficoInterativoSerieModel()
|
||||||
{
|
{
|
||||||
Titulo = $"{camNome} RAM %",
|
Titulo = $"{camNome} RAM Mb",
|
||||||
Valores = camSolo.Select(x => (double)(x?.performance?.memoria_usada ?? 0)).ToList(),
|
Valores = camSolo.Select(x => (double)(x?.performance?.memoria_usada ?? 0)).ToList(),
|
||||||
Visivel = true,
|
Visivel = true,
|
||||||
MostrarValor = true
|
MostrarValor = true
|
||||||
|
|
@ -865,7 +869,7 @@ namespace AgroBase.Forms.Operacoes
|
||||||
{
|
{
|
||||||
new GraficoInterativoSerieModel()
|
new GraficoInterativoSerieModel()
|
||||||
{
|
{
|
||||||
Titulo = $"{camNome} RAM %",
|
Titulo = $"{camNome} RAM Mb",
|
||||||
Valores = camCaminho.Select(x => (double)(x?.performance?.memoria_usada ?? 0)).ToList(),
|
Valores = camCaminho.Select(x => (double)(x?.performance?.memoria_usada ?? 0)).ToList(),
|
||||||
Visivel = true,
|
Visivel = true,
|
||||||
MostrarValor = true
|
MostrarValor = true
|
||||||
|
|
@ -895,10 +899,8 @@ namespace AgroBase.Forms.Operacoes
|
||||||
dtComandosDir.Columns.Add("clTipoMovimento", "Tipo Movimento");
|
dtComandosDir.Columns.Add("clTipoMovimento", "Tipo Movimento");
|
||||||
|
|
||||||
dtComandosAtu.Columns.Clear();
|
dtComandosAtu.Columns.Clear();
|
||||||
dtComandosAtu.Columns.Add("clB0", "B0");
|
for (int i = 1; i <= VariaveisEquipamento.QuantidadeBicosPulverizadores; i++)
|
||||||
dtComandosAtu.Columns.Add("clB1", "B1");
|
dtComandosAtu.Columns.Add($"clB{i}", $"B{i}");
|
||||||
dtComandosAtu.Columns.Add("clB2", "B2");
|
|
||||||
dtComandosAtu.Columns.Add("clB3", "B3");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InicializarCombosBusca()
|
private void InicializarCombosBusca()
|
||||||
|
|
@ -1029,10 +1031,10 @@ namespace AgroBase.Forms.Operacoes
|
||||||
|
|
||||||
private Bitmap CarregarImagemCamera(string Caminho, string complemento = "")
|
private Bitmap CarregarImagemCamera(string Caminho, string complemento = "")
|
||||||
{
|
{
|
||||||
string caminhoCompleto = Caminho + trbMomento.Value + ".jpeg";
|
string caminhoCompleto = Caminho + trbMomento.Value + ".jpg";
|
||||||
if (!string.IsNullOrEmpty(complemento))
|
if (!string.IsNullOrEmpty(complemento))
|
||||||
{
|
{
|
||||||
caminhoCompleto = caminhoCompleto.Replace(".jpeg", $"{complemento}.jpeg");
|
caminhoCompleto = caminhoCompleto.Replace(".jpg", $"{complemento}.jpg");
|
||||||
}
|
}
|
||||||
Bitmap frame = new Bitmap(1, 1);
|
Bitmap frame = new Bitmap(1, 1);
|
||||||
using (Graphics g = Graphics.FromImage(frame))
|
using (Graphics g = Graphics.FromImage(frame))
|
||||||
|
|
@ -1126,6 +1128,7 @@ namespace AgroBase.Forms.Operacoes
|
||||||
{
|
{
|
||||||
var Log = LogsOperacao[idxMomentoAtual];
|
var Log = LogsOperacao[idxMomentoAtual];
|
||||||
var LogAtu = LogsAtuador[idxMomentoAtual];
|
var LogAtu = LogsAtuador[idxMomentoAtual];
|
||||||
|
var LogWw = LogsWeedWorker[idxMomentoAtual];
|
||||||
|
|
||||||
lblPercentualBateria.Text = $"Bateria {Log.Bateria.PercentualBateria.ToString("0.00")}%";
|
lblPercentualBateria.Text = $"Bateria {Log.Bateria.PercentualBateria.ToString("0.00")}%";
|
||||||
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualBateria, Log.Bateria.PercentualBateria);
|
FuncoesGlobais.PreencheValorProgressBar(pgbPercentualBateria, Log.Bateria.PercentualBateria);
|
||||||
|
|
@ -1145,7 +1148,7 @@ namespace AgroBase.Forms.Operacoes
|
||||||
txtHerbicidaPorErva.Text = LogAtu.HerbicidaPorAtuacao.ToString("0.00") + " ml";
|
txtHerbicidaPorErva.Text = LogAtu.HerbicidaPorAtuacao.ToString("0.00") + " ml";
|
||||||
txtDentroRua.Text = Log.Trajetoria.CorredorAtual.Dentro ? "Sim" : "Não";
|
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 + ")";
|
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");
|
txtErvasTerreno.Text = Log.Atuador.PercentualErvasTerreno.ToString("0.00");
|
||||||
txtTipoMovimento.Text = Log.Controle.TipoMovimento.ToString();
|
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)";
|
txtVelocidade.Text = (Log.Movimentacao.VelocidadeMedia * 3.6).ToString("0.00") + " km/h (" + Log.Movimentacao.VelocidadeMedia.ToString("0.00") + " m/s)";
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ namespace AgroBase.Forms
|
||||||
lblLeituraDebug.Text = $"Leitura em: " + (analise?.timestamp ?? DateTime.MinValue).ToString("dd/MM/yyyy HH:mm:ss");
|
lblLeituraDebug.Text = $"Leitura em: " + (analise?.timestamp ?? DateTime.MinValue).ToString("dd/MM/yyyy HH:mm:ss");
|
||||||
OAKCameraFrameModel frame = VisualWorkerService.DadosLeitura.CameraFrames[TipoFrameCamera.Heatmap];
|
OAKCameraFrameModel frame = VisualWorkerService.DadosLeitura.CameraFrames[TipoFrameCamera.Heatmap];
|
||||||
picDebug.Image?.Dispose();
|
picDebug.Image?.Dispose();
|
||||||
picDebug.Image = analise.PlotarAnalise(frame);
|
//picDebug.Image = analise.PlotarAnalise(frame);
|
||||||
|
|
||||||
//PreencherGridAnomalias(analise.anomalias ?? new List<VisualWorkerMessageAnaliseBBoxModel>());
|
//PreencherGridAnomalias(analise.anomalias ?? new List<VisualWorkerMessageAnaliseBBoxModel>());
|
||||||
//PreencherGridSolo(analise.solo?.bbox_list ?? new List<VisualWorkerMessageAnaliseBBoxModel>());
|
//PreencherGridSolo(analise.solo?.bbox_list ?? new List<VisualWorkerMessageAnaliseBBoxModel>());
|
||||||
|
|
@ -254,7 +254,7 @@ namespace AgroBase.Forms
|
||||||
chartPerfilSolo.Legends[0].Docking = Docking.Bottom;
|
chartPerfilSolo.Legends[0].Docking = Docking.Bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlotarGraficoPerfilCorredor(List<VisualWorkerMessageRadar2DPerfilModel> perfilCorredor)
|
/*void PlotarGraficoPerfilCorredor(List<VisualWorkerMessageRadar2DPerfilModel> perfilCorredor)
|
||||||
{
|
{
|
||||||
chartCorredor.Series.Clear();
|
chartCorredor.Series.Clear();
|
||||||
|
|
||||||
|
|
@ -303,7 +303,7 @@ namespace AgroBase.Forms
|
||||||
|
|
||||||
chartCorredor.ChartAreas[0].AxisX.Crossing = 0; // 🔥 Eixo X cruza no centro (0 lateral)
|
chartCorredor.ChartAreas[0].AxisX.Crossing = 0; // 🔥 Eixo X cruza no centro (0 lateral)
|
||||||
|
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private void pnlInclinacao_Paint(object sender, PaintEventArgs e)
|
private void pnlInclinacao_Paint(object sender, PaintEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -405,6 +405,7 @@ namespace AgroBase.Models
|
||||||
AtuPercentualInicioPulverizacao = 70,
|
AtuPercentualInicioPulverizacao = 70,
|
||||||
AtuPressaoLinha = 85,
|
AtuPressaoLinha = 85,
|
||||||
AtuAgitadorModo = ModoAgitadorCalda.SemAgitacao,
|
AtuAgitadorModo = ModoAgitadorCalda.SemAgitacao,
|
||||||
|
AtuModoControle = ModoControleBomba.OnOff
|
||||||
};
|
};
|
||||||
p.ModulosMandatorios = new List<OperacaoModulosMandatoriosModel>()
|
p.ModulosMandatorios = new List<OperacaoModulosMandatoriosModel>()
|
||||||
{
|
{
|
||||||
|
|
@ -515,7 +516,7 @@ namespace AgroBase.Models
|
||||||
AtuPercentualInicioPulverizacao = 70,
|
AtuPercentualInicioPulverizacao = 70,
|
||||||
AtuPressaoLinha = 85,
|
AtuPressaoLinha = 85,
|
||||||
AtuAgitadorModo = ModoAgitadorCalda.Continuo,
|
AtuAgitadorModo = ModoAgitadorCalda.Continuo,
|
||||||
AtuModoControle = ModoControleBomba.PID,
|
AtuModoControle = ModoControleBomba.OnOff,
|
||||||
};
|
};
|
||||||
p.ModulosMandatorios = new List<OperacaoModulosMandatoriosModel>()
|
p.ModulosMandatorios = new List<OperacaoModulosMandatoriosModel>()
|
||||||
{
|
{
|
||||||
|
|
@ -2087,7 +2088,9 @@ namespace AgroBase.Models
|
||||||
SalvarLogLine(T_Code.Sen.ToString(), logSen);
|
SalvarLogLine(T_Code.Sen.ToString(), logSen);
|
||||||
|
|
||||||
SalvarLogCameraSolo();
|
SalvarLogCameraSolo();
|
||||||
|
SalvarLogLine("WeedWorker", Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorErvas);
|
||||||
SalvarLogCameraCaminho();
|
SalvarLogCameraCaminho();
|
||||||
|
SalvarLogLine("VisualWorker", Variaveis.OperacaoEmAndamento.Sensoriamento.OperadorVisual);
|
||||||
|
|
||||||
string ArquivoOp = Variaveis.CaminhoOperacoes + Variaveis.OperacaoEmAndamento.ID + "/data.lgop";
|
string ArquivoOp = Variaveis.CaminhoOperacoes + Variaveis.OperacaoEmAndamento.ID + "/data.lgop";
|
||||||
if (!File.Exists(ArquivoOp))
|
if (!File.Exists(ArquivoOp))
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
using System;
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using static AgroBase.Models.Enums;
|
using static AgroBase.Models.Enums;
|
||||||
|
|
||||||
namespace AgroBase.Models.Operadores
|
namespace AgroBase.Models.Operadores
|
||||||
|
|
@ -13,12 +14,15 @@ namespace AgroBase.Models.Operadores
|
||||||
public bool Pronto { get; set; }
|
public bool Pronto { get; set; }
|
||||||
public DateTime ProntoEm { get; set; }
|
public DateTime ProntoEm { get; set; }
|
||||||
public DateTime UltimaMensagem { get; set; }
|
public DateTime UltimaMensagem { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
public Dictionary<TipoFrameCamera, OAKCameraFrameModel> CameraFrames { get; set; } = new Dictionary<TipoFrameCamera, OAKCameraFrameModel>();
|
public Dictionary<TipoFrameCamera, OAKCameraFrameModel> CameraFrames { get; set; } = new Dictionary<TipoFrameCamera, OAKCameraFrameModel>();
|
||||||
public VisualWorkerMessageAnaliseModel Analises { get; set; } = new VisualWorkerMessageAnaliseModel();
|
public VisualWorkerMessageAnaliseModel Analises { get; set; } = new VisualWorkerMessageAnaliseModel();
|
||||||
public VisualWorkerMessageIMUModel Imu { get; set; } = new VisualWorkerMessageIMUModel();
|
public VisualWorkerMessageIMUModel Imu { get; set; } = new VisualWorkerMessageIMUModel();
|
||||||
public StatusModulo Status { get; set; }
|
public StatusModulo Status { get; set; }
|
||||||
public bool StatusValido => new List<StatusModulo>() { StatusModulo.Operante, StatusModulo.Alerta }.Contains(Status);
|
public bool StatusValido => new List<StatusModulo>() { StatusModulo.Operante, StatusModulo.Alerta }.Contains(Status);
|
||||||
public VisualWorkerResumoModel Resumo { get; set; }
|
public VisualWorkerResumoModel Resumo { get; set; }
|
||||||
|
public VisualWorkerPerformanceModel Performance { get; set; } = new VisualWorkerPerformanceModel();
|
||||||
|
public VisualWorkerRedisTimestampsModel Timestamps { get; set; } = new VisualWorkerRedisTimestampsModel();
|
||||||
|
|
||||||
public VisualWorkerModel Clone()
|
public VisualWorkerModel Clone()
|
||||||
{
|
{
|
||||||
|
|
@ -33,7 +37,9 @@ namespace AgroBase.Models.Operadores
|
||||||
Imu = Imu?.Clone(),
|
Imu = Imu?.Clone(),
|
||||||
UltimaMensagem = UltimaMensagem,
|
UltimaMensagem = UltimaMensagem,
|
||||||
Status = Status,
|
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();
|
Imu = new VisualWorkerMessageIMUModel();
|
||||||
Resumo = new VisualWorkerResumoModel();
|
Resumo = new VisualWorkerResumoModel();
|
||||||
Status = StatusModulo.Desconectado;
|
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 class VisualWorkerMessageIMUModel
|
||||||
{
|
{
|
||||||
public long timestamp { get; set; }
|
public bool valido { get; set; }
|
||||||
|
public double timestamp { get; set; }
|
||||||
|
|
||||||
public double roll { get; set; }
|
public double roll { get; set; }
|
||||||
public double pitch { get; set; }
|
public double pitch { get; set; }
|
||||||
public double yaw { get; set; }
|
public double yaw { get; set; }
|
||||||
public double yaw_fixed { 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()
|
public VisualWorkerMessageIMUModel Clone()
|
||||||
{
|
{
|
||||||
return new VisualWorkerMessageIMUModel()
|
return new VisualWorkerMessageIMUModel
|
||||||
{
|
{
|
||||||
|
valido = valido,
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
roll = roll,
|
roll = roll,
|
||||||
pitch = pitch,
|
pitch = pitch,
|
||||||
yaw = yaw,
|
yaw = yaw,
|
||||||
};
|
yaw_fixed = yaw_fixed,
|
||||||
}
|
frequencia_hz = frequencia_hz,
|
||||||
}
|
latencia_ms = latencia_ms,
|
||||||
|
rugosidade = rugosidade,
|
||||||
public class VisualWorkerMessageSetupModel
|
impacto = impacto,
|
||||||
{
|
estabilidade = estabilidade,
|
||||||
public long timestamp { get; set; }
|
movimento_detectado = movimento_detectado,
|
||||||
public bool status { get; set; }
|
Extra = Extra?.ToDictionary(
|
||||||
|
x => x.Key,
|
||||||
private bool _newData = false;
|
x => x.Value?.DeepClone()
|
||||||
public bool newData
|
) ?? new Dictionary<string, JToken>()
|
||||||
{
|
|
||||||
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
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -255,160 +195,20 @@ namespace AgroBase.Models.Operadores
|
||||||
public class VisualWorkerMessageAnaliseModel
|
public class VisualWorkerMessageAnaliseModel
|
||||||
{
|
{
|
||||||
public DateTime timestamp { get; set; }
|
public DateTime timestamp { get; set; }
|
||||||
//public List<VisualWorkerMessageAnaliseBBoxModel> anomalias { get; set; }
|
public VisualWorkerMessageSegmentacaoSemanticaModel segmentacao { get; set; } = new VisualWorkerMessageSegmentacaoSemanticaModel();
|
||||||
//public List<VisualWorkerMessageAnaliseBBoxModel> sombras { get; set; }
|
public VisualWorkerMessageMatrizConfiancaModel matriz_confianca { get; set; } = new VisualWorkerMessageMatrizConfiancaModel();
|
||||||
//public VisualWorkerMessageAnaliseSoloModel solo { get; set; }
|
public List<VisualWorkerMessageDeteccaoModel> deteccao { get; set; } = new List<VisualWorkerMessageDeteccaoModel>();
|
||||||
//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 VisualWorkerMessageAnaliseModel Clone()
|
public VisualWorkerMessageAnaliseModel Clone()
|
||||||
{
|
{
|
||||||
return new VisualWorkerMessageAnaliseModel()
|
return new VisualWorkerMessageAnaliseModel()
|
||||||
{
|
{
|
||||||
timestamp = timestamp,
|
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(),
|
segmentacao = segmentacao?.Clone() ?? new VisualWorkerMessageSegmentacaoSemanticaModel(),
|
||||||
matriz_confianca = matriz_confianca?.Clone() ?? new VisualWorkerMessageMatrizConfiancaModel(),
|
matriz_confianca = matriz_confianca?.Clone() ?? new VisualWorkerMessageMatrizConfiancaModel(),
|
||||||
deteccao = deteccao?.Select(x => x.Clone()).ToList() ?? new List<VisualWorkerMessageDeteccaoModel>()
|
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
|
public class VisualWorkerMessageAnaliseBBoxModel
|
||||||
|
|
@ -423,142 +223,6 @@ namespace AgroBase.Models.Operadores
|
||||||
public double? variacao { get; set; } // delta Z ou null
|
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 class VisualWorkerMessageSegmentacaoSemanticaModel
|
||||||
{
|
{
|
||||||
public double timestamp { get; set; }
|
public double timestamp { get; set; }
|
||||||
|
|
@ -569,8 +233,8 @@ namespace AgroBase.Models.Operadores
|
||||||
public StatusCarroMapa status_corredor { get; set; }
|
public StatusCarroMapa status_corredor { get; set; }
|
||||||
public StatusCarroMapa status_corredor_anterior { get; set; }
|
public StatusCarroMapa status_corredor_anterior { get; set; }
|
||||||
public VisualWorkerMessageSegmentacaoSemanticaDebugCorredorModel status_corredor_debug { get; set; }
|
public VisualWorkerMessageSegmentacaoSemanticaDebugCorredorModel status_corredor_debug { get; set; }
|
||||||
public List<double?[]> centros_corredor { get; set; }
|
public List<double?[]> centros_corredor { get; set; } = new List<double?[]>();
|
||||||
public List<int> larguras_px { get; set; }
|
public List<int> larguras_px { get; set; } = new List<int>();
|
||||||
|
|
||||||
public VisualWorkerMessageSegmentacaoSemanticaModel Clone()
|
public VisualWorkerMessageSegmentacaoSemanticaModel Clone()
|
||||||
{
|
{
|
||||||
|
|
@ -583,8 +247,11 @@ namespace AgroBase.Models.Operadores
|
||||||
erro_lateral_pct = erro_lateral_pct,
|
erro_lateral_pct = erro_lateral_pct,
|
||||||
status_corredor = status_corredor,
|
status_corredor = status_corredor,
|
||||||
status_corredor_anterior = status_corredor_anterior,
|
status_corredor_anterior = status_corredor_anterior,
|
||||||
status_corredor_debug = status_corredor_debug,
|
status_corredor_debug = status_corredor_debug?.Clone(),
|
||||||
centros_corredor = new List<double?[]>(centros_corredor ?? new List<double?[]>()),
|
centros_corredor = centros_corredor?
|
||||||
|
.Select(x => x?.ToArray())
|
||||||
|
.ToList()
|
||||||
|
?? new List<double?[]>(),
|
||||||
larguras_px = new List<int>(larguras_px ?? new List<int>()),
|
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 StatusCarroMapa status_heuristico { get; set; }
|
||||||
public string status_heuristico_nome { get; set; }
|
public string status_heuristico_nome { get; set; }
|
||||||
public dynamic heuristica_debug { 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
|
public class VisualWorkerMessageMatrizConfiancaModel
|
||||||
|
|
@ -609,10 +300,10 @@ namespace AgroBase.Models.Operadores
|
||||||
public int seq { get; set; }
|
public int seq { get; set; }
|
||||||
public int grid_w { get; set; }
|
public int grid_w { get; set; }
|
||||||
public int grid_h { get; set; }
|
public int grid_h { get; set; }
|
||||||
public List<float> y_range_m { get; set; }
|
public List<float> y_range_m { get; set; } = new List<float>();
|
||||||
public List<float> row_dist_m { get; set; }
|
public List<float> row_dist_m { get; set; } = new List<float>();
|
||||||
public List<float> row_scale_x_m { get; set; }
|
public List<float> row_scale_x_m { get; set; } = new List<float>();
|
||||||
public VisualWorkerMessageMatrizConfiancaBlockModel block { get; set; }
|
public VisualWorkerMessageMatrizConfiancaBlockModel block { get; set; } = new VisualWorkerMessageMatrizConfiancaBlockModel();
|
||||||
|
|
||||||
public VisualWorkerMessageMatrizConfiancaModel Clone()
|
public VisualWorkerMessageMatrizConfiancaModel Clone()
|
||||||
{
|
{
|
||||||
|
|
@ -622,10 +313,10 @@ namespace AgroBase.Models.Operadores
|
||||||
seq = seq,
|
seq = seq,
|
||||||
grid_w = grid_w,
|
grid_w = grid_w,
|
||||||
grid_h = grid_h,
|
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_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>()),
|
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 string track_status { get; set; }
|
||||||
public bool tem_tracker { get; set; }
|
public bool tem_tracker { get; set; }
|
||||||
public List<double> xyz_m { get; set; }
|
public List<double> xyz_m { get; set; }
|
||||||
public double distancia_m { get; set; }
|
public double? distancia_m { get; set; }
|
||||||
public double lateral_m { get; set; }
|
public double? lateral_m { get; set; }
|
||||||
public double altura_relativa_m { get; set; }
|
public double? altura_relativa_m { get; set; }
|
||||||
public List<double> bbox_full { get; set; }
|
public List<double> bbox_full { get; set; }
|
||||||
|
|
||||||
public VisualWorkerMessageDeteccaoModel Clone()
|
public VisualWorkerMessageDeteccaoModel Clone()
|
||||||
|
|
@ -739,22 +430,158 @@ namespace AgroBase.Models.Operadores
|
||||||
{
|
{
|
||||||
label_id = label_id,
|
label_id = label_id,
|
||||||
label = label,
|
label = label,
|
||||||
bbox_norm = bbox_norm,
|
bbox_norm = bbox_norm != null
|
||||||
bbox_px = bbox_px,
|
? new List<double>(bbox_norm)
|
||||||
|
: new List<double>(),
|
||||||
|
bbox_px = bbox_px != null
|
||||||
|
? new List<double>(bbox_px)
|
||||||
|
: new List<double>(),
|
||||||
conf = conf,
|
conf = conf,
|
||||||
track_id = track_id,
|
track_id = track_id,
|
||||||
track_status = track_status,
|
track_status = track_status,
|
||||||
tem_tracker = tem_tracker,
|
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,
|
distancia_m = distancia_m,
|
||||||
lateral_m = lateral_m,
|
lateral_m = lateral_m,
|
||||||
altura_relativa_m = altura_relativa_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
|
public enum VisualWorkerCommandType
|
||||||
{
|
{
|
||||||
ScriptCarregado = 1,
|
ScriptCarregado = 1,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
using System;
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using static AgroBase.Models.Enums;
|
using static AgroBase.Models.Enums;
|
||||||
|
|
||||||
namespace AgroBase.Models.Operadores
|
namespace AgroBase.Models.Operadores
|
||||||
|
|
@ -11,21 +14,35 @@ namespace AgroBase.Models.Operadores
|
||||||
public bool Pronto { get; set; }
|
public bool Pronto { get; set; }
|
||||||
public DateTime ProntoEm { get; set; }
|
public DateTime ProntoEm { get; set; }
|
||||||
public DateTime UltimaMensagem { get; set; }
|
public DateTime UltimaMensagem { get; set; }
|
||||||
|
[JsonIgnore]
|
||||||
public Dictionary<TipoFrameCamera, OAKCameraFrameModel> CameraFrames { get; set; } = new Dictionary<TipoFrameCamera, OAKCameraFrameModel>();
|
public Dictionary<TipoFrameCamera, OAKCameraFrameModel> CameraFrames { get; set; } = new Dictionary<TipoFrameCamera, OAKCameraFrameModel>();
|
||||||
public WeedWorkerAnaliseModel Analise { get; set; } = new WeedWorkerAnaliseModel();
|
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()
|
public WeedWorkerModel Clone()
|
||||||
{
|
{
|
||||||
return new WeedWorkerModel()
|
return new WeedWorkerModel
|
||||||
{
|
{
|
||||||
Iniciado = Iniciado,
|
Iniciado = Iniciado,
|
||||||
IniciadoEm = IniciadoEm,
|
IniciadoEm = IniciadoEm,
|
||||||
Pronto = Pronto,
|
Pronto = Pronto,
|
||||||
ProntoEm = ProntoEm,
|
ProntoEm = ProntoEm,
|
||||||
CameraFrames = new Dictionary<TipoFrameCamera, OAKCameraFrameModel>(CameraFrames ?? new Dictionary<TipoFrameCamera, OAKCameraFrameModel>()),
|
|
||||||
Analise = Analise.Clone(),
|
|
||||||
UltimaMensagem = UltimaMensagem,
|
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;
|
Iniciado = false;
|
||||||
IniciadoEm = DateTime.MinValue;
|
IniciadoEm = DateTime.MinValue;
|
||||||
|
|
||||||
Pronto = false;
|
Pronto = false;
|
||||||
ProntoEm = DateTime.MinValue;
|
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 double timestamp { get; set; }
|
||||||
public int height { get; set; }
|
public int height { get; set; }
|
||||||
public int width { 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 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()
|
public WeedWorkerAnaliseModel Clone()
|
||||||
{
|
{
|
||||||
|
|
@ -64,28 +147,17 @@ namespace AgroBase.Models.Operadores
|
||||||
height = height,
|
height = height,
|
||||||
width = width,
|
width = width,
|
||||||
ervas_no_radar = ervas_no_radar,
|
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()
|
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 class WeedWorkerAnaliseEstatisticasModel
|
||||||
{
|
{
|
||||||
public WeedWorkerAnaliseEstatisticasErvasModel erva { get; set; }
|
public WeedWorkerAnaliseEstatisticasErvasModel erva { get; set; } = new WeedWorkerAnaliseEstatisticasErvasModel();
|
||||||
public WeedWorkerAnaliseEstatisticasBicosModel bicos { get; set; }
|
public WeedWorkerAnaliseEstatisticasBicosModel bicos { get; set; } = new WeedWorkerAnaliseEstatisticasBicosModel();
|
||||||
|
|
||||||
public WeedWorkerAnaliseEstatisticasModel Clone()
|
public WeedWorkerAnaliseEstatisticasModel Clone()
|
||||||
{
|
{
|
||||||
|
|
@ -120,19 +192,62 @@ namespace AgroBase.Models.Operadores
|
||||||
|
|
||||||
public class WeedWorkerAnaliseEstatisticasBicosModel
|
public class WeedWorkerAnaliseEstatisticasBicosModel
|
||||||
{
|
{
|
||||||
public List<double> larguras { get; set; }
|
public string motivo { get; set; }
|
||||||
public List<double> contagem_cana_px_por_bico { get; set; }
|
|
||||||
public List<double> contagem_cana_frac_por_bico { 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; }
|
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()
|
public WeedWorkerAnaliseEstatisticasBicosModel Clone()
|
||||||
{
|
{
|
||||||
return new WeedWorkerAnaliseEstatisticasBicosModel()
|
return new WeedWorkerAnaliseEstatisticasBicosModel
|
||||||
{
|
{
|
||||||
larguras = new List<double>(larguras),
|
motivo = motivo,
|
||||||
contagem_cana_frac_por_bico = new List<double>(contagem_cana_frac_por_bico ?? new List<double>()),
|
frac_erva_por_bico =
|
||||||
contagem_cana_px_por_bico = new List<double>(contagem_cana_px_por_bico ?? new List<double>()),
|
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()
|
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
|
public enum WeedWorkerCommandType
|
||||||
{
|
{
|
||||||
ScriptCarregado = 1,
|
ScriptCarregado = 1,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,10 @@ namespace AgroBase.Services.Operadores
|
||||||
|
|
||||||
private bool DebugMode = true;
|
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)
|
public void MostrarLog(string message, int limite = 500)
|
||||||
{
|
{
|
||||||
|
|
@ -143,92 +146,211 @@ namespace AgroBase.Services.Operadores
|
||||||
|
|
||||||
public static void AtualizarAnalise()
|
public static void AtualizarAnalise()
|
||||||
{
|
{
|
||||||
// IMU (simples e direto)
|
AtualizarImu();
|
||||||
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 */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
string json = RedisService.Get(CtxKey.DadosVisualWorker);
|
||||||
var json = RedisService.Get(CtxKey.DadosVisualWorker);
|
|
||||||
if (string.IsNullOrWhiteSpace(json)) return;
|
if (string.IsNullOrWhiteSpace(json))
|
||||||
|
return;
|
||||||
|
|
||||||
JObject root;
|
JObject root;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
root = JObject.Parse(json);
|
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
|
catch
|
||||||
{
|
{
|
||||||
return; // payload inválido
|
// Opcional: registrar erro de contrato
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ts_analise (Unix)
|
_lastTsSegmentacao = tsSegmentacao;
|
||||||
long tsUnix = root["ts_analise"]?.Value<long>() ?? 0;
|
}
|
||||||
if (tsUnix != 0)
|
|
||||||
|
if (tsDeteccao > 0 &&
|
||||||
|
tsDeteccao != _lastTsDeteccao)
|
||||||
{
|
{
|
||||||
// atualiza o DateTime sempre que vier um ts válido
|
var token = root["deteccao"];
|
||||||
DadosLeitura.Analises.timestamp = FuncoesGlobais.UnixToDateTime(tsUnix.ToString());
|
|
||||||
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Se o timestamp não mudou, evita desserializar objetos grandes
|
_lastTsDeteccao = tsDeteccao;
|
||||||
if (tsUnix != 0 && tsUnix == _lastTsVW)
|
}
|
||||||
|
|
||||||
|
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;
|
return;
|
||||||
|
|
||||||
_lastTsVW = tsUnix;
|
string cameraJson = RedisService.Get(RedisService.CamKey(mxId));
|
||||||
|
|
||||||
// segmentação (sem re-serializar o token)
|
if (string.IsNullOrWhiteSpace(cameraJson))
|
||||||
var segTok = root["segmentacao"];
|
return;
|
||||||
if (segTok != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var seg = segTok.ToObject<VisualWorkerMessageSegmentacaoSemanticaModel>();
|
|
||||||
if (seg != null) DadosLeitura.Analises.segmentacao = seg;
|
|
||||||
}
|
|
||||||
catch { /* opcional: log */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
// matriz de confiança
|
JObject root = JObject.Parse(cameraJson);
|
||||||
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)
|
JToken imuToken = root["imu"];
|
||||||
var detTok = root["deteccao"];
|
|
||||||
if (detTok != null)
|
if (imuToken == null ||
|
||||||
{
|
imuToken.Type == JTokenType.Null)
|
||||||
try
|
return;
|
||||||
{
|
|
||||||
var det = detTok.ToObject<List<VisualWorkerMessageDeteccaoModel>>();
|
var imu = imuToken.ToObject<VisualWorkerMessageIMUModel>();
|
||||||
if (det != null) DadosLeitura.Analises.deteccao = det;
|
|
||||||
|
if (imu != null)
|
||||||
|
DadosLeitura.Imu = imu;
|
||||||
}
|
}
|
||||||
catch { /* opcional: log */ }
|
catch
|
||||||
|
{
|
||||||
|
// Mantém a última leitura válida.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ReiniciarLeituraAnalise()
|
public static void ReiniciarLeituraAnalise()
|
||||||
{
|
{
|
||||||
RedisService.AtualizarCampos(
|
RedisService.AtualizarCampos(
|
||||||
CtxKey.DadosWeedWorker,
|
CtxKey.DadosVisualWorker,
|
||||||
("analise.segmentacao", new VisualWorkerMessageSegmentacaoSemanticaModel()),
|
("segmentacao", new VisualWorkerMessageSegmentacaoSemanticaModel()),
|
||||||
("analise.matriz_confianca", new VisualWorkerMessageMatrizConfiancaModel()),
|
("matriz_confianca", new VisualWorkerMessageMatrizConfiancaModel()),
|
||||||
("analise.deteccao", new List<VisualWorkerMessageDeteccaoModel>())
|
("deteccao", new List<VisualWorkerMessageDeteccaoModel>()),
|
||||||
|
("ts_segmentacao", 0.0),
|
||||||
|
("ts_matriz_confianca", 0.0),
|
||||||
|
("ts_deteccao", 0.0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
_lastTsSegmentacao = -1;
|
||||||
|
_lastTsMatrizConfianca = -1;
|
||||||
|
_lastTsDeteccao = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ namespace AgroBase.Services.Operadores
|
||||||
|
|
||||||
private bool DebugMode = true;
|
private bool DebugMode = true;
|
||||||
|
|
||||||
|
private static double _lastTsAnaliseWeed = -1;
|
||||||
|
private static double _lastTsPerformanceWeed = -1;
|
||||||
|
|
||||||
public void MostrarLog(string message, int limite = 500)
|
public void MostrarLog(string message, int limite = 500)
|
||||||
{
|
{
|
||||||
if (DebugMode)
|
if (DebugMode)
|
||||||
|
|
@ -171,20 +174,106 @@ namespace AgroBase.Services.Operadores
|
||||||
|
|
||||||
public static void AtualizarAnalise()
|
public static void AtualizarAnalise()
|
||||||
{
|
{
|
||||||
var json = RedisService.Get(CtxKey.DadosWeedWorker);
|
string json = RedisService.Get(CtxKey.DadosWeedWorker);
|
||||||
if (string.IsNullOrWhiteSpace(json)) return;
|
|
||||||
|
|
||||||
var root = JObject.Parse(json);
|
if (string.IsNullOrWhiteSpace(json))
|
||||||
var analise = root["analise"] as JObject;
|
return;
|
||||||
if (analise == null) return;
|
|
||||||
|
JObject root;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DadosLeitura.Analise = JsonConvert.DeserializeObject<WeedWorkerAnaliseModel>(root["analise"].ToString());
|
root = JObject.Parse(json);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
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(
|
RedisService.AtualizarCampos(
|
||||||
CtxKey.DadosWeedWorker,
|
CtxKey.DadosWeedWorker,
|
||||||
("analise.ervas_no_radar", false),
|
|
||||||
("analise.percentual_ervas_no_radar", 0),
|
("analise.analise.ervas_no_radar", false),
|
||||||
("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.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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,66 @@ class CameraManager:
|
||||||
def __init__(self, mostrar_log):
|
def __init__(self, mostrar_log):
|
||||||
self.mostrar_log = mostrar_log
|
self.mostrar_log = mostrar_log
|
||||||
self._ultimo_scan = 0
|
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
|
||||||
|
já 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):
|
def atualizar_cameras(self):
|
||||||
agora = time.time()
|
agora = time.time()
|
||||||
|
|
@ -88,6 +148,9 @@ class CameraManager:
|
||||||
cam = ContextoGlobalRedis.get_camera(cam_id) or val
|
cam = ContextoGlobalRedis.get_camera(cam_id) or val
|
||||||
|
|
||||||
timestamp = cam.get("timestamp", val.get("timestamp", 0))
|
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
|
idade = agora - timestamp
|
||||||
#self.mostrar_log(f"mx_id: {cam_id}, ts: {timestamp}, idade: {idade}")
|
#self.mostrar_log(f"mx_id: {cam_id}, ts: {timestamp}, idade: {idade}")
|
||||||
|
|
||||||
|
|
@ -114,7 +177,7 @@ class CameraManager:
|
||||||
val["status_scan"] = "provavelmente_em_uso"
|
val["status_scan"] = "provavelmente_em_uso"
|
||||||
|
|
||||||
# Se passou muito tempo sem scan e sem saúde, remove
|
# 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)
|
ids_para_remover.append(cam_id)
|
||||||
|
|
||||||
# Se apareceu no scan, mantém
|
# 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,
|
"status": status.value,
|
||||||
"saude": saude,
|
"saude": saude,
|
||||||
"motivos": motivos,
|
"motivos": motivos,
|
||||||
"saude_idividual": []
|
"saude_individual": []
|
||||||
}
|
}
|
||||||
#if not conectado:
|
#if not conectado:
|
||||||
# _cameras[mx_id] = {}
|
# _cameras[mx_id] = {}
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ VISUAL_DEFAULT_CONFIG = {
|
||||||
"debug_visual": False,
|
"debug_visual": False,
|
||||||
|
|
||||||
# Publica logs de performance no console.
|
# Publica logs de performance no console.
|
||||||
"debug_perf": True,
|
"debug_perf": False,
|
||||||
|
|
||||||
# Tamanho dos frames de preview/debug enviados ao C#.
|
# Tamanho dos frames de preview/debug enviados ao C#.
|
||||||
"preview_size": (1280, 720),
|
"preview_size": (1280, 720),
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,22 @@ def main():
|
||||||
|
|
||||||
def inicializar():
|
def inicializar():
|
||||||
mostrar_log("🚀 Iniciando Visual Worker...")
|
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.ouvir_comandos(CmdKey.VisualWorkerRx, redis_callback)
|
||||||
ContextoGlobalRedis.publicar_comando(CmdKey.VisualWorkerTx, { "cmd": VisualWorkerCommandType.ScriptCarregado.value })
|
ContextoGlobalRedis.publicar_comando(CmdKey.VisualWorkerTx, { "cmd": VisualWorkerCommandType.ScriptCarregado.value })
|
||||||
loop_ativo()
|
loop_ativo()
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ WEED_DEFAULT_CONFIG = {
|
||||||
"debug_visual": False,
|
"debug_visual": False,
|
||||||
|
|
||||||
# Publica logs de performance no console.
|
# Publica logs de performance no console.
|
||||||
"debug_perf": True,
|
"debug_perf": False,
|
||||||
|
|
||||||
# Inclui tempos internos do WeedDetector no payload de análise.
|
# Inclui tempos internos do WeedDetector no payload de análise.
|
||||||
# Barato e útil nesta fase; pode desligar na versão final final.
|
# Barato e útil nesta fase; pode desligar na versão final final.
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,16 @@ def main():
|
||||||
|
|
||||||
def inicializar():
|
def inicializar():
|
||||||
mostrar_log("🚀 Iniciando Weed Worker...")
|
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.ouvir_comandos(CmdKey.WeedWorkerRx, redis_callback)
|
||||||
ContextoGlobalRedis.publicar_comando(CmdKey.WeedWorkerTx, { "cmd": WeedWorkerCommandType.ScriptCarregado.value })
|
ContextoGlobalRedis.publicar_comando(CmdKey.WeedWorkerTx, { "cmd": WeedWorkerCommandType.ScriptCarregado.value })
|
||||||
loop_ativo()
|
loop_ativo()
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,8 @@ class WeedDetector:
|
||||||
# Mantém o nome antigo para não quebrar payload/C# agora.
|
# Mantém o nome antigo para não quebrar payload/C# agora.
|
||||||
# Semântica atual: True se há alvo pulverizável no radar.
|
# Semântica atual: True se há alvo pulverizável no radar.
|
||||||
"ervas_no_radar": bool(target_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": {
|
"estatisticas": {
|
||||||
# Mantém a chave "erva" para compatibilidade do payload.
|
# Mantém a chave "erva" para compatibilidade do payload.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue