TesteCaminhao/TesteImagemCaminhao/Controllers/Circle1DetectionController.cs
2025-03-17 11:13:59 -03:00

389 lines
16 KiB
C#

using Microsoft.AspNetCore.Mvc;
using OpenCvSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using CircleDetectionApi.Helpers;
namespace CircleDetectionApi.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class Circle1DetectionController : ControllerBase
{
private readonly IWebHostEnvironment _environment;
private readonly VehicleDetectionHelper _vehicleDetector;
public Circle1DetectionController(IWebHostEnvironment environment)
{
_environment = environment;
// Caminho para os arquivos do modelo YOLO
var modelPath = Path.Combine(environment.ContentRootPath, "Models", "yolov4.weights");
var configPath = Path.Combine(environment.ContentRootPath, "Models", "yolov4.cfg");
var classesPath = Path.Combine(environment.ContentRootPath, "Models", "coco.names");
// Inicializar o detector de veículos
_vehicleDetector = new VehicleDetectionHelper(modelPath, configPath, classesPath);
}
[HttpPost]
public async Task<IActionResult> DetectCircles(IFormFile image, bool detectVehicle)
{
// Verificar se a imagem foi enviada
if (image == null || image.Length == 0)
{
return BadRequest(new { error = "Nenhuma imagem foi enviada" });
}
// Verificar o tipo do arquivo
var allowedExtensions = new[] { ".jpg", ".jpeg", ".png", ".bmp", ".tiff" };
var extension = Path.GetExtension(image.FileName).ToLowerInvariant();
if (!allowedExtensions.Contains(extension))
{
return BadRequest(new { error = "Tipo de arquivo não suportado. Por favor, envie uma imagem JPG, PNG, BMP ou TIFF." });
}
try
{
// Ler a imagem em um MemoryStream
using var memoryStream = new MemoryStream();
await image.CopyToAsync(memoryStream);
memoryStream.Position = 0;
// Carregar a imagem usando OpenCvSharp
using var mat = Mat.FromImageData(memoryStream.ToArray(), ImreadModes.Color);
// Variáveis para armazenar informações sobre o veículo
bool isVehicle = false;
string vehicleClass = "Não detectado";
Rect vehicleBox = new Rect();
// Detectar veículo (se solicitado)
if (detectVehicle)
{
(isVehicle, vehicleClass, vehicleBox) = _vehicleDetector.DetectVehicle(mat);
}
// Converter para escala de cinza
using var grayMat = new Mat();
Cv2.CvtColor(mat, grayMat, ColorConversionCodes.BGR2GRAY);
// Aplicar blur para reduzir ruído
using var blurredMat = new Mat();
Cv2.MedianBlur(grayMat, blurredMat, 5);
// Usar o algoritmo de Hough Circle para detectar círculos
CircleSegment[] circles = Cv2.HoughCircles(
blurredMat,
HoughModes.Gradient,
1, // Razão entre resolução da imagem e acumulador
240, // Distância mínima entre centros de círculos detectados
param1: 250, // Limite superior para detector de bordas Canny
param2: 50, // Limite para detecção de centros
minRadius: 5, // Raio mínimo do círculo
maxRadius: 200 // Raio máximo do círculo
);
// Também tentar o método de detecção avançado
var wheelDetections = VehicleDetectionHelper.DetectWheelsAndAxles(mat);
// Criar lista para armazenar os círculos detectados
var detectedCircles = new List<object>();
// Criar uma cópia colorida da imagem para desenhar os círculos
using var colorMat = mat.Clone(); // Simplesmente clonar a imagem original
// Variável para armazenar contagem de rodas
int wheelCount = 0;
int estimatedAxles = 0; // Adicionar a variável estimatedAxles
if (circles != null && circles.Length > 0)
{
foreach (var circle in circles)
{
// Adicionar à lista de resultados
detectedCircles.Add(new
{
center_x = (int)circle.Center.X,
center_y = (int)circle.Center.Y,
radius = (int)circle.Radius
});
// Desenhar o círculo (como no código Python)
Cv2.Circle(colorMat,
(int)circle.Center.X,
(int)circle.Center.Y,
(int)circle.Radius,
new Scalar(0, 255, 0),
2);
// Desenhar o centro do círculo (como no código Python)
Cv2.Circle(colorMat,
(int)circle.Center.X,
(int)circle.Center.Y,
2,
new Scalar(0, 0, 255),
1);
}
// Atualizar contagem de rodas
wheelCount = detectedCircles.Count;
// Não precisamos mais deste bloco, pois já temos a classe do veículo
}
// Se o parâmetro saveImage for true, salve a imagem marcada e retorne o URL
bool saveImage = HttpContext.Request.Query.ContainsKey("saveImage") &&
bool.TryParse(HttpContext.Request.Query["saveImage"], out var saveValue) &&
saveValue;
string imageUrl = null;
if (saveImage)
{
// Criar diretório para imagens se não existir
var imagesDir = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images");
Directory.CreateDirectory(imagesDir);
// Salvar a imagem com os círculos marcados
var filename = $"circles_{DateTime.Now:yyyyMMddHHmmss}.jpg";
var filePath = Path.Combine(imagesDir, filename);
Cv2.ImWrite(filePath, colorMat);
// Gerar URL para a imagem
imageUrl = $"{Request.Scheme}://{Request.Host}/images/{filename}";
}
// Desenhar a caixa delimitadora do veículo, se detectado
if (detectVehicle && isVehicle)
{
_vehicleDetector.DrawVehicleBox(colorMat, vehicleBox, vehicleClass);
}
// Determinar o tipo de veículo baseado na classe detectada e no número de rodas
string vehicleType = GetVehicleTypeFromClassAndWheels(vehicleClass, wheelCount);
// Se não detectou nenhuma roda mas identificou um caminhão, estimar um número padrão (4 ou 6)
if (wheelCount == 0 && vehicleClass.ToLower() == "truck")
{
wheelCount = 4; // Valor padrão conservador
}
// Retornar o resultado como JSON
return Ok(new
{
count = detectedCircles.Count,
estimatedWheels = wheelCount,
estimatedAxles = estimatedAxles,
circles = detectedCircles,
imageUrl = imageUrl,
vehicleInfo = detectVehicle ? new
{
isVehicle = isVehicle,
detectedClass = vehicleClass,
suggestedType = vehicleType,
wheelCount = wheelCount
} : null
});
}
catch (Exception ex)
{
return StatusCode(500, new { error = $"Erro ao processar a imagem: {ex.Message}" });
}
}
[HttpGet("file")]
public IActionResult DetectCirclesFromFile([FromQuery] string filename)
{
if (string.IsNullOrEmpty(filename))
{
return BadRequest(new { error = "Nome do arquivo não especificado" });
}
// Obter o caminho do arquivo
var imagesPath = Path.Combine(_environment.ContentRootPath, "Images");
var filePath = Path.Combine(imagesPath, filename);
// Verificar se o arquivo existe
if (!System.IO.File.Exists(filePath))
{
return NotFound(new { error = $"Arquivo {filename} não encontrado" });
}
try
{
// Carregar a imagem usando OpenCvSharp
using var mat = Cv2.ImRead(filePath, ImreadModes.Color);
// Verificar se a detecção de veículos está habilitada
bool detectVehicle = HttpContext.Request.Query.ContainsKey("detectVehicle") &&
bool.TryParse(HttpContext.Request.Query["detectVehicle"], out var detectValue) &&
detectValue;
// Variáveis para armazenar informações sobre o veículo
bool isVehicle = false;
string vehicleClass = "Não detectado";
Rect vehicleBox = new Rect();
// Detectar veículo (se solicitado)
if (detectVehicle)
{
(isVehicle, vehicleClass, vehicleBox) = _vehicleDetector.DetectVehicle(mat);
}
// Converter para escala de cinza
using var grayMat = new Mat();
Cv2.CvtColor(mat, grayMat, ColorConversionCodes.BGR2GRAY);
// Aplicar blur para reduzir ruído (medianBlur como no código original)
using var blurredMat = new Mat();
Cv2.MedianBlur(grayMat, blurredMat, 5);
// Usar o algoritmo de Hough Circle para detectar círculos
CircleSegment[] circles = Cv2.HoughCircles(
blurredMat,
HoughModes.Gradient,
1, // Razão entre resolução da imagem e acumulador
240, // Distância mínima entre centros
param1: 250, // Limite superior para detector de bordas Canny
param2: 50, // Limite para detecção de centros
minRadius: 5, // Raio mínimo do círculo
maxRadius: 200 // Raio máximo do círculo
);
// Preparar o resultado
var detectedCircles = new List<object>();
// Criar uma cópia colorida da imagem para desenhar os círculos
using var colorMat = new Mat();
Cv2.CvtColor(blurredMat, colorMat, ColorConversionCodes.GRAY2BGR);
// Variável para armazenar contagem de rodas
int wheelCount = 0;
if (circles != null && circles.Length > 0)
{
foreach (var circle in circles)
{
// Adicionar à lista de resultados
detectedCircles.Add(new
{
center_x = (int)circle.Center.X,
center_y = (int)circle.Center.Y,
radius = (int)circle.Radius
});
// Desenhar o círculo
Cv2.Circle(colorMat,
(int)circle.Center.X,
(int)circle.Center.Y,
(int)circle.Radius,
new Scalar(0, 255, 0),
2);
// Desenhar o centro do círculo
Cv2.Circle(colorMat,
(int)circle.Center.X,
(int)circle.Center.Y,
2,
new Scalar(0, 0, 255),
1);
}
// Atualizar contagem de rodas
wheelCount = detectedCircles.Count;
// Não precisamos mais deste bloco, pois já temos a classe do veículo
}
// Se o parâmetro saveImage for true, salve a imagem marcada e retorne o URL
bool saveImage = HttpContext.Request.Query.ContainsKey("saveImage") &&
bool.TryParse(HttpContext.Request.Query["saveImage"], out var saveValue) &&
saveValue;
string imageUrl = null;
if (saveImage)
{
// Criar diretório para imagens se não existir
var imagesDir = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images");
Directory.CreateDirectory(imagesDir);
// Salvar a imagem com os círculos marcados
var outputFilename = $"circles_{Path.GetFileNameWithoutExtension(filename)}_{DateTime.Now:yyyyMMddHHmmss}.jpg";
var outputPath = Path.Combine(imagesDir, outputFilename);
Cv2.ImWrite(outputPath, colorMat);
// Gerar URL para a imagem
imageUrl = $"{Request.Scheme}://{Request.Host}/images/{outputFilename}";
}
// Desenhar a caixa delimitadora do veículo, se detectado
if (detectVehicle && isVehicle)
{
_vehicleDetector.DrawVehicleBox(colorMat, vehicleBox, vehicleClass);
}
// Determinar o tipo de veículo baseado na classe detectada e no número de rodas
string vehicleType = GetVehicleTypeFromClassAndWheels(vehicleClass, wheelCount);
// Retornar o resultado como JSON
return Ok(new
{
count = detectedCircles.Count,
circles = detectedCircles,
imageUrl = imageUrl,
vehicleInfo = detectVehicle ? new
{
isVehicle = isVehicle,
detectedClass = vehicleClass,
suggestedType = vehicleType,
wheelCount = wheelCount
} : null
});
}
catch (Exception ex)
{
return StatusCode(500, new { error = $"Erro ao processar a imagem: {ex.Message}" });
}
}
// Método para determinar o tipo de veículo com base na classe detectada e no número de rodas
private string GetVehicleTypeFromClassAndWheels(string vehicleClass, int wheelCount)
{
if (string.IsNullOrEmpty(vehicleClass) || vehicleClass == "Não detectado")
return "Veículo não identificado";
// Combinamos a classe detectada com o número de rodas para uma classificação mais precisa
switch (vehicleClass.ToLower())
{
case "car":
if (wheelCount <= 0) return "Carro (rodas não detectadas)";
if (wheelCount <= 4) return "Carro compacto/Sedan";
return "SUV/Crossover";
case "truck":
if (wheelCount <= 0) return "Caminhão (rodas não detectadas)";
if (wheelCount <= 4) return "Pickup";
if (wheelCount <= 6) return "Caminhão pequeno";
if (wheelCount <= 10) return "Caminhão médio";
return "Caminhão grande/Carreta";
case "bus":
return "Ônibus";
case "bicycle":
return "Bicicleta";
case "motorbike":
if (wheelCount == 3) return "Triciclo/Sidecar";
return "Motocicleta";
default:
if (wheelCount <= 0) return $"{vehicleClass} (rodas não detectadas)";
return $"{vehicleClass} com {wheelCount} rodas";
}
}
}
}