Difuminado automático de rostros: privacidad con AWS y .NET
En el mundo digital actual, proteger la privacidad personal es más importante que nunca. En este artículo crearemos una aplicación .NET que aprovecha AWS Rekognition para detectar rostros en imágenes y que luego usa una biblioteca de procesamiento de imágenes para difuminar esas áreas automáticamente. La detección puede pasar por alto algunos rostros, y el difuminado no garantiza el anonimato ni el cumplimiento de las normativas de privacidad. Revisa los resultados antes de compartirlos y envía imágenes a AWS únicamente cuando tengas permiso para hacerlo.
Configura tu proyecto .NET
Usa .NET 8 o una versión posterior. Primero, crea una nueva aplicación de consola .NET. Abre tu terminal y ejecuta:
dotnet new console -n FaceBlurAutomation
cd FaceBlurAutomation
A continuación, agrega los paquetes NuGet necesarios. Usaremos el AWS SDK (Amazon.Rekognition) para la detección de rostros y SixLabors.ImageSharp para el procesamiento de imágenes:
dotnet add package AWSSDK.Rekognition --version 4.0.100.13
dotnet add package SixLabors.ImageSharp --version 2.1.13
Este ejemplo se mantiene en la línea de parches 2.1 de ImageSharp; usa una versión parcheada en
lugar de 2.1.3. Configura las credenciales mediante la
cadena de proveedores de credenciales predeterminada del SDK,
por ejemplo con un perfil local de AWS o un rol de IAM. La identidad necesita el permiso rekognition:DetectFaces.
Define la región en tu perfil o con AWS_REGION, por ejemplo us-east-1. El cliente que aparece más
abajo usa esa configuración sin incrustar credenciales. Las solicitudes a Rekognition generan cargos
en AWS.
Comprende AWS Rekognition
AWS Rekognition ofrece herramientas potentes para el análisis de imágenes. Su API DetectFaces devuelve
información detallada sobre los rasgos faciales, incluidos los cuadros delimitadores, que son
relativos a las dimensiones de la imagen. Podemos usar estos detalles para localizar rostros y
aplicar efectos de posprocesamiento como el difuminado. DetectFaces devuelve como máximo los 100
rostros más grandes, por lo que no puede determinar que se hayan encontrado todos los rostros de una
imagen.
Implementación de la detección de rostros y el difuminado
A continuación se muestra un ejemplo completo en C# que carga una imagen, detecta rostros y difumina
cada región detectada con ImageSharp. Reemplaza Program.cs con este código y ejecuta dotnet run -- input.jpg output.png,
eligiendo una imagen de al menos 80 píxeles de ancho y de alto y un archivo de salida que todavía no
exista:
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Amazon.Rekognition;
using Amazon.Rekognition.Model;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
namespace FaceBlurAutomation;
public class Program
{
public static async Task Main(string[] args)
{
try
{
if (args.Length < 2)
{
throw new ArgumentException("Usage: FaceBlurAutomation <inputImagePath> <outputImagePath>");
}
string inputImagePath = args[0];
string outputImagePath = args[1];
if (!File.Exists(inputImagePath))
{
throw new FileNotFoundException("Input image file not found", inputImagePath);
}
using var rekognitionClient = new AmazonRekognitionClient();
await ProcessImageAsync(inputImagePath, outputImagePath, rekognitionClient);
Console.WriteLine($"Processed image saved to {outputImagePath}");
}
catch (Exception ex)
{
Console.Error.WriteLine($"Error: {ex.Message}");
Environment.Exit(1);
}
}
private static async Task ProcessImageAsync(
string inputPath, string outputPath, IAmazonRekognition rekognitionClient)
{
if (!string.Equals(Path.GetExtension(outputPath), ".png", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("Choose a .png output path", nameof(outputPath));
}
if (File.Exists(outputPath))
{
throw new IOException("Choose an output file that does not already exist");
}
using var image = await SixLabors.ImageSharp.Image.LoadAsync(inputPath);
// Send exactly the oriented pixels that we will blur, without EXIF orientation metadata.
image.Mutate(ctx => ctx.AutoOrient());
image.Metadata.ExifProfile = null;
using var imageStream = new MemoryStream();
await image.SaveAsPngAsync(imageStream);
if (imageStream.Length > 5 * 1024 * 1024)
{
throw new InvalidDataException("The normalized PNG exceeds Rekognition's 5 MB Bytes limit");
}
imageStream.Position = 0;
var detectRequest = new DetectFacesRequest
{
Image = new Amazon.Rekognition.Model.Image
{
Bytes = imageStream
},
Attributes = new List<string> { "DEFAULT" }
};
var detectResponse = await rekognitionClient.DetectFacesAsync(detectRequest);
var faces = detectResponse.FaceDetails ?? new List<FaceDetail>();
if (faces.Count == 0)
{
Console.WriteLine("No faces detected; the output is unblurred and needs manual review");
}
foreach (var faceDetail in faces)
{
var box = faceDetail.BoundingBox;
if (box?.Left is not float left || box.Top is not float top
|| box.Width is not float width || box.Height is not float height
|| !float.IsFinite(left) || !float.IsFinite(top)
|| !float.IsFinite(width) || !float.IsFinite(height)
|| width <= 0 || height <= 0)
{
throw new InvalidDataException("Rekognition returned an invalid face bounding box");
}
// Edge faces can extend outside the image. Round outward, then clamp to its bounds.
int x1 = (int)Math.Floor(Math.Clamp((double)left * image.Width, 0, image.Width));
int y1 = (int)Math.Floor(Math.Clamp((double)top * image.Height, 0, image.Height));
int x2 = (int)Math.Ceiling(Math.Clamp(((double)left + width) * image.Width, 0, image.Width));
int y2 = (int)Math.Ceiling(Math.Clamp(((double)top + height) * image.Height, 0, image.Height));
if (x2 <= x1 || y2 <= y1)
{
throw new InvalidDataException("A face bounding box does not intersect the image");
}
var faceRegion = new Rectangle(x1, y1, x2 - x1, y2 - y1);
image.Mutate(ctx => ctx.GaussianBlur(10, faceRegion));
}
using var output = new FileStream(outputPath, FileMode.CreateNew, FileAccess.Write);
await image.SaveAsPngAsync(output);
}
}
Cómo funciona
- Cargamos y orientamos la imagen, la codificamos como PNG y la pasamos a
DetectFacesAsync. El PNG normalizado debe respetar el límite de 5 MB para Bytes directos. El límite independiente de 15 MB para objetos de S3 no se aplica a este ejemplo. - Rekognition devuelve una lista de detalles de rostros, cada uno con un cuadro delimitador normalizado para la región del rostro detectado.
- Convertimos estas coordenadas en píxeles dentro de la misma imagen orientada. Los cuadros delimitadores pueden extenderse más allá de un borde, así que los recortamos a los límites y descartamos los cuadros no válidos o que no se intersecan.
- Para cada rostro detectado, aplicamos un difuminado gaussiano. Puede que haya que ajustar el radio de difuminado fijo después de inspeccionar el resultado.
- Por último, guardamos un nuevo archivo PNG sin sobrescribir un archivo existente.
Manejo de errores y pruebas
El ejemplo incluye manejo de errores para situaciones comunes:
- Argumentos de línea de comandos ausentes o no válidos
- Archivos de entrada inexistentes
- Errores del servicio de AWS
- Fallos en el procesamiento de imágenes
- Casos en los que no se detecta ningún rostro
Los fallos del servicio y del procesamiento de imágenes se propagan a Main, que finaliza sin
éxito. No se escribe ninguna salida cuando la detección de rostros falla o devuelve un cuadro
delimitador no válido. En una aplicación de servidor, devuelve un error genérico a quienes la
llaman y guarda diagnósticos redactados en los registros del servidor en lugar de exponer los
mensajes de excepción. Aplica límites de tamaño de entrada y de píxeles decodificados antes de
aceptar subidas que no sean de confianza.
Amplía tu aplicación
Este ejemplo básico se puede ampliar de varias maneras:
- Integrarlo con una API web para procesar las imágenes que suben los usuarios.
- Usar un servicio de almacenamiento como Amazon S3 para las imágenes de entrada y de salida.
- Combinar esta técnica con otras herramientas de análisis de imágenes para crear un conjunto integral de protección de la privacidad.
Resumen
Ya has creado una aplicación .NET que aprovecha AWS Rekognition para detectar rostros y aplica un efecto de difuminado que reduce el detalle facial visible. Este enfoque demuestra cómo integrar el análisis de imágenes en la nube con bibliotecas modernas de .NET para resolver desafíos del mundo real.
Por cierto, Transloadit también aprovecha técnicas similares de análisis de imágenes de AWS en su Robot /image/describe para mejorar los flujos de trabajo de procesamiento de imágenes.
