implementado gerenciamento do gnss
This commit is contained in:
parent
71de765823
commit
c5e90f7b44
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -733,7 +733,7 @@ namespace AgroBase.Models
|
|||
float y = centerY - (float)((lat - _posicaoAtual.Lat0) * _zoom);
|
||||
|
||||
// Usa a mesma origem ENU do GeoLeverArm
|
||||
var (xE, yN) = GeoLeverArm.GeodeticToENU(lat, lon, _posicaoAtual.Lat0, _posicaoAtual.Lon0);
|
||||
var (xE, yN) = GPSService.LeverArm.GeodeticToENU(lat, lon, _posicaoAtual.Lat0, _posicaoAtual.Lon0);
|
||||
float scale = (float)_zoom / 1e7f;
|
||||
|
||||
float px = centerX + (float)(xE * scale); // Leste para +X
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ namespace AgroBase.Models
|
|||
MqttServiceLocal.Topicos.Clear();
|
||||
}
|
||||
|
||||
if (MqttServiceBase != null && !IsAgroMonitor)
|
||||
if (MqttServiceBase != null)
|
||||
{
|
||||
foreach (var topico in MqttServiceBase.Topicos.Where(x => x.Inscrever))
|
||||
{
|
||||
|
|
@ -109,7 +109,7 @@ namespace AgroBase.Models
|
|||
MqttServiceBase.Topicos.Clear();
|
||||
}
|
||||
|
||||
MqttServiceLocal = new MqttService("localhost", 1883, IsAgroMonitor ? "base" : VariaveisEquipamento.Parametros.serial_number, true);
|
||||
MqttServiceLocal = new MqttService("localhost", 1883, IsAgroMonitor ? "base" : VariaveisEquipamento.Parametros.serial_number, true, msg => Console.WriteLine($"[MQTT localhost:{1883}] - {msg}"));
|
||||
await MqttServiceLocal.AdicionarNovoTopico(MapasVariaveisModel.TopicoCoordenadasGPS);
|
||||
await MqttServiceLocal.AdicionarNovoTopico(MapasVariaveisModel.TopicoTrajetoriaDinamica);
|
||||
await MqttServiceLocal.AdicionarNovoTopico(MapasVariaveisModel.TopicoSelecaoRuasMapa, true, 1, async (message) =>
|
||||
|
|
@ -117,75 +117,56 @@ namespace AgroBase.Models
|
|||
OperacaoEmAndamento.Mapa.AtualizarRuasSelecionadas();
|
||||
});
|
||||
|
||||
if (IsAgroMonitor)
|
||||
MqttServiceBase = new MqttService(VariaveisEquipamento.Parametros.base_ip, 1883, VariaveisEquipamento.Parametros.serial_number, false, msg => Console.WriteLine($"[MQTT {VariaveisEquipamento.Parametros.base_ip}:{1883}] - {msg}"));
|
||||
await MqttServiceBase.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttDispositivos);
|
||||
await MqttServiceBase.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", VariaveisEquipamento.Parametros.serial_number));
|
||||
await MqttServiceBase.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", VariaveisEquipamento.Parametros.serial_number), true, 1, async (message) =>
|
||||
{
|
||||
await MqttServiceLocal.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttRTCM);
|
||||
await MqttServiceLocal.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttDispositivos, true, 1, async (message) =>
|
||||
if (string.IsNullOrEmpty(message.Mensagem))
|
||||
return;
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
string device_id = message.Mensagem;
|
||||
VariaveisMonitoramento.AdicionarNovoRoverNaRede(message.Mensagem);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Erro ao deserializar ping do rover: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
string json = message.Mensagem;
|
||||
var cmd = JsonConvert.DeserializeObject<OperacaoControleBaseModel>(json);
|
||||
OperacaoEmAndamento.ExecutaComandoDaBase(cmd);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Erro ao deserializar comando da base: {ex.Message}");
|
||||
}
|
||||
});
|
||||
await MqttServiceBase.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttRTCM, true, 1, async (message) =>
|
||||
{
|
||||
MqttServiceBase = new MqttService(VariaveisEquipamento.Parametros.base_ip, 1883, VariaveisEquipamento.Parametros.serial_number, false);
|
||||
await MqttServiceBase.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttDispositivos);
|
||||
await MqttServiceBase.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", VariaveisEquipamento.Parametros.serial_number));
|
||||
await MqttServiceBase.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", VariaveisEquipamento.Parametros.serial_number), true, 1, async (message) =>
|
||||
if (message.Bytes == null || message.Bytes.Length == 0)
|
||||
return;
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(message.Mensagem))
|
||||
return;
|
||||
try
|
||||
var bytes = message.Bytes;
|
||||
if (bytes != null && bytes.Length > 0)
|
||||
{
|
||||
string json = message.Mensagem;
|
||||
var cmd = JsonConvert.DeserializeObject<OperacaoControleBaseModel>(json);
|
||||
OperacaoEmAndamento.ExecutaComandoDaBase(cmd);
|
||||
GPSService.AplicarCorrecaoRTK_Mqtt(bytes, bytes.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Erro ao deserializar comando da base: {ex.Message}");
|
||||
}
|
||||
});
|
||||
await MqttServiceBase.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttRTCM, true, 1, async (message) =>
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (message.Bytes == null || message.Bytes.Length == 0)
|
||||
return;
|
||||
try
|
||||
{
|
||||
var bytes = message.Bytes;
|
||||
if (bytes != null && bytes.Length > 0)
|
||||
{
|
||||
GPSService.AplicarCorrecaoRTK_Mqtt(bytes, bytes.Length);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Erro ao deserializar RTCM da base: {ex.Message}");
|
||||
}
|
||||
});
|
||||
await MqttServiceBase.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttPosicao, true, 1, async (message) =>
|
||||
Console.WriteLine($"Erro ao deserializar RTCM da base: {ex.Message}");
|
||||
}
|
||||
});
|
||||
await MqttServiceBase.AdicionarNovoTopico(VariaveisMonitoramento.TopicoMqttPosicao, true, 1, async (message) =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(message.Mensagem))
|
||||
return;
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(message.Mensagem))
|
||||
return;
|
||||
try
|
||||
{
|
||||
string json = message.Mensagem;
|
||||
var posicao = JsonConvert.DeserializeObject<GPSModel>(json);
|
||||
VariaveisOperacao.PosicaoBase = posicao;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Erro ao deserializar dados da base: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
string json = message.Mensagem;
|
||||
var posicao = JsonConvert.DeserializeObject<GPSModel>(json);
|
||||
VariaveisOperacao.PosicaoBase = posicao;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Erro ao deserializar dados da base: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using AgroBase.Models;
|
||||
using AgroMonitor;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -10,10 +9,8 @@ using System.IO.Ports;
|
|||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static AgroBase.Models.Enums;
|
||||
using static AgroBase.Services.GPSService;
|
||||
|
||||
namespace AgroBase.Services
|
||||
{
|
||||
|
|
@ -52,6 +49,7 @@ namespace AgroBase.Services
|
|||
private static bool LoopRTK_Ntrip = false;
|
||||
public static bool CorrecaoRTK_Ntrip = false;
|
||||
public static DateTime UltimoEnvioCorrecaoRTK = DateTime.MinValue;
|
||||
public static GeoLeverArm LeverArm = new GeoLeverArm(VariaveisEquipamento.LeverArmFrontal, VariaveisEquipamento.LeverArmLateral);
|
||||
|
||||
public static void AtualizarPortaCOM(SerialPort Porta)
|
||||
{
|
||||
|
|
@ -100,31 +98,7 @@ namespace AgroBase.Services
|
|||
public static async Task ConfigurarModulo()
|
||||
{
|
||||
Console.WriteLine("Iniciando configuração do módulo GPS...");
|
||||
if (Variaveis.IsAgroMonitor)
|
||||
{
|
||||
bool sucesso = await BaseFixService.FixarBaseViaNtripAsync(
|
||||
startNtrip: async () =>
|
||||
{
|
||||
Console.WriteLine("Iniciando correção NTRIP...");
|
||||
CorrecaoRTK_Ntrip = true;
|
||||
Task.Run(async () => await AplicarCorrecaoRTK_Ntrip());
|
||||
},
|
||||
stopNtrip: async () =>
|
||||
{
|
||||
Console.WriteLine("Parando correção NTRIP...");
|
||||
CorrecaoRTK_Ntrip = false;
|
||||
},
|
||||
segsFixEstavel: 120
|
||||
);
|
||||
if (!sucesso)
|
||||
{
|
||||
await ConfigurarModuloBase(tempo_fixacao: 600);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await ConfigurarModuloRover(comprimento_antena: 130);
|
||||
}
|
||||
await ConfigurarModuloRover(comprimento_antena: 130);
|
||||
}
|
||||
|
||||
private static async Task ConfigurarModuloRover(string porta_usb = "com3", string porta_entrada = "com2", int comprimento_antena = 100, int tolerancia_antena = 5)
|
||||
|
|
@ -486,7 +460,7 @@ namespace AgroBase.Services
|
|||
// 2) se já temos origem e um heading válido, aplica lever arm
|
||||
if (UltimaLeitura.EnuOriginSet)
|
||||
{
|
||||
(double latCor, double lonCorr) = GeoLeverArm.FixLeverArmLatLon_Fast(latitude, longitude, UltimaLeitura.OrientacaoReal);
|
||||
(double latCor, double lonCorr) = LeverArm.FixLeverArmLatLon_Fast(latitude, longitude, UltimaLeitura.OrientacaoReal);
|
||||
UltimaLeitura.Latitude = latCor;
|
||||
UltimaLeitura.Longitude = lonCorr;
|
||||
}
|
||||
|
|
@ -1352,346 +1326,29 @@ namespace AgroBase.Services
|
|||
}
|
||||
}
|
||||
|
||||
public static class BaseFixService
|
||||
{
|
||||
private static int _lastReadHeartbeat = -1;
|
||||
public static List<GgaFix> amostras_pos = new List<GgaFix>(1000);
|
||||
private static DateTime? inicioProcesso = null;
|
||||
private static DateTime? inicioFix = null;
|
||||
private static DateTime? fimProcesso = null;
|
||||
private static int segundosFixEstavel = 120;
|
||||
private static int maxJanelaSegundos = 120;
|
||||
public static double Progresso
|
||||
{
|
||||
get
|
||||
{
|
||||
double progresso = inicioFix is null ? 0 : (DateTime.UtcNow - inicioFix.Value).TotalSeconds / segundosFixEstavel * 100.0;
|
||||
return progresso;
|
||||
}
|
||||
}
|
||||
public static double ProgressoGeral
|
||||
{
|
||||
get
|
||||
{
|
||||
double progresso = inicioProcesso is null ? 0 : (DateTime.UtcNow - inicioProcesso.Value).TotalSeconds / maxJanelaSegundos * 100.0;
|
||||
return progresso;
|
||||
}
|
||||
}
|
||||
public static string ProgressoStr
|
||||
{
|
||||
get
|
||||
{
|
||||
string progresso = "";
|
||||
if (CorrecaoEmAndamento)
|
||||
{
|
||||
progresso = $"Recebendo correção RTK via Ntrip. Progresso geral: {ProgressoGeral.ToString("0.00")}%, Progresso correção: {Progresso.ToString("0.00")}%";
|
||||
}
|
||||
else if (CorrecaoAbsoluta && inicioProcesso.HasValue && fimProcesso.HasValue)
|
||||
{
|
||||
progresso = $"Correção absoluta concluída com {amostras_pos.Count} amostras em {(fimProcesso.Value - inicioProcesso.Value).TotalSeconds.ToString("0.00")} segundos";
|
||||
}
|
||||
else if (inicioProcesso.HasValue && fimProcesso.HasValue)
|
||||
{
|
||||
progresso = $"Correção absoluta falhou com {amostras_pos.Count} amostras em {(fimProcesso.Value - inicioProcesso.Value).TotalSeconds.ToString("0.00")} segundos";
|
||||
}
|
||||
else
|
||||
{
|
||||
progresso = $"Correção absoluta não realizada";
|
||||
}
|
||||
return progresso;
|
||||
}
|
||||
}
|
||||
public static bool CorrecaoAbsoluta = false;
|
||||
public static bool CorrecaoEmAndamento = false;
|
||||
public static bool FixLiberado = false;
|
||||
|
||||
// ===== 1) Função principal =====
|
||||
public static async Task<bool> FixarBaseViaNtripAsync(string portaUsb = "com3", string portaEntrada = "com2", string portaSaida = "com2", string baseId = "957", int segsFixEstavel = 120, int maxJanelaSegs = 600, double madK = 3.5, Func<Task> startNtrip = null, Func<Task> stopNtrip = null)
|
||||
{
|
||||
if (CorrecaoEmAndamento)
|
||||
return false;
|
||||
|
||||
CorrecaoEmAndamento = true;
|
||||
fimProcesso = null;
|
||||
|
||||
segundosFixEstavel = segsFixEstavel;
|
||||
maxJanelaSegundos = maxJanelaSegs;
|
||||
|
||||
// 1.1 Config temporária como rover parado + NMEA
|
||||
await ConfigurarComoRoverParadoAsync(portaUsb, portaEntrada);
|
||||
|
||||
// 1.2 Ligar NTRIP (injeta RTCM na portaEntrada)
|
||||
if (startNtrip != null) await startNtrip();
|
||||
|
||||
try
|
||||
{
|
||||
// 2) Esperar FIX sustentado e coletar GNGGA
|
||||
var amostras = await EsperarFixEAmostrarAsync();
|
||||
|
||||
if (amostras.Count < 10)
|
||||
{
|
||||
Console.WriteLine("Poucas amostras de RTK FIX coletadas. Tente aumentar o tempo ou verificar sinais.");
|
||||
CorrecaoAbsoluta = false;
|
||||
return CorrecaoAbsoluta;
|
||||
}
|
||||
|
||||
// 3) Filtro robusto (MAD) + média final
|
||||
var (lat, lon, h, nAmostras) = FiltrarEAgrupar(amostras, madK);
|
||||
|
||||
// 4) Alternar para base FIX + perfil RTCM
|
||||
await AplicarBaseFixAsync(portaUsb, portaSaida, baseId, lat, lon, h);
|
||||
|
||||
Console.WriteLine($"[BASE/FIX] Coordenadas aplicadas (n={nAmostras}):");
|
||||
Console.WriteLine($" lat = {lat:0.000000000}, lon = {lon:0.000000000}, h = {h:0.000}");
|
||||
CorrecaoAbsoluta = true;
|
||||
return CorrecaoAbsoluta;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (stopNtrip != null) await stopNtrip();
|
||||
fimProcesso = DateTime.UtcNow;
|
||||
CorrecaoEmAndamento = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 1.1 Rover parado + NMEA + limpar logs =====
|
||||
private static async Task ConfigurarComoRoverParadoAsync(string portaUsb, string portaEntrada)
|
||||
{
|
||||
Console.WriteLine("Configurando base como modo rover parado...");
|
||||
string freq = "1.0";
|
||||
string[] cmds = {
|
||||
// Ajuste de bauds
|
||||
$"config {portaUsb} 115200\r\n",
|
||||
$"config {portaEntrada} 115200\r\n",
|
||||
|
||||
// Limpa logs
|
||||
$"unlog com1\r\n",
|
||||
$"unlog com2\r\n",
|
||||
$"unlog com3\r\n",
|
||||
|
||||
// Rover parado (vamos usar NTRIP p/ obter FIX)
|
||||
$"mode rover uav\r\n",
|
||||
|
||||
// NMEA na USB
|
||||
$"gngga {portaUsb} {freq}\r\n",
|
||||
$"gpths {portaUsb} {freq}\r\n",
|
||||
|
||||
$"saveconfig\r\n"
|
||||
};
|
||||
|
||||
await Task.Delay(1000);
|
||||
foreach (var c in cmds)
|
||||
{
|
||||
var b = Encoding.ASCII.GetBytes(c);
|
||||
PortaGPS.Write(b, 0, b.Length);
|
||||
await Task.Delay(250);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 2) Coleta GNGGA com FIX sustentado =====
|
||||
private static async Task<List<GgaFix>> EsperarFixEAmostrarAsync()
|
||||
{
|
||||
Console.WriteLine("Inciando coleta de dados...");
|
||||
|
||||
amostras_pos = new List<GgaFix>(1000);
|
||||
inicioProcesso = DateTime.UtcNow;
|
||||
inicioFix = null;
|
||||
|
||||
// Você já deve ter um leitor da COM que devolve linhas NMEA.
|
||||
// Abaixo, vamos supor um método async que lê GGA parseado.
|
||||
while (ProgressoGeral < 100)
|
||||
{
|
||||
// Lê próxima sentença (bloqueante/assíncrono)
|
||||
var gga = await LerProximoGgaAsync(); // implemente no seu stack
|
||||
|
||||
if (gga is null) continue;
|
||||
|
||||
// Considera "RTK FIX" como qualidade válida
|
||||
if (!FixLiberado || !new List<TiposCorrecaoGPS>() { TiposCorrecaoGPS.RTKFixo }.Contains(gga.FixQuality))
|
||||
{
|
||||
inicioFix = null; // reset
|
||||
continue;
|
||||
}
|
||||
|
||||
// Marca início da janela de FIX estável
|
||||
if (inicioFix is null)
|
||||
{
|
||||
Console.WriteLine("RTK Fixo definido! Iniciando coleta de dados com precisão...");
|
||||
inicioFix = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
amostras_pos.Add(gga);
|
||||
Console.WriteLine("Nova coordenada registrada!");
|
||||
|
||||
// Verifica se já temos FIX estável pelo período necessário
|
||||
if (Progresso >= 100)
|
||||
break;
|
||||
}
|
||||
|
||||
return amostras_pos;
|
||||
}
|
||||
|
||||
// ===== 2.1) Ajuste a assinatura se quiser passar timeout e CT de fora
|
||||
private static async Task<GgaFix> LerProximoGgaAsync(int timeoutMs = 5000, CancellationToken ct = default)
|
||||
{
|
||||
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||
int startHb = System.Threading.Volatile.Read(ref _lastReadHeartbeat);
|
||||
|
||||
// 1) Espera um novo heartbeat
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
int currentHb = UltimaLeitura.Heartbeat; // <- leitura normal da propriedade
|
||||
if (currentHb != startHb) break;
|
||||
|
||||
if (sw.ElapsedMilliseconds >= timeoutMs)
|
||||
//throw new TimeoutException("Timeout aguardando nova leitura GGA.");
|
||||
return new GgaFix(DateTime.UtcNow, 0, 0, 0, TiposCorrecaoGPS.SemCorrecao);
|
||||
|
||||
await Task.Delay(75, ct).ConfigureAwait(false);
|
||||
}
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
// 2) Snapshot consistente
|
||||
while (true)
|
||||
{
|
||||
int hbBefore = UltimaLeitura.Heartbeat;
|
||||
|
||||
// Captura TODOS os campos que você precisa em variáveis locais
|
||||
DateTime tsUtc = UltimaLeitura.DataHora.ToUniversalTime();
|
||||
double lat = UltimaLeitura.Latitude;
|
||||
double lon = UltimaLeitura.Longitude;
|
||||
double altElips = UltimaLeitura.AltitudeElipsoidal; // garanta que já é elipsoidal no parser
|
||||
var fixQual = UltimaLeitura.QualidadeFix; // enum? ok.
|
||||
|
||||
int hbAfter = UltimaLeitura.Heartbeat;
|
||||
|
||||
// Se o heartbeat não mudou durante o snapshot, temos dados coerentes
|
||||
if (hbBefore == hbAfter)
|
||||
{
|
||||
// marca como lido
|
||||
System.Threading.Volatile.Write(ref _lastReadHeartbeat, hbAfter);
|
||||
|
||||
// monta o DTO
|
||||
return new GgaFix(
|
||||
tsUtc: tsUtc,
|
||||
latDeg: lat,
|
||||
lonDeg: lon,
|
||||
altElipsoidalM: altElips,
|
||||
fixQuality: fixQual
|
||||
);
|
||||
}
|
||||
|
||||
// caso contrário, alguém atualizou no meio — tenta de novo rápido
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 3) Filtro robusto (MAD) + média =====
|
||||
private static (double lat, double lon, double h, int n) FiltrarEAgrupar(List<GgaFix> amostras, double madK = 3.5)
|
||||
{
|
||||
Console.WriteLine("Filtrando dados aferidos...");
|
||||
// Medianas
|
||||
var lats = amostras.Select(a => a.LatDeg).OrderBy(x => x).ToArray();
|
||||
var lons = amostras.Select(a => a.LonDeg).OrderBy(x => x).ToArray();
|
||||
var hs = amostras.Select(a => a.AltElipsoidalM).OrderBy(x => x).ToArray();
|
||||
|
||||
double medLat = Mediana(lats);
|
||||
double medLon = Mediana(lons);
|
||||
double medH = Mediana(hs);
|
||||
|
||||
// Desvios absolutos da mediana (MAD)
|
||||
var dLat = amostras.Select(a => Math.Abs(a.LatDeg - medLat)).OrderBy(x => x).ToArray();
|
||||
var dLon = amostras.Select(a => Math.Abs(a.LonDeg - medLon)).OrderBy(x => x).ToArray();
|
||||
var dH = amostras.Select(a => Math.Abs(a.AltElipsoidalM - medH)).OrderBy(x => x).ToArray();
|
||||
|
||||
double madLat = Mediana(dLat) + 1e-12;
|
||||
double madLon = Mediana(dLon) + 1e-12;
|
||||
double madHgt = Mediana(dH) + 1e-12;
|
||||
|
||||
// Filtra outliers (|x - med| / MAD <= madK)
|
||||
var filtradas = amostras.Where(a =>
|
||||
(Math.Abs(a.LatDeg - medLat) / madLat) <= madK &&
|
||||
(Math.Abs(a.LonDeg - medLon) / madLon) <= madK &&
|
||||
(Math.Abs(a.AltElipsoidalM - medH) / madHgt) <= madK
|
||||
).ToList();
|
||||
|
||||
// Média final
|
||||
double lat = filtradas.Average(a => a.LatDeg);
|
||||
double lon = filtradas.Average(a => a.LonDeg);
|
||||
double h = filtradas.Average(a => a.AltElipsoidalM);
|
||||
|
||||
return (lat, lon, h, filtradas.Count);
|
||||
|
||||
double Mediana(double[] arr)
|
||||
{
|
||||
int n = arr.Length;
|
||||
if (n == 0) return double.NaN;
|
||||
return (n % 2 == 1) ? arr[n / 2] : 0.5 * (arr[n / 2 - 1] + arr[n / 2]);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 4) Aplicar base FIX + RTCM + save =====
|
||||
private static async Task AplicarBaseFixAsync(string portaUsb, string portaSaida, string baseId, double latDeg, double lonDeg, double hEllipsM)
|
||||
{
|
||||
Console.WriteLine("Aplicando dados de correção...");
|
||||
var ci = System.Globalization.CultureInfo.InvariantCulture;
|
||||
// Desliga logs antes de trocar modo
|
||||
string[] pre = {
|
||||
$"unlog com1\r\n",
|
||||
$"unlog com2\r\n",
|
||||
$"unlog com3\r\n"
|
||||
};
|
||||
foreach (var c in pre) { PortaGPS.Write(Encoding.ASCII.GetBytes(c), 0, c.Length); await Task.Delay(150); }
|
||||
|
||||
var latStr = latDeg.ToString("0.000000000", ci);
|
||||
var lonStr = lonDeg.ToString("0.000000000", ci);
|
||||
var hStr = hEllipsM.ToString("0.000", ci);
|
||||
|
||||
var fix = Encoding.ASCII.GetBytes($"mode base {baseId} {latStr} {lonStr} {hStr}\r\n");
|
||||
PortaGPS.Write(fix, 0, fix.Length);
|
||||
await Task.Delay(250);
|
||||
|
||||
// Reativar RTCM no canal de saída para o LoRa
|
||||
string[] rtcmCmds = {
|
||||
// RTCM perfil (comece leve; ative mais constelações se o LoRa aguentar)
|
||||
$"RTCM1006 {portaSaida} 10\r\n",
|
||||
$"RTCM1033 {portaSaida} 30\r\n",
|
||||
$"RTCM1074 {portaSaida} 1\r\n", // GPS MSM4
|
||||
$"RTCM1124 {portaSaida} 1\r\n", // BeiDou MSM4
|
||||
|
||||
// (Opcional) ativar mais constelações:
|
||||
$"RTCM1094 {portaSaida} 1\r\n", // Galileo MSM4
|
||||
$"RTCM1084 {portaSaida} 1\r\n", // GLONASS MSM4
|
||||
//$"RTCM1230 {portaSaida} 10\r\n",// Bias GLONASS (OBRIGATÓRIO se 1084 estiver ativo)
|
||||
};
|
||||
|
||||
foreach (var c in rtcmCmds) { var b = Encoding.ASCII.GetBytes(c); PortaGPS.Write(b, 0, b.Length); await Task.Delay(200); }
|
||||
|
||||
// NMEA mínimo na USB p/ debug
|
||||
var nmea = $"gngga {portaUsb} 1\r\n";
|
||||
PortaGPS.Write(Encoding.ASCII.GetBytes(nmea), 0, nmea.Length);
|
||||
await Task.Delay(150);
|
||||
|
||||
// Persistir
|
||||
var save = "saveconfig\r\n";
|
||||
PortaGPS.Write(Encoding.ASCII.GetBytes(save), 0, save.Length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class GeoLeverArm
|
||||
{
|
||||
const double R = 6378137.0; // WGS84
|
||||
public static double xB = Variaveis.IsAgroMonitor ? VariaveisMonitoramento.LeverArmFrontal : VariaveisEquipamento.LeverArmFrontal; // +frente (m)
|
||||
public static double yB = Variaveis.IsAgroMonitor ? VariaveisMonitoramento.LeverArmLateral : VariaveisEquipamento.LeverArmLateral; // +direita (m)
|
||||
public static bool invertHeading = false;
|
||||
public static bool mirrorLateral = false;
|
||||
public GeoLeverArm(double _xb = 0, double _yb = 0, bool _invH = false, bool _mirrL = false)
|
||||
{
|
||||
xB = _xb;
|
||||
yB = _yb;
|
||||
invertHeading = _invH;
|
||||
mirrorLateral = _mirrL;
|
||||
}
|
||||
|
||||
static double ToRad(double deg) => deg * Math.PI / 180.0;
|
||||
static double ToDeg(double rad) => rad * 180.0 / Math.PI;
|
||||
const double R = 6378137.0; // WGS84
|
||||
private readonly double xB; // +frente (m)
|
||||
private readonly double yB; // +direita (m)
|
||||
private readonly bool invertHeading = false;
|
||||
private readonly bool mirrorLateral = false;
|
||||
|
||||
private double ToRad(double deg) => deg * Math.PI / 180.0;
|
||||
private double ToDeg(double rad) => rad * 180.0 / Math.PI;
|
||||
|
||||
// lat/lon -> ENU (aproximação local, boa para ~km)
|
||||
public static (double x, double y) GeodeticToENU(double lat, double lon, double lat0, double lon0)
|
||||
public (double x, double y) GeodeticToENU(double lat, double lon, double lat0, double lon0)
|
||||
{
|
||||
double latR = ToRad(lat), lonR = ToRad(lon);
|
||||
double lat0R = ToRad(lat0), lon0R = ToRad(lon0);
|
||||
|
|
@ -1701,7 +1358,7 @@ namespace AgroBase.Services
|
|||
return (xEast, yNorth);
|
||||
}
|
||||
|
||||
public static (double lat, double lon) ENUToGeodetic(double x, double y, double lat0, double lon0)
|
||||
public (double lat, double lon) ENUToGeodetic(double x, double y, double lat0, double lon0)
|
||||
{
|
||||
double lat0R = ToRad(lat0);
|
||||
double dLat = y / R;
|
||||
|
|
@ -1713,7 +1370,7 @@ namespace AgroBase.Services
|
|||
|
||||
// Aplica lever arm: retorna o CENTRO dado ANTENA + heading.
|
||||
// Convenção: θ=0 norte; +horário→leste (igual ao seu modelo: x+=sinθ, y+=cosθ).
|
||||
public static (double xCtr, double yCtr) ApplyLeverArmENU(double xAnt, double yAnt, double thetaRad, double lFwd, double lLeft)
|
||||
public (double xCtr, double yCtr) ApplyLeverArmENU(double xAnt, double yAnt, double thetaRad, double lFwd, double lLeft)
|
||||
{
|
||||
double s = Math.Sin(thetaRad), c = Math.Cos(thetaRad);
|
||||
// vetores no mundo
|
||||
|
|
@ -1726,9 +1383,9 @@ namespace AgroBase.Services
|
|||
return (xAnt - rx, yAnt - ry);
|
||||
}
|
||||
|
||||
public static (double lat, double lon) FixLeverArmLatLon_Fast(double latAnt_deg, double lonAnt_deg, double headingDeg)
|
||||
public (double lat, double lon) FixLeverArmLatLon_Fast(double latAnt_deg, double lonAnt_deg, double headingDeg)
|
||||
{
|
||||
if (mirrorLateral) yB = -yB; // espelha lateral (D<->E)
|
||||
double _yB = (mirrorLateral) ? -yB : yB; // espelha lateral (D<->E)
|
||||
|
||||
double th = headingDeg * Math.PI / 180.0;
|
||||
if (invertHeading) th = -th; // inverte sentido do ângulo
|
||||
|
|
@ -1737,8 +1394,8 @@ namespace AgroBase.Services
|
|||
double fE = Math.Sin(th), fN = Math.Cos(th); // forward (E,N)
|
||||
double rE = fN, rN = -fE; // right (E,N)
|
||||
|
||||
double dE = xB * fE + yB * rE; // body -> ENU
|
||||
double dN = xB * fN + yB * rN;
|
||||
double dE = xB * fE + _yB * rE; // body -> ENU
|
||||
double dN = xB * fN + _yB * rN;
|
||||
|
||||
double latRad = latAnt_deg * Math.PI / 180.0;
|
||||
double dLat_deg = (dN / R) * 180.0 / Math.PI;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using AgroBase.Models;
|
||||
using AgroBase.Services;
|
||||
using MQTTnet;
|
||||
using MQTTnet.Client;
|
||||
using MQTTnet.Client.Options;
|
||||
|
|
@ -16,16 +15,14 @@ public class MqttService
|
|||
private string _brokerAddr;
|
||||
private int _brokerPort;
|
||||
private AsyncTaskTimerModel tmrCheck;
|
||||
private readonly Action<string> _logDebug;
|
||||
|
||||
public List<MqttTopicosModel> Topicos;
|
||||
|
||||
private void LogDebug(string msg)
|
||||
public MqttService(string brokerAddress, int brokerPort, string client_id, bool local, Action<string> logDebug)
|
||||
{
|
||||
Console.WriteLine($"[MQTT {_brokerAddr}:{_brokerPort}] - {msg}");
|
||||
}
|
||||
_logDebug = logDebug;
|
||||
|
||||
public MqttService(string brokerAddress, int brokerPort, string client_id, bool local)
|
||||
{
|
||||
_brokerAddr = brokerAddress;
|
||||
_brokerPort = brokerPort;
|
||||
|
||||
|
|
@ -42,8 +39,8 @@ public class MqttService
|
|||
|
||||
_client.UseConnectedHandler(async e =>
|
||||
{
|
||||
LogDebug("Connected to MQTT Broker.");
|
||||
if (Topicos.Any(x => x.Inscrever))
|
||||
_logDebug("Connected to MQTT Broker.");
|
||||
if (Topicos?.Any(x => x.Inscrever) ?? false)
|
||||
{
|
||||
foreach (var topic in Topicos)
|
||||
{
|
||||
|
|
@ -54,7 +51,7 @@ public class MqttService
|
|||
|
||||
_client.UseDisconnectedHandler(e =>
|
||||
{
|
||||
LogDebug("Disconnected from MQTT Broker.");
|
||||
_logDebug("Disconnected from MQTT Broker.");
|
||||
});
|
||||
|
||||
_client.UseApplicationMessageReceivedHandler(e =>
|
||||
|
|
@ -97,7 +94,7 @@ public class MqttService
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogDebug($"Erro no callback do tópico '{topico.Topico}': {ex}");
|
||||
_logDebug($"Erro no callback do tópico '{topico.Topico}': {ex}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -132,7 +129,7 @@ public class MqttService
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogDebug("Erro ao tentar se conectar ao MQTT Broker: " + ex.Message);
|
||||
_logDebug("Erro ao tentar se conectar ao MQTT Broker: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -187,11 +184,11 @@ public class MqttService
|
|||
await ConnectAsync();
|
||||
}
|
||||
await _client.SubscribeAsync(new TopicFilterBuilder().WithTopic(topic.Topico).Build());
|
||||
LogDebug($"Subscribed to topic: {topic.Topico}");
|
||||
_logDebug($"Subscribed to topic: {topic.Topico}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogDebug($"An error occurred while subscribing from the topic: {ex.Message}");
|
||||
_logDebug($"An error occurred while subscribing from the topic: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,11 +205,11 @@ public class MqttService
|
|||
await ConnectAsync();
|
||||
}
|
||||
await _client.UnsubscribeAsync(new string[] { topic.Topico });
|
||||
LogDebug($"Unsubscribed from topic: {topic.Topico}");
|
||||
_logDebug($"Unsubscribed from topic: {topic.Topico}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogDebug($"An error occurred while unsubscribing from the topic: {ex.Message}");
|
||||
_logDebug($"An error occurred while unsubscribing from the topic: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -259,7 +256,7 @@ public class MqttService
|
|||
.Build();
|
||||
|
||||
await _client.PublishAsync(mensagem);
|
||||
LogDebug($"Mensagem retida limpa para o tópico: {topico}");
|
||||
_logDebug($"Mensagem retida limpa para o tópico: {topico}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -505,6 +505,8 @@ namespace AgroBase.Services
|
|||
Porta.BaudRate = 115200;
|
||||
Porta.Open();
|
||||
await Task.Delay(100);
|
||||
var nmea = $"gngga com3 1\r\n";
|
||||
Porta.Write(Encoding.ASCII.GetBytes(nmea), 0, nmea.Length);
|
||||
AtualizarConsole($"{Porta.PortName} - Procurando dispositivo GPS");
|
||||
await Task.Delay(1000);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace AgroMonitor
|
|||
{
|
||||
InitializeComponent();
|
||||
|
||||
Variaveis.IniciarMQTT();
|
||||
//Variaveis.IniciarMQTT();
|
||||
|
||||
RedisService.Iniciar();
|
||||
RedisService.LimparDadosIniciais();
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,7 +1,8 @@
|
|||
<Application x:Class="OperationControl.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
StartupUri="Windows/MainWindow.xaml">
|
||||
Startup="Application_Startup"
|
||||
>
|
||||
<Application.Resources>
|
||||
|
||||
<Style x:Key="RoundedLabel" TargetType="Label">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System.Configuration;
|
||||
using System.Data;
|
||||
using OperationControl.Models;
|
||||
using System.Windows;
|
||||
|
||||
namespace OperationControl
|
||||
|
|
@ -9,6 +8,15 @@ namespace OperationControl
|
|||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
public AppShell Shell { get; private set; }
|
||||
|
||||
private void Application_Startup(object sender, StartupEventArgs e)
|
||||
{
|
||||
// Cria o “controlador”/janela raiz
|
||||
Shell = new AppShell();
|
||||
Shell.Inicializar();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
using OpenTK.Wpf;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices.JavaScript;
|
||||
|
||||
namespace OperationControl.Controls
|
||||
{
|
||||
|
|
@ -25,7 +19,7 @@ namespace OperationControl.Controls
|
|||
bool dragLeft, dragMid;
|
||||
|
||||
// ======= parâmetros de cena =======
|
||||
readonly List<LivoxBboxModel> boxes = new();
|
||||
readonly List<AgroBase.Models.LivoxBboxModel> boxes = new();
|
||||
public float GridHalf { get; set; } = 12f;
|
||||
public float RobotHalfW { get; set; } = 0.30f;
|
||||
public float RobotL { get; set; } = 0.60f;
|
||||
|
|
@ -57,7 +51,7 @@ namespace OperationControl.Controls
|
|||
}
|
||||
|
||||
// ======= API pública =======
|
||||
public void SetBboxes(IEnumerable<LivoxBboxModel> list)
|
||||
public void SetBboxes(IEnumerable<AgroBase.Models.LivoxBboxModel> list)
|
||||
{
|
||||
boxes.Clear();
|
||||
if (list != null) boxes.AddRange(list);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@
|
|||
|
||||
<Polygon x:Name="CourseArrow" Points="150,35 143,55 157,55" Fill="Green" Visibility="Collapsed">
|
||||
<Polygon.RenderTransform>
|
||||
<RotateTransform x:Name="CourseRotation" CenterX="150" CenterY="150" Angle="0"/>
|
||||
<RotateTransform x:Name="CourseRotation" CenterX="150" CenterY="150"/>
|
||||
</Polygon.RenderTransform>
|
||||
</Polygon>
|
||||
|
||||
|
|
@ -93,15 +93,15 @@
|
|||
</Grid>
|
||||
|
||||
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding DifHeading, RelativeSource={RelativeSource AncestorType=UserControl}, StringFormat={}{0:0.0}°}" Foreground="{Binding DifHeading, RelativeSource={RelativeSource AncestorType=UserControl}, Converter={StaticResource DifHeadingToColorConverter}}" FontWeight="Bold" FontSize="40" Opacity="0.95"/>
|
||||
<TextBlock x:Name="txtHeadingDif" Text="{Binding DifHeading, RelativeSource={RelativeSource AncestorType=UserControl}, StringFormat={}{0:0.0}°}" Foreground="White" FontWeight="Bold" FontSize="40" Opacity="0.95"/>
|
||||
</Grid>
|
||||
|
||||
<Grid HorizontalAlignment="Left" VerticalAlignment="Top">
|
||||
<TextBlock Text="{Binding CourseHeading, RelativeSource={RelativeSource AncestorType=UserControl}, StringFormat={}{0:0.0}°}" Foreground="Green" FontWeight="Bold" FontSize="35" Opacity="0.95" Margin="-20 -30 0 0"/>
|
||||
<TextBlock x:Name="txtHeadingCourse" Visibility="Collapsed" Text="{Binding CourseHeading, RelativeSource={RelativeSource AncestorType=UserControl}, StringFormat={}{0:0.0}°}" Foreground="Green" FontWeight="Bold" FontSize="35" Opacity="0.95" Margin="-20 -30 0 0"/>
|
||||
</Grid>
|
||||
|
||||
<Grid HorizontalAlignment="Right" VerticalAlignment="Top">
|
||||
<TextBlock Text="{Binding Heading, RelativeSource={RelativeSource AncestorType=UserControl}, StringFormat={}{0:0.0}°}" Foreground="Yellow" FontWeight="Bold" FontSize="35" Opacity="0.95" Margin="0 -30 -20 0"/>
|
||||
<TextBlock x:Name="txtHeading" Visibility="Collapsed" Text="{Binding Heading, RelativeSource={RelativeSource AncestorType=UserControl}, StringFormat={}{0:0.0}°}" Foreground="Yellow" FontWeight="Bold" FontSize="35" Opacity="0.95" Margin="0 -30 -20 0"/>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace OperationControl.Controls
|
||||
{
|
||||
|
|
@ -77,16 +78,38 @@ namespace OperationControl.Controls
|
|||
if (double.IsNaN(CourseHeading))
|
||||
{
|
||||
CourseArrow.Visibility = Visibility.Collapsed;
|
||||
txtHeading.Visibility = Visibility.Collapsed;
|
||||
txtHeadingCourse.Visibility = Visibility.Collapsed;
|
||||
DifHeading = Heading;
|
||||
UpdateChrome();
|
||||
return;
|
||||
}
|
||||
|
||||
// mostra a seta e gira pelo delta (curso - heading atual)
|
||||
CourseArrow.Visibility = Visibility.Visible;
|
||||
txtHeading.Visibility = Visibility.Visible;
|
||||
txtHeadingCourse.Visibility = Visibility.Visible;
|
||||
double delta = NormalizeDelta(CourseHeading - Heading);
|
||||
CourseRotation.Angle = delta;
|
||||
|
||||
DifHeading = NormalizeDelta(Heading - CourseHeading);
|
||||
UpdateChrome();
|
||||
}
|
||||
|
||||
private void UpdateChrome()
|
||||
{
|
||||
if (Chrome == null) return;
|
||||
|
||||
bool no_course = double.IsNaN(CourseHeading);
|
||||
var a = no_course ? 0 : DifHeading;
|
||||
var cor = new SolidColorBrush(Color.FromRgb(0x2E, 0xCC, 0x71)); // verde
|
||||
if (a >= 10)
|
||||
cor = new SolidColorBrush(Color.FromRgb(0xE7, 0x4C, 0x3C)); // vermelho
|
||||
else if (a >= 5)
|
||||
cor = new SolidColorBrush(Color.FromRgb(0xF1, 0xC4, 0x0F)); // amarelo
|
||||
|
||||
Chrome.BorderBrush = cor;
|
||||
txtHeadingDif.Foreground = no_course ? new SolidColorBrush(Colors.White) : cor;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
<UserControl x:Class="OperationControl.Controls.MapViewControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:m="clr-namespace:Mapsui.UI.Wpf;assembly=Mapsui.UI.Wpf"
|
||||
x:Name="Root"
|
||||
MinHeight="100"
|
||||
MinWidth="300">
|
||||
<Grid>
|
||||
<!-- Mapsui MapControl preenche todo o espaço disponível (responsivo) -->
|
||||
<m:MapControl x:Name="Mapa"/>
|
||||
|
||||
<!-- Overlay simples para mensagens (ex.: MBTiles não encontrado) -->
|
||||
<Border x:Name="OverlayMessage" Background="#AA111111" CornerRadius="8" Padding="10" Margin="12" HorizontalAlignment="Left" VerticalAlignment="Top" Visibility="Collapsed">
|
||||
<TextBlock x:Name="OverlayText" Foreground="White" FontSize="12" TextWrapping="Wrap"/>
|
||||
</Border>
|
||||
|
||||
<ComboBox x:Name="CmbBaseMap" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,10,10,0" Width="189" SelectionChanged="OnBaseMapChanged"/>
|
||||
|
||||
<Button Content="Carregar Mapa" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,97,10" Padding="8,4" Background="#2ECC71" Foreground="White" FontWeight="Bold" Click="OnLoadMapClicked"/>
|
||||
<Button Content="Centralizar" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,10,10" Padding="8,4" Background="#2ECC71" Foreground="White" FontWeight="Bold" Click="OnCenterAreaClicked"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,49 @@
|
|||
using AgroBase.Models;
|
||||
using AgroBase.Services;
|
||||
using OperationControl.Services;
|
||||
using OperationControl.Windows;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace OperationControl.Models
|
||||
{
|
||||
public class AppShell
|
||||
{
|
||||
private readonly System.Timers.Timer tmrComunicacao = new(1000) { AutoReset = true };
|
||||
private int tmrComunicacaoTicks = 0;
|
||||
private bool tmrComunicacaoTicking = false;
|
||||
|
||||
public MainWindow Main { get; private set; }
|
||||
|
||||
public void Inicializar()
|
||||
{
|
||||
APIService.IniciarRotinas();
|
||||
Variaveis.IniciarMQTT();
|
||||
|
||||
tmrComunicacao.Elapsed += (_, __) => tmrComunicacao_Elapsed();
|
||||
tmrComunicacao.Start();
|
||||
|
||||
Show();
|
||||
}
|
||||
|
||||
private void Show()
|
||||
{
|
||||
// Aqui você decide qual janela é a inicial de fato
|
||||
Main = new MainWindow();
|
||||
Main.Show();
|
||||
}
|
||||
|
||||
private void tmrComunicacao_Elapsed()
|
||||
{
|
||||
if (tmrComunicacaoTicking) return;
|
||||
tmrComunicacaoTicking = true;
|
||||
if (tmrComunicacaoTicks % VariaveisEquipamento.TempoEntrePingsConexao == 0 && Variaveis.GpsService != null)
|
||||
{
|
||||
VariaveisControleOperacao.EnviarDadosPosicao(Variaveis.GpsService.UltimaLeitura);
|
||||
}
|
||||
VariaveisControleOperacao.AtualizarListaRoversNaRede();
|
||||
tmrComunicacaoTicks++;
|
||||
tmrComunicacaoTicking = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OperationControl.Models
|
||||
{
|
||||
public class Enums
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
using AgroBase.Models;
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics;
|
||||
using System.Windows;
|
||||
using OperationControl.Services;
|
||||
|
||||
namespace OperationControl.Models
|
||||
{
|
||||
public class Variaveis
|
||||
{
|
||||
public static MqttService MqttService;
|
||||
public static GpsService GpsService;
|
||||
|
||||
public static void MostrarLog(string message)
|
||||
{
|
||||
Debug.WriteLine(message);
|
||||
}
|
||||
|
||||
public static async void IniciarMQTT()
|
||||
{
|
||||
if (MqttService != null)
|
||||
{
|
||||
foreach (var topico in MqttService.Topicos.Where(x => x.Inscrever))
|
||||
{
|
||||
await MqttService.UnsubscribeAsync(topico);
|
||||
}
|
||||
MqttService.Topicos.Clear();
|
||||
}
|
||||
|
||||
MqttService = new MqttService("localhost", 1883, "base", true, msg => MostrarLog($"[MQTT localhost:1883] - {msg}"));
|
||||
|
||||
await MqttService.AdicionarNovoTopico(VariaveisControleOperacao.TopicoMqttRTCM);
|
||||
await MqttService.AdicionarNovoTopico(VariaveisControleOperacao.TopicoMqttDispositivos, true, 1, async (message) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string device_id = message.Mensagem;
|
||||
VariaveisControleOperacao.AdicionarNovoRoverNaRede(message.Mensagem);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MostrarLog($"Erro ao deserializar ping do rover: {ex.Message}");
|
||||
}
|
||||
});
|
||||
|
||||
GpsService = new GpsService();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class VariaveisControleOperacao
|
||||
{
|
||||
public static double LeverArmFrontal { get; } = 0.0;
|
||||
public static double LeverArmLateral { get; } = 0.0;
|
||||
|
||||
public static readonly string BaseMarkerID = "BASE";
|
||||
public static string TopicoMqttDispositivos { get; } = $"agrobot/v1/base/devices";
|
||||
public static string TopicoMqttPosicao { get; } = $"agrobot/v1/base/position";
|
||||
public static string TopicoMqttRTCM { get; } = $"agrobot/v1/base/rtcm";
|
||||
private static readonly object _RoversLock = new object();
|
||||
public static Dictionary<string, OperacaoSensoriamentoLogModel> RoversNaRede { get; set; } = new Dictionary<string, OperacaoSensoriamentoLogModel>();
|
||||
public static string SelectedRoverId { get; set; } = BaseMarkerID;
|
||||
|
||||
public static async void AdicionarNovoRoverNaRede(string device_id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(device_id))
|
||||
return;
|
||||
|
||||
bool rover_ja_adicionado = false;
|
||||
lock (_RoversLock)
|
||||
{
|
||||
rover_ja_adicionado = RoversNaRede.ContainsKey(device_id);
|
||||
}
|
||||
|
||||
if (!rover_ja_adicionado)
|
||||
{
|
||||
lock (_RoversLock)
|
||||
{
|
||||
RoversNaRede.Add(device_id, new OperacaoSensoriamentoLogModel() { Momento = DateTime.Now });
|
||||
}
|
||||
|
||||
await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", device_id));
|
||||
await Variaveis.MqttService.AdicionarNovoTopico(VariaveisEquipamento.TopicoMqttTelemetria.Replace("<id>", device_id), true, 1, async (message) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
string json = message.Mensagem;
|
||||
var obj = JsonConvert.DeserializeObject<OperacaoSensoriamentoLogModel>(json);
|
||||
lock (_RoversLock)
|
||||
{
|
||||
RoversNaRede[device_id] = obj;
|
||||
|
||||
((App)Application.Current).Shell.Main.AtualizarDadosTela_Telemetria(device_id);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Variaveis.MostrarLog($"Erro ao deserializar dados de telemetria do rover {device_id}: {ex.Message}");
|
||||
}
|
||||
});
|
||||
|
||||
await Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
List<string> dispositivos_ids = new List<string>() { "BASE" };
|
||||
dispositivos_ids.Union(RoversNaRede.Select(x => x.Key).ToList());
|
||||
((App)Application.Current).Shell.Main.AtualizarListaDispositivos(dispositivos_ids);
|
||||
}
|
||||
catch (Exception exUi)
|
||||
{
|
||||
Variaveis.MostrarLog($"Erro ao atualizar UI lista dispositivos: {exUi.Message}");
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public static async void AtualizarListaRoversNaRede()
|
||||
{
|
||||
List<string> rovers_desconectados = new List<string>();
|
||||
var rovers_atual = new Dictionary<string, OperacaoSensoriamentoLogModel>();
|
||||
lock (_RoversLock)
|
||||
{
|
||||
rovers_atual = new Dictionary<string, OperacaoSensoriamentoLogModel>(RoversNaRede);
|
||||
}
|
||||
foreach (var rover in rovers_atual)
|
||||
{
|
||||
double tempo_sem_resposta = (DateTime.Now - rover.Value.Momento).TotalSeconds;
|
||||
if (tempo_sem_resposta > 5.0)
|
||||
{
|
||||
rovers_desconectados.Add(rover.Key);
|
||||
}
|
||||
}
|
||||
foreach (var device_id in rovers_desconectados)
|
||||
{
|
||||
lock (_RoversLock)
|
||||
{
|
||||
RoversNaRede.Remove(device_id);
|
||||
|
||||
if (SelectedRoverId == device_id)
|
||||
{
|
||||
((App)Application.Current).Shell.Main.LimparDadosTela_Telemetria();
|
||||
}
|
||||
}
|
||||
var topicos_rover = Variaveis.MqttService.Topicos.Where(x => x.Topico.Contains(device_id)).ToList();
|
||||
foreach (var topico in topicos_rover)
|
||||
{
|
||||
await Variaveis.MqttService.UnsubscribeAsync(topico);
|
||||
Variaveis.MqttService.Topicos.Remove(topico);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async void EnviarDadosControle(string rover_id, OperacaoControleBaseModel controle)
|
||||
{
|
||||
var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == VariaveisEquipamento.TopicoMqttComandos.Replace("<id>", rover_id));
|
||||
if (topico != null)
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(controle);
|
||||
await Variaveis.MqttService.PublishAsync(topico, json);
|
||||
}
|
||||
}
|
||||
|
||||
public static async void EnviarDadosPosicao(GPSModel posicao)
|
||||
{
|
||||
var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == TopicoMqttPosicao);
|
||||
if (topico != null)
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(posicao);
|
||||
await Variaveis.MqttService.PublishAsync(topico, json);
|
||||
}
|
||||
}
|
||||
|
||||
public static async void EnviarDadosCorrecaoRTCM(byte[] correcao)
|
||||
{
|
||||
var topico = Variaveis.MqttService.Topicos.FirstOrDefault(x => x.Topico == TopicoMqttRTCM);
|
||||
if (topico != null)
|
||||
{
|
||||
await Variaveis.MqttService.PublishAsync(topico, correcao);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -19,8 +19,18 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BruTile" Version="6.0.0" />
|
||||
<PackageReference Include="BruTile.MbTiles" Version="6.0.0" />
|
||||
<PackageReference Include="Mapsui" Version="5.0.0" />
|
||||
<PackageReference Include="Mapsui.Extensions" Version="5.0.0" />
|
||||
<PackageReference Include="Mapsui.Wpf" Version="5.0.0" />
|
||||
<PackageReference Include="Mapsui3.Geometries" Version="3.0.0-alpha.3" />
|
||||
<PackageReference Include="NetTopologySuite" Version="2.6.0" />
|
||||
<PackageReference Include="NetTopologySuite.IO.GeoJSON" Version="4.0.0" />
|
||||
<PackageReference Include="NetTopologySuite.IO.ShapeFile" Version="2.1.0" />
|
||||
<PackageReference Include="OpenTK" Version="4.9.4" />
|
||||
<PackageReference Include="ScottPlot.WPF" Version="5.1.57" />
|
||||
<PackageReference Include="System.IO.Ports" Version="10.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -33,4 +43,8 @@
|
|||
<Resource Include="Resources\robo_superior.jpg" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\AgroBase\AgroBase.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@
|
|||
<Compile Update="Controls\ManualControlPad.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Controls\MapViewControl.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Controls\ProgressBarText.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
|
@ -48,6 +51,9 @@
|
|||
<Page Update="Controls\ManualControlPad.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Controls\MapViewControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Controls\ProgressBarText.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -10,11 +10,11 @@
|
|||
<Grid>
|
||||
|
||||
<Border x:Name="brdRovers" BorderBrush="Black" BorderThickness="1" CornerRadius="8" Margin="10,0,1460,943">
|
||||
<Canvas>
|
||||
<Canvas Height="64" VerticalAlignment="Bottom">
|
||||
<Image HorizontalAlignment="Center" Height="66" VerticalAlignment="Top" Width="94" Source="/Resources/logo.png" Canvas.Top="2" Canvas.Left="1"/>
|
||||
<Label Content="Rover em foco" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Left="100" Canvas.Top="9"/>
|
||||
<Label Content="OK" Style="{StaticResource RoundedLabel}" Background="Green" Height="22" Width="50" Canvas.Left="393" Canvas.Top="11" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<ComboBox HorizontalAlignment="Left" VerticalAlignment="Center" Width="164" Canvas.Left="224" Canvas.Top="11">
|
||||
<ComboBox x:Name="cmbDispositivo" HorizontalAlignment="Left" VerticalAlignment="Center" Width="164" Canvas.Left="224" Canvas.Top="11" SelectionChanged="cmbDispositivo_SelectionChanged">
|
||||
<ComboBoxItem Content="R0-NS241436"/>
|
||||
<ComboBoxItem Content="R1-NS561486"/>
|
||||
</ComboBox>
|
||||
|
|
@ -137,22 +137,21 @@
|
|||
</Canvas>
|
||||
</Border>
|
||||
|
||||
<Border x:Name="brdGNSS" BorderBrush="Black" BorderThickness="1" CornerRadius="8" Margin="465,0,1266,943">
|
||||
<Border x:Name="brdGNSS" BorderBrush="Black" BorderThickness="1" CornerRadius="8" Margin="465,0,1266,943" Height="66" VerticalAlignment="Bottom">
|
||||
<Canvas>
|
||||
<Label Content="Posição" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Left="0" Canvas.Top="-3"/>
|
||||
<Label Content="Correção RTKFixo" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="16" FontSize="9"/>
|
||||
<Label Content="Satélites 29" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="29" FontSize="9"/>
|
||||
<Label Content="Precisão 0,60 cm" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="42" FontSize="9"/>
|
||||
<Label Content="Idade B 1,3 s" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="92" Canvas.Top="16" FontSize="9"/>
|
||||
<Label Content="Altitude 634,21 m" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="92" Canvas.Top="29" FontSize="9"/>
|
||||
<Label Content="Dist. base 574,65 m" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Left="92" Canvas.Top="42" FontSize="9"/>
|
||||
<Label x:Name="lblGNSS_Posicao" Content="Posição" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Left="0" Canvas.Top="-3"/>
|
||||
<Label x:Name="lblGNSS_Correcao" Content="Correção RTKFixo B 1,3 s" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="16" FontSize="9"/>
|
||||
<Label x:Name="lblGNSS_Satelites" Content="Satélites 29 (0,60 cm)" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="29" FontSize="9"/>
|
||||
<Label x:Name="lblGNSS_Altitude" Content="Altitude 634,21 m" HorizontalAlignment="Left" VerticalAlignment="Top" Canvas.Left="-1" Canvas.Top="42" FontSize="9"/>
|
||||
<Button x:Name="btnGNSS_FixarBase" Content="Fixar" Canvas.Left="127" Canvas.Top="17" Click="btnGNSS_FixarBase_Click" HorizontalAlignment="Left" VerticalAlignment="Center" Width="50"/>
|
||||
<Label x:Name="lblGNSS_Progresso" Content="0,00%" HorizontalAlignment="Right" VerticalAlignment="Center" Canvas.Left="143" Canvas.Top="42" FontSize="9"/>
|
||||
</Canvas>
|
||||
</Border>
|
||||
|
||||
|
||||
|
||||
<Border x:Name="brdAjustesOperacao" BorderBrush="Black" BorderThickness="1" CornerRadius="8" Margin="1048,0,475,943">
|
||||
<Canvas>
|
||||
<Canvas Height="64" VerticalAlignment="Bottom">
|
||||
<Label Content="Parâmetros da Operação" FontWeight="Bold" FontSize="11" Canvas.Top="-3" HorizontalAlignment="Center" VerticalAlignment="Top"/>
|
||||
<Label Content="Vel. com Ervas" FontSize="9" Canvas.Top="15" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
<Label Content="Vel. sem Ervas" FontSize="9" Canvas.Top="30" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Left="1"/>
|
||||
|
|
@ -179,7 +178,7 @@
|
|||
|
||||
<Border x:Name="brdMapa" BorderBrush="Black" BorderThickness="1" Margin="465,71,475,63">
|
||||
<Canvas>
|
||||
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Source="/Resources/mapa.jpg" Stretch="UniformToFill" Width="977" Height="873"/>
|
||||
<controls:MapViewControl x:Name="MAP" MarkerClicked="MAP_MarkerClicked" StreetMapClicked="MAP_StreetMapClicked" MbTilesPath="Data/basemap.mbtiles" Latitude="-22.1726572492617" Longitude="-47.3952163870556" Scale="5000" Height="873" Width="978" />
|
||||
<controls:HeadingIndicator x:Name="HDG" Width="130" Height="130" Canvas.Left="10" Canvas.Top="10" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||
<controls:AttitudeIndicator x:Name="IMU" Width="160" Height="180" Canvas.Left="10" Canvas.Top="683" CriticalLimit="20" WarningLimit="10" HorizontalAlignment="Left" VerticalAlignment="Center"/>
|
||||
</Canvas>
|
||||
|
|
@ -194,7 +193,6 @@
|
|||
<Border Name="brdMapaInfo" BorderBrush="Black" BorderThickness="1" Height="26" Width="980" Canvas.Top="878" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="465,951,0,0">
|
||||
<Canvas>
|
||||
<Label Content="Próximo Ponto: 15 | Aproximando | Distância próximo ponto: 1,32 m | Distância ponto anterior: 0,74 m | Corredor: Dentro | Margem: Não | Disância Esquerda: 34 cm | Distância Direita: 36 cm | Status: CaminhandoRua" FontSize="9" HorizontalAlignment="Center" VerticalAlignment="Top" Canvas.Top="1"/>
|
||||
<Button Content="Carregar Mapa" Canvas.Left="882" Canvas.Top="2" HorizontalAlignment="Left" VerticalAlignment="Center" Width="86"/>
|
||||
</Canvas>
|
||||
</Border>
|
||||
|
||||
|
|
@ -215,6 +213,7 @@
|
|||
<Border x:Name="brdBicos" BorderBrush="Black" BorderThickness="1" CornerRadius="8" Margin="1453,523,7,421">
|
||||
<Canvas>
|
||||
<Image HorizontalAlignment="Left" Height="59" VerticalAlignment="Center" Width="454" Source="/Resources/barra.jpg" Canvas.Top="2" Canvas.Left="2" Stretch="UniformToFill"/>
|
||||
<Button x:Name="btnB0" Content="Ligar" Height="20" Canvas.Left="2" Width="58" HorizontalAlignment="Left" VerticalAlignment="Center" Canvas.Top="32" Click="btnB0_Click"/>
|
||||
</Canvas>
|
||||
</Border>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,13 @@ using Colors = ScottPlot.Colors; // Timer
|
|||
|
||||
using System.Windows.Threading;
|
||||
using OperationControl.Controls;
|
||||
using System.Diagnostics;
|
||||
using OperationControl.Models;
|
||||
using AgroBase.Models.Components;
|
||||
using OperationControl.Services;
|
||||
using System.Windows.Controls;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace OperationControl.Windows
|
||||
{
|
||||
|
|
@ -34,6 +41,11 @@ namespace OperationControl.Windows
|
|||
{
|
||||
InitializeComponent();
|
||||
|
||||
|
||||
|
||||
AtualizarListaDispositivos(new List<string>() { VariaveisControleOperacao.SelectedRoverId });
|
||||
|
||||
|
||||
// Título / eixos
|
||||
Plot.Plot.Title("MOV ET – Corrente / Tensão / Temp / RPM (últimos 60s)");
|
||||
Plot.Plot.Axes.Bottom.Label.Text = "Tempo (s)";
|
||||
|
|
@ -52,26 +64,12 @@ namespace OperationControl.Windows
|
|||
|
||||
DataContext = this;
|
||||
|
||||
HDG.CourseHeading = 0;
|
||||
|
||||
_clock.Interval = TimeSpan.FromMilliseconds(150);
|
||||
_clock.Tick += (s, e) =>
|
||||
{
|
||||
IMU.RollDeg += (_rand.NextDouble() - 0.5) * 2; // suavemente variando
|
||||
IMU.PitchDeg += (_rand.NextDouble() - 0.5) * 2;
|
||||
HDG.Heading += (_rand.NextDouble() - 0.5) * 2;
|
||||
HDG.CourseHeading += (_rand.NextDouble() - 0.5) * 5;
|
||||
|
||||
// disparar notificação se estiver usando INotifyPropertyChanged
|
||||
};
|
||||
_clock.Start();
|
||||
|
||||
// atualizar as caixas
|
||||
BBoxes3D.SetBboxes(new[]
|
||||
{
|
||||
new LivoxBboxModel{ cx=1.2, cy=0.5, cz=0.4, d=0.6, w=0.4, h=0.8 },
|
||||
new LivoxBboxModel{ cx=3.0, cy=-0.7, cz=0.6, d=0.8, w=0.5, h=1.2 },
|
||||
});
|
||||
//BBoxes3D.SetBboxes(new[]
|
||||
//{
|
||||
// new AgroBase.Models.LivoxBboxModel{ cx=1.2, cy=0.5, cz=0.4, d=0.6, w=0.4, h=0.8 },
|
||||
// new AgroBase.Models.LivoxBboxModel{ cx=3.0, cy=-0.7, cz=0.6, d=0.8, w=0.5, h=1.2 },
|
||||
//});
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -149,6 +147,218 @@ namespace OperationControl.Windows
|
|||
Plot.Refresh();
|
||||
}
|
||||
|
||||
#region DISPOSITIVOS
|
||||
|
||||
public void AtualizarListaDispositivos(List<string> dispositivos)
|
||||
{
|
||||
cmbDispositivo.Items.Clear();
|
||||
foreach (var d in dispositivos)
|
||||
{
|
||||
cmbDispositivo.Items.Add(d);
|
||||
if (!MAP.markers.Added(d))
|
||||
{
|
||||
if (d == VariaveisControleOperacao.BaseMarkerID)
|
||||
{
|
||||
MAP.markers.AddMarker(
|
||||
d,
|
||||
Variaveis.GpsService?.UltimaLeitura?.Latitude ?? 0,
|
||||
Variaveis.GpsService?.UltimaLeitura?.Longitude ?? 0,
|
||||
Variaveis.GpsService?.UltimaLeitura?.OrientacaoReal ?? 0,
|
||||
MAP.markers.GetColorForMarker(d, isBase: true),
|
||||
"Base"
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.Key == d);
|
||||
if (rover.Value != null)
|
||||
{
|
||||
MAP.markers.AddMarker(
|
||||
d,
|
||||
rover.Value.Gps?.Latitude ?? 0,
|
||||
rover.Value.Gps?.Longitude ?? 0,
|
||||
rover.Value.Gps?.AnguloCarroDefinido ?? 0,
|
||||
MAP.markers.GetColorForMarker(d, isBase: false),
|
||||
rover.Key
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int idx_selected = dispositivos.IndexOf(VariaveisControleOperacao.SelectedRoverId);
|
||||
if (idx_selected > -1)
|
||||
cmbDispositivo.SelectedIndex = idx_selected;
|
||||
}
|
||||
|
||||
private void cmbDispositivo_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
AtualizarDadosTela_Telemetria(((ComboBox)sender).SelectedValue.ToString());
|
||||
}
|
||||
|
||||
public void LimparDadosTela_Telemetria()
|
||||
{
|
||||
VariaveisControleOperacao.SelectedRoverId = "";
|
||||
}
|
||||
|
||||
public void AtualizarDadosTela_Telemetria(string rover_id)
|
||||
{
|
||||
if (rover_id != VariaveisControleOperacao.SelectedRoverId) return;
|
||||
|
||||
if (rover_id == VariaveisControleOperacao.BaseMarkerID)
|
||||
{
|
||||
Variaveis.MostrarLog($"Atualizando dados da tela para a base");
|
||||
|
||||
AtualizarDadosTela_GNSS(Variaveis.GpsService?.UltimaLeitura ?? new AgroBase.Models.GPSModel());
|
||||
AtualizarDadosTela_Heading(Variaveis.GpsService?.UltimaLeitura?.AnguloCarroDefinido ?? 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var rover = VariaveisControleOperacao.RoversNaRede.FirstOrDefault(x => x.Key == rover_id);
|
||||
if (rover.Value == null) return;
|
||||
|
||||
Variaveis.MostrarLog($"Atualizando dados da tela para o dispositivo {rover_id}");
|
||||
|
||||
AtualizarDadosTela_GNSS(rover.Value.Gps);
|
||||
AtualizarDadosTela_Heading(rover.Value.Gps.AnguloCarroDefinido, rover.Value.Modo == AgroBase.Models.Enums.ModoOperacao.Manual ? double.NaN : rover.Value.Trajetoria.AnguloCaminho);
|
||||
AtualizarDadosTela_IMU(rover.Value.IMU.InclinacaoLateral, rover.Value.IMU.InclinacaoFrontal);
|
||||
AtualizarDadostela_LIDAR(rover.Value.LivoxLidar.bboxes);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region IMU
|
||||
|
||||
public void AtualizarDadosTela_IMU(double roll, double pitch)
|
||||
{
|
||||
IMU.RollDeg = roll;
|
||||
IMU.PitchDeg = pitch;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region HEADING
|
||||
|
||||
public void AtualizarDadosTela_Heading(double headingRover, double headingCourse = double.NaN)
|
||||
{
|
||||
HDG.Heading = headingRover;
|
||||
HDG.CourseHeading = headingCourse;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MAPA
|
||||
|
||||
private void MAP_MarkerClicked(object? sender, MapMarkerManager.MarkerClickedEventArgs e)
|
||||
{
|
||||
Variaveis.MostrarLog($"Rover em foco: {e.MarkerId}");
|
||||
if (string.IsNullOrEmpty(e.MarkerId))
|
||||
{
|
||||
LimparDadosTela_Telemetria();
|
||||
}
|
||||
else
|
||||
{
|
||||
VariaveisControleOperacao.SelectedRoverId = e.MarkerId;
|
||||
AtualizarDadosTela_Telemetria(e.MarkerId);
|
||||
}
|
||||
}
|
||||
|
||||
private void MAP_StreetMapClicked(object? sender, MapViewControl.StreetMapClickedEventArgs e)
|
||||
{
|
||||
Variaveis.MostrarLog($"Rua clicada: {e.StreetId}. Ruas selecionadas: {string.Join(",", e.SelectedStreetsIds)}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PULVERIZADOR
|
||||
|
||||
private void btnB0_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
btnB0.Content = (btnB0.Content.ToString() == "Ligar") ? "Desligar" : "Ligar";
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region POSICAO
|
||||
|
||||
public void AtualizarDadosTela_GNSS(AgroBase.Models.GPSModel dados, string marker_id = null, double progresso = double.NaN)
|
||||
{
|
||||
lblGNSS_Posicao.Foreground = dados.Inicializado ? new SolidColorBrush(System.Windows.Media.Colors.Green) : new SolidColorBrush(System.Windows.Media.Colors.Red);
|
||||
lblGNSS_Correcao.Content = $"Correção {dados.QualidadeFix} " +
|
||||
(dados.QualidadeFix == AgroBase.Models.Enums.TiposCorrecaoGPS.BaseFix ?
|
||||
(dados.OrientacaoReal.ToString("0.00") + "°") :
|
||||
((dados.Ntrip_ativado ? "N" : "B") + $" {dados.IdadeCorrecao.ToString("0.0")} s"));
|
||||
lblGNSS_Satelites.Content = $"Satélites {dados.NumeroSatelites} ({dados.PrecisaoCm.ToString("0.00")} cm)";
|
||||
lblGNSS_Altitude.Content = $"Altitude {dados.Altitude.ToString("0.00")} m";
|
||||
|
||||
if (double.IsNaN(progresso))
|
||||
{
|
||||
lblGNSS_Progresso.Visibility = Visibility.Hidden;
|
||||
btnGNSS_FixarBase.Visibility = Visibility.Hidden;
|
||||
}
|
||||
else
|
||||
{
|
||||
lblGNSS_Progresso.Visibility = Visibility.Visible;
|
||||
btnGNSS_FixarBase.Visibility = Visibility.Visible;
|
||||
|
||||
lblGNSS_Progresso.Content = $"{progresso.ToString("0.00")}%";
|
||||
if ((Variaveis.GpsService?.BaseFix?.CorrecaoAbsoluta ?? false) && Variaveis.GpsService.BaseFix.FixLiberado && btnGNSS_FixarBase.Content.ToString() == "Parar")
|
||||
{
|
||||
Variaveis.GpsService.BaseFix.FixLiberado = false;
|
||||
btnGNSS_FixarBase.Content = "Fixar";
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(marker_id))
|
||||
MAP.markers.UpdateMarkerPosition(marker_id, dados.Latitude, dados.Longitude, dados.OrientacaoReal);
|
||||
}
|
||||
|
||||
|
||||
private void btnGNSS_FixarBase_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!Variaveis.GpsService.BaseFix.FixLiberado)
|
||||
{
|
||||
if (Variaveis.GpsService.BaseFix.CorrecaoAbsoluta)
|
||||
{
|
||||
var res = MessageBox.Show("Mudar posição da base?", "Tem certeza que deseja fixar a posição da base novamente?", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (res == MessageBoxResult.Yes)
|
||||
{
|
||||
btnGNSS_FixarBase.Content = "Parar";
|
||||
Variaveis.GpsService.BaseFix.FixLiberado = true;
|
||||
|
||||
Task.Run(async () => await Variaveis.GpsService.ConfigurarModulo());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
btnGNSS_FixarBase.Content = "Parar";
|
||||
Variaveis.GpsService.BaseFix.FixLiberado = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
btnGNSS_FixarBase.Content = "Fixar";
|
||||
Variaveis.GpsService.BaseFix.FixLiberado = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LIDAR
|
||||
|
||||
public void AtualizarDadostela_LIDAR(List<AgroBase.Models.LivoxBboxModel> bboxes)
|
||||
{
|
||||
BBoxes3D.SetBboxes(bboxes);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/AForge.Video.DirectShow.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/AForge.Video.DirectShow.dll (Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/AForge.Video.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/AForge.Video.dll (Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/AForge.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/AForge.dll (Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.1" newVersion="8.0.0.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Drawing.Common" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/BitMiracle.LibTiff.NET.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/BitMiracle.LibTiff.NET.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/BruTile.MbTiles.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/BruTile.MbTiles.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/BruTile.XmlSerializers.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/BruTile.XmlSerializers.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/BruTile.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/BruTile.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/DotSpatial.Projections.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/DotSpatial.Projections.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/ExCSS.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/ExCSS.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/HarfBuzzSharp.dll (Stored with Git LFS)
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/HarfBuzzSharp.dll (Stored with Git LFS)
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/MQTTnet.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/MQTTnet.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.Extensions.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.Extensions.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.Geometries.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.Geometries.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.Nts.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.Nts.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.Rendering.Skia.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.Rendering.Skia.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.Tiling.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.Tiling.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.UI.Wpf.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.UI.Wpf.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Mapsui.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Microsoft.Extensions.Logging.Abstractions.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Microsoft.Extensions.Logging.Abstractions.dll (Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Microsoft.Kinect.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Microsoft.Kinect.dll (Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Microsoft.Web.WebView2.Core.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Microsoft.Web.WebView2.Core.dll (Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Microsoft.Web.WebView2.WinForms.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Microsoft.Web.WebView2.WinForms.dll (Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1,510 @@
|
|||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>Microsoft.Web.WebView2.WinForms</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties">
|
||||
<summary>
|
||||
This class is a bundle of the most common parameters used to create <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2Environment"/> and <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2Controller"/> instances.
|
||||
Its main purpose is to be set to <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CreationProperties"/> in order to customize the environment and/or controller used by a <see cref="T:Microsoft.Web.WebView2.WinForms.WebView2"/> during implicit initialization.
|
||||
</summary>
|
||||
<remarks>
|
||||
This class isn't intended to contain all possible environment or controller customization options.
|
||||
If you need complete control over the environment and/or controller used by a WebView2 control then you'll need to initialize the control explicitly by
|
||||
creating your own environment (with <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(System.String,System.String,Microsoft.Web.WebView2.Core.CoreWebView2EnvironmentOptions)"/>) and/or controller options (with <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateCoreWebView2ControllerOptions"/>) and passing them to <see cref="M:Microsoft.Web.WebView2.WinForms.WebView2.EnsureCoreWebView2Async(Microsoft.Web.WebView2.Core.CoreWebView2Environment,Microsoft.Web.WebView2.Core.CoreWebView2ControllerOptions)"/>
|
||||
*before* you set the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.Source"/> property to anything.
|
||||
See the <see cref="T:Microsoft.Web.WebView2.WinForms.WebView2"/> class documentation for an initialization overview.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties.#ctor">
|
||||
<summary>
|
||||
Creates a new instance of <see cref="T:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties"/> with default data for all properties.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties.BrowserExecutableFolder">
|
||||
<summary>
|
||||
Gets or sets the value to pass as the browserExecutableFolder parameter of <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(System.String,System.String,Microsoft.Web.WebView2.Core.CoreWebView2EnvironmentOptions)"/> when creating an environment with this instance.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties.UserDataFolder">
|
||||
<summary>
|
||||
Gets or sets the value to pass as the userDataFolder parameter of <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(System.String,System.String,Microsoft.Web.WebView2.Core.CoreWebView2EnvironmentOptions)"/> when creating an environment with this instance.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties.Language">
|
||||
<summary>
|
||||
Gets or sets the value to use for the Language property of the CoreWebView2EnvironmentOptions parameter passed to <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(System.String,System.String,Microsoft.Web.WebView2.Core.CoreWebView2EnvironmentOptions)"/> when creating an environment with this instance.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties.ProfileName">
|
||||
<summary>
|
||||
Gets or sets the value to use for the ProfileName property of the CoreWebView2ControllerOptions parameter passed to CreateCoreWebView2ControllerWithOptionsAsync when creating an controller with this instance.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties.AdditionalBrowserArguments">
|
||||
<summary>
|
||||
Gets or sets the value to pass as the AdditionalBrowserArguments parameter of <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2EnvironmentOptions"/> which is passed to <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(System.String,System.String,Microsoft.Web.WebView2.Core.CoreWebView2EnvironmentOptions)"/> when creating an environment with this instance.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties.IsInPrivateModeEnabled">
|
||||
<summary>
|
||||
Gets or sets the value to use for the IsInPrivateModeEnabled property of the CoreWebView2ControllerOptions parameter passed to CreateCoreWebView2ControllerWithOptionsAsync when creating an controller with this instance.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties.CreateEnvironmentAsync">
|
||||
<summary>
|
||||
Create a <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2Environment"/> using the current values of this instance's properties.
|
||||
</summary>
|
||||
<returns>A task which will provide the created environment on completion, or null if no environment-related options are set.</returns>
|
||||
<remarks>
|
||||
As long as no other properties on this instance are changed, repeated calls to this method will return the same task/environment as earlier calls.
|
||||
If some other property is changed then the next call to this method will return a different task/environment.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.CoreWebView2CreationProperties.CreateCoreWebView2ControllerOptions(Microsoft.Web.WebView2.Core.CoreWebView2Environment)">
|
||||
<summary>
|
||||
Creates a <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2ControllerOptions"/> using the current values of this instance's properties.
|
||||
</summary>
|
||||
<returns>A <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2ControllerOptions"/> object or null if no controller-related properties are set.</returns>
|
||||
<exception cref="T:System.NullReferenceException">Thrown if the parameter environment is null.</exception>
|
||||
</member>
|
||||
<member name="T:Microsoft.Web.WebView2.WinForms.WebView2">
|
||||
<summary>
|
||||
Control to embed WebView2 in WinForms.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.#ctor">
|
||||
<summary>
|
||||
Create a new WebView2 WinForms control.
|
||||
After construction the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> property is <c>null</c>.
|
||||
Call <see cref="M:Microsoft.Web.WebView2.WinForms.WebView2.EnsureCoreWebView2Async(Microsoft.Web.WebView2.Core.CoreWebView2Environment,Microsoft.Web.WebView2.Core.CoreWebView2ControllerOptions)"/> to initialize the underlying <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2"/>.
|
||||
</summary>
|
||||
<remarks>
|
||||
This control is effectively a wrapper around the WebView2 COM API, which you can find documentation for here: https://aka.ms/webview2
|
||||
You can directly access the underlying ICoreWebView2 interface and all of its functionality by accessing the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> property.
|
||||
Some of the most common COM functionality is also accessible directly through wrapper methods/properties/events on the control.
|
||||
|
||||
Upon creation, the control's CoreWebView2 property will be null.
|
||||
This is because creating the CoreWebView2 is an expensive operation which involves things like launching Edge browser processes.
|
||||
There are two ways to cause the CoreWebView2 to be created:
|
||||
1) Call the <see cref="M:Microsoft.Web.WebView2.WinForms.WebView2.EnsureCoreWebView2Async(Microsoft.Web.WebView2.Core.CoreWebView2Environment,Microsoft.Web.WebView2.Core.CoreWebView2ControllerOptions)"/> method. This is referred to as explicit initialization.
|
||||
2) Set the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.Source"/> property. This is referred to as implicit initialization.
|
||||
Either option will start initialization in the background and return back to the caller without waiting for it to finish.
|
||||
To specify options regarding the initialization process, either pass your own <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2Environment"/> to EnsureCoreWebView2Async or set the control's <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CreationProperties"/> property prior to initialization.
|
||||
|
||||
When initialization has finished (regardless of how it was triggered) then the following things will occur, in this order:
|
||||
1) The control's <see cref="E:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2InitializationCompleted"/> event will be invoked. If you need to perform one time setup operations on the CoreWebView2 prior to its use then you should do so in a handler for that event.
|
||||
2) If a Uri has been set to the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.Source"/> property then the control will start navigating to it in the background (i.e. these steps will continue without waiting for the navigation to finish).
|
||||
3) The Task returned from <see cref="M:Microsoft.Web.WebView2.WinForms.WebView2.EnsureCoreWebView2Async(Microsoft.Web.WebView2.Core.CoreWebView2Environment,Microsoft.Web.WebView2.Core.CoreWebView2ControllerOptions)"/> will complete.
|
||||
|
||||
For more details about any of the methods/properties/events involved in the initialization process, see its specific documentation.
|
||||
|
||||
Accelerator key presses (e.g. Ctrl+P) that occur within the control will
|
||||
fire standard key press events such as OnKeyDown. You can suppress the
|
||||
control's default implementation of an accelerator key press (e.g.
|
||||
printing, in the case of Ctrl+P) by setting the Handled property of its
|
||||
EventArgs to true. Also note that the underlying browser process is
|
||||
blocked while these handlers execute, so:
|
||||
<list type="number">
|
||||
<item>
|
||||
You should avoid doing a lot of work in these handlers.
|
||||
</item>
|
||||
<item>
|
||||
Some of the WebView2 and CoreWebView2 APIs may throw errors if
|
||||
invoked within these handlers due to being unable to communicate with
|
||||
the browser process.
|
||||
</item>
|
||||
</list>
|
||||
If you need to do a lot of work and/or invoke WebView2 APIs in response to
|
||||
accelerator keys then consider kicking off a background task or queuing
|
||||
the work for later execution on the UI thread.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.Dispose(System.Boolean)">
|
||||
<summary>
|
||||
Cleans up any resources being used.
|
||||
</summary>
|
||||
<param name="disposing"><c>true</c> if managed resources should be disposed; otherwise, <c>false</c>.</param>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.OnPaint(System.Windows.Forms.PaintEventArgs)">
|
||||
<summary>
|
||||
Overrides the base OnPaint event to have custom actions
|
||||
in designer mode
|
||||
</summary>
|
||||
<param name="e">The graphics devices which is the source</param>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.WndProc(System.Windows.Forms.Message@)">
|
||||
<summary>
|
||||
Overrides the base WndProc events to handle specific window messages.
|
||||
</summary>
|
||||
<param name="m">The Message object containing the HWND window message and parameters</param>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.WebView2.CreationProperties">
|
||||
<summary>
|
||||
Gets or sets a bag of options which are used during initialization of the control's <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/>.
|
||||
This property cannot be modified (an exception will be thrown) after initialization of the control's CoreWebView2 has started.
|
||||
</summary>
|
||||
<exception cref="T:System.InvalidOperationException">Thrown if initialization of the control's CoreWebView2 has already started.</exception>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.EnsureCoreWebView2Async(Microsoft.Web.WebView2.Core.CoreWebView2Environment,Microsoft.Web.WebView2.Core.CoreWebView2ControllerOptions)">
|
||||
<summary>
|
||||
Explicitly trigger initialization of the control's <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/>.
|
||||
</summary>
|
||||
<param name="environment">
|
||||
A pre-created <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2Environment"/> that should be used to create the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/>.
|
||||
Creating your own environment gives you control over several options that affect how the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is initialized.
|
||||
If you pass <c>null</c> (the default value) then a default environment will be created and used automatically.
|
||||
</param>
|
||||
<param name="controllerOptions">
|
||||
A pre-created <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2ControllerOptions"/> that should be used to create the <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2"/>.
|
||||
Creating your own controller options gives you control over several options that affect how the <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2"/> is initialized.
|
||||
If you pass a controllerOptions to this method then it will override any settings specified on the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CreationProperties"/> property.
|
||||
If you pass <c>null</c> (the default value) and no value has been set to <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CreationProperties"/> then a default controllerOptions will be created and used automatically.
|
||||
</param>
|
||||
<returns>
|
||||
A Task that represents the background initialization process.
|
||||
When the task completes then the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> property will be available for use (i.e. non-null).
|
||||
Note that the control's <see cref="E:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2InitializationCompleted"/> event will be invoked before the task completes
|
||||
or on exceptions.
|
||||
</returns>
|
||||
<remarks>
|
||||
Unless previous initialization has already failed, calling this method additional times with the same parameter will have no effect (any specified environment is ignored) and return the same Task as the first call.
|
||||
Unless previous initialization has already failed, calling this method after initialization has been implicitly triggered by setting the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.Source"/> property will have no effect if no environment is given
|
||||
and simply return a Task representing that initialization already in progress.
|
||||
Unless previous initialization has already failed, calling this method with a different environment after initialization has begun will result in an <see cref="T:System.ArgumentException"/>. For example, this can happen if you begin initialization
|
||||
by setting the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.Source"/> property and then call this method with a new environment, if you begin initialization with <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CreationProperties"/> and then call this method with a new
|
||||
environment, or if you begin initialization with one environment and then call this method with no environment specified.
|
||||
When this method is called after previous initialization has failed, it will trigger initialization of the control's <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> again.
|
||||
Note that even though this method is asynchronous and returns a Task, it still must be called on the UI thread like most public functionality of most UI controls.
|
||||
<para>
|
||||
The following summarizes the possible error values and a description of why these errors occur.
|
||||
<list type="table">
|
||||
<listheader>
|
||||
<description>Error Value</description>
|
||||
<description>Description</description>
|
||||
</listheader>
|
||||
<item>
|
||||
<description><c>HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)</c></description>
|
||||
<description>*\\Edge\\Application* path used in browserExecutableFolder.</description>
|
||||
</item>
|
||||
<item>
|
||||
<description><c>HRESULT_FROM_WIN32(ERROR_INVALID_STATE)</c></description>
|
||||
<description>Specified options do not match the options of the WebViews that are currently running in the shared browser process.</description>
|
||||
</item>
|
||||
<item>
|
||||
<description><c>HRESULT_FROM_WIN32(ERROR_INVALID_WINDOW_HANDLE)</c></description>
|
||||
<description>WebView2 Initialization failed due to an invalid host HWND parentWindow.</description>
|
||||
</item>
|
||||
<item>
|
||||
<description><c>HRESULT_FROM_WIN32(ERROR_DISK_FULL)</c></description>
|
||||
<description>WebView2 Initialization failed due to reaching the maximum number of installed runtime versions.</description>
|
||||
</item>
|
||||
<item>
|
||||
<description><c>HRESULT_FROM_WIN32(ERROR_PRODUCT_UNINSTALLED</c></description>
|
||||
<description>If the Webview depends upon an installed WebView2 Runtime version and it is uninstalled.</description>
|
||||
</item>
|
||||
<item>
|
||||
<description><c>HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)</c></description>
|
||||
<description>Could not find Edge installation.</description>
|
||||
</item>
|
||||
<item>
|
||||
<description><c>HRESULT_FROM_WIN32(ERROR_FILE_EXISTS)</c></description>
|
||||
<description>User data folder cannot be created because a file with the same name already exists.</description>
|
||||
</item>
|
||||
<item>
|
||||
<description><c>E_ACCESSDENIED</c></description>
|
||||
<description>Unable to create user data folder, Access Denied.</description>
|
||||
</item>
|
||||
<item>
|
||||
<description><c>E_FAIL</c></description>
|
||||
<description>Edge runtime unable to start.</description>
|
||||
</item>
|
||||
</list>
|
||||
</para>
|
||||
</remarks>
|
||||
<exception cref="T:System.ArgumentException">
|
||||
Thrown if this method is called with a different environment than when it was initialized. See Remarks for more info.
|
||||
</exception>
|
||||
<exception cref="T:System.InvalidOperationException">
|
||||
Thrown if this instance of <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is already disposed, or if the calling thread isn't the thread which created this object (usually the UI thread). See <see cref="P:System.Windows.Forms.Control.InvokeRequired"/> for more info.
|
||||
May also be thrown if the browser process has crashed unexpectedly and left the control in an invalid state. We are considering throwing a different type of exception for this case in the future.
|
||||
</exception>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.EnsureCoreWebView2Async(Microsoft.Web.WebView2.Core.CoreWebView2Environment)">
|
||||
<summary>
|
||||
Explicitly trigger initialization of the control's <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/>.
|
||||
</summary>
|
||||
<param name="environment">
|
||||
A pre-created <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2Environment"/> that should be used to create the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/>.
|
||||
Creating your own environment gives you control over several options that affect how the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is initialized.
|
||||
If you pass <c>null</c> then a default environment will be created and used automatically.
|
||||
</param>
|
||||
<returns>
|
||||
A Task that represents the background initialization process.
|
||||
When the task completes then the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> property will be available for use (i.e. non-null).
|
||||
Note that the control's <see cref="E:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2InitializationCompleted"/> event will be invoked before the task completes
|
||||
or on exceptions.
|
||||
</returns>
|
||||
<remarks>
|
||||
Unless previous initialization has already failed, calling this method additional times with the same parameter will have no effect (any specified environment is ignored) and return the same Task as the first call.
|
||||
Unless previous initialization has already failed, calling this method after initialization has been implicitly triggered by setting the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.Source"/> property will have no effect if no environment is given
|
||||
and simply return a Task representing that initialization already in progress.
|
||||
Unless previous initialization has already failed, calling this method with a different environment after initialization has begun will result in an <see cref="T:System.ArgumentException"/>. For example, this can happen if you begin initialization
|
||||
by setting the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.Source"/> property and then call this method with a new environment, if you begin initialization with <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CreationProperties"/> and then call this method with a new
|
||||
environment, or if you begin initialization with one environment and then call this method with no environment specified.
|
||||
When this method is called after previous initialization has failed, it will trigger initialization of the control's <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> again.
|
||||
Note that even though this method is asynchronous and returns a Task, it still must be called on the UI thread like most public functionality of most UI controls.
|
||||
</remarks>
|
||||
<exception cref="T:System.ArgumentException">
|
||||
Thrown if this method is called with a different environment than when it was initialized. See Remarks for more info.
|
||||
</exception>
|
||||
<exception cref="T:System.InvalidOperationException">
|
||||
Thrown if this instance of <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is already disposed, or if the calling thread isn't the thread which created this object (usually the UI thread). See <see cref="P:System.Windows.Forms.Control.InvokeRequired"/> for more info.
|
||||
May also be thrown if the browser process has crashed unexpectedly and left the control in an invalid state. We are considering throwing a different type of exception for this case in the future.
|
||||
</exception>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.InitCoreWebView2Async(Microsoft.Web.WebView2.Core.CoreWebView2Environment,Microsoft.Web.WebView2.Core.CoreWebView2ControllerOptions)">
|
||||
<summary>
|
||||
This is the private function which implements the actual background initialization task.
|
||||
Cannot be called if the control is already initialized or has been disposed.
|
||||
</summary>
|
||||
<param name="environment">
|
||||
The environment to use to create the <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2Controller"/>.
|
||||
If that is null then a default environment is created with <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(System.String,System.String,Microsoft.Web.WebView2.Core.CoreWebView2EnvironmentOptions)"/> and its default parameters.
|
||||
</param>
|
||||
<param name="controllerOptions">
|
||||
The controllerOptions to use to create the <see cref="T:Microsoft.Web.WebView2.Core.CoreWebView2Controller"/>.
|
||||
If that is null then a default controllerOptions is created with its default parameters.
|
||||
</param>
|
||||
<returns>A task representing the background initialization process.</returns>
|
||||
<remarks>All the event handlers added here need to be removed in <see cref="M:Microsoft.Web.WebView2.WinForms.WebView2.Dispose(System.Boolean)"/>.</remarks>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.WebView2.CreateParams">
|
||||
<summary>
|
||||
Protected CreateParams property. Used to set custom window styles to the forms HWND.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.OnVisibleChanged(System.EventArgs)">
|
||||
<summary>
|
||||
Protected VisibilityChanged handler.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.OnSizeChanged(System.EventArgs)">
|
||||
<summary>
|
||||
Protected SizeChanged handler.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.Select(System.Boolean,System.Boolean)">
|
||||
<summary>
|
||||
Protected Select method: override this to capture tab direction when WebView control is activated
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.ProcessDialogKey(System.Windows.Forms.Keys)">
|
||||
<summary>Processes a dialog key.</summary>
|
||||
<param name="keyData">One of the <see cref="T:System.Windows.Forms.Keys" /> values that represents the key to process.</param>
|
||||
<returns>
|
||||
<see langword="true" /> if the key was processed by the control; otherwise, <see langword="false" />.</returns>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.OnGotFocus(System.EventArgs)">
|
||||
<summary>
|
||||
Protected OnGotFocus handler.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.OnParentChanged(System.EventArgs)">
|
||||
<summary>
|
||||
Protected OnParentChanged handler.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.WebView2.IsInitialized">
|
||||
<summary>
|
||||
True if initialization finished successfully and the control is not disposed yet.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.GetSitedParentSite(System.Windows.Forms.Control)">
|
||||
<summary>
|
||||
Recursive retrieval of the parent control
|
||||
</summary>
|
||||
<param name="control">The control to get the parent for</param>
|
||||
<returns>The root parent control</returns>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2">
|
||||
<summary>
|
||||
The underlying CoreWebView2. Use this property to perform more operations on the WebView2 content than is exposed
|
||||
on the WebView2. This value is null until it is initialized and the object itself has undefined behaviour once the control is disposed.
|
||||
You can force the underlying CoreWebView2 to
|
||||
initialize via the <see cref="M:Microsoft.Web.WebView2.WinForms.WebView2.EnsureCoreWebView2Async(Microsoft.Web.WebView2.Core.CoreWebView2Environment,Microsoft.Web.WebView2.Core.CoreWebView2ControllerOptions)"/> method.
|
||||
</summary>
|
||||
<exception cref="T:System.InvalidOperationException">Thrown if the calling thread isn't the thread which created this object (usually the UI thread). See <see cref="P:System.Windows.Forms.Control.InvokeRequired"/> for more info.</exception>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.WebView2.ZoomFactor">
|
||||
<summary>
|
||||
The zoom factor for the WebView.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.WebView2.AllowExternalDrop">
|
||||
<summary>
|
||||
Enable/disable external drop.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.WebView2.Source">
|
||||
<summary>
|
||||
The Source property is the URI of the top level document of the
|
||||
WebView2. Setting the Source is equivalent to calling <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.Navigate(System.String)"/>.
|
||||
Setting the Source will trigger initialization of the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/>, if not already initialized.
|
||||
The default value of Source is <c>null</c>, indicating that the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is not yet initialized.
|
||||
</summary>
|
||||
<exception cref="T:System.ArgumentException">Specified value is not an absolute <see cref="T:System.Uri"/>.</exception>
|
||||
<exception cref="T:System.NotImplementedException">Specified value is <c>null</c> and the control is initialized.</exception>
|
||||
<seealso cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.Navigate(System.String)"/>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.WebView2.CanGoForward">
|
||||
<summary>
|
||||
Returns true if the webview can navigate to a next page in the
|
||||
navigation history via the <see cref="M:Microsoft.Web.WebView2.WinForms.WebView2.GoForward"/> method.
|
||||
This is equivalent to the <see cref="P:Microsoft.Web.WebView2.Core.CoreWebView2.CanGoForward"/>.
|
||||
If the underlying <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is not yet initialized, this property is <c>false</c>.
|
||||
</summary>
|
||||
<seealso cref="P:Microsoft.Web.WebView2.Core.CoreWebView2.CanGoForward"/>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.WebView2.CanGoBack">
|
||||
<summary>
|
||||
Returns <c>true</c> if the webview can navigate to a previous page in the
|
||||
navigation history via the <see cref="M:Microsoft.Web.WebView2.WinForms.WebView2.GoBack"/> method.
|
||||
This is equivalent to the <see cref="P:Microsoft.Web.WebView2.Core.CoreWebView2.CanGoBack"/>.
|
||||
If the underlying <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is not yet initialized, this property is <c>false</c>.
|
||||
</summary>
|
||||
<seealso cref="P:Microsoft.Web.WebView2.Core.CoreWebView2.CanGoBack"/>
|
||||
</member>
|
||||
<member name="P:Microsoft.Web.WebView2.WinForms.WebView2.DefaultBackgroundColor">
|
||||
<summary>
|
||||
The default background color for the WebView.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.ExecuteScriptAsync(System.String)">
|
||||
<summary>
|
||||
Executes the provided script in the top level document of the <see cref="T:Microsoft.Web.WebView2.WinForms.WebView2"/>.
|
||||
This is equivalent to <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.ExecuteScriptAsync(System.String)"/>.
|
||||
</summary>
|
||||
<exception cref="T:System.InvalidOperationException">The underlying <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is not yet initialized.</exception>
|
||||
<exception cref="T:System.InvalidOperationException">Thrown when browser process has unexpectedly and left this control in an invalid state. We are considering throwing a different type of exception for this case in the future.</exception>
|
||||
<seealso cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.ExecuteScriptAsync(System.String)"/>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.Reload">
|
||||
<summary>
|
||||
Reloads the top level document of the <see cref="T:Microsoft.Web.WebView2.WinForms.WebView2"/>.
|
||||
This is equivalent to <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.Reload"/>.
|
||||
</summary>
|
||||
<exception cref="T:System.InvalidOperationException">The underlying <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is not yet initialized.</exception>
|
||||
<exception cref="T:System.InvalidOperationException">Thrown when browser process has unexpectedly and left this control in an invalid state. We are considering throwing a different type of exception for this case in the future.</exception>
|
||||
<seealso cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.Reload"/>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.GoForward">
|
||||
<summary>
|
||||
Navigates to the next page in navigation history.
|
||||
This is equivalent to <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.GoForward"/>.
|
||||
If the underlying <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is not yet initialized, this method does nothing.
|
||||
</summary>
|
||||
<seealso cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.GoForward"/>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.GoBack">
|
||||
<summary>
|
||||
Navigates to the previous page in navigation history.
|
||||
This is equivalent to <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.GoBack"/>.
|
||||
If the underlying <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is not yet initialized, this method does nothing.
|
||||
</summary>
|
||||
<seealso cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.GoBack"/>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.NavigateToString(System.String)">
|
||||
<summary>
|
||||
Renders the provided HTML as the top level document of the <see cref="T:Microsoft.Web.WebView2.WinForms.WebView2"/>.
|
||||
This is equivalent to <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.NavigateToString(System.String)"/>.
|
||||
</summary>
|
||||
<exception cref="T:System.InvalidOperationException">The underlying <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is not yet initialized.</exception>
|
||||
<exception cref="T:System.InvalidOperationException">Thrown when browser process has unexpectedly and left this control in an invalid state. We are considering throwing a different type of exception for this case in the future.</exception>
|
||||
<remarks>The <c>htmlContent</c> parameter may not be larger than 2 MB (2 * 1024 * 1024 bytes) in total size. The origin of the new page is <c>about:blank</c>.</remarks>
|
||||
<seealso cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.NavigateToString(System.String)"/>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.Stop">
|
||||
<summary>
|
||||
Stops any in progress navigation in the <see cref="T:Microsoft.Web.WebView2.WinForms.WebView2"/>.
|
||||
This is equivalent to <see cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.Stop"/>.
|
||||
If the underlying <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> is not yet initialized, this method does nothing.
|
||||
</summary>
|
||||
<seealso cref="M:Microsoft.Web.WebView2.Core.CoreWebView2.Stop"/>
|
||||
</member>
|
||||
<member name="E:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2InitializationCompleted">
|
||||
<summary>
|
||||
This event is triggered either 1) when the control's <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.CoreWebView2"/> has finished being initialized (regardless of how it was triggered or whether it succeeded) but before it is used for anything
|
||||
OR 2) the initialization failed.
|
||||
You should handle this event if you need to perform one time setup operations on the CoreWebView2 which you want to affect all of its usages
|
||||
(e.g. adding event handlers, configuring settings, installing document creation scripts, adding host objects).
|
||||
</summary>
|
||||
<remarks>
|
||||
This sender will be the WebView2 control, whose CoreWebView2 property will now be valid (i.e. non-null) for the first time
|
||||
if <see cref="P:Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs.IsSuccess"/> is true.
|
||||
Unlikely this event can fire second time (after reporting initialization success first)
|
||||
if the initialization is followed by navigation which fails.
|
||||
</remarks>
|
||||
</member>
|
||||
<member name="E:Microsoft.Web.WebView2.WinForms.WebView2.NavigationStarting">
|
||||
<summary>
|
||||
NavigationStarting dispatches before a new navigate starts for the top
|
||||
level document of the <see cref="T:Microsoft.Web.WebView2.WinForms.WebView2"/>.
|
||||
This is equivalent to the <see cref="E:Microsoft.Web.WebView2.Core.CoreWebView2.NavigationStarting"/> event.
|
||||
</summary>
|
||||
<seealso cref="E:Microsoft.Web.WebView2.Core.CoreWebView2.NavigationStarting"/>
|
||||
</member>
|
||||
<member name="E:Microsoft.Web.WebView2.WinForms.WebView2.NavigationCompleted">
|
||||
<summary>
|
||||
NavigationCompleted dispatches after a navigate of the top level
|
||||
document completes rendering either successfully or not.
|
||||
This is equivalent to the <see cref="E:Microsoft.Web.WebView2.Core.CoreWebView2.NavigationCompleted"/> event.
|
||||
</summary>
|
||||
<seealso cref="E:Microsoft.Web.WebView2.Core.CoreWebView2.NavigationCompleted"/>
|
||||
</member>
|
||||
<member name="E:Microsoft.Web.WebView2.WinForms.WebView2.WebMessageReceived">
|
||||
<summary>
|
||||
WebMessageReceived dispatches after web content sends a message to the
|
||||
app host via <c>chrome.webview.postMessage</c>.
|
||||
This is equivalent to the <see cref="E:Microsoft.Web.WebView2.Core.CoreWebView2.WebMessageReceived"/> event.
|
||||
</summary>
|
||||
<seealso cref="E:Microsoft.Web.WebView2.Core.CoreWebView2.WebMessageReceived"/>
|
||||
</member>
|
||||
<member name="E:Microsoft.Web.WebView2.WinForms.WebView2.SourceChanged">
|
||||
<summary>
|
||||
SourceChanged dispatches after the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.Source"/> property changes. This may happen
|
||||
during a navigation or if otherwise the script in the page changes the
|
||||
URI of the document.
|
||||
This is equivalent to the <see cref="E:Microsoft.Web.WebView2.Core.CoreWebView2.SourceChanged"/> event.
|
||||
</summary>
|
||||
<seealso cref="E:Microsoft.Web.WebView2.Core.CoreWebView2.SourceChanged"/>
|
||||
</member>
|
||||
<member name="E:Microsoft.Web.WebView2.WinForms.WebView2.ContentLoading">
|
||||
<summary>
|
||||
ContentLoading dispatches after a navigation begins to a new URI and the
|
||||
content of that URI begins to render.
|
||||
This is equivalent to the <see cref="E:Microsoft.Web.WebView2.Core.CoreWebView2.ContentLoading"/> event.
|
||||
</summary>
|
||||
<seealso cref="E:Microsoft.Web.WebView2.Core.CoreWebView2.ContentLoading"/>
|
||||
</member>
|
||||
<member name="E:Microsoft.Web.WebView2.WinForms.WebView2.ZoomFactorChanged">
|
||||
<summary>
|
||||
ZoomFactorChanged dispatches when the <see cref="P:Microsoft.Web.WebView2.WinForms.WebView2.ZoomFactor"/> property changes.
|
||||
This is equivalent to the <see cref="E:Microsoft.Web.WebView2.Core.CoreWebView2Controller.ZoomFactorChanged"/> event.
|
||||
</summary>
|
||||
<seealso cref="E:Microsoft.Web.WebView2.Core.CoreWebView2Controller.ZoomFactorChanged"/>
|
||||
</member>
|
||||
<member name="F:Microsoft.Web.WebView2.WinForms.WebView2.components">
|
||||
<summary>
|
||||
Required designer variable.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:Microsoft.Web.WebView2.WinForms.WebView2.InitializeComponent">
|
||||
<summary>
|
||||
Required method for Designer support - do not modify
|
||||
the contents of this method with the code editor.
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/NetTopologySuite.Features.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/NetTopologySuite.Features.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/NetTopologySuite.IO.GeoJSON.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/NetTopologySuite.IO.GeoJSON.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/NetTopologySuite.IO.GeoJSON4STJ.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/NetTopologySuite.IO.GeoJSON4STJ.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/NetTopologySuite.IO.ShapeFile.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/NetTopologySuite.IO.ShapeFile.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/NetTopologySuite.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/NetTopologySuite.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Newtonsoft.Json.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Newtonsoft.Json.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/OpenHardwareMonitorLib.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/OpenHardwareMonitorLib.dll (Stored with Git LFS)
Normal file
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/OpenTK.GLControl.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/OpenTK.GLControl.dll (Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1,191 @@
|
|||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>OpenTK.GLControl</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="T:OpenTK.GLControl">
|
||||
<summary>
|
||||
OpenGL-aware WinForms control.
|
||||
The WinForms designer will always call the default constructor.
|
||||
Inherit from this class and call one of its specialized constructors
|
||||
to enable antialiasing or custom <see cref="P:OpenTK.GLControl.GraphicsMode"/>s.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:OpenTK.GLControl.components">
|
||||
<summary>
|
||||
Required designer variable.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.Dispose(System.Boolean)">
|
||||
<summary>
|
||||
Clean up any resources being used.
|
||||
</summary>
|
||||
<param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.InitializeComponent">
|
||||
<summary>
|
||||
Required method for Designer support - do not modify
|
||||
the contents of this method with the code editor.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.#ctor">
|
||||
<summary>
|
||||
Constructs a new instance.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.#ctor(OpenTK.Graphics.GraphicsMode)">
|
||||
<summary>
|
||||
Constructs a new instance with the specified GraphicsMode.
|
||||
</summary>
|
||||
<param name="mode">The OpenTK.Graphics.GraphicsMode of the control.</param>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.#ctor(OpenTK.Graphics.GraphicsMode,System.Int32,System.Int32,OpenTK.Graphics.GraphicsContextFlags)">
|
||||
<summary>
|
||||
Constructs a new instance with the specified GraphicsMode.
|
||||
</summary>
|
||||
<param name="mode">The OpenTK.Graphics.GraphicsMode of the control.</param>
|
||||
<param name="major">The major version for the OpenGL GraphicsContext.</param>
|
||||
<param name="minor">The minor version for the OpenGL GraphicsContext.</param>
|
||||
<param name="flags">The GraphicsContextFlags for the OpenGL GraphicsContext.</param>
|
||||
</member>
|
||||
<member name="P:OpenTK.GLControl.CreateParams">
|
||||
<summary>
|
||||
Gets the <c>CreateParams</c> instance for this <c>GLControl</c>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.OnHandleCreated(System.EventArgs)">
|
||||
<summary>Raises the HandleCreated event.</summary>
|
||||
<param name="e">Not used.</param>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.OnHandleDestroyed(System.EventArgs)">
|
||||
<summary>Raises the HandleDestroyed event.</summary>
|
||||
<param name="e">Not used.</param>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.OnPaint(System.Windows.Forms.PaintEventArgs)">
|
||||
<summary>
|
||||
Raises the System.Windows.Forms.Control.Paint event.
|
||||
</summary>
|
||||
<param name="e">A System.Windows.Forms.PaintEventArgs that contains the event data.</param>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.OnResize(System.EventArgs)">
|
||||
<summary>
|
||||
Raises the Resize event.
|
||||
Note: this method may be called before the OpenGL context is ready.
|
||||
Check that IsHandleCreated is true before using any OpenGL methods.
|
||||
</summary>
|
||||
<param name="e">A System.EventArgs that contains the event data.</param>
|
||||
</member>
|
||||
<member name="T:OpenTK.GLControl.DelayUpdate">
|
||||
<summary>
|
||||
Needed to delay the invoke on OS X. Also needed because OpenTK is .NET 2, otherwise I'd use an inline Action.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.PerformContextUpdate">
|
||||
<summary>
|
||||
Execute the delayed context update
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.OnParentChanged(System.EventArgs)">
|
||||
<summary>
|
||||
Raises the ParentChanged event.
|
||||
</summary>
|
||||
<param name="e">A System.EventArgs that contains the event data.</param>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.SwapBuffers">
|
||||
<summary>
|
||||
Swaps the front and back buffers, presenting the rendered scene to the screen.
|
||||
This method will have no effect on a single-buffered <c>GraphicsMode</c>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.MakeCurrent">
|
||||
<summary>
|
||||
<para>
|
||||
Makes <see cref="P:OpenTK.GLControl.Context"/> current in the calling thread.
|
||||
All OpenGL commands issued are hereafter interpreted by this context.
|
||||
</para>
|
||||
<para>
|
||||
When using multiple <c>GLControl</c>s, calling <c>MakeCurrent</c> on
|
||||
one control will make all other controls non-current in the calling thread.
|
||||
</para>
|
||||
<seealso cref="P:OpenTK.GLControl.Context"/>
|
||||
<para>
|
||||
A <c>GLControl</c> can only be current in one thread at a time.
|
||||
To make a control non-current, call <c>GLControl.Context.MakeCurrent(null)</c>.
|
||||
</para>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:OpenTK.GLControl.IsIdle">
|
||||
<summary>
|
||||
Gets a value indicating whether the current thread contains pending system messages.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:OpenTK.GLControl.Context">
|
||||
<summary>
|
||||
Gets the <c>IGraphicsContext</c> instance that is associated with the <c>GLControl</c>.
|
||||
The associated <c>IGraphicsContext</c> is updated whenever the <c>GLControl</c>
|
||||
handle is created or recreated.
|
||||
When using multiple <c>GLControl</c>s, ensure that <c>Context</c>
|
||||
is current before performing any OpenGL operations.
|
||||
<seealso cref="M:OpenTK.GLControl.MakeCurrent"/>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:OpenTK.GLControl.AspectRatio">
|
||||
<summary>
|
||||
Gets the aspect ratio of this GLControl.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:OpenTK.GLControl.VSync">
|
||||
<summary>
|
||||
Gets or sets a value indicating whether vsync is active for this <c>GLControl</c>.
|
||||
When using multiple <c>GLControl</c>s, ensure that <see cref="P:OpenTK.GLControl.Context"/>
|
||||
is current before accessing this property.
|
||||
<seealso cref="P:OpenTK.GLControl.Context"/>
|
||||
<seealso cref="M:OpenTK.GLControl.MakeCurrent"/>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:OpenTK.GLControl.GraphicsMode">
|
||||
<summary>
|
||||
Gets the <c>GraphicsMode</c> of the <c>IGraphicsContext</c> associated with
|
||||
this <c>GLControl</c>. If you wish to change <c>GraphicsMode</c>, you must
|
||||
destroy and recreate the <c>GLControl</c>.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:OpenTK.GLControl.WindowInfo">
|
||||
<summary>
|
||||
Gets the <see cref="T:OpenTK.Platform.IWindowInfo"/> for this instance.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:OpenTK.GLControl.GrabScreenshot">
|
||||
<summary>
|
||||
Grabs a screenshot of the frontbuffer contents.
|
||||
When using multiple <c>GLControl</c>s, ensure that <see cref="P:OpenTK.GLControl.Context"/>
|
||||
is current before accessing this property.
|
||||
<seealso cref="P:OpenTK.GLControl.Context"/>
|
||||
<seealso cref="M:OpenTK.GLControl.MakeCurrent"/>
|
||||
</summary>
|
||||
<returns>A System.Drawing.Bitmap, containing the contents of the frontbuffer.</returns>
|
||||
<exception cref="T:OpenTK.Graphics.GraphicsContextException">
|
||||
Occurs when no OpenTK.Graphics.GraphicsContext is current in the calling thread.
|
||||
</exception>
|
||||
</member>
|
||||
<member name="M:OpenTK.Platform.MacOS.Agl.aglChoosePixelFormat(System.IntPtr,System.Int32,System.Int32[])">
|
||||
<summary>
|
||||
Use this overload only with IntPtr.Zero for the first argument.
|
||||
</summary>
|
||||
<param name="gdevs">
|
||||
</param>
|
||||
<param name="ndev">
|
||||
</param>
|
||||
<param name="attribs">
|
||||
</param>
|
||||
<returns>
|
||||
</returns>
|
||||
</member>
|
||||
<member name="T:OpenTK.Platform.MacOS.AglContext">
|
||||
<summary>
|
||||
AGL context implementation for WinForms compatibility.
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/OpenTK.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/OpenTK.dll (Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/OperationControl.dll (Stored with Git LFS)
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/OperationControl.dll (Stored with Git LFS)
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Pipelines.Sockets.Unofficial.dll (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Pipelines.Sockets.Unofficial.dll (Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,2 @@
|
|||
from .modeling import *
|
||||
from ._deeplab import convert_to_separable_conv
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
import torch
|
||||
from torch import nn
|
||||
from torch.nn import functional as F
|
||||
|
||||
from .utils import _SimpleSegmentationModel
|
||||
|
||||
|
||||
__all__ = ["DeepLabV3"]
|
||||
|
||||
|
||||
class DeepLabV3(_SimpleSegmentationModel):
|
||||
"""
|
||||
Implements DeepLabV3 model from
|
||||
`"Rethinking Atrous Convolution for Semantic Image Segmentation"
|
||||
<https://arxiv.org/abs/1706.05587>`_.
|
||||
|
||||
Arguments:
|
||||
backbone (nn.Module): the network used to compute the features for the model.
|
||||
The backbone should return an OrderedDict[Tensor], with the key being
|
||||
"out" for the last feature map used, and "aux" if an auxiliary classifier
|
||||
is used.
|
||||
classifier (nn.Module): module that takes the "out" element returned from
|
||||
the backbone and returns a dense prediction.
|
||||
aux_classifier (nn.Module, optional): auxiliary classifier used during training
|
||||
"""
|
||||
pass
|
||||
|
||||
class DeepLabHeadV3Plus(nn.Module):
|
||||
def __init__(self, in_channels, low_level_channels, num_classes, aspp_dilate=[12, 24, 36]):
|
||||
super(DeepLabHeadV3Plus, self).__init__()
|
||||
self.project = nn.Sequential(
|
||||
nn.Conv2d(low_level_channels, 48, 1, bias=False),
|
||||
nn.BatchNorm2d(48),
|
||||
nn.ReLU(inplace=True),
|
||||
)
|
||||
|
||||
self.aspp = ASPP(in_channels, aspp_dilate)
|
||||
|
||||
self.classifier = nn.Sequential(
|
||||
nn.Conv2d(304, 256, 3, padding=1, bias=False),
|
||||
nn.BatchNorm2d(256),
|
||||
nn.ReLU(inplace=True),
|
||||
nn.Conv2d(256, num_classes, 1)
|
||||
)
|
||||
self._init_weight()
|
||||
|
||||
def forward(self, feature):
|
||||
low_level_feature = self.project( feature['low_level'] )
|
||||
output_feature = self.aspp(feature['out'])
|
||||
output_feature = F.interpolate(output_feature, size=low_level_feature.shape[2:], mode='bilinear', align_corners=False)
|
||||
return self.classifier( torch.cat( [ low_level_feature, output_feature ], dim=1 ) )
|
||||
|
||||
def _init_weight(self):
|
||||
for m in self.modules():
|
||||
if isinstance(m, nn.Conv2d):
|
||||
nn.init.kaiming_normal_(m.weight)
|
||||
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
|
||||
nn.init.constant_(m.weight, 1)
|
||||
nn.init.constant_(m.bias, 0)
|
||||
|
||||
class DeepLabHead(nn.Module):
|
||||
def __init__(self, in_channels, num_classes, aspp_dilate=[12, 24, 36]):
|
||||
super(DeepLabHead, self).__init__()
|
||||
|
||||
self.classifier = nn.Sequential(
|
||||
ASPP(in_channels, aspp_dilate),
|
||||
nn.Conv2d(256, 256, 3, padding=1, bias=False),
|
||||
nn.BatchNorm2d(256),
|
||||
nn.ReLU(inplace=True),
|
||||
nn.Conv2d(256, num_classes, 1)
|
||||
)
|
||||
self._init_weight()
|
||||
|
||||
def forward(self, feature):
|
||||
return self.classifier( feature['out'] )
|
||||
|
||||
def _init_weight(self):
|
||||
for m in self.modules():
|
||||
if isinstance(m, nn.Conv2d):
|
||||
nn.init.kaiming_normal_(m.weight)
|
||||
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
|
||||
nn.init.constant_(m.weight, 1)
|
||||
nn.init.constant_(m.bias, 0)
|
||||
|
||||
class AtrousSeparableConvolution(nn.Module):
|
||||
""" Atrous Separable Convolution
|
||||
"""
|
||||
def __init__(self, in_channels, out_channels, kernel_size,
|
||||
stride=1, padding=0, dilation=1, bias=True):
|
||||
super(AtrousSeparableConvolution, self).__init__()
|
||||
self.body = nn.Sequential(
|
||||
# Separable Conv
|
||||
nn.Conv2d( in_channels, in_channels, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, bias=bias, groups=in_channels ),
|
||||
# PointWise Conv
|
||||
nn.Conv2d( in_channels, out_channels, kernel_size=1, stride=1, padding=0, bias=bias),
|
||||
)
|
||||
|
||||
self._init_weight()
|
||||
|
||||
def forward(self, x):
|
||||
return self.body(x)
|
||||
|
||||
def _init_weight(self):
|
||||
for m in self.modules():
|
||||
if isinstance(m, nn.Conv2d):
|
||||
nn.init.kaiming_normal_(m.weight)
|
||||
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
|
||||
nn.init.constant_(m.weight, 1)
|
||||
nn.init.constant_(m.bias, 0)
|
||||
|
||||
class ASPPConv(nn.Sequential):
|
||||
def __init__(self, in_channels, out_channels, dilation):
|
||||
modules = [
|
||||
nn.Conv2d(in_channels, out_channels, 3, padding=dilation, dilation=dilation, bias=False),
|
||||
nn.BatchNorm2d(out_channels),
|
||||
nn.ReLU(inplace=True)
|
||||
]
|
||||
super(ASPPConv, self).__init__(*modules)
|
||||
|
||||
class ASPPPooling(nn.Sequential):
|
||||
def __init__(self, in_channels, out_channels):
|
||||
super(ASPPPooling, self).__init__(
|
||||
nn.AdaptiveAvgPool2d(1),
|
||||
nn.Conv2d(in_channels, out_channels, 1, bias=False),
|
||||
nn.BatchNorm2d(out_channels),
|
||||
nn.ReLU(inplace=True))
|
||||
|
||||
def forward(self, x):
|
||||
size = x.shape[-2:]
|
||||
x = super(ASPPPooling, self).forward(x)
|
||||
return F.interpolate(x, size=size, mode='bilinear', align_corners=False)
|
||||
|
||||
class ASPP(nn.Module):
|
||||
def __init__(self, in_channels, atrous_rates):
|
||||
super(ASPP, self).__init__()
|
||||
out_channels = 256
|
||||
modules = []
|
||||
modules.append(nn.Sequential(
|
||||
nn.Conv2d(in_channels, out_channels, 1, bias=False),
|
||||
nn.BatchNorm2d(out_channels),
|
||||
nn.ReLU(inplace=True)))
|
||||
|
||||
rate1, rate2, rate3 = tuple(atrous_rates)
|
||||
modules.append(ASPPConv(in_channels, out_channels, rate1))
|
||||
modules.append(ASPPConv(in_channels, out_channels, rate2))
|
||||
modules.append(ASPPConv(in_channels, out_channels, rate3))
|
||||
modules.append(ASPPPooling(in_channels, out_channels))
|
||||
|
||||
self.convs = nn.ModuleList(modules)
|
||||
|
||||
self.project = nn.Sequential(
|
||||
nn.Conv2d(5 * out_channels, out_channels, 1, bias=False),
|
||||
nn.BatchNorm2d(out_channels),
|
||||
nn.ReLU(inplace=True),
|
||||
nn.Dropout(0.1),)
|
||||
|
||||
def forward(self, x):
|
||||
res = []
|
||||
for conv in self.convs:
|
||||
res.append(conv(x))
|
||||
res = torch.cat(res, dim=1)
|
||||
return self.project(res)
|
||||
|
||||
|
||||
|
||||
def convert_to_separable_conv(module):
|
||||
new_module = module
|
||||
if isinstance(module, nn.Conv2d) and module.kernel_size[0]>1:
|
||||
new_module = AtrousSeparableConvolution(module.in_channels,
|
||||
module.out_channels,
|
||||
module.kernel_size,
|
||||
module.stride,
|
||||
module.padding,
|
||||
module.dilation,
|
||||
module.bias)
|
||||
for name, child in module.named_children():
|
||||
new_module.add_module(name, convert_to_separable_conv(child))
|
||||
return new_module
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
from . import resnet
|
||||
from . import mobilenetv2
|
||||
from . import hrnetv2
|
||||
from . import xception
|
||||
|
|
@ -0,0 +1,345 @@
|
|||
import torch
|
||||
from torch import nn
|
||||
import torch.nn.functional as F
|
||||
import os
|
||||
|
||||
__all__ = ['HRNet', 'hrnetv2_48', 'hrnetv2_32']
|
||||
|
||||
# Checkpoint path of pre-trained backbone (edit to your path). Download backbone pretrained model hrnetv2-32 @
|
||||
# https://drive.google.com/file/d/1NxCK7Zgn5PmeS7W1jYLt5J9E0RRZ2oyF/view?usp=sharing .Personally, I added the backbone
|
||||
# weights to the folder /checkpoints
|
||||
|
||||
model_urls = {
|
||||
'hrnetv2_32': './checkpoints/model_best_epoch96_edit.pth',
|
||||
'hrnetv2_48': None
|
||||
}
|
||||
|
||||
|
||||
def check_pth(arch):
|
||||
CKPT_PATH = model_urls[arch]
|
||||
if os.path.exists(CKPT_PATH):
|
||||
print(f"Backbone HRNet Pretrained weights at: {CKPT_PATH}, only usable for HRNetv2-32")
|
||||
else:
|
||||
print("No backbone checkpoint found for HRNetv2, please set pretrained=False when calling model")
|
||||
return CKPT_PATH
|
||||
# HRNetv2-48 not available yet, but you can train the whole model from scratch.
|
||||
|
||||
|
||||
class Bottleneck(nn.Module):
|
||||
expansion = 4
|
||||
|
||||
def __init__(self, inplanes, planes, stride=1, downsample=None):
|
||||
super(Bottleneck, self).__init__()
|
||||
self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
|
||||
self.bn1 = nn.BatchNorm2d(planes)
|
||||
self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
|
||||
self.bn2 = nn.BatchNorm2d(planes)
|
||||
self.conv3 = nn.Conv2d(planes, planes * self.expansion, kernel_size=1, bias=False)
|
||||
self.bn3 = nn.BatchNorm2d(planes * self.expansion)
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
self.downsample = downsample
|
||||
|
||||
def forward(self, x):
|
||||
identity = x
|
||||
|
||||
out = self.conv1(x)
|
||||
out = self.bn1(out)
|
||||
out = self.relu(out)
|
||||
out = self.conv2(out)
|
||||
out = self.bn2(out)
|
||||
out = self.relu(out)
|
||||
out = self.conv3(out)
|
||||
out = self.bn3(out)
|
||||
|
||||
if self.downsample is not None:
|
||||
identity = self.downsample(x)
|
||||
|
||||
out += identity
|
||||
out = self.relu(out)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class BasicBlock(nn.Module):
|
||||
expansion = 1
|
||||
|
||||
def __init__(self, inplanes, planes, stride=1, downsample=None):
|
||||
super(BasicBlock, self).__init__()
|
||||
self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
|
||||
self.bn1 = nn.BatchNorm2d(planes)
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
self.conv2 = nn.Conv2d(inplanes, planes, kernel_size=3, stride=1, padding=1, bias=False)
|
||||
self.bn2 = nn.BatchNorm2d(planes)
|
||||
self.downsample = downsample
|
||||
|
||||
def forward(self, x):
|
||||
identity = x
|
||||
|
||||
out = self.conv1(x)
|
||||
out = self.bn1(out)
|
||||
out = self.relu(out)
|
||||
out = self.conv2(out)
|
||||
out = self.bn2(out)
|
||||
|
||||
if self.downsample is not None:
|
||||
identity = self.downsample(x)
|
||||
|
||||
out += identity
|
||||
out = self.relu(out)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class StageModule(nn.Module):
|
||||
def __init__(self, stage, output_branches, c):
|
||||
super(StageModule, self).__init__()
|
||||
|
||||
self.number_of_branches = stage # number of branches is equivalent to the stage configuration.
|
||||
self.output_branches = output_branches
|
||||
|
||||
self.branches = nn.ModuleList()
|
||||
|
||||
# Note: Resolution + Number of channels maintains the same throughout respective branch.
|
||||
for i in range(self.number_of_branches): # Stage scales with the number of branches. Ex: Stage 2 -> 2 branch
|
||||
channels = c * (2 ** i) # Scale channels by 2x for branch with lower resolution,
|
||||
|
||||
# Paper does x4 basic block for each forward sequence in each branch (x4 basic block considered as a block)
|
||||
branch = nn.Sequential(*[BasicBlock(channels, channels) for _ in range(4)])
|
||||
|
||||
self.branches.append(branch) # list containing all forward sequence of individual branches.
|
||||
|
||||
# For each branch requires repeated fusion with all other branches after passing through x4 basic blocks.
|
||||
self.fuse_layers = nn.ModuleList()
|
||||
|
||||
for branch_output_number in range(self.output_branches):
|
||||
|
||||
self.fuse_layers.append(nn.ModuleList())
|
||||
|
||||
for branch_number in range(self.number_of_branches):
|
||||
if branch_number == branch_output_number:
|
||||
self.fuse_layers[-1].append(nn.Sequential()) # Used in place of "None" because it is callable
|
||||
elif branch_number > branch_output_number:
|
||||
self.fuse_layers[-1].append(nn.Sequential(
|
||||
nn.Conv2d(c * (2 ** branch_number), c * (2 ** branch_output_number), kernel_size=1, stride=1,
|
||||
bias=False),
|
||||
nn.BatchNorm2d(c * (2 ** branch_output_number), eps=1e-05, momentum=0.1, affine=True,
|
||||
track_running_stats=True),
|
||||
nn.Upsample(scale_factor=(2.0 ** (branch_number - branch_output_number)), mode='nearest'),
|
||||
))
|
||||
elif branch_number < branch_output_number:
|
||||
downsampling_fusion = []
|
||||
for _ in range(branch_output_number - branch_number - 1):
|
||||
downsampling_fusion.append(nn.Sequential(
|
||||
nn.Conv2d(c * (2 ** branch_number), c * (2 ** branch_number), kernel_size=3, stride=2,
|
||||
padding=1,
|
||||
bias=False),
|
||||
nn.BatchNorm2d(c * (2 ** branch_number), eps=1e-05, momentum=0.1, affine=True,
|
||||
track_running_stats=True),
|
||||
nn.ReLU(inplace=True),
|
||||
))
|
||||
downsampling_fusion.append(nn.Sequential(
|
||||
nn.Conv2d(c * (2 ** branch_number), c * (2 ** branch_output_number), kernel_size=3,
|
||||
stride=2, padding=1,
|
||||
bias=False),
|
||||
nn.BatchNorm2d(c * (2 ** branch_output_number), eps=1e-05, momentum=0.1, affine=True,
|
||||
track_running_stats=True),
|
||||
))
|
||||
self.fuse_layers[-1].append(nn.Sequential(*downsampling_fusion))
|
||||
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
|
||||
def forward(self, x):
|
||||
|
||||
# input to each stage is a list of inputs for each branch
|
||||
x = [branch(branch_input) for branch, branch_input in zip(self.branches, x)]
|
||||
|
||||
x_fused = []
|
||||
for branch_output_index in range(
|
||||
self.output_branches): # Amount of output branches == total length of fusion layers
|
||||
for input_index in range(self.number_of_branches): # The inputs of other branches to be fused.
|
||||
if input_index == 0:
|
||||
x_fused.append(self.fuse_layers[branch_output_index][input_index](x[input_index]))
|
||||
else:
|
||||
x_fused[branch_output_index] = x_fused[branch_output_index] + self.fuse_layers[branch_output_index][
|
||||
input_index](x[input_index])
|
||||
|
||||
# After fusing all streams together, you will need to pass the fused layers
|
||||
for i in range(self.output_branches):
|
||||
x_fused[i] = self.relu(x_fused[i])
|
||||
|
||||
return x_fused # returning a list of fused outputs
|
||||
|
||||
|
||||
class HRNet(nn.Module):
|
||||
def __init__(self, c=48, num_blocks=[1, 4, 3], num_classes=1000):
|
||||
super(HRNet, self).__init__()
|
||||
|
||||
# Stem:
|
||||
self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1, bias=False)
|
||||
self.bn1 = nn.BatchNorm2d(64, eps=1e-05, affine=True, track_running_stats=True)
|
||||
self.conv2 = nn.Conv2d(64, 64, kernel_size=3, stride=2, padding=1, bias=False)
|
||||
self.bn2 = nn.BatchNorm2d(64, eps=1e-05, affine=True, track_running_stats=True)
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
|
||||
# Stage 1:
|
||||
downsample = nn.Sequential(
|
||||
nn.Conv2d(64, 256, kernel_size=1, stride=1, bias=False),
|
||||
nn.BatchNorm2d(256, eps=1e-05, affine=True, track_running_stats=True),
|
||||
)
|
||||
# Note that bottleneck module will expand the output channels according to the output channels*block.expansion
|
||||
bn_expansion = Bottleneck.expansion # The channel expansion is set in the bottleneck class.
|
||||
self.layer1 = nn.Sequential(
|
||||
Bottleneck(64, 64, downsample=downsample), # Input is 64 for first module connection
|
||||
Bottleneck(bn_expansion * 64, 64),
|
||||
Bottleneck(bn_expansion * 64, 64),
|
||||
Bottleneck(bn_expansion * 64, 64),
|
||||
)
|
||||
|
||||
# Transition 1 - Creation of the first two branches (one full and one half resolution)
|
||||
# Need to transition into high resolution stream and mid resolution stream
|
||||
self.transition1 = nn.ModuleList([
|
||||
nn.Sequential(
|
||||
nn.Conv2d(256, c, kernel_size=3, stride=1, padding=1, bias=False),
|
||||
nn.BatchNorm2d(c, eps=1e-05, affine=True, track_running_stats=True),
|
||||
nn.ReLU(inplace=True),
|
||||
),
|
||||
nn.Sequential(nn.Sequential( # Double Sequential to fit with official pretrained weights
|
||||
nn.Conv2d(256, c * 2, kernel_size=3, stride=2, padding=1, bias=False),
|
||||
nn.BatchNorm2d(c * 2, eps=1e-05, affine=True, track_running_stats=True),
|
||||
nn.ReLU(inplace=True),
|
||||
)),
|
||||
])
|
||||
|
||||
# Stage 2:
|
||||
number_blocks_stage2 = num_blocks[0]
|
||||
self.stage2 = nn.Sequential(
|
||||
*[StageModule(stage=2, output_branches=2, c=c) for _ in range(number_blocks_stage2)])
|
||||
|
||||
# Transition 2 - Creation of the third branch (1/4 resolution)
|
||||
self.transition2 = self._make_transition_layers(c, transition_number=2)
|
||||
|
||||
# Stage 3:
|
||||
number_blocks_stage3 = num_blocks[1] # number blocks you want to create before fusion
|
||||
self.stage3 = nn.Sequential(
|
||||
*[StageModule(stage=3, output_branches=3, c=c) for _ in range(number_blocks_stage3)])
|
||||
|
||||
# Transition - Creation of the fourth branch (1/8 resolution)
|
||||
self.transition3 = self._make_transition_layers(c, transition_number=3)
|
||||
|
||||
# Stage 4:
|
||||
number_blocks_stage4 = num_blocks[2] # number blocks you want to create before fusion
|
||||
self.stage4 = nn.Sequential(
|
||||
*[StageModule(stage=4, output_branches=4, c=c) for _ in range(number_blocks_stage4)])
|
||||
|
||||
# Classifier (extra module if want to use for classification):
|
||||
# pool, reduce dimensionality, flatten, connect to linear layer for classification:
|
||||
out_channels = sum([c * 2 ** i for i in range(len(num_blocks)+1)]) # total output channels of HRNetV2
|
||||
pool_feature_map = 8
|
||||
self.bn_classifier = nn.Sequential(
|
||||
nn.Conv2d(out_channels, out_channels // 4, kernel_size=1, bias=False),
|
||||
nn.BatchNorm2d(out_channels // 4, eps=1e-05, affine=True, track_running_stats=True),
|
||||
nn.ReLU(inplace=True),
|
||||
nn.AdaptiveAvgPool2d(pool_feature_map),
|
||||
nn.Flatten(),
|
||||
nn.Linear(pool_feature_map * pool_feature_map * (out_channels // 4), num_classes),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _make_transition_layers(c, transition_number):
|
||||
return nn.Sequential(
|
||||
nn.Conv2d(c * (2 ** (transition_number - 1)), c * (2 ** transition_number), kernel_size=3, stride=2,
|
||||
padding=1, bias=False),
|
||||
nn.BatchNorm2d(c * (2 ** transition_number), eps=1e-05, affine=True,
|
||||
track_running_stats=True),
|
||||
nn.ReLU(inplace=True),
|
||||
)
|
||||
|
||||
def forward(self, x):
|
||||
# Stem:
|
||||
x = self.conv1(x)
|
||||
x = self.bn1(x)
|
||||
x = self.relu(x)
|
||||
x = self.conv2(x)
|
||||
x = self.bn2(x)
|
||||
x = self.relu(x)
|
||||
|
||||
# Stage 1
|
||||
x = self.layer1(x)
|
||||
x = [trans(x) for trans in self.transition1] # split to 2 branches, form a list.
|
||||
|
||||
# Stage 2
|
||||
x = self.stage2(x)
|
||||
x.append(self.transition2(x[-1]))
|
||||
|
||||
# Stage 3
|
||||
x = self.stage3(x)
|
||||
x.append(self.transition3(x[-1]))
|
||||
|
||||
# Stage 4
|
||||
x = self.stage4(x)
|
||||
|
||||
# HRNetV2 Example: (follow paper, upsample via bilinear interpolation and to highest resolution size)
|
||||
output_h, output_w = x[0].size(2), x[0].size(3) # Upsample to size of highest resolution stream
|
||||
x1 = F.interpolate(x[1], size=(output_h, output_w), mode='bilinear', align_corners=False)
|
||||
x2 = F.interpolate(x[2], size=(output_h, output_w), mode='bilinear', align_corners=False)
|
||||
x3 = F.interpolate(x[3], size=(output_h, output_w), mode='bilinear', align_corners=False)
|
||||
|
||||
# Upsampling all the other resolution streams and then concatenate all (rather than adding/fusing like HRNetV1)
|
||||
x = torch.cat([x[0], x1, x2, x3], dim=1)
|
||||
x = self.bn_classifier(x)
|
||||
return x
|
||||
|
||||
|
||||
def _hrnet(arch, channels, num_blocks, pretrained, progress, **kwargs):
|
||||
model = HRNet(channels, num_blocks, **kwargs)
|
||||
if pretrained:
|
||||
CKPT_PATH = check_pth(arch)
|
||||
checkpoint = torch.load(CKPT_PATH)
|
||||
model.load_state_dict(checkpoint['state_dict'])
|
||||
return model
|
||||
|
||||
|
||||
def hrnetv2_48(pretrained=False, progress=True, number_blocks=[1, 4, 3], **kwargs):
|
||||
w_channels = 48
|
||||
return _hrnet('hrnetv2_48', w_channels, number_blocks, pretrained, progress,
|
||||
**kwargs)
|
||||
|
||||
|
||||
def hrnetv2_32(pretrained=False, progress=True, number_blocks=[1, 4, 3], **kwargs):
|
||||
w_channels = 32
|
||||
return _hrnet('hrnetv2_32', w_channels, number_blocks, pretrained, progress,
|
||||
**kwargs)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
try:
|
||||
CKPT_PATH = os.path.join(os.path.abspath("."), '../../checkpoints/hrnetv2_32_model_best_epoch96.pth')
|
||||
print("--- Running file as MAIN ---")
|
||||
print(f"Backbone HRNET Pretrained weights as __main__ at: {CKPT_PATH}")
|
||||
except:
|
||||
print("No backbone checkpoint found for HRNetv2, please set pretrained=False when calling model")
|
||||
|
||||
# Models
|
||||
model = hrnetv2_32(pretrained=True)
|
||||
#model = hrnetv2_48(pretrained=False)
|
||||
|
||||
if torch.cuda.is_available():
|
||||
torch.backends.cudnn.deterministic = True
|
||||
device = torch.device('cuda')
|
||||
else:
|
||||
device = torch.device('cpu')
|
||||
model.to(device)
|
||||
in_ = torch.ones(1, 3, 768, 768).to(device)
|
||||
y = model(in_)
|
||||
print(y.shape)
|
||||
|
||||
# Calculate total number of parameters:
|
||||
# pytorch_total_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
|
||||
# print(pytorch_total_params)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
from torch import nn
|
||||
try: # for torchvision<0.4
|
||||
from torchvision.models.utils import load_state_dict_from_url
|
||||
except: # for torchvision>=0.4
|
||||
from torch.hub import load_state_dict_from_url
|
||||
import torch.nn.functional as F
|
||||
|
||||
__all__ = ['MobileNetV2', 'mobilenet_v2']
|
||||
|
||||
|
||||
model_urls = {
|
||||
'mobilenet_v2': 'https://download.pytorch.org/models/mobilenet_v2-b0353104.pth',
|
||||
}
|
||||
|
||||
|
||||
def _make_divisible(v, divisor, min_value=None):
|
||||
"""
|
||||
This function is taken from the original tf repo.
|
||||
It ensures that all layers have a channel number that is divisible by 8
|
||||
It can be seen here:
|
||||
https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
|
||||
:param v:
|
||||
:param divisor:
|
||||
:param min_value:
|
||||
:return:
|
||||
"""
|
||||
if min_value is None:
|
||||
min_value = divisor
|
||||
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
|
||||
# Make sure that round down does not go down by more than 10%.
|
||||
if new_v < 0.9 * v:
|
||||
new_v += divisor
|
||||
return new_v
|
||||
|
||||
|
||||
class ConvBNReLU(nn.Sequential):
|
||||
def __init__(self, in_planes, out_planes, kernel_size=3, stride=1, dilation=1, groups=1):
|
||||
#padding = (kernel_size - 1) // 2
|
||||
super(ConvBNReLU, self).__init__(
|
||||
nn.Conv2d(in_planes, out_planes, kernel_size, stride, 0, dilation=dilation, groups=groups, bias=False),
|
||||
nn.BatchNorm2d(out_planes),
|
||||
nn.ReLU6(inplace=True)
|
||||
)
|
||||
|
||||
def fixed_padding(kernel_size, dilation):
|
||||
kernel_size_effective = kernel_size + (kernel_size - 1) * (dilation - 1)
|
||||
pad_total = kernel_size_effective - 1
|
||||
pad_beg = pad_total // 2
|
||||
pad_end = pad_total - pad_beg
|
||||
return (pad_beg, pad_end, pad_beg, pad_end)
|
||||
|
||||
class InvertedResidual(nn.Module):
|
||||
def __init__(self, inp, oup, stride, dilation, expand_ratio):
|
||||
super(InvertedResidual, self).__init__()
|
||||
self.stride = stride
|
||||
assert stride in [1, 2]
|
||||
|
||||
hidden_dim = int(round(inp * expand_ratio))
|
||||
self.use_res_connect = self.stride == 1 and inp == oup
|
||||
|
||||
layers = []
|
||||
if expand_ratio != 1:
|
||||
# pw
|
||||
layers.append(ConvBNReLU(inp, hidden_dim, kernel_size=1))
|
||||
|
||||
layers.extend([
|
||||
# dw
|
||||
ConvBNReLU(hidden_dim, hidden_dim, stride=stride, dilation=dilation, groups=hidden_dim),
|
||||
# pw-linear
|
||||
nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
|
||||
nn.BatchNorm2d(oup),
|
||||
])
|
||||
self.conv = nn.Sequential(*layers)
|
||||
|
||||
self.input_padding = fixed_padding( 3, dilation )
|
||||
|
||||
def forward(self, x):
|
||||
x_pad = F.pad(x, self.input_padding)
|
||||
if self.use_res_connect:
|
||||
return x + self.conv(x_pad)
|
||||
else:
|
||||
return self.conv(x_pad)
|
||||
|
||||
class MobileNetV2(nn.Module):
|
||||
def __init__(self, num_classes=1000, output_stride=8, width_mult=1.0, inverted_residual_setting=None, round_nearest=8):
|
||||
"""
|
||||
MobileNet V2 main class
|
||||
|
||||
Args:
|
||||
num_classes (int): Number of classes
|
||||
width_mult (float): Width multiplier - adjusts number of channels in each layer by this amount
|
||||
inverted_residual_setting: Network structure
|
||||
round_nearest (int): Round the number of channels in each layer to be a multiple of this number
|
||||
Set to 1 to turn off rounding
|
||||
"""
|
||||
super(MobileNetV2, self).__init__()
|
||||
block = InvertedResidual
|
||||
input_channel = 32
|
||||
last_channel = 1280
|
||||
self.output_stride = output_stride
|
||||
current_stride = 1
|
||||
if inverted_residual_setting is None:
|
||||
inverted_residual_setting = [
|
||||
# t, c, n, s
|
||||
[1, 16, 1, 1],
|
||||
[6, 24, 2, 2],
|
||||
[6, 32, 3, 2],
|
||||
[6, 64, 4, 2],
|
||||
[6, 96, 3, 1],
|
||||
[6, 160, 3, 2],
|
||||
[6, 320, 1, 1],
|
||||
]
|
||||
|
||||
# only check the first element, assuming user knows t,c,n,s are required
|
||||
if len(inverted_residual_setting) == 0 or len(inverted_residual_setting[0]) != 4:
|
||||
raise ValueError("inverted_residual_setting should be non-empty "
|
||||
"or a 4-element list, got {}".format(inverted_residual_setting))
|
||||
|
||||
# building first layer
|
||||
input_channel = _make_divisible(input_channel * width_mult, round_nearest)
|
||||
self.last_channel = _make_divisible(last_channel * max(1.0, width_mult), round_nearest)
|
||||
features = [ConvBNReLU(3, input_channel, stride=2)]
|
||||
current_stride *= 2
|
||||
dilation=1
|
||||
previous_dilation = 1
|
||||
|
||||
# building inverted residual blocks
|
||||
for t, c, n, s in inverted_residual_setting:
|
||||
output_channel = _make_divisible(c * width_mult, round_nearest)
|
||||
previous_dilation = dilation
|
||||
if current_stride == output_stride:
|
||||
stride = 1
|
||||
dilation *= s
|
||||
else:
|
||||
stride = s
|
||||
current_stride *= s
|
||||
output_channel = int(c * width_mult)
|
||||
|
||||
for i in range(n):
|
||||
if i==0:
|
||||
features.append(block(input_channel, output_channel, stride, previous_dilation, expand_ratio=t))
|
||||
else:
|
||||
features.append(block(input_channel, output_channel, 1, dilation, expand_ratio=t))
|
||||
input_channel = output_channel
|
||||
# building last several layers
|
||||
features.append(ConvBNReLU(input_channel, self.last_channel, kernel_size=1))
|
||||
# make it nn.Sequential
|
||||
self.features = nn.Sequential(*features)
|
||||
|
||||
# building classifier
|
||||
self.classifier = nn.Sequential(
|
||||
nn.Dropout(0.2),
|
||||
nn.Linear(self.last_channel, num_classes),
|
||||
)
|
||||
|
||||
# weight initialization
|
||||
for m in self.modules():
|
||||
if isinstance(m, nn.Conv2d):
|
||||
nn.init.kaiming_normal_(m.weight, mode='fan_out')
|
||||
if m.bias is not None:
|
||||
nn.init.zeros_(m.bias)
|
||||
elif isinstance(m, nn.BatchNorm2d):
|
||||
nn.init.ones_(m.weight)
|
||||
nn.init.zeros_(m.bias)
|
||||
elif isinstance(m, nn.Linear):
|
||||
nn.init.normal_(m.weight, 0, 0.01)
|
||||
nn.init.zeros_(m.bias)
|
||||
|
||||
def forward(self, x):
|
||||
x = self.features(x)
|
||||
x = x.mean([2, 3])
|
||||
x = self.classifier(x)
|
||||
return x
|
||||
|
||||
|
||||
def mobilenet_v2(pretrained=False, progress=True, **kwargs):
|
||||
"""
|
||||
Constructs a MobileNetV2 architecture from
|
||||
`"MobileNetV2: Inverted Residuals and Linear Bottlenecks" <https://arxiv.org/abs/1801.04381>`_.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
model = MobileNetV2(**kwargs)
|
||||
if pretrained:
|
||||
state_dict = load_state_dict_from_url(model_urls['mobilenet_v2'],
|
||||
progress=progress)
|
||||
model.load_state_dict(state_dict)
|
||||
return model
|
||||
|
|
@ -0,0 +1,346 @@
|
|||
import torch
|
||||
import torch.nn as nn
|
||||
try: # for torchvision<0.4
|
||||
from torchvision.models.utils import load_state_dict_from_url
|
||||
except: # for torchvision>=0.4
|
||||
from torch.hub import load_state_dict_from_url
|
||||
|
||||
|
||||
__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101',
|
||||
'resnet152', 'resnext50_32x4d', 'resnext101_32x8d',
|
||||
'wide_resnet50_2', 'wide_resnet101_2']
|
||||
|
||||
|
||||
model_urls = {
|
||||
'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
|
||||
'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
|
||||
'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
|
||||
'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
|
||||
'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
|
||||
'resnext50_32x4d': 'https://download.pytorch.org/models/resnext50_32x4d-7cdf4587.pth',
|
||||
'resnext101_32x8d': 'https://download.pytorch.org/models/resnext101_32x8d-8ba56ff5.pth',
|
||||
'wide_resnet50_2': 'https://download.pytorch.org/models/wide_resnet50_2-95faca4d.pth',
|
||||
'wide_resnet101_2': 'https://download.pytorch.org/models/wide_resnet101_2-32ee1156.pth',
|
||||
}
|
||||
|
||||
|
||||
def conv3x3(in_planes, out_planes, stride=1, groups=1, dilation=1):
|
||||
"""3x3 convolution with padding"""
|
||||
return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
|
||||
padding=dilation, groups=groups, bias=False, dilation=dilation)
|
||||
|
||||
|
||||
def conv1x1(in_planes, out_planes, stride=1):
|
||||
"""1x1 convolution"""
|
||||
return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
|
||||
|
||||
|
||||
class BasicBlock(nn.Module):
|
||||
expansion = 1
|
||||
|
||||
def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
|
||||
base_width=64, dilation=1, norm_layer=None):
|
||||
super(BasicBlock, self).__init__()
|
||||
if norm_layer is None:
|
||||
norm_layer = nn.BatchNorm2d
|
||||
if groups != 1 or base_width != 64:
|
||||
raise ValueError('BasicBlock only supports groups=1 and base_width=64')
|
||||
if dilation > 1:
|
||||
raise NotImplementedError("Dilation > 1 not supported in BasicBlock")
|
||||
# Both self.conv1 and self.downsample layers downsample the input when stride != 1
|
||||
self.conv1 = conv3x3(inplanes, planes, stride)
|
||||
self.bn1 = norm_layer(planes)
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
self.conv2 = conv3x3(planes, planes)
|
||||
self.bn2 = norm_layer(planes)
|
||||
self.downsample = downsample
|
||||
self.stride = stride
|
||||
|
||||
def forward(self, x):
|
||||
identity = x
|
||||
|
||||
out = self.conv1(x)
|
||||
out = self.bn1(out)
|
||||
out = self.relu(out)
|
||||
|
||||
out = self.conv2(out)
|
||||
out = self.bn2(out)
|
||||
|
||||
if self.downsample is not None:
|
||||
identity = self.downsample(x)
|
||||
|
||||
out += identity
|
||||
out = self.relu(out)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class Bottleneck(nn.Module):
|
||||
expansion = 4
|
||||
|
||||
def __init__(self, inplanes, planes, stride=1, downsample=None, groups=1,
|
||||
base_width=64, dilation=1, norm_layer=None):
|
||||
super(Bottleneck, self).__init__()
|
||||
if norm_layer is None:
|
||||
norm_layer = nn.BatchNorm2d
|
||||
width = int(planes * (base_width / 64.)) * groups
|
||||
# Both self.conv2 and self.downsample layers downsample the input when stride != 1
|
||||
self.conv1 = conv1x1(inplanes, width)
|
||||
self.bn1 = norm_layer(width)
|
||||
self.conv2 = conv3x3(width, width, stride, groups, dilation)
|
||||
self.bn2 = norm_layer(width)
|
||||
self.conv3 = conv1x1(width, planes * self.expansion)
|
||||
self.bn3 = norm_layer(planes * self.expansion)
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
self.downsample = downsample
|
||||
self.stride = stride
|
||||
|
||||
def forward(self, x):
|
||||
identity = x
|
||||
|
||||
out = self.conv1(x)
|
||||
out = self.bn1(out)
|
||||
out = self.relu(out)
|
||||
|
||||
out = self.conv2(out)
|
||||
out = self.bn2(out)
|
||||
out = self.relu(out)
|
||||
|
||||
out = self.conv3(out)
|
||||
out = self.bn3(out)
|
||||
|
||||
if self.downsample is not None:
|
||||
identity = self.downsample(x)
|
||||
|
||||
out += identity
|
||||
out = self.relu(out)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
class ResNet(nn.Module):
|
||||
|
||||
def __init__(self, block, layers, num_classes=1000, zero_init_residual=False,
|
||||
groups=1, width_per_group=64, replace_stride_with_dilation=None,
|
||||
norm_layer=None):
|
||||
super(ResNet, self).__init__()
|
||||
if norm_layer is None:
|
||||
norm_layer = nn.BatchNorm2d
|
||||
self._norm_layer = norm_layer
|
||||
|
||||
self.inplanes = 64
|
||||
self.dilation = 1
|
||||
if replace_stride_with_dilation is None:
|
||||
# each element in the tuple indicates if we should replace
|
||||
# the 2x2 stride with a dilated convolution instead
|
||||
replace_stride_with_dilation = [False, False, False]
|
||||
if len(replace_stride_with_dilation) != 3:
|
||||
raise ValueError("replace_stride_with_dilation should be None "
|
||||
"or a 3-element tuple, got {}".format(replace_stride_with_dilation))
|
||||
self.groups = groups
|
||||
self.base_width = width_per_group
|
||||
self.conv1 = nn.Conv2d(3, self.inplanes, kernel_size=7, stride=2, padding=3,
|
||||
bias=False)
|
||||
self.bn1 = norm_layer(self.inplanes)
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
|
||||
self.layer1 = self._make_layer(block, 64, layers[0])
|
||||
self.layer2 = self._make_layer(block, 128, layers[1], stride=2,
|
||||
dilate=replace_stride_with_dilation[0])
|
||||
self.layer3 = self._make_layer(block, 256, layers[2], stride=2,
|
||||
dilate=replace_stride_with_dilation[1])
|
||||
self.layer4 = self._make_layer(block, 512, layers[3], stride=2,
|
||||
dilate=replace_stride_with_dilation[2])
|
||||
self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
|
||||
self.fc = nn.Linear(512 * block.expansion, num_classes)
|
||||
|
||||
for m in self.modules():
|
||||
if isinstance(m, nn.Conv2d):
|
||||
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
|
||||
elif isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
|
||||
nn.init.constant_(m.weight, 1)
|
||||
nn.init.constant_(m.bias, 0)
|
||||
|
||||
# Zero-initialize the last BN in each residual branch,
|
||||
# so that the residual branch starts with zeros, and each residual block behaves like an identity.
|
||||
# This improves the model by 0.2~0.3% according to https://arxiv.org/abs/1706.02677
|
||||
if zero_init_residual:
|
||||
for m in self.modules():
|
||||
if isinstance(m, Bottleneck):
|
||||
nn.init.constant_(m.bn3.weight, 0)
|
||||
elif isinstance(m, BasicBlock):
|
||||
nn.init.constant_(m.bn2.weight, 0)
|
||||
|
||||
def _make_layer(self, block, planes, blocks, stride=1, dilate=False):
|
||||
norm_layer = self._norm_layer
|
||||
downsample = None
|
||||
previous_dilation = self.dilation
|
||||
if dilate:
|
||||
self.dilation *= stride
|
||||
stride = 1
|
||||
if stride != 1 or self.inplanes != planes * block.expansion:
|
||||
downsample = nn.Sequential(
|
||||
conv1x1(self.inplanes, planes * block.expansion, stride),
|
||||
norm_layer(planes * block.expansion),
|
||||
)
|
||||
|
||||
layers = []
|
||||
layers.append(block(self.inplanes, planes, stride, downsample, self.groups,
|
||||
self.base_width, previous_dilation, norm_layer))
|
||||
self.inplanes = planes * block.expansion
|
||||
for _ in range(1, blocks):
|
||||
layers.append(block(self.inplanes, planes, groups=self.groups,
|
||||
base_width=self.base_width, dilation=self.dilation,
|
||||
norm_layer=norm_layer))
|
||||
|
||||
return nn.Sequential(*layers)
|
||||
|
||||
def forward(self, x):
|
||||
x = self.conv1(x)
|
||||
x = self.bn1(x)
|
||||
x = self.relu(x)
|
||||
x = self.maxpool(x)
|
||||
|
||||
x = self.layer1(x)
|
||||
x = self.layer2(x)
|
||||
x = self.layer3(x)
|
||||
x = self.layer4(x)
|
||||
|
||||
x = self.avgpool(x)
|
||||
x = torch.flatten(x, 1)
|
||||
x = self.fc(x)
|
||||
|
||||
return x
|
||||
|
||||
|
||||
def _resnet(arch, block, layers, pretrained, progress, **kwargs):
|
||||
model = ResNet(block, layers, **kwargs)
|
||||
if pretrained:
|
||||
state_dict = load_state_dict_from_url(model_urls[arch],
|
||||
progress=progress)
|
||||
model.load_state_dict(state_dict)
|
||||
return model
|
||||
|
||||
|
||||
def resnet18(pretrained=False, progress=True, **kwargs):
|
||||
r"""ResNet-18 model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
return _resnet('resnet18', BasicBlock, [2, 2, 2, 2], pretrained, progress,
|
||||
**kwargs)
|
||||
|
||||
|
||||
def resnet34(pretrained=False, progress=True, **kwargs):
|
||||
r"""ResNet-34 model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
return _resnet('resnet34', BasicBlock, [3, 4, 6, 3], pretrained, progress,
|
||||
**kwargs)
|
||||
|
||||
|
||||
def resnet50(pretrained=False, progress=True, **kwargs):
|
||||
r"""ResNet-50 model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
return _resnet('resnet50', Bottleneck, [3, 4, 6, 3], pretrained, progress,
|
||||
**kwargs)
|
||||
|
||||
|
||||
def resnet101(pretrained=False, progress=True, **kwargs):
|
||||
r"""ResNet-101 model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
return _resnet('resnet101', Bottleneck, [3, 4, 23, 3], pretrained, progress,
|
||||
**kwargs)
|
||||
|
||||
|
||||
def resnet152(pretrained=False, progress=True, **kwargs):
|
||||
r"""ResNet-152 model from
|
||||
`"Deep Residual Learning for Image Recognition" <https://arxiv.org/pdf/1512.03385.pdf>`_
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
return _resnet('resnet152', Bottleneck, [3, 8, 36, 3], pretrained, progress,
|
||||
**kwargs)
|
||||
|
||||
|
||||
def resnext50_32x4d(pretrained=False, progress=True, **kwargs):
|
||||
r"""ResNeXt-50 32x4d model from
|
||||
`"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
kwargs['groups'] = 32
|
||||
kwargs['width_per_group'] = 4
|
||||
return _resnet('resnext50_32x4d', Bottleneck, [3, 4, 6, 3],
|
||||
pretrained, progress, **kwargs)
|
||||
|
||||
|
||||
def resnext101_32x8d(pretrained=False, progress=True, **kwargs):
|
||||
r"""ResNeXt-101 32x8d model from
|
||||
`"Aggregated Residual Transformation for Deep Neural Networks" <https://arxiv.org/pdf/1611.05431.pdf>`_
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
kwargs['groups'] = 32
|
||||
kwargs['width_per_group'] = 8
|
||||
return _resnet('resnext101_32x8d', Bottleneck, [3, 4, 23, 3],
|
||||
pretrained, progress, **kwargs)
|
||||
|
||||
|
||||
def wide_resnet50_2(pretrained=False, progress=True, **kwargs):
|
||||
r"""Wide ResNet-50-2 model from
|
||||
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_
|
||||
|
||||
The model is the same as ResNet except for the bottleneck number of channels
|
||||
which is twice larger in every block. The number of channels in outer 1x1
|
||||
convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048
|
||||
channels, and in Wide ResNet-50-2 has 2048-1024-2048.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
kwargs['width_per_group'] = 64 * 2
|
||||
return _resnet('wide_resnet50_2', Bottleneck, [3, 4, 6, 3],
|
||||
pretrained, progress, **kwargs)
|
||||
|
||||
|
||||
def wide_resnet101_2(pretrained=False, progress=True, **kwargs):
|
||||
r"""Wide ResNet-101-2 model from
|
||||
`"Wide Residual Networks" <https://arxiv.org/pdf/1605.07146.pdf>`_
|
||||
|
||||
The model is the same as ResNet except for the bottleneck number of channels
|
||||
which is twice larger in every block. The number of channels in outer 1x1
|
||||
convolutions is the same, e.g. last block in ResNet-50 has 2048-512-2048
|
||||
channels, and in Wide ResNet-50-2 has 2048-1024-2048.
|
||||
|
||||
Args:
|
||||
pretrained (bool): If True, returns a model pre-trained on ImageNet
|
||||
progress (bool): If True, displays a progress bar of the download to stderr
|
||||
"""
|
||||
kwargs['width_per_group'] = 64 * 2
|
||||
return _resnet('wide_resnet101_2', Bottleneck, [3, 4, 23, 3],
|
||||
pretrained, progress, **kwargs)
|
||||
|
|
@ -0,0 +1,238 @@
|
|||
|
||||
"""
|
||||
Xception is adapted from https://github.com/Cadene/pretrained-models.pytorch/blob/master/pretrainedmodels/models/xception.py
|
||||
|
||||
Ported to pytorch thanks to [tstandley](https://github.com/tstandley/Xception-PyTorch)
|
||||
@author: tstandley
|
||||
Adapted by cadene
|
||||
Creates an Xception Model as defined in:
|
||||
Francois Chollet
|
||||
Xception: Deep Learning with Depthwise Separable Convolutions
|
||||
https://arxiv.org/pdf/1610.02357.pdf
|
||||
This weights ported from the Keras implementation. Achieves the following performance on the validation set:
|
||||
Loss:0.9173 Prec@1:78.892 Prec@5:94.292
|
||||
REMEMBER to set your image size to 3x299x299 for both test and validation
|
||||
normalize = transforms.Normalize(mean=[0.5, 0.5, 0.5],
|
||||
std=[0.5, 0.5, 0.5])
|
||||
The resize parameter of the validation transform should be 333, and make sure to center crop at 299x299
|
||||
"""
|
||||
from __future__ import print_function, division, absolute_import
|
||||
import math
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
import torch.utils.model_zoo as model_zoo
|
||||
from torch.nn import init
|
||||
|
||||
__all__ = ['xception']
|
||||
|
||||
pretrained_settings = {
|
||||
'xception': {
|
||||
'imagenet': {
|
||||
'url': 'http://data.lip6.fr/cadene/pretrainedmodels/xception-43020ad28.pth',
|
||||
'input_space': 'RGB',
|
||||
'input_size': [3, 299, 299],
|
||||
'input_range': [0, 1],
|
||||
'mean': [0.5, 0.5, 0.5],
|
||||
'std': [0.5, 0.5, 0.5],
|
||||
'num_classes': 1000,
|
||||
'scale': 0.8975 # The resize parameter of the validation transform should be 333, and make sure to center crop at 299x299
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SeparableConv2d(nn.Module):
|
||||
def __init__(self,in_channels,out_channels,kernel_size=1,stride=1,padding=0,dilation=1,bias=False):
|
||||
super(SeparableConv2d,self).__init__()
|
||||
|
||||
self.conv1 = nn.Conv2d(in_channels,in_channels,kernel_size,stride,padding,dilation,groups=in_channels,bias=bias)
|
||||
self.pointwise = nn.Conv2d(in_channels,out_channels,1,1,0,1,1,bias=bias)
|
||||
|
||||
def forward(self,x):
|
||||
x = self.conv1(x)
|
||||
x = self.pointwise(x)
|
||||
return x
|
||||
|
||||
|
||||
class Block(nn.Module):
|
||||
def __init__(self,in_filters,out_filters,reps,strides=1,start_with_relu=True,grow_first=True, dilation=1):
|
||||
super(Block, self).__init__()
|
||||
|
||||
if out_filters != in_filters or strides!=1:
|
||||
self.skip = nn.Conv2d(in_filters,out_filters,1,stride=strides, bias=False)
|
||||
self.skipbn = nn.BatchNorm2d(out_filters)
|
||||
else:
|
||||
self.skip=None
|
||||
|
||||
rep=[]
|
||||
|
||||
filters=in_filters
|
||||
if grow_first:
|
||||
rep.append(nn.ReLU(inplace=True))
|
||||
rep.append(SeparableConv2d(in_filters,out_filters,3,stride=1,padding=dilation, dilation=dilation, bias=False))
|
||||
rep.append(nn.BatchNorm2d(out_filters))
|
||||
filters = out_filters
|
||||
|
||||
for i in range(reps-1):
|
||||
rep.append(nn.ReLU(inplace=True))
|
||||
rep.append(SeparableConv2d(filters,filters,3,stride=1,padding=dilation,dilation=dilation,bias=False))
|
||||
rep.append(nn.BatchNorm2d(filters))
|
||||
|
||||
if not grow_first:
|
||||
rep.append(nn.ReLU(inplace=True))
|
||||
rep.append(SeparableConv2d(in_filters,out_filters,3,stride=1,padding=dilation,dilation=dilation,bias=False))
|
||||
rep.append(nn.BatchNorm2d(out_filters))
|
||||
|
||||
if not start_with_relu:
|
||||
rep = rep[1:]
|
||||
else:
|
||||
rep[0] = nn.ReLU(inplace=False)
|
||||
|
||||
if strides != 1:
|
||||
rep.append(nn.MaxPool2d(3,strides,1))
|
||||
self.rep = nn.Sequential(*rep)
|
||||
|
||||
def forward(self,inp):
|
||||
x = self.rep(inp)
|
||||
|
||||
if self.skip is not None:
|
||||
skip = self.skip(inp)
|
||||
skip = self.skipbn(skip)
|
||||
else:
|
||||
skip = inp
|
||||
x+=skip
|
||||
return x
|
||||
|
||||
|
||||
class Xception(nn.Module):
|
||||
"""
|
||||
Xception optimized for the ImageNet dataset, as specified in
|
||||
https://arxiv.org/pdf/1610.02357.pdf
|
||||
"""
|
||||
def __init__(self, num_classes=1000, replace_stride_with_dilation=None):
|
||||
""" Constructor
|
||||
Args:
|
||||
num_classes: number of classes
|
||||
"""
|
||||
super(Xception, self).__init__()
|
||||
|
||||
self.num_classes = num_classes
|
||||
self.dilation = 1
|
||||
if replace_stride_with_dilation is None:
|
||||
# each element in the tuple indicates if we should replace
|
||||
# the 2x2 stride with a dilated convolution instead
|
||||
replace_stride_with_dilation = [False, False, False, False]
|
||||
if len(replace_stride_with_dilation) != 4:
|
||||
raise ValueError("replace_stride_with_dilation should be None "
|
||||
"or a 4-element tuple, got {}".format(replace_stride_with_dilation))
|
||||
|
||||
self.conv1 = nn.Conv2d(3, 32, 3,2, 0, bias=False) # 1 / 2
|
||||
self.bn1 = nn.BatchNorm2d(32)
|
||||
self.relu1 = nn.ReLU(inplace=True)
|
||||
|
||||
self.conv2 = nn.Conv2d(32,64,3,bias=False)
|
||||
self.bn2 = nn.BatchNorm2d(64)
|
||||
self.relu2 = nn.ReLU(inplace=True)
|
||||
#do relu here
|
||||
|
||||
self.block1=self._make_block(64,128,2,2,start_with_relu=False,grow_first=True, dilate=replace_stride_with_dilation[0]) # 1 / 4
|
||||
self.block2=self._make_block(128,256,2,2,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[1]) # 1 / 8
|
||||
self.block3=self._make_block(256,728,2,2,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2]) # 1 / 16
|
||||
|
||||
self.block4=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
|
||||
self.block5=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
|
||||
self.block6=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
|
||||
self.block7=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
|
||||
|
||||
self.block8=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
|
||||
self.block9=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
|
||||
self.block10=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
|
||||
self.block11=self._make_block(728,728,3,1,start_with_relu=True,grow_first=True, dilate=replace_stride_with_dilation[2])
|
||||
|
||||
self.block12=self._make_block(728,1024,2,2,start_with_relu=True,grow_first=False, dilate=replace_stride_with_dilation[3]) # 1 / 32
|
||||
|
||||
self.conv3 = SeparableConv2d(1024,1536,3,1,1, dilation=self.dilation)
|
||||
self.bn3 = nn.BatchNorm2d(1536)
|
||||
self.relu3 = nn.ReLU(inplace=True)
|
||||
|
||||
#do relu here
|
||||
self.conv4 = SeparableConv2d(1536,2048,3,1,1, dilation=self.dilation)
|
||||
self.bn4 = nn.BatchNorm2d(2048)
|
||||
|
||||
self.fc = nn.Linear(2048, num_classes)
|
||||
|
||||
# #------- init weights --------
|
||||
# for m in self.modules():
|
||||
# if isinstance(m, nn.Conv2d):
|
||||
# n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
|
||||
# m.weight.data.normal_(0, math.sqrt(2. / n))
|
||||
# elif isinstance(m, nn.BatchNorm2d):
|
||||
# m.weight.data.fill_(1)
|
||||
# m.bias.data.zero_()
|
||||
# #-----------------------------
|
||||
|
||||
def _make_block(self, in_filters,out_filters,reps,strides=1,start_with_relu=True,grow_first=True, dilate=False):
|
||||
if dilate:
|
||||
self.dilation *= strides
|
||||
strides = 1
|
||||
return Block(in_filters,out_filters,reps,strides,start_with_relu=start_with_relu,grow_first=grow_first, dilation=self.dilation)
|
||||
|
||||
def features(self, input):
|
||||
x = self.conv1(input)
|
||||
x = self.bn1(x)
|
||||
x = self.relu1(x)
|
||||
|
||||
x = self.conv2(x)
|
||||
x = self.bn2(x)
|
||||
x = self.relu2(x)
|
||||
|
||||
x = self.block1(x)
|
||||
x = self.block2(x)
|
||||
x = self.block3(x)
|
||||
x = self.block4(x)
|
||||
x = self.block5(x)
|
||||
x = self.block6(x)
|
||||
x = self.block7(x)
|
||||
x = self.block8(x)
|
||||
x = self.block9(x)
|
||||
x = self.block10(x)
|
||||
x = self.block11(x)
|
||||
x = self.block12(x)
|
||||
|
||||
x = self.conv3(x)
|
||||
x = self.bn3(x)
|
||||
x = self.relu3(x)
|
||||
|
||||
x = self.conv4(x)
|
||||
x = self.bn4(x)
|
||||
return x
|
||||
|
||||
def logits(self, features):
|
||||
x = nn.ReLU(inplace=True)(features)
|
||||
|
||||
x = F.adaptive_avg_pool2d(x, (1, 1))
|
||||
x = x.view(x.size(0), -1)
|
||||
x = self.last_linear(x)
|
||||
return x
|
||||
|
||||
def forward(self, input):
|
||||
x = self.features(input)
|
||||
x = self.logits(x)
|
||||
return x
|
||||
|
||||
|
||||
def xception(num_classes=1000, pretrained='imagenet', replace_stride_with_dilation=None):
|
||||
model = Xception(num_classes=num_classes, replace_stride_with_dilation=replace_stride_with_dilation)
|
||||
if pretrained:
|
||||
settings = pretrained_settings['xception'][pretrained]
|
||||
assert num_classes == settings['num_classes'], \
|
||||
"num_classes should be {}, but is {}".format(settings['num_classes'], num_classes)
|
||||
|
||||
model = Xception(num_classes=num_classes, replace_stride_with_dilation=replace_stride_with_dilation)
|
||||
model.load_state_dict(model_zoo.load_url(settings['url']))
|
||||
|
||||
# TODO: ugly
|
||||
model.last_linear = model.fc
|
||||
del model.fc
|
||||
return model
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
from .utils import IntermediateLayerGetter
|
||||
from ._deeplab import DeepLabHead, DeepLabHeadV3Plus, DeepLabV3
|
||||
from .backbone import (
|
||||
resnet,
|
||||
mobilenetv2,
|
||||
hrnetv2,
|
||||
xception
|
||||
)
|
||||
|
||||
def _segm_hrnet(name, backbone_name, num_classes, pretrained_backbone):
|
||||
|
||||
backbone = hrnetv2.__dict__[backbone_name](pretrained_backbone)
|
||||
# HRNetV2 config:
|
||||
# the final output channels is dependent on highest resolution channel config (c).
|
||||
# output of backbone will be the inplanes to assp:
|
||||
hrnet_channels = int(backbone_name.split('_')[-1])
|
||||
inplanes = sum([hrnet_channels * 2 ** i for i in range(4)])
|
||||
low_level_planes = 256 # all hrnet version channel output from bottleneck is the same
|
||||
aspp_dilate = [12, 24, 36] # If follow paper trend, can put [24, 48, 72].
|
||||
|
||||
if name=='deeplabv3plus':
|
||||
return_layers = {'stage4': 'out', 'layer1': 'low_level'}
|
||||
classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate)
|
||||
elif name=='deeplabv3':
|
||||
return_layers = {'stage4': 'out'}
|
||||
classifier = DeepLabHead(inplanes, num_classes, aspp_dilate)
|
||||
|
||||
backbone = IntermediateLayerGetter(backbone, return_layers=return_layers, hrnet_flag=True)
|
||||
model = DeepLabV3(backbone, classifier)
|
||||
return model
|
||||
|
||||
def _segm_resnet(name, backbone_name, num_classes, output_stride, pretrained_backbone):
|
||||
|
||||
if output_stride==8:
|
||||
replace_stride_with_dilation=[False, True, True]
|
||||
aspp_dilate = [12, 24, 36]
|
||||
else:
|
||||
replace_stride_with_dilation=[False, False, True]
|
||||
aspp_dilate = [6, 12, 18]
|
||||
|
||||
backbone = resnet.__dict__[backbone_name](
|
||||
pretrained=pretrained_backbone,
|
||||
replace_stride_with_dilation=replace_stride_with_dilation)
|
||||
|
||||
inplanes = 2048
|
||||
low_level_planes = 256
|
||||
|
||||
if name=='deeplabv3plus':
|
||||
return_layers = {'layer4': 'out', 'layer1': 'low_level'}
|
||||
classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate)
|
||||
elif name=='deeplabv3':
|
||||
return_layers = {'layer4': 'out'}
|
||||
classifier = DeepLabHead(inplanes , num_classes, aspp_dilate)
|
||||
backbone = IntermediateLayerGetter(backbone, return_layers=return_layers)
|
||||
|
||||
model = DeepLabV3(backbone, classifier)
|
||||
return model
|
||||
|
||||
|
||||
def _segm_xception(name, backbone_name, num_classes, output_stride, pretrained_backbone):
|
||||
if output_stride==8:
|
||||
replace_stride_with_dilation=[False, False, True, True]
|
||||
aspp_dilate = [12, 24, 36]
|
||||
else:
|
||||
replace_stride_with_dilation=[False, False, False, True]
|
||||
aspp_dilate = [6, 12, 18]
|
||||
|
||||
backbone = xception.xception(pretrained= 'imagenet' if pretrained_backbone else False, replace_stride_with_dilation=replace_stride_with_dilation)
|
||||
|
||||
inplanes = 2048
|
||||
low_level_planes = 128
|
||||
|
||||
if name=='deeplabv3plus':
|
||||
return_layers = {'conv4': 'out', 'block1': 'low_level'}
|
||||
classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate)
|
||||
elif name=='deeplabv3':
|
||||
return_layers = {'conv4': 'out'}
|
||||
classifier = DeepLabHead(inplanes , num_classes, aspp_dilate)
|
||||
backbone = IntermediateLayerGetter(backbone, return_layers=return_layers)
|
||||
model = DeepLabV3(backbone, classifier)
|
||||
return model
|
||||
|
||||
|
||||
def _segm_mobilenet(name, backbone_name, num_classes, output_stride, pretrained_backbone):
|
||||
if output_stride==8:
|
||||
aspp_dilate = [12, 24, 36]
|
||||
else:
|
||||
aspp_dilate = [6, 12, 18]
|
||||
|
||||
backbone = mobilenetv2.mobilenet_v2(pretrained=pretrained_backbone, output_stride=output_stride)
|
||||
|
||||
# rename layers
|
||||
backbone.low_level_features = backbone.features[0:4]
|
||||
backbone.high_level_features = backbone.features[4:-1]
|
||||
backbone.features = None
|
||||
backbone.classifier = None
|
||||
|
||||
inplanes = 320
|
||||
low_level_planes = 24
|
||||
|
||||
if name=='deeplabv3plus':
|
||||
return_layers = {'high_level_features': 'out', 'low_level_features': 'low_level'}
|
||||
classifier = DeepLabHeadV3Plus(inplanes, low_level_planes, num_classes, aspp_dilate)
|
||||
elif name=='deeplabv3':
|
||||
return_layers = {'high_level_features': 'out'}
|
||||
classifier = DeepLabHead(inplanes , num_classes, aspp_dilate)
|
||||
backbone = IntermediateLayerGetter(backbone, return_layers=return_layers)
|
||||
|
||||
model = DeepLabV3(backbone, classifier)
|
||||
return model
|
||||
|
||||
def _load_model(arch_type, backbone, num_classes, output_stride, pretrained_backbone):
|
||||
|
||||
if backbone=='mobilenetv2':
|
||||
model = _segm_mobilenet(arch_type, backbone, num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
elif backbone.startswith('resnet'):
|
||||
model = _segm_resnet(arch_type, backbone, num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
elif backbone.startswith('hrnetv2'):
|
||||
model = _segm_hrnet(arch_type, backbone, num_classes, pretrained_backbone=pretrained_backbone)
|
||||
elif backbone=='xception':
|
||||
model = _segm_xception(arch_type, backbone, num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
return model
|
||||
|
||||
|
||||
# Deeplab v3
|
||||
def deeplabv3_hrnetv2_48(num_classes=21, output_stride=4, pretrained_backbone=False): # no pretrained backbone yet
|
||||
return _load_model('deeplabv3', 'hrnetv2_48', output_stride, num_classes, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
def deeplabv3_hrnetv2_32(num_classes=21, output_stride=4, pretrained_backbone=True):
|
||||
return _load_model('deeplabv3', 'hrnetv2_32', output_stride, num_classes, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
def deeplabv3_resnet50(num_classes=21, output_stride=8, pretrained_backbone=True):
|
||||
"""Constructs a DeepLabV3 model with a ResNet-50 backbone.
|
||||
|
||||
Args:
|
||||
num_classes (int): number of classes.
|
||||
output_stride (int): output stride for deeplab.
|
||||
pretrained_backbone (bool): If True, use the pretrained backbone.
|
||||
"""
|
||||
return _load_model('deeplabv3', 'resnet50', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
def deeplabv3_resnet101(num_classes=21, output_stride=8, pretrained_backbone=True):
|
||||
"""Constructs a DeepLabV3 model with a ResNet-101 backbone.
|
||||
|
||||
Args:
|
||||
num_classes (int): number of classes.
|
||||
output_stride (int): output stride for deeplab.
|
||||
pretrained_backbone (bool): If True, use the pretrained backbone.
|
||||
"""
|
||||
return _load_model('deeplabv3', 'resnet101', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
def deeplabv3_mobilenet(num_classes=21, output_stride=8, pretrained_backbone=True, **kwargs):
|
||||
"""Constructs a DeepLabV3 model with a MobileNetv2 backbone.
|
||||
|
||||
Args:
|
||||
num_classes (int): number of classes.
|
||||
output_stride (int): output stride for deeplab.
|
||||
pretrained_backbone (bool): If True, use the pretrained backbone.
|
||||
"""
|
||||
return _load_model('deeplabv3', 'mobilenetv2', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
def deeplabv3_xception(num_classes=21, output_stride=8, pretrained_backbone=True, **kwargs):
|
||||
"""Constructs a DeepLabV3 model with a Xception backbone.
|
||||
|
||||
Args:
|
||||
num_classes (int): number of classes.
|
||||
output_stride (int): output stride for deeplab.
|
||||
pretrained_backbone (bool): If True, use the pretrained backbone.
|
||||
"""
|
||||
return _load_model('deeplabv3', 'xception', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
|
||||
# Deeplab v3+
|
||||
def deeplabv3plus_hrnetv2_48(num_classes=21, output_stride=4, pretrained_backbone=False): # no pretrained backbone yet
|
||||
return _load_model('deeplabv3plus', 'hrnetv2_48', num_classes, output_stride, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
def deeplabv3plus_hrnetv2_32(num_classes=21, output_stride=4, pretrained_backbone=True):
|
||||
return _load_model('deeplabv3plus', 'hrnetv2_32', num_classes, output_stride, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
def deeplabv3plus_resnet50(num_classes=21, output_stride=8, pretrained_backbone=True):
|
||||
"""Constructs a DeepLabV3 model with a ResNet-50 backbone.
|
||||
|
||||
Args:
|
||||
num_classes (int): number of classes.
|
||||
output_stride (int): output stride for deeplab.
|
||||
pretrained_backbone (bool): If True, use the pretrained backbone.
|
||||
"""
|
||||
return _load_model('deeplabv3plus', 'resnet50', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
|
||||
def deeplabv3plus_resnet101(num_classes=21, output_stride=8, pretrained_backbone=True):
|
||||
"""Constructs a DeepLabV3+ model with a ResNet-101 backbone.
|
||||
|
||||
Args:
|
||||
num_classes (int): number of classes.
|
||||
output_stride (int): output stride for deeplab.
|
||||
pretrained_backbone (bool): If True, use the pretrained backbone.
|
||||
"""
|
||||
return _load_model('deeplabv3plus', 'resnet101', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
|
||||
def deeplabv3plus_mobilenet(num_classes=21, output_stride=8, pretrained_backbone=True):
|
||||
"""Constructs a DeepLabV3+ model with a MobileNetv2 backbone.
|
||||
|
||||
Args:
|
||||
num_classes (int): number of classes.
|
||||
output_stride (int): output stride for deeplab.
|
||||
pretrained_backbone (bool): If True, use the pretrained backbone.
|
||||
"""
|
||||
return _load_model('deeplabv3plus', 'mobilenetv2', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
|
||||
def deeplabv3plus_xception(num_classes=21, output_stride=8, pretrained_backbone=True):
|
||||
"""Constructs a DeepLabV3+ model with a Xception backbone.
|
||||
|
||||
Args:
|
||||
num_classes (int): number of classes.
|
||||
output_stride (int): output stride for deeplab.
|
||||
pretrained_backbone (bool): If True, use the pretrained backbone.
|
||||
"""
|
||||
return _load_model('deeplabv3plus', 'xception', num_classes, output_stride=output_stride, pretrained_backbone=pretrained_backbone)
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
import torch
|
||||
import torch.nn as nn
|
||||
import numpy as np
|
||||
import torch.nn.functional as F
|
||||
from collections import OrderedDict
|
||||
|
||||
class _SimpleSegmentationModel(nn.Module):
|
||||
def __init__(self, backbone, classifier):
|
||||
super(_SimpleSegmentationModel, self).__init__()
|
||||
self.backbone = backbone
|
||||
self.classifier = classifier
|
||||
|
||||
def forward(self, x):
|
||||
input_shape = x.shape[-2:]
|
||||
features = self.backbone(x)
|
||||
x = self.classifier(features)
|
||||
x = F.interpolate(x, size=input_shape, mode='bilinear', align_corners=False)
|
||||
return x
|
||||
|
||||
|
||||
class IntermediateLayerGetter(nn.ModuleDict):
|
||||
"""
|
||||
Module wrapper that returns intermediate layers from a model
|
||||
|
||||
It has a strong assumption that the modules have been registered
|
||||
into the model in the same order as they are used.
|
||||
This means that one should **not** reuse the same nn.Module
|
||||
twice in the forward if you want this to work.
|
||||
|
||||
Additionally, it is only able to query submodules that are directly
|
||||
assigned to the model. So if `model` is passed, `model.feature1` can
|
||||
be returned, but not `model.feature1.layer2`.
|
||||
|
||||
Arguments:
|
||||
model (nn.Module): model on which we will extract the features
|
||||
return_layers (Dict[name, new_name]): a dict containing the names
|
||||
of the modules for which the activations will be returned as
|
||||
the key of the dict, and the value of the dict is the name
|
||||
of the returned activation (which the user can specify).
|
||||
|
||||
Examples::
|
||||
|
||||
>>> m = torchvision.models.resnet18(pretrained=True)
|
||||
>>> # extract layer1 and layer3, giving as names `feat1` and feat2`
|
||||
>>> new_m = torchvision.models._utils.IntermediateLayerGetter(m,
|
||||
>>> {'layer1': 'feat1', 'layer3': 'feat2'})
|
||||
>>> out = new_m(torch.rand(1, 3, 224, 224))
|
||||
>>> print([(k, v.shape) for k, v in out.items()])
|
||||
>>> [('feat1', torch.Size([1, 64, 56, 56])),
|
||||
>>> ('feat2', torch.Size([1, 256, 14, 14]))]
|
||||
"""
|
||||
def __init__(self, model, return_layers, hrnet_flag=False):
|
||||
if not set(return_layers).issubset([name for name, _ in model.named_children()]):
|
||||
raise ValueError("return_layers are not present in model")
|
||||
|
||||
self.hrnet_flag = hrnet_flag
|
||||
|
||||
orig_return_layers = return_layers
|
||||
return_layers = {k: v for k, v in return_layers.items()}
|
||||
layers = OrderedDict()
|
||||
for name, module in model.named_children():
|
||||
layers[name] = module
|
||||
if name in return_layers:
|
||||
del return_layers[name]
|
||||
if not return_layers:
|
||||
break
|
||||
|
||||
super(IntermediateLayerGetter, self).__init__(layers)
|
||||
self.return_layers = orig_return_layers
|
||||
|
||||
def forward(self, x):
|
||||
out = OrderedDict()
|
||||
for name, module in self.named_children():
|
||||
if self.hrnet_flag and name.startswith('transition'): # if using hrnet, you need to take care of transition
|
||||
if name == 'transition1': # in transition1, you need to split the module to two streams first
|
||||
x = [trans(x) for trans in module]
|
||||
else: # all other transition is just an extra one stream split
|
||||
x.append(module(x[-1]))
|
||||
else: # other models (ex:resnet,mobilenet) are convolutions in series.
|
||||
x = module(x)
|
||||
|
||||
if name in self.return_layers:
|
||||
out_name = self.return_layers[name]
|
||||
if name == 'stage4' and self.hrnet_flag: # In HRNetV2, we upsample and concat all outputs streams together
|
||||
output_h, output_w = x[0].size(2), x[0].size(3) # Upsample to size of highest resolution stream
|
||||
x1 = F.interpolate(x[1], size=(output_h, output_w), mode='bilinear', align_corners=False)
|
||||
x2 = F.interpolate(x[2], size=(output_h, output_w), mode='bilinear', align_corners=False)
|
||||
x3 = F.interpolate(x[3], size=(output_h, output_w), mode='bilinear', align_corners=False)
|
||||
x = torch.cat([x[0], x1, x2, x3], dim=1)
|
||||
out[out_name] = x
|
||||
else:
|
||||
out[out_name] = x
|
||||
return out
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
person
|
||||
bicycle
|
||||
car
|
||||
motorbike
|
||||
aeroplane
|
||||
bus
|
||||
train
|
||||
truck
|
||||
boat
|
||||
traffic light
|
||||
fire hydrant
|
||||
stop sign
|
||||
parking meter
|
||||
bench
|
||||
bird
|
||||
cat
|
||||
dog
|
||||
horse
|
||||
sheep
|
||||
cow
|
||||
elephant
|
||||
bear
|
||||
zebra
|
||||
giraffe
|
||||
backpack
|
||||
umbrella
|
||||
handbag
|
||||
tie
|
||||
suitcase
|
||||
frisbee
|
||||
skis
|
||||
snowboard
|
||||
sports ball
|
||||
kite
|
||||
baseball bat
|
||||
baseball glove
|
||||
skateboard
|
||||
surfboard
|
||||
tennis racket
|
||||
bottle
|
||||
wine glass
|
||||
cup
|
||||
fork
|
||||
knife
|
||||
spoon
|
||||
bowl
|
||||
banana
|
||||
apple
|
||||
sandwich
|
||||
orange
|
||||
broccoli
|
||||
carrot
|
||||
hot dog
|
||||
pizza
|
||||
donut
|
||||
cake
|
||||
chair
|
||||
sofa
|
||||
pottedplant
|
||||
bed
|
||||
diningtable
|
||||
toilet
|
||||
tvmonitor
|
||||
laptop
|
||||
mouse
|
||||
remote
|
||||
keyboard
|
||||
cell phone
|
||||
microwave
|
||||
oven
|
||||
toaster
|
||||
sink
|
||||
refrigerator
|
||||
book
|
||||
clock
|
||||
vase
|
||||
scissors
|
||||
teddy bear
|
||||
hair drier
|
||||
toothbrush
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
person
|
||||
bicycle
|
||||
car
|
||||
motorbike
|
||||
aeroplane
|
||||
bus
|
||||
train
|
||||
truck
|
||||
boat
|
||||
traffic light
|
||||
fire hydrant
|
||||
stop sign
|
||||
parking meter
|
||||
bench
|
||||
bird
|
||||
cat
|
||||
dog
|
||||
horse
|
||||
sheep
|
||||
cow
|
||||
elephant
|
||||
bear
|
||||
zebra
|
||||
giraffe
|
||||
backpack
|
||||
umbrella
|
||||
handbag
|
||||
tie
|
||||
suitcase
|
||||
frisbee
|
||||
skis
|
||||
snowboard
|
||||
sports ball
|
||||
kite
|
||||
baseball bat
|
||||
baseball glove
|
||||
skateboard
|
||||
surfboard
|
||||
tennis racket
|
||||
bottle
|
||||
wine glass
|
||||
cup
|
||||
fork
|
||||
knife
|
||||
spoon
|
||||
bowl
|
||||
banana
|
||||
apple
|
||||
sandwich
|
||||
orange
|
||||
broccoli
|
||||
carrot
|
||||
hot dog
|
||||
pizza
|
||||
donut
|
||||
cake
|
||||
chair
|
||||
sofa
|
||||
pottedplant
|
||||
bed
|
||||
diningtable
|
||||
toilet
|
||||
tvmonitor
|
||||
laptop
|
||||
mouse
|
||||
remote
|
||||
keyboard
|
||||
cell phone
|
||||
microwave
|
||||
oven
|
||||
toaster
|
||||
sink
|
||||
refrigerator
|
||||
book
|
||||
clock
|
||||
vase
|
||||
scissors
|
||||
teddy bear
|
||||
hair drier
|
||||
toothbrush
|
||||
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Python/Models/yolo/crop_weed_detection.weights (Stored with Git LFS)
Normal file
BIN
AgroBase/OperationControl/bin/Debug/net8.0-windows7.0/Python/Models/yolo/crop_weed_detection.weights (Stored with Git LFS)
Normal file
Binary file not shown.
|
|
@ -0,0 +1,182 @@
|
|||
[net]
|
||||
# Testing
|
||||
batch=1
|
||||
subdivisions=1
|
||||
# Training
|
||||
# batch=64
|
||||
# subdivisions=2
|
||||
width=416
|
||||
height=416
|
||||
channels=3
|
||||
momentum=0.9
|
||||
decay=0.0005
|
||||
angle=0
|
||||
saturation = 1.5
|
||||
exposure = 1.5
|
||||
hue=.1
|
||||
|
||||
learning_rate=0.001
|
||||
burn_in=1000
|
||||
max_batches = 500200
|
||||
policy=steps
|
||||
steps=400000,450000
|
||||
scales=.1,.1
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=16
|
||||
size=3
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
[maxpool]
|
||||
size=2
|
||||
stride=2
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=32
|
||||
size=3
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
[maxpool]
|
||||
size=2
|
||||
stride=2
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=64
|
||||
size=3
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
[maxpool]
|
||||
size=2
|
||||
stride=2
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=128
|
||||
size=3
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
[maxpool]
|
||||
size=2
|
||||
stride=2
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=256
|
||||
size=3
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
[maxpool]
|
||||
size=2
|
||||
stride=2
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=512
|
||||
size=3
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
[maxpool]
|
||||
size=2
|
||||
stride=1
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=1024
|
||||
size=3
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
###########
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=256
|
||||
size=1
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=512
|
||||
size=3
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
[convolutional]
|
||||
size=1
|
||||
stride=1
|
||||
pad=1
|
||||
filters=255
|
||||
activation=linear
|
||||
|
||||
|
||||
|
||||
[yolo]
|
||||
mask = 3,4,5
|
||||
anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319
|
||||
classes=80
|
||||
num=6
|
||||
jitter=.3
|
||||
ignore_thresh = .7
|
||||
truth_thresh = 1
|
||||
random=1
|
||||
|
||||
[route]
|
||||
layers = -4
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=128
|
||||
size=1
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
[upsample]
|
||||
stride=2
|
||||
|
||||
[route]
|
||||
layers = -1, 8
|
||||
|
||||
[convolutional]
|
||||
batch_normalize=1
|
||||
filters=256
|
||||
size=3
|
||||
stride=1
|
||||
pad=1
|
||||
activation=leaky
|
||||
|
||||
[convolutional]
|
||||
size=1
|
||||
stride=1
|
||||
pad=1
|
||||
filters=255
|
||||
activation=linear
|
||||
|
||||
[yolo]
|
||||
mask = 0,1,2
|
||||
anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319
|
||||
classes=80
|
||||
num=6
|
||||
jitter=.3
|
||||
ignore_thresh = .7
|
||||
truth_thresh = 1
|
||||
random=1
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue