• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Замена лиц на документах с помощью нейросети

CognitoInc

(L3) cache
Пользователь
Регистрация
22.01.2024
Сообщения
155
Реакции
346
Nejroseti-1536x864.jpg
Что ж, дамы и господа, в последнее время нейронные сети захватывают все больше сфер деятельности, и в данной теме я хочу немного помочь вам разобраться в том, как устроено обучение нейронных сетей, работающих с графикой, а также привести один из примеров того, как можно применить это на практике. В данном случае - в переделывании документов, удостоверяющих личность.
Код, который будет предоставлен, не претендует на идеальное качество. Он написан с целью привести пример того, как использовать нейронные сети и обучать их. Замена лица также не происходит идеально, так как для этого требуется хорошее обучение. А для хорошего обучения требуются вычислительные мощности и терпение при разметке обучающих материалов. Но обо всем по порядку.

Для начала нам нужно разобраться, как мы будем определять лица на документах для последующей замены. В этом нам поможет библиотека на Python с названием "ultralytics". Она содержит в себе метод компьютерного зрения под названием YOLO. В данный момент мы будем использовать YOLOv8 - это самая последняя и лучшая версия, которая опережает предыдущие в скорости определения объекта и в точности определения объектов.

Теперь следует понять, как обучать нейронную сеть на YOLO. Однако разработчики YOLO уже предоставляют обученные модели, способные успешно определять огромное количество объектов.
Для начала я покажу сам код программы, а затем разберу каждый участок кода подробнее. В конце предоставлю инструкцию о том, как самому обучить нейронную сеть на своих данных.
Код:
import os
from ultralytics import YOLO
from PIL import Image, ImageFilter

# Загрузка обученной модели
model = YOLO("yolov8n.pt")

# Загрузить изображение с лицом, которое вы хотите вставить
insert_image = Image.open("insert_image.png").convert("RGBA")

# Папка с документами
input_folder = "docs"

# Создаем папку для результатов, если она не существует
output_folder = "results"
os.makedirs(output_folder, exist_ok=True)

# Перебор файлов в папке docs
for filename in os.listdir(input_folder):
    if filename.endswith(".png") or filename.endswith(".jpg"):
        # Загружаем документ
        source_image = Image.open(os.path.join(input_folder, filename))

        # Определяем объекты на изображении
        results = model.predict(source_image)

        # Создаем копию исходного изображения для работы
        result_img = source_image.copy()

        result = results[0]

        # Был ли обнаружен объект "person" с уверенностью больше или равной 0.8
        person_detected = False

        # Перебираем найденные объекты
        for box in result.boxes:
            class_id = result.names[box.cls[0].item()]
            cords = box.xyxy[0].tolist()
            cords = [round(x) for x in cords]
            conf = round(box.conf[0].item(), 2)

            print("Object type:", class_id)
            print("Coordinates:", cords)
            print("Probability:", conf)

            # Если найден объект с идентификатором 0 (person) и уверенность больше или равна 0.8, вставляем другую картинку на те же координаты
            if class_id == "person" and conf >= 0.8:
                # Получаем координаты объекта person
                x_min, y_min, x_max, y_max = cords

                # Вычисляем размеры вставляемого изображения
                insert_width = x_max - x_min
                insert_height = y_max - y_min

                # Изменяем размер вставляемого изображения
                insert_resized = insert_image.resize((insert_width, insert_height))

                # Вставляем изображение на те же координаты
                result_img.paste(insert_resized, (x_min, y_min), mask=insert_resized)

                # Объект был обнаружен
                person_detected = True

        # Если объект "person" не был обнаружен, или не был обнаружен с уверенностью меньше 0.8, не сохраняем измененное изображение
        if person_detected:
            # Применяем размытие к результату
            blurred_result_img = result_img.filter(ImageFilter.GaussianBlur(radius=1))
            blurred_result_img.save(os.path.join(output_folder, f"blurred_result_{filename}"))

