agrobot_base/AgroBase/AgroBase/Models/CameraCaminhoModel.cs

295 lines
10 KiB
C#

using AgroBase.Services;
using Microsoft.Web.WebView2.WinForms;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AgroBase.Models
{
public class CameraCaminhoModel
{
public Bitmap bitmapSegmentado;
public string ID { get; set; }
public string Nome { get; set; }
public int Posicao { get; set; }
public bool Iniciada { get; set; } = false;
public CameraService camera { get; set; }
public WebView2 browserRgb { get; set; }
public Panel panelRgb { get; set; }
public WebView2 browserHeatmap { get; set; }
public Panel panelHeatmap { get; set; }
public ComboBox combo { get; set; }
public string ArquivoLeitura { get; set; }
public int MaxLeituras { get; set; }
public string VideoPorta { get; set; }
public string VideoRgbUrl { get; set; }
public string VideoHeatmapUrl { get; set; }
public string DeviceID { get; set; }
public string MqttTopico { get; set; } = "street_detector";
public Dictionary<string, Color> ClassMap = new Dictionary<string, Color>()
{
{ "background", Color.Black },
{ "rua", Color.DarkRed },
{ "cana", Color.DarkGreen },
{ "ceu", Color.Gold },
};
public CameraDeepLabV3PlusModel Leitura { get; set; } = new CameraDeepLabV3PlusModel();
public List<Point> PontosExtremos { get; set; } = new List<Point>();
public double Angulo { get; set; }
public double AnguloEsquerdo { get; set; }
public double AnguloDireito { get; set; }
public DateTime UltimaMensagemRecebida { get; set; } = DateTime.MinValue;
public DateTime UltimaMensagemProcessada { get; set; } = DateTime.MinValue;
public SonarCamModel Sonar { get; set; } = new SonarCamModel();
public void DesligarCamera()
{
try
{
Iniciada = false;
Variaveis.MqttServiceLocal.Topicos.Remove(camera._mqttTopico);
if (panelRgb != null)
{
panelRgb.Controls.Remove(browserRgb);
}
browserRgb = null;
Task.Run(async () => await Variaveis.MqttServiceLocal.UnsubscribeAsync(camera._mqttTopico));
lock (camera.processLock)
{
if (camera.pythonProcess != null)
{
camera.pythonProcess.Kill();
camera.pythonProcess = null;
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public static List<Point> DefinirPontosExtremos(List<Point> PontosCamera)
{
if (!PontosCamera.Any())
{
return new List<Point>();
}
List<Point> Pontos = new List<Point>()
{
new Point(9999, -1), // Ponto 0 - Mais a esquerda e abaixo
new Point(9999, -1), // Ponto 1 - Mais a esquerda e abaixo, e esquerda > Ponto0.X
new Point(9999, 9999), // Ponto 2 - Mais a esquerda e acima
new Point(-1, 9999), // Ponto 3 - Mais a direita e acima
new Point(-1, -1), // Ponto 4 - Mais a direita e abaixo, e direita < Ponto5.X
new Point(-1, -1), // Ponto 5 - Mais a direita e abaixo
};
foreach (var Ponto in PontosCamera)
{
// Ponto 0 - Mais a esquerda e abaixo
if (Ponto.X < Pontos[0].X)
{
Pontos[0] = new Point() { X = Ponto.X, Y = Ponto.Y };
}
// Ponto 5 - Mais a direita e abaixo
if (Ponto.X > Pontos[5].X)
{
Pontos[5] = new Point() { X = Ponto.X, Y = Ponto.Y };
}
}
var Ponto0 = PontosCamera.Where(Ponto => Ponto.X == Pontos[0].X).OrderByDescending(Ponto => Ponto.Y).First();
Pontos[0] = Ponto0;
var Ponto5 = PontosCamera.Where(Ponto => Ponto.X == Pontos[5].X).OrderByDescending(Ponto => Ponto.Y).First();
Pontos[5] = Ponto5;
foreach (var Ponto in PontosCamera)
{
// Ponto 1 - Mais a esquerda e abaixo, e esquerda > Ponto0.X
if (Ponto.X < Pontos[1].X && Ponto.X > Ponto0.X)
{
Pontos[1] = new Point() { X = Ponto.X, Y = Ponto.Y };
}
// Ponto 4 Mais a direita e abaixo, e direita < Ponto5.X
if (Ponto.X > Pontos[4].X && Ponto.X < Ponto5.X)
{
Pontos[4] = new Point() { X = Ponto.X, Y = Ponto.Y };
}
}
var Ponto1 = PontosCamera.Where(Ponto => Ponto.X == Pontos[1].X).OrderByDescending(Ponto => Ponto.Y).First();
Pontos[1] = Ponto1;
var Ponto4 = PontosCamera.Where(Ponto => Ponto.X == Pontos[4].X).OrderByDescending(Ponto => Ponto.Y).First();
Pontos[4] = Ponto4;
int Y_min = PontosCamera.OrderBy(Ponto => Ponto.Y).First().Y;
foreach (var Ponto in PontosCamera.Where(x => x.Y == Y_min))
{
// Ponto 2 - Mais a esquerda e acima
if (Ponto.X < Pontos[2].X)
{
Pontos[2] = new Point() { X = Ponto.X, Y = Ponto.Y };
}
// Ponto 3 - Mais a direita e acima
if (Ponto.X > Pontos[3].X)
{
Pontos[3] = new Point() { X = Ponto.X, Y = Ponto.Y };
}
}
return Pontos;
}
// 🔹 Gera um mapa de calor corretamente escalado
public Bitmap GenerateHeatmapBitmap()
{
double MaxDepth = 10000;
var depth_data = Leitura.depth_data;
if (depth_data == null || depth_data.Count == 0)
{
return null;
//throw new InvalidOperationException("Dados de profundidade inválidos.");
}
int height = depth_data.Count;
int width = depth_data[0].Count;
Bitmap heatmap = new Bitmap(width, height);
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int depth = depth_data[y][x];
// 🔹 Normaliza a profundidade entre 0 (vermelho, perto) e 10.000 mm (azul, longe)
int normalized = (int)FuncoesMatematicas.Clamp(255 - ((depth * 255) / MaxDepth), 0, 255);
Color color = ApplyJetColormap(normalized);
heatmap.SetPixel(x, y, color);
}
}
return heatmap;
}
// 🔹 Função para converter um valor normalizado (0-255) para um colormap "Jet" correto
private Color ApplyJetColormap(int value)
{
double normalized = value / 255.0;
int r = (int)(FuncoesMatematicas.Clamp(255 * Math.Max(0, Math.Min(1, 1.5 - Math.Abs(normalized * 2 - 1.5))), 0, 255));
int g = (int)(FuncoesMatematicas.Clamp(255 * Math.Max(0, Math.Min(1, 1.5 - Math.Abs(normalized * 2 - 1.0))), 0, 255));
int b = (int)(FuncoesMatematicas.Clamp(255 * Math.Max(0, Math.Min(1, 1.5 - Math.Abs(normalized * 2 - 0.5))), 0, 255));
return Color.FromArgb(r, g, b);
}
}
public class GridMap
{
public int x_max { get; set; }
public int y_max { get; set; }
public Subdivisoes subdivisoes_cima { get; set; }
public Subdivisoes subdivisoes_chao { get; set; }
}
public class Subdivisoes
{
public int num_linhas { get; set; }
public int num_colunas { get; set; }
public List<Celula> celulas { get; set; }
}
public class Celula
{
public int linha { get; set; }
public int coluna { get; set; }
public int x { get; set; }
public int y { get; set; }
public int largura { get; set; }
public int altura { get; set; }
public double profundidade_calibragem { get; set; }
public double profundidade_media { get; set; }
public double dif_profundidade
{
get
{
return profundidade_media - profundidade_calibragem;
}
}
public Color cor
{
get
{
double margem = 200;
if (dif_profundidade < margem)
{
return Color.Red;
}
else if (dif_profundidade > margem)
{
return Color.Gold;
}
return Color.Transparent;
}
}
}
public class GridDrawer
{
public static GridMap LoadJson(string json)
{
return JsonConvert.DeserializeObject<GridMap>(json);
}
public static Bitmap DrawGridOnBitmap(GridMap gridMap, Bitmap image)
{
Bitmap output = new Bitmap(image);
using (Graphics g = Graphics.FromImage(output))
{
foreach (var celula in gridMap.subdivisoes_chao.celulas)
{
using (Brush brush = new SolidBrush(Color.FromArgb(100, celula.cor))) // 100 = opacidade
{
g.FillRectangle(brush, celula.x, celula.y, celula.largura, celula.altura);
}
g.DrawRectangle(Pens.White, celula.x, celula.y, celula.largura, celula.altura);
}
foreach (var celula in gridMap.subdivisoes_cima.celulas)
{
using (Brush brush = new SolidBrush(Color.FromArgb(100, celula.cor)))
{
g.FillRectangle(brush, celula.x, celula.y, celula.largura, celula.altura);
}
g.DrawRectangle(Pens.White, celula.x, celula.y, celula.largura, celula.altura);
}
}
return output;
}
}
}