Хабрахабр

DeepFake своими руками [часть 1]

Не смотря на все прелести интернета, у него есть много минусов, и один из самых ужасных – это введения людей в заблуждение. Кликбейт, монтаж фотографий, ложные новости – все эти инструменты активно используются для обмана обычных пользователей в мировой сети, но в последние годы набирает обороты новый потенциально опасный инструмент, известный как DeepFake.

Впервые о ней я узнал из доклада одного из спикеров на “AI Conference 2018”. Меня данная технология заинтересовала недавно. Ссылка на подборку видео созданных с помощью этой технологии. Там демонстрировалось видео, в котором по аудиозаписи алгоритм сгенерировал видео с обращением Барака Обамы. Для этого я решил написать DeepFake на языке C#. Результаты меня сильно вдохновили, и мною было принято решение лучше разобраться с данной технологией, чтобы в будущем противодействовать ей. В итоге получил такой результат.

image

Приятного чтения!

Общие принципы

Из него я узнал как, именно, работает замена лица на видео. Отправной точкой стал этот проект.

1) Загрузка картинки с которой мы будем брать лицо
2) Извлечение лица
3) Создание 3D маски
4) Видео разбивается на кадры
5) Вычисляется область локализации лица в кадре
6) Вычисляется ракурс и выражение лица
7) Перенос поворота и выражения лица на 3D модель
8) Рендеринг
9) Замена реального лица на кадре результатом рендеринга

Видео с демонстрацией работы проекта «FaceSwap»:

Работу я решил разбить на 3 части:
1-я) Замена лица на одном фото лицом с другого, без использования 3D маски
2-я) Доработка замены с применением 3D маски
3-я) Обработка видео

Замену лица на фото можно разложить на следующие пункты:

1) Загрузка картинки с которой мы будем брать лицо
2) Загрузка картинки на которую будем проецировать лицо
3) Извлечение лиц
4) Масштабирование лица взятого с изображения 2 к пропорциям в изображении 1
5) Замена лица в картинке 1 на лицо в картинке 2

Встраивание одного изображения в другое

Для демонстрации встраивания в оригинальном проекте используется скрипт zad1.py.
В результате создается файл «eyeHandBlend.jpg», где глаз встраивается в руку. Первое с чего я начал работу — это встраивание одного изображения в другое.

eyeHandBlend.jpg

Вторая делает края картинки с нужным лицом прозрачными уменьшая прозрачность по мере приближения к центру изображения. Данный алгоритм состоит из 2х частей, первая переносит цвет из участка с лицом на исходной картинке, на то лицо, которое необходимо вставить.

Первую часть я полностью перенес из оригинального проекта.

Код на питоне

def colorTransfer(src, dst, mask): transferredDst = np.copy(dst) #indeksy nie czarnych pikseli maski maskIndices = np.where(mask != 0) #src[maskIndices[0], maskIndices[1]] zwraca piksele w nie czarnym obszarze maski maskedSrc = src[maskIndices[0], maskIndices[1]].astype(np.int32) maskedDst = dst[maskIndices[0], maskIndices[1]].astype(np.int32) meanSrc = np.mean(maskedSrc, axis=0) meanDst = np.mean(maskedDst, axis=0) maskedDst = maskedDst - meanDst maskedDst = maskedDst + meanSrc maskedDst = np.clip(maskedDst, 0, 255) transferredDst[maskIndices[0], maskIndices[1]] = maskedDst return transferredDst

Код перенесенный на C#

static public Bitmap NewColor(Bitmap src, Bitmap ins, Rectangle r) .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); }

2 \cdot W})^2+(\frac{j-C_h}{H})^2 \\ \alpha = 255 \cdot exp({-k\cdot r}^n)$" data-tex="inline"/> Чтобы края были более прозрачными, чем центральная часть изображения, для расчета альфа канала, была введена радиально-базисная функция следующего вида:
<img src="https://habrastorage.org/getpro/habr/formulas/4c7/ee3/aaf/4c7ee3aaf57278357f490d24ca42647f.svg" alt="$\\k = 190 \\n = 3 \\r= (\frac{i-C_w}{1.

k и n были подобраны эмпирически.
i — индекс пикселя по оси OX
j — индекс пикселя по оси OY
$C_w$ — компонента x центра изображения
$C_h$ — компонента y центра изображения

В итоге я получил следующий результат:
eyeHandBlend.jpg

Поиск лица

Для поиска лица на фото существует множество алгоритмов:

  • Алгоритм Виолы-Джонса(каскады Хаара)
  • Hog+SVM
  • R-CNN
  • Fast R-CNN
  • Faster R-CNN
  • Yolo

выделял лица не точно. Изначально использовался алгоритм Виолы-Джонса, но он оказался не достаточно точным, т.к. Лица могут быть смещены, т.е. Область выделения одного лица не совпадала с областью выделения второго, из-за чего замена происходила с дефектами, пример выделения лиц с помощь данного алгоритма показан ниже. Такие дефекты довольно плохо сказываются на конечном результате (на фото работа с DLib, предыдущая библиотека не всегда находила лицо, но к сожалению скриншоты не сохранились).
в на одном изображении оно захватывает оба уха, на другом только одно.

Нашел DlibDotNet, который написан на . Далее я решил использовать Landmarks из библиотеки Dlib. Для использования в . Net Core. Net Standard 2. Net Framework был создан промежуточный проект на . 0 с основными функциями, поиска лица и выделения Landmarks.

Код на 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;
}

Net Framework 4. После чего написал библиотеку на . 1, в которой реализовал всю логику. 6.

Пример получения Langmarks:

Лицо можно выделить точнее, находя самую левую, правую, верхнюю и нижнюю точки и строя рамки по ним.

Потом лицо вырезалось из картинки в правом нижнем углу и вставлялось, с помощью описанного выше алгоритма, в картину: «Caballero de la mano en el pecho».
Был получен следующий результат.
image

В следующей статье я планирую рассмотреть создание 3D маски по фотографии.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть