implementado gerenciamento do gnss

This commit is contained in:
Diego Freitas 2025-11-14 14:11:58 -03:00
parent 71de765823
commit c5e90f7b44
1401 changed files with 527740 additions and 741 deletions

Binary file not shown.

View File

@ -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

View File

@ -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}");
}
});
}
}

View File

@ -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;

View File

@ -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}");
}
}

View File

@ -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);

View File

@ -17,7 +17,7 @@ namespace AgroMonitor
{
InitializeComponent();
Variaveis.IniciarMQTT();
//Variaveis.IniciarMQTT();
RedisService.Iniciar();
RedisService.LimparDadosIniciais();

View File

@ -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">

View File

@ -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();
}
}
}

View File

@ -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);

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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
{
}
}

View File

@ -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);
}
}
}
}

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -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.

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.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -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>

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.

View File

@ -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>

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,2 @@
from .modeling import *
from ._deeplab import convert_to_separable_conv

View File

@ -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

View File

@ -0,0 +1,4 @@
from . import resnet
from . import mobilenetv2
from . import hrnetv2
from . import xception

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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