Стилизация фотографий под мультфильмы с помощью Python

Чтобы придать фотографиям особый эффект рисованного мультфильма, можно применить на них методы машинного обучения Python

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

Существует библиотека под названием OpenCV, которая работает вкупе с программами компьютерного зрения и содержит в себе оптимизированные алгоритмы машинного обучения. Ее используют для распознавания объектов, а также для обнаружения и создания изображений высокого разрешения.

В этой статье мы разберемся, как добиться подобного мультяшного эффекта на основе Python с библиотекой OpenCV. Полную версию программы можно найти на Google Colab по этой ссылке.

Чтобы наложить на фото мультяшный эффект, следует обратить внимание на две вещи: на контуры и на цветовую палитру. Именно они отличают фотографии от мультфильмов. Для настройки этих двух компонентов нам понадобится проделать четыре основных шага:

  1. Загрузить изображение.

2. Создать контурную маску.

3. Снизить цветовую палитру.

4. Совместить контурную маску с окрашенным изображением.

Перед началом работы убедитесь, что импортировали все необходимые библиотеки (cv2, NumPy) в ваш рабочий файл.

import cv2
import numpy as np

# нужны, если вы используете Google Colab
from google.colab.patches import cv2_imshow
from google.colab import files

1. Загрузка изображения

Первым делом нужно загрузить изображение в программу. Создайте функцию read_file(), в которой будет метод cv2_imshow, чтобы загрузить выбранную фотографию в функцию:

def read_file(filename):
  img = cv2.imread(filename)
  cv2_imshow(img)
  return img

Затем вызовите эту функцию, чтобы загрузить фото:

uploaded = files.upload()
filename = next(iter(uploaded))
img = read_file(filename)

Мы выбрали это фото, чтобы проверить на нем нужный эффект.

Оригинальная фотография

2. Создание контурной маски

Обычно мультяшный стиль подчеркивает толщину линий изображения. Обнаружить контуры объектов можно с помощью функции cv2.adaptiveThreshold().

Общую функцию edge_mask() можно определить следующим образом:

def edge_mask(img, line_size, blur_value):
  gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  gray_blur = cv2.medianBlur(gray, blur_value)
  edges = cv2.adaptiveThreshold(gray_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, line_size, blur_value)
  return edges

В ней мы преобразуем изображение по градациям серого цвета. Затем уменьшаем шумы размытого изображения, используя метод cv2.medianBlur. Чем больше значение размытия, тем меньше шумов будет на картинке. После этого применим функцию adaptiveThreshold(), чтобы определить толщину контуров. Более толстые линии обозначают более толстые контуры, которые будут подчеркнуты на изображении.

После определения функции, вызовем ее и посмотрим на результат:

line_size = 7
blur_value = 7

edges = edge_mask(img, line_size, blur_value)
cv2_imshow(edges)
Обнаружение контуров

3. Снижение цветовой палитры

Основным отличием между фотографией и рисунком с точки зрения палитры является количество различимых цветов в каждом из них. Рисунок всегда имеет меньше цветов, чем фото. Именно поэтому мы применим цветовое квантование (разбиение цветов на блоки), чтобы снизить их количество на фотографии.

Цветовое квантование

Для квантования цветов мы применим метод k-средних, который доступен в библиотеке OpenCV. Чтобы облегчить себе задачу на следующих этапах, можно определить функцию color_quantization() как показано ниже:

def color_quantization(img, k):
# Преобразуем изображение
  data = np.float32(img).reshape((-1, 3))

# Задаем критерии
  criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 0.001)

# Внедряем метод k-средних
  ret, label, center = cv2.kmeans(data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
  center = np.uint8(center)
  result = center[label.flatten()]
  result = result.reshape(img.shape)
  return result

Мы можем регулировать значение k, чтобы определить количество цветов, которое хотим оставить у изображения.

total_color = 9
img = color_quantization(img, total_color)

В нашем случае значение k будет равняться 9. Результат можно увидеть ниже:

Результат цветового квантования

Двусторонний фильтр

После цветового квантования можно уменьшить шум изображения с помощью двустороннего фильтра, который придаст ему немного размытия и слегка снизит шумы:

blurred = cv2.bilateralFilter(img, d=7, sigmaColor=200,sigmaSpace=200)

Есть 3 параметра, которые можно настраивать для получения различных результатов:

  • d  —  диаметр смешения соседних пикселей;
  • sigmaColor  —  большее значение этого параметра означает большую площадь схожих цветов;
  • sigmaSpace  —  большее значение этого параметра означает, что отдаленные пиксели будут влиять друг на друга до тех пор, пока не станут похожими по оттенку.
Результат двустороннего фильтра

4. Совмещение контурной маски с окрашенным изображением

Последним шагом будет совмещение контурной маски с созданным ранее обработанным изображением. Чтобы сделать это, используйте функцию cv2.bitwise_and():

cartoon = cv2.bitwise_and(blurred, blurred, mask=edges)

Вот и все. Такой вот результат:

Финальный результат

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Tazki Anida Asrul: Turn Photos into Cartoons Using Python

Предыдущая статьяЕС ужесточает регулирование в сфере использования искусственного интеллекта
Следующая статья4 Продвинутых приема работы с функциями Python, о которых вы могли не знать