618 lines
22 KiB
C#
618 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using static AgroBase.Models.Enums;
|
|
|
|
namespace AgroBase.Models.Operadores
|
|
{
|
|
public class VisualWorkerModel
|
|
{
|
|
public bool Iniciado { get; set; }
|
|
public DateTime IniciadoEm { get; set; }
|
|
public bool Pronto { get; set; }
|
|
public DateTime ProntoEm { get; set; }
|
|
public DateTime UltimaMensagem { get; set; }
|
|
public Dictionary<CameraFrameType, OAKCameraFrameModel> CameraFrames { get; set; } = new Dictionary<CameraFrameType, OAKCameraFrameModel>();
|
|
public VisualWorkerMessageAnaliseModel Analises { get; set; } = new VisualWorkerMessageAnaliseModel();
|
|
public VisualWorkerMessageIMUModel Imu { get; set; } = new VisualWorkerMessageIMUModel();
|
|
|
|
public VisualWorkerModel Clone()
|
|
{
|
|
return new VisualWorkerModel()
|
|
{
|
|
Iniciado = Iniciado,
|
|
IniciadoEm = IniciadoEm,
|
|
Pronto = Pronto,
|
|
ProntoEm = ProntoEm,
|
|
CameraFrames = new Dictionary<CameraFrameType, OAKCameraFrameModel>(CameraFrames ?? new Dictionary<CameraFrameType, OAKCameraFrameModel>()),
|
|
Analises = Analises.Clone(),
|
|
Imu = Imu.Clone(),
|
|
UltimaMensagem = UltimaMensagem,
|
|
};
|
|
}
|
|
|
|
public void ReiniciarEstado()
|
|
{
|
|
Iniciado = false;
|
|
IniciadoEm = DateTime.MinValue;
|
|
Pronto = false;
|
|
ProntoEm = DateTime.MinValue;
|
|
CameraFrames = new Dictionary<CameraFrameType, OAKCameraFrameModel>();
|
|
Analises = new VisualWorkerMessageAnaliseModel();
|
|
Imu = new VisualWorkerMessageIMUModel();
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerDadosModel
|
|
{
|
|
public bool DesvioNecessario { get; set; }
|
|
public Enums.Direcao DirecaoDesvio { get; set; }
|
|
public Obstaculo ObstaculoCritico { get; set; }
|
|
public List<Obstaculo> Obstaculos { get; set; }
|
|
|
|
public VisualWorkerDadosModel Clone()
|
|
{
|
|
return new VisualWorkerDadosModel()
|
|
{
|
|
DesvioNecessario = DesvioNecessario,
|
|
DirecaoDesvio = DirecaoDesvio,
|
|
ObstaculoCritico = ObstaculoCritico?.Clone(),
|
|
Obstaculos = new List<Obstaculo>(Obstaculos ?? new List<Obstaculo>()),
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
public class VisualWorkerMessageResponseModel
|
|
{
|
|
public VisualWorkerCommandType cmd { get; set; }
|
|
public VisualWorkerMessageResponseSaveFramesModel save_frames { get; set; }
|
|
|
|
public VisualWorkerMessageResponseModel Clone()
|
|
{
|
|
return new VisualWorkerMessageResponseModel()
|
|
{
|
|
cmd = cmd,
|
|
save_frames = save_frames.Clone()
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageResponseSaveFramesModel
|
|
{
|
|
public long timestamp { get; set; }
|
|
public List<string> frames { get; set; }
|
|
|
|
private bool _newData = false;
|
|
public bool newData
|
|
{
|
|
get
|
|
{
|
|
if (_newData)
|
|
{
|
|
_newData = false;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
set
|
|
{
|
|
_newData = value;
|
|
}
|
|
}
|
|
|
|
public VisualWorkerMessageResponseSaveFramesModel Clone()
|
|
{
|
|
return new VisualWorkerMessageResponseSaveFramesModel()
|
|
{
|
|
timestamp = timestamp,
|
|
frames = new List<string>(frames),
|
|
newData = true
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageIMUModel
|
|
{
|
|
public long timestamp { get; set; }
|
|
public double roll { get; set; }
|
|
public double pitch { get; set; }
|
|
public double yaw { get; set; }
|
|
public double yaw_fixed { get; set; }
|
|
|
|
public VisualWorkerMessageIMUModel Clone()
|
|
{
|
|
return new VisualWorkerMessageIMUModel()
|
|
{
|
|
timestamp = timestamp,
|
|
roll = roll,
|
|
pitch = pitch,
|
|
yaw = yaw,
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageSetupModel
|
|
{
|
|
public long timestamp { get; set; }
|
|
public bool status { get; set; }
|
|
|
|
private bool _newData = false;
|
|
public bool newData
|
|
{
|
|
get
|
|
{
|
|
if (_newData)
|
|
{
|
|
_newData = false;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
set
|
|
{
|
|
_newData = value;
|
|
}
|
|
}
|
|
public VisualWorkerMessageSetupModel Clone()
|
|
{
|
|
return new VisualWorkerMessageSetupModel()
|
|
{
|
|
timestamp = timestamp,
|
|
status = status,
|
|
newData = true
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageAnaliseModel
|
|
{
|
|
public DateTime timestamp { get; set; }
|
|
//public List<VisualWorkerMessageAnaliseBBoxModel> anomalias { get; set; }
|
|
//public List<VisualWorkerMessageAnaliseBBoxModel> sombras { get; set; }
|
|
//public VisualWorkerMessageAnaliseSoloModel solo { get; set; }
|
|
//public List<VisualWorkerMessageRadar2DPerfilModel> corredor_prof { get; set; }
|
|
//public List<VisualWorkerMessageRadar2DPerfilModel> corredor_seg { get; set; }
|
|
public VisualWorkerMessageSegmentacaoSemanticaModel segmentacao { get; set; }
|
|
public VisualWorkerMessageMatrizConfiancaModel matriz_confianca { get; set; }
|
|
public List<VisualWorkerMessageDeteccaoModel> deteccao { get; set; }
|
|
|
|
public VisualWorkerMessageAnaliseModel Clone()
|
|
{
|
|
return new VisualWorkerMessageAnaliseModel()
|
|
{
|
|
timestamp = timestamp,
|
|
//anomalias = new List<VisualWorkerMessageAnaliseBBoxModel>(anomalias ?? new List<VisualWorkerMessageAnaliseBBoxModel>()),
|
|
//sombras = new List<VisualWorkerMessageAnaliseBBoxModel>(sombras ?? new List<VisualWorkerMessageAnaliseBBoxModel>()),
|
|
//solo = solo?.Clone(),
|
|
//corredor_prof = new List<VisualWorkerMessageRadar2DPerfilModel>(corredor_prof ?? new List<VisualWorkerMessageRadar2DPerfilModel>()),
|
|
//corredor_seg = new List<VisualWorkerMessageRadar2DPerfilModel>(corredor_seg ?? new List<VisualWorkerMessageRadar2DPerfilModel>()),
|
|
segmentacao = segmentacao?.Clone() ?? new VisualWorkerMessageSegmentacaoSemanticaModel(),
|
|
matriz_confianca = matriz_confianca?.Clone() ?? new VisualWorkerMessageMatrizConfiancaModel(),
|
|
deteccao = deteccao?.Select(x => x.Clone()).ToList() ?? new List<VisualWorkerMessageDeteccaoModel>()
|
|
};
|
|
}
|
|
|
|
public Bitmap PlotarAnalise(OAKCameraFrameModel frame)
|
|
{
|
|
return null;
|
|
/*Bitmap img = frame?.image();
|
|
if (img == null) return null;
|
|
|
|
using (Graphics g = Graphics.FromImage(img))
|
|
{
|
|
Pen penObstaculo = new Pen(Color.Red, 2);
|
|
Pen penErosao = new Pen(Color.Blue, 2);
|
|
Pen penLombada = new Pen(Color.Orange, 2);
|
|
Pen penFaixaSolo = new Pen(Color.Black, 2);
|
|
Pen penGrafico = new Pen(Color.DarkGreen, 2);
|
|
|
|
Font font = new Font("Arial", 8);
|
|
Brush brush = Brushes.Black;
|
|
|
|
// 🔸 Definir brushes semi-transparentes para preenchimento
|
|
Brush brushObstaculo = new SolidBrush(Color.FromArgb(60, Color.Red));
|
|
Brush brushErosao = new SolidBrush(Color.FromArgb(60, Color.Blue));
|
|
Brush brushLombada = new SolidBrush(Color.FromArgb(60, Color.Orange));
|
|
|
|
int imgWidth = img.Width;
|
|
int imgHeight = img.Height;
|
|
|
|
// 🔸 Desenhar Bounding Boxes (Anomalias + Solo)
|
|
List<VisualWorkerMessageAnaliseBBoxModel> bboxes = new List<VisualWorkerMessageAnaliseBBoxModel>();
|
|
if (anomalias != null) bboxes.AddRange(anomalias);
|
|
//if (solo?.bbox_list != null) bboxes.AddRange(solo.bbox_list);
|
|
|
|
foreach (var bbox in bboxes)
|
|
{
|
|
Pen pen = penObstaculo;
|
|
Brush fill = brushObstaculo;
|
|
|
|
if (bbox.tipo == "erosao")
|
|
{
|
|
pen = penErosao;
|
|
fill = brushErosao;
|
|
}
|
|
if (bbox.tipo == "lombada")
|
|
{
|
|
pen = penLombada;
|
|
fill = brushLombada;
|
|
}
|
|
|
|
int x = (int)(bbox.bbox[0] * imgWidth);
|
|
int y = (int)(bbox.bbox[1] * imgHeight);
|
|
int w = (int)(bbox.bbox[2] * imgWidth);
|
|
int h = (int)(bbox.bbox[3] * imgHeight);
|
|
var rect = new Rectangle(x, y, w, h);
|
|
|
|
// 🔸 Preencher com opacidade
|
|
g.FillRectangle(fill, rect);
|
|
|
|
// 🔸 Contorno
|
|
g.DrawRectangle(pen, rect);
|
|
|
|
// 🔸 Label
|
|
string label = $"{bbox.tipo} {bbox.distancia_m}m Δ{bbox.variacao}mm";
|
|
g.DrawString(label, font, brush, rect.X, rect.Y - 12);
|
|
}
|
|
|
|
// 🔸 Linha da faixa do solo
|
|
if (solo != null)
|
|
{
|
|
int yInicio = imgHeight - (int)(solo.percent_y * imgHeight);
|
|
g.DrawLine(penFaixaSolo, 0, yInicio, imgWidth, yInicio);
|
|
}
|
|
|
|
// 🔸 Gráfico do perfil de solo
|
|
if (solo?.perfil != null && solo.perfil.Count > 1)
|
|
{
|
|
var perfil = solo.perfil;
|
|
int setores = solo.perfil.Count;
|
|
int yInicio = imgHeight - (int)(solo.percent_y * imgHeight);
|
|
int alturaRegiao = imgHeight / solo.perfil.Count;
|
|
|
|
double maxZ = perfil.Max();
|
|
double minZ = perfil.Min();
|
|
if (maxZ == minZ) maxZ += 1; // evita divisão por zero
|
|
|
|
for (int i = 0; i < perfil.Count - 1; i++)
|
|
{
|
|
float x1 = (float)(i * imgWidth / setores + imgWidth / (2.0 * setores));
|
|
float x2 = (float)((i + 1) * imgWidth / setores + imgWidth / (2.0 * setores));
|
|
|
|
float y1 = (float)(yInicio + alturaRegiao - ((perfil[i] - minZ) / (maxZ - minZ)) * alturaRegiao);
|
|
float y2 = (float)(yInicio + alturaRegiao - ((perfil[i + 1] - minZ) / (maxZ - minZ)) * alturaRegiao);
|
|
|
|
g.DrawLine(penGrafico, x1, y1, x2, y2);
|
|
g.FillEllipse(Brushes.DarkGreen, x1 - 3, y1 - 3, 6, 6);
|
|
}
|
|
|
|
// Desenha o último ponto
|
|
float xLast = (float)((perfil.Count - 1) * imgWidth / setores + imgWidth / (2.0 * setores));
|
|
float yLast = (float)(yInicio + alturaRegiao - ((perfil.Last() - minZ) / (maxZ - minZ)) * alturaRegiao);
|
|
g.FillEllipse(Brushes.DarkGreen, xLast - 3, yLast - 3, 6, 6);
|
|
}
|
|
}
|
|
|
|
return img;*/
|
|
}
|
|
|
|
}
|
|
|
|
public class VisualWorkerMessageAnaliseSoloModel
|
|
{
|
|
public List<double> perfil { get; set; }
|
|
public double percent_y { get; set; }
|
|
public double inclinacao { get; set; }
|
|
//public List<VisualWorkerMessageAnaliseBBoxModel> bbox_list { get; set; }
|
|
//public int y_inicio { get; set; }
|
|
//public int altura_regiao { get; set; }
|
|
//public int n_setores { get; set; }
|
|
|
|
public VisualWorkerMessageAnaliseSoloModel Clone()
|
|
{
|
|
return new VisualWorkerMessageAnaliseSoloModel()
|
|
{
|
|
perfil = new List<double>(perfil),
|
|
percent_y = percent_y,
|
|
inclinacao = inclinacao,
|
|
//bbox_list = new List<VisualWorkerMessageAnaliseBBoxModel>(bbox_list),
|
|
//y_inicio = y_inicio,
|
|
//altura_regiao = altura_regiao,
|
|
//n_setores = n_setores,
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageAnaliseBBoxModel
|
|
{
|
|
public string tipo { get; set; }
|
|
public List<double> bbox { get; set; } // [x, y, w, h]
|
|
public List<double> centro_percentual { get; set; } // [x%, y%]
|
|
public double? distancia_m { get; set; }
|
|
public double? largura_m { get; set; }
|
|
public double? altura_m { get; set; }
|
|
public List<double> profundidades { get; set; } // [z1, z2] ou null
|
|
public double? variacao { get; set; } // delta Z ou null
|
|
}
|
|
|
|
public class VisualWorkerMessageRadar2DModel
|
|
{
|
|
public OAKCameraFrameModel frame { get; set; }
|
|
public VisualWorkerMessageRadar2DAnaliseModel analise { get; set; }
|
|
|
|
private bool _newData = false;
|
|
public bool newData
|
|
{
|
|
get
|
|
{
|
|
if (_newData)
|
|
{
|
|
_newData = false;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
set
|
|
{
|
|
_newData = value;
|
|
}
|
|
}
|
|
public VisualWorkerMessageRadar2DModel Clone()
|
|
{
|
|
return new VisualWorkerMessageRadar2DModel()
|
|
{
|
|
frame = frame.Clone(),
|
|
analise = analise.Clone(),
|
|
newData = true
|
|
};
|
|
}
|
|
|
|
public Bitmap PlotarAnalsie(Bitmap img)
|
|
{
|
|
/*try
|
|
{
|
|
using (Graphics g = Graphics.FromImage(img))
|
|
{
|
|
var grid = analise.grid_info;
|
|
|
|
double cellSize = grid.cell_size;
|
|
double escala = grid.escala;
|
|
int imgSize = (int)grid.img_size;
|
|
int centerX = (int)grid.center_x;
|
|
int centerY = (int)grid.center_y;
|
|
int gridX = (int)(2 * grid.distancia_max / cellSize);
|
|
int gridZ = (int)(grid.distancia_max / cellSize);
|
|
|
|
foreach (var bbox in analise.bboxes_sombra)
|
|
{
|
|
int xGrid = bbox.bbox[0];
|
|
int zGrid = bbox.bbox[1];
|
|
int wGrid = bbox.bbox[2];
|
|
int hGrid = bbox.bbox[3];
|
|
|
|
// 🔸 Converte X (grid → metros → pixels com margem)
|
|
int pixelX = (int)(centerX + (xGrid - gridX / 2.0) * cellSize * escala);
|
|
|
|
// 🔸 Converte Z/Y (grid → metros → pixels com inversão vertical + margem)
|
|
int pixelY = (int)((centerY / 3) + zGrid * cellSize * escala);
|
|
|
|
// 🔸 Tamanho da bbox em pixels
|
|
int pixelW = (int)(wGrid * cellSize * escala);
|
|
int pixelH = (int)(hGrid * cellSize * escala);
|
|
|
|
// 🔸 Desenha a bbox
|
|
var rect = new Rectangle(pixelX, pixelY, pixelW, pixelH);
|
|
g.DrawRectangle(new Pen(Color.Red, 2), rect);
|
|
|
|
// 🔸 Desenha o centro da bbox
|
|
int centroX = pixelX + pixelW / 2;
|
|
int centroY = pixelY + pixelH / 2;
|
|
g.FillEllipse(Brushes.Red, centroX - 3, centroY - 3, 6, 6);
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
|
|
}*/
|
|
return img;
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageRadar2DAnaliseModel
|
|
{
|
|
public List<VisualWorkerMessageAnaliseBBoxModel> bboxes_sombra { get; set; }
|
|
public List<VisualWorkerMessageRadar2DPerfilModel> corredor_perfil { get; set; }
|
|
public VisualWorkerMessageRadar2DGridInfoModel grid_info { get; set; }
|
|
|
|
public VisualWorkerMessageRadar2DAnaliseModel Clone()
|
|
{
|
|
return new VisualWorkerMessageRadar2DAnaliseModel()
|
|
{
|
|
bboxes_sombra = new List<VisualWorkerMessageAnaliseBBoxModel>(bboxes_sombra),
|
|
corredor_perfil = new List<VisualWorkerMessageRadar2DPerfilModel>(corredor_perfil),
|
|
grid_info = grid_info.Clone()
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageRadar2DPerfilModel
|
|
{
|
|
public double distancia_m { get; set; }
|
|
public double esquerda_m { get; set; }
|
|
public double direita_m { get; set; }
|
|
public double largura_m { get; set; }
|
|
}
|
|
|
|
public class VisualWorkerMessageRadar2DGridInfoModel
|
|
{
|
|
public double escala { get; set; }
|
|
public double img_size { get; set; }
|
|
public double center_x { get; set; }
|
|
public double center_y { get; set; }
|
|
public double cell_size { get; set; }
|
|
public double distancia_max { get; set; }
|
|
public double largura_max { get; set; }
|
|
public VisualWorkerMessageRadar2DGridInfoModel Clone()
|
|
{
|
|
return new VisualWorkerMessageRadar2DGridInfoModel()
|
|
{
|
|
escala = escala,
|
|
img_size = img_size,
|
|
center_x = center_x,
|
|
center_y = center_y,
|
|
cell_size = cell_size,
|
|
distancia_max = distancia_max,
|
|
largura_max = largura_max
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageSegmentacaoSemanticaModel
|
|
{
|
|
public int height { get; set; }
|
|
public int width { get; set; }
|
|
public double erro_angular { get; set; }
|
|
public double erro_lateral_pct { get; set; }
|
|
public StatusCarroMapa status_corredor { get; set; }
|
|
public List<double[]> centros_corredor { get; set; }
|
|
|
|
public VisualWorkerMessageSegmentacaoSemanticaModel Clone()
|
|
{
|
|
return new VisualWorkerMessageSegmentacaoSemanticaModel()
|
|
{
|
|
height = height,
|
|
width = width,
|
|
erro_angular = erro_angular,
|
|
erro_lateral_pct = erro_lateral_pct,
|
|
status_corredor = status_corredor,
|
|
centros_corredor = new List<double[]>(centros_corredor ?? new List<double[]>())
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageMatrizConfiancaModel
|
|
{
|
|
public float ts { get; set; }
|
|
public int seq { get; set; }
|
|
public int grid_w { get; set; }
|
|
public int grid_h { get; set; }
|
|
public List<float> y_range_m { get; set; }
|
|
public List<float> row_dist_m { get; set; }
|
|
public List<float> row_scale_x_m { get; set; }
|
|
public VisualWorkerMessageMatrizConfiancaBlockModel block { get; set; }
|
|
|
|
public VisualWorkerMessageMatrizConfiancaModel Clone()
|
|
{
|
|
return new VisualWorkerMessageMatrizConfiancaModel()
|
|
{
|
|
ts = ts,
|
|
seq = seq,
|
|
grid_w = grid_w,
|
|
grid_h = grid_h,
|
|
y_range_m = y_range_m,
|
|
row_dist_m = new List<float>(row_dist_m),
|
|
row_scale_x_m = new List<float>(row_scale_x_m),
|
|
block = block.Clone()
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageMatrizConfiancaBlockModel
|
|
{
|
|
public float? d_block_line_m { get; set; }
|
|
public float d_obs_true_min_m { get; set; }
|
|
public bool blocked { get; set; }
|
|
public bool blocked_raw { get; set; }
|
|
public string reason { get; set; }
|
|
public string reason_detail { get; set; }
|
|
public VisualWorkerMessageMatrizConfiancaBlockDecisionModel decision { get; set; }
|
|
|
|
public VisualWorkerMessageMatrizConfiancaBlockModel Clone()
|
|
{
|
|
return new VisualWorkerMessageMatrizConfiancaBlockModel()
|
|
{
|
|
d_block_line_m = d_block_line_m,
|
|
d_obs_true_min_m = d_obs_true_min_m,
|
|
blocked = blocked,
|
|
blocked_raw = blocked_raw,
|
|
reason = reason,
|
|
reason_detail = reason_detail,
|
|
decision = decision.Clone()
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageMatrizConfiancaBlockDecisionModel
|
|
{
|
|
public bool parar { get; set; }
|
|
public float dist_necessaria { get; set; }
|
|
public float? v_max_sugerida_mps { get; set; }
|
|
public int frames_on { get; set; }
|
|
public int frames_off { get; set; }
|
|
public int N_on { get; set; }
|
|
public int N_off { get; set; }
|
|
|
|
public VisualWorkerMessageMatrizConfiancaBlockDecisionModel Clone()
|
|
{
|
|
return new VisualWorkerMessageMatrizConfiancaBlockDecisionModel()
|
|
{
|
|
parar = parar,
|
|
dist_necessaria = dist_necessaria,
|
|
v_max_sugerida_mps = v_max_sugerida_mps,
|
|
frames_on = frames_on,
|
|
frames_off = frames_off,
|
|
N_on = N_on,
|
|
N_off = N_off,
|
|
};
|
|
}
|
|
}
|
|
|
|
public class VisualWorkerMessageDeteccaoModel
|
|
{
|
|
public int label_id { get; set; }
|
|
public string label { get; set; }
|
|
public double conf { get; set; }
|
|
public List<double> bbox_norm { get; set; }
|
|
public List<double> bbox_px { get; set; }
|
|
|
|
public VisualWorkerMessageDeteccaoModel Clone()
|
|
{
|
|
return new VisualWorkerMessageDeteccaoModel()
|
|
{
|
|
label_id = label_id,
|
|
label = label,
|
|
bbox_norm = bbox_norm,
|
|
bbox_px = bbox_px,
|
|
conf = conf
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
public enum VisualWorkerCommandType
|
|
{
|
|
ScriptCarregado = 1,
|
|
CalibrarProfundidade = 2,
|
|
IniciarCameraManager = 3,
|
|
AtualizarSaudeCamera = 4,
|
|
GetCameraFrame = 5,
|
|
SaveCameraFrames = 6,
|
|
EnviarImagemMock = 7
|
|
}
|
|
|
|
|
|
|
|
}
|