print("Процесс завершен. Результаты сохранены в папке 'results'.")

Теперь будем разбирать этот код по частям:
Код:
model = YOLO("yolov8n.pt")
Данную строку всегда нужно указывать первым делом. Она отвечает за загрузку обученной модели, благодаря которой и происходит определение объектов. Можно сказать, это мозг нейронной сети. Если указать yolov8n.pt, то тогда при запуске программы будет подкачиваться готовая обученная модель, которую любезно предоставили разработчики YOLO. Данная модель называется нано-моделью. Из готовых решений от разработчиков есть также YOLOv8s (маленькая модель) и YOLOv8m (средняя модель). Они отличаются количеством данных, на которых были обучены, и соответственно точностью определения. Чем большее количество данных было поглащено, тем сильнее будет нагружаться система при определении нужных нам объектов но и точность определения будет выше. Подходящую модель нужно выбирать под конкретные задачи и мощность железа. Лично я всегда использую yolov8n, так как это легковесная модель, которая достаточно хорошо определяет, при этом не нагружая систему. У остальных же моделей разница в точности определения, по моему мнению, не сильно повышается, зато они потребляют больше ресурсов компьютера, особенно это заметно на слабых системах.
Код:
 # Загружаем документ
        source_image = Image.open(os.path.join(input_folder, filename))

        # Определяем объекты на изображении
        results = model.predict(source_image)
Тут все просто, выбираем документ (допустим паспорт) который находится в папка docs а затем вызываем model.predict из библиотеки ultralytics для загрузки наших документов в Yolo с последующим определением объектов
Код:
class_id = result.names[box.cls[0].item()]
            cords = box.xyxy[0].tolist()
            cords = [round(x) for x in cords]
            conf = round(box.conf[0].item(), 2)
Первая строка отвечает за извлечение класса объекта (id). В используемой в данном коде модели есть 80 типов объектов, и первый объект имеет id 0, который является человеком.
Вторая строка отвечает за извлечение координат прямоугольника, которым выделяется объект.
Третья строка округляет координаты.
Четвертая строка определяет точность определения того или иного объекта. Если проще, то эти данные показывают, насколько нейронная сеть уверена в том, что объект, который она нашла, является тем объектом, которым она его считает.

Код:
if class_id == "person" and conf >= 0.8:
Эта строка устанавливает условие: "если объект является человеком (person) и нейронная сеть определила это с точностью не менее 0.8". Если это условие выполняется, то получаются координаты прямоугольника, в котором находится обнаруженный объект. Затем вычисляются размеры вставляемого изображения (нового лица), которое изменяется до таких размеров, чтобы поместиться внутри прямоугольника, где был найден объект. Затем это новое лицо вставляется на место старого.
Также в коде присутствует добавление размытия на получившуюся новую картинку, чтобы вставленное изображение лица выглядело более естественно. Однако это уже работа другой библиотеки, не связанной с нейронной сетью, а просто инструментом для работы с изображениями.
Код:
{0: 'person',
 1: 'bicycle',
 2: 'car',
 3: 'motorcycle',
 4: 'airplane',
 5: 'bus',
 6: 'train',
 7: 'truck',
 8: 'boat',
 9: 'traffic light',
 10: 'fire hydrant',
 11: 'stop sign',
 12: 'parking meter',
 13: 'bench',
 14: 'bird',
 15: 'cat',
 16: 'dog',
 17: 'horse',
 18: 'sheep',
 19: 'cow',
 20: 'elephant',
 21: 'bear',
 22: 'zebra',
 23: 'giraffe',
 24: 'backpack',
 25: 'umbrella',
 26: 'handbag',
 27: 'tie',
 28: 'suitcase',
 29: 'frisbee',
 30: 'skis',
 31: 'snowboard',
 32: 'sports ball',
 33: 'kite',
 34: 'baseball bat',
 35: 'baseball glove',
 36: 'skateboard',
 37: 'surfboard',
 38: 'tennis racket',
 39: 'bottle',
 40: 'wine glass',
 41: 'cup',
 42: 'fork',
 43: 'knife',
 44: 'spoon',
 45: 'bowl',
 46: 'banana',
 47: 'apple',
 48: 'sandwich',
 49: 'orange',
 50: 'broccoli',
 51: 'carrot',
 52: 'hot dog',
 53: 'pizza',
 54: 'donut',
 55: 'cake',
 56: 'chair',
 57: 'couch',
 58: 'potted plant',
 59: 'bed',
 60: 'dining table',
 61: 'toilet',
 62: 'tv',
 63: 'laptop',
 64: 'mouse',
 65: 'remote',
 66: 'keyboard',
 67: 'cell phone',
 68: 'microwave',
 69: 'oven',
 70: 'toaster',
 71: 'sink',
 72: 'refrigerator',
 73: 'book',
 74: 'clock',
 75: 'vase',
 76: 'scissors',
 77: 'teddy bear',
 78: 'hair drier',
 79: 'toothbrush'}

Ну а теперь поговорим о самостоятельном обучении нейронной сети на своих собственных данных, в нашем случае на своих картинках.
1. Первое что нам нужно так это налутать фотографии которые в последствии будут использованы для разметки а затем для обучения. Просто заходим в гугл картинки и выкачиваем все фотографии такого типа:
1713492103490.png


2. Теперь нам понадобится зайти на сайт https://app.roboflow.com/ и зарегестрироваться. На главной странице данного сайта нам нужно создать новый проект, нажимаем на кнопку:
1713492673384.png


3. Затем, в открывшемся окне мы можем ввести абсолютно любое название проекта, а в Annotation Group нам нужно ввести названия объектов, которые мы будем выделять. Можно, конечно, использовать рандомные символы, но при наличии множества объектов можно запутаться.
1713492855255.png


4. После создания проекта нам потребуется загрузить наши изображения, на которых нейронная сеть в последствии будет обучаться определять лица людей. По моим наблюдениям, для адекватного определения объектов нужно не менее 1500 изображений. Также изображения не должны иметь один и тот же постоянный задний фон. Так же не является вариантом простое размножение одного и того же изображения, так как нейронная сеть деградирует и будет распознавать объект только на том изображении, которое было загружено. Поэтому очень важно иметь разнообразие изображений.
1713493085576.png

1713493155561.png


5. После сохранения проекта ждем пока все наши изображения загрузятся на сервера roboflow а затем нажимаем на "Annotate images" и приступаем к самой нудной части всей разработки какой либо нейронной сети - к разметке (после сотни с лишним тысяч размеченных фотографий у меня начинается нервный тик от одной только мысли о том что мне придется делать это снова), можно конечно обойтись и без ручной разметки, благо в интернете да и на том же roboflow есть уже готовые датасеты, но проблема таких датасетов в том что они сделаны на фотографиях ужасного качества и разметка тоже сделана автоматическая, из-за чего она неточная и соответственно результаты обучения будут не утешительными, поэтому всегда делайте разметку вручную
1713493342081.png


6. Разметка это в принципе не сложно технически, вам просто на просто нужно как в пайнте выделять все нужные вам объекты на фотографии и назначать им классы:
1713494113996.png

1713494186148.png


7. После того как вы закончили разметку, время собрать из всего этого датасет нажатием на кнопку Add images to Dataset и распределяем фотографии в таком же процентом соотношении как и на скриншоте ниже:
1713494403619.png

1713494654307.png


Что же означают эти ваши "Train", "Valid", "Test" ? Сейчас объясню.
  1. Train это всегда самый большой набор изображений, именно на них нейронка смотрит разметку и обучается.
  2. Valid позволяет сравнить то как нейросеть определила самостоятельно и то как на самом деле.
  3. Test это то на чем нейросеть проверяет свои знания и пытается определить объекты.
8. Теперь, когда мы разобрались с "Train", "Valid", "Test" можно приступать к последнему шагу в сборке датасета в полноценный набор данных для обучения, нужно нажать на кнопку как показано на скриншоте:
1713496221489.png


9. После нажатия на кнопку откроется меню с редактированием размера изображений, аугментацией и прочим.
1713496352174.png

Размеры советую ставить квадратными и не очень большими иначе, если изображения будут больших размеров, это скажется на скорости работы софта, 640 на 640 это можно сказать ГОСТ и я его постоянно придерживаюсь.

1713496789117.png


10. Далее следует меню аугментации, что же это опять такое, спросите вы? А я отвечу - аугментация позволяет увеличить количество изображений для обучения в несколько раз. Она берет ваши изображения и добавляет на них различные помехи, например, блюр, шум, поворот картинки, добавление черных квадратов на фото и т.д. Это позволяет нейронной сети получить большую вариативность в ваших скриншотах, больше различных ситуаций, где нужно определить объект, но с аугментацией также не стоит перебарщивать, т.к. если накидать множество эффектов, объект может быть супер плохо виден или вообще полностью перекрыт каким-либо эффектом, а разметка при этом остается на месте. Соответственно, нейронка запутается и в последствии ее может триггерить на объекты, которых на самом деле нету. Лично я добавляю лишь небольшой поворот фотографий и темные квадратные области.

11. На этом подготовка датасета закончена и осталось его только скачать. Нам понадобится прямая ссылка на датасет так что просто нажимаем на кнопки как показано на скриншотах:
1713497036588.png

1713497072989.png

1713497109906.png

После того, как вы скачаете датасет, осталось только обучить на нем модель.
Заходим в папку с нашим распакованным датасетом и открываем в этой папке cmd.
1713497386979.png

1713497501481.png

Вводим команду "yolo task=detect mode=train imgsz=640 data=Путь_до_файла_data.yaml epochs=45 batch=8 name=yolov8n_v8_50" Все, что вам нужно понимать в этой команде, так это epochs. Эпохи - это количество раз, сколько нейронка будет прогонять весь ваш датасет и с каждым разом у нее будет все больше данных о верном выборе и определении объекта на изображении, по моим наблюдениям, 45-50 эпох самое то для 1500 изображений. Если переборщить с их количеством, то нейронная сеть начнет триггерить на всякий мусор, а этого нам не надо. После окончания обучения на датасете у вас появится файл с форматом .pt, это и есть наша обученная модель, теперь мы можем смело ее вставлять в проект вместо той модели, которая предоставлена разработчиками yolo.

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


Статья написана CognitoInc специально для форума xss.pro
 

Вложения

  • main.zip
    1.4 КБ · Просмотры: 41
Пожалуйста, обратите внимание, что пользователь заблокирован
какие мощностя нужны для работы этой нейронки?
 
какие мощностя нужны для работы этой нейронки?
Yolo v8 предназначена для видеокарт NVIDIA, но и на процессорах работает если ей не требуется обработка по 30-40 кадров в секунду.
Для такой задачи как у меня в теме ей скорее всего хватит любого процессора на i5 и выше. Сразу говорю, мой код как пример, нужно дописать много кода по работе с изображением по типу, наложения эффектов а так же надо как-то придумать что бы стирало предыдущее лицо с фотографии т.к иногда старое лицо немного выпирает под новым. На счет этого я пока ничего не предумал, но опять же, это уже нужно разбираться с библиотекой которая с изображениями работает
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Я возможно дурак, однако, а какой толк от пассов которых даже в базах нету, тоби ж ни рейтинга ни истории мфо и тп
Но в то же время как просто описания принципа ai, автору респект.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
1715019145822.png

:D:D:D я не понимаю, почему я везде вижу конкретно этого дропа везде?
кто ещё его замечал?)
я же не один такой
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх