A pesar de todas las delicias de Internet, tiene muchas desventajas, y una de las más terribles es engañar a las personas. Clickbait, edición de fotos, noticias falsas: todas estas herramientas se utilizan activamente para engañar a los usuarios comunes en la red global, pero en los últimos años una nueva herramienta potencialmente peligrosa conocida como DeepFake ha ido ganando impulso.
Estaba interesado en esta tecnología recientemente. Por primera vez, me enteré del informe de uno de los oradores en la "Conferencia de AI 2018". Allí se mostró un video en el que, mediante grabación de audio, el algoritmo generó un video con el atractivo de Barack Obama.
Enlace a una selección de videos creados con esta tecnología . Los resultados me inspiraron enormemente y decidí entender mejor esta tecnología para oponerme a ella en el futuro. Para esto, decidí escribir DeepFake en C #. Como resultado, obtuve tal resultado.

Que tengas una buena lectura!
Principios generalesEl punto de partida fue
este proyecto. De él, aprendí exactamente cómo funciona el reemplazo de rostros en video.
- Cargando una foto con la que tomaremos una cara
- Extracción de la cara
- Creación de máscara 3D
- El video se divide en cuadros
- Se calcula el área de localización de caras en el marco
- Se calculan el ángulo y la expresión facial.
- Transferencia de rotación y expresiones faciales a un modelo 3D
- Renderizado
- Reemplazar a una persona real en el marco con el resultado de renderizar
Video que muestra el trabajo del
proyecto FaceSwap :
Decidí dividir el trabajo en 3 partes:
1º) Reemplazar una cara en una foto con una cara de otra, sin usar una máscara 3D
2º) Finalización del reemplazo usando la máscara 3D
3º) Procesamiento de video
El reemplazo facial en la foto se puede descomponer en los siguientes puntos:
- Cargando una foto con la que tomaremos una cara
- Cargando la imagen sobre la cual proyectaremos la cara
- Extracción de la cara
- Escalando la cara tomada de la imagen 2 a la relación de aspecto en la imagen 1
- Reemplazar la cara en la imagen 1 con la cara en la imagen 2
Incrustar una imagen en otraLo primero con lo que comencé fue incrustar una imagen en otra. El script
zad1.py se usa para demostrar la incrustación en el proyecto original.
Como resultado, se crea el archivo "eyeHandBlend.jpg", donde el ojo está incrustado en la mano.

Este algoritmo consta de 2 partes, la primera transfiere el color del área con la cara en la imagen original a la cara que debe insertarse. El segundo hace que los bordes de la imagen con la cara deseada sean transparentes, reduciendo la transparencia a medida que se acerca al centro de la imagen.
Transferí completamente la primera parte del proyecto original.
Código de Pythondef colorTransfer(src, dst, mask): transferredDst = np.copy(dst)
Código portado a C # static public Bitmap NewColor(Bitmap src, Bitmap ins, Rectangle r) { List<Vector> srV = new List<Vector>(); List<Vector> inV = new List<Vector>(); ; for (int i = rX; i < rX + r.Width-2; i+=3) { for (int j = rY; j < rY + r.Height-3; j+=4) { Color color = src.GetPixel(i, j); Color color2 = ins.GetPixel(i, j); srV.Add(new double[] { color.R, color.G, color.B }.ToVector()); inV.Add(new double[] { color2.R, color2.G, color2.B }.ToVector()); } } Vector meanSrc = Vector.Mean(srV.ToArray()) / 255; Vector meanInk = Vector.Mean(inV.ToArray()) / 255; Tensor tensor = ImgConverter.BmpToTensor (ins.Clone(r, PixelFormat.Format32bppArgb)); tensor = tensor.DivD(meanInk); tensor = tensor.PlusD(meanSrc); tensor = tensor.TransformTensor(x => { if (x < 0) x = 0; if (x > 1) x = 1; return x; }); return ImgConverter.TensorToBitmap(tensor); }
Para hacer los bordes más transparentes que la parte central de la imagen, para calcular el canal alfa, se introdujo una función de base radial de la siguiente forma:
k y n fueron seleccionados empíricamente.
i - índice de píxeles a lo largo del eje OX
j - índice de píxeles a lo largo del eje OY
- componente x del centro de la imagen
- componente y del centro de la imagen
Como resultado, obtuve el siguiente resultado:
Búsqueda de carasPara buscar caras en la foto, hay muchos algoritmos:
- Algoritmo Viola-Jones (Cascadas Haar)
- Cerdo + svm
- R-CNN
- R-cnn rápido
- R-cnn más rápido
- Yolo
Inicialmente, se utilizó el algoritmo Viola-Jones, pero resultó no ser lo suficientemente preciso, porque caras resaltadas no exactamente. El área de selección de una persona no coincidió con el área de selección de la segunda, debido a que el reemplazo se produjo con defectos, a continuación se muestra un ejemplo de la selección de caras usando este algoritmo. Las caras pueden ser desplazadas, es decir en una imagen captura ambos oídos, en el otro solo. Tales defectos afectan bastante mal el resultado final (en la foto, trabajando con DLib, la biblioteca anterior no siempre encontraba la cara, pero desafortunadamente las capturas de pantalla no se guardaron).

Luego, decidí usar Señales de la biblioteca Dlib. Encontramos
DlibDotNet , que está escrito en .Net Core. Para su uso en .Net Framework, se creó un proyecto intermedio en .Net Standard 2.0 con las funciones principales, búsqueda de caras y resaltado de puntos de referencia.
Código C # public int[] Face(byte[] bts, int row, int col, int st) { var img = Dlib.LoadImageData<RgbPixel> (ImagePixelFormat.Bgr, bts, (uint)row, (uint)col, (uint)st ); var face = faceDetector.Operator(img)[0]; int[] rect = { face.Left, face.Top, (int)face.Width, (int)face.Height}; return rect; } public List<int[]> FacePoints(byte[] bts, int row, int col, int st) { List<int[]> points = new List<int[]>(); var img = Dlib.LoadImageData<RgbPixel> (ImagePixelFormat.Bgr, bts, (uint)row, (uint)col, (uint)st); var face = faceDetector.Operator(img)[0]; var shape = shapePredictor.Detect(img, face); for (var i = 0; i < shape.Parts; i++) { var point = shape.GetPart((uint)i); points.Add(new int[] { point.X, point.Y }); } return points; }
Luego escribió una biblioteca en .Net Framework 4.6.1, en la que implementó toda la lógica.
Un ejemplo de cómo obtener Langmarks:

Una persona se puede distinguir con mayor precisión al encontrar los puntos más a la izquierda, derecha, superior e inferior y construir marcos en ellos.

Luego se cortó la cara de la imagen en la esquina inferior derecha y se insertó, usando el algoritmo descrito anteriormente, en la imagen: "Caballero de la mano en el pecho".
Se obtuvo el siguiente resultado.

En el próximo artículo, planeo considerar crear una máscara 3D a partir de una fotografía.