Преобразование видео в мультфильм на python и cv2
Возможно, последние несколько месяцев вы могли видеть некоторые генерации нейросетей наподобие этой:
К сожалению, не все обладают достаточным количеством времени, чтобы обрабатывать видео по одной картинке, а вычислительных мощностей многих компьютеров (например, моего ноутбука) не всегда хватает на использование stable diffusion.
Тогда попробуем сделать мультик из видео другим способом!
Сразу приведу готовый код, чтобы вы его не искали по всей статье, а по ходу буду его объяснять:
import cv2
import numpy as np
def color_quantization(img, k):
# Transform the image
data = np.float32(img).reshape((-1, 3))
# Determine criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 0.001)
# Implementing K-Means
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
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
print("количество цветов на видео (рекомендуется 10-100)")
total_color = int(input())
line_size = 7
blur_value = 7
print("создание изображений...")
count = 1
vidcap = cv2.VideoCapture('vid.mp4')
success, image = vidcap.read()
while success:
success, image = vidcap.read()
edges = edge_mask(image, line_size, blur_value)
## cv2.imshow('what',edges)
image = color_quantization(image, total_color)
##cv2.imshow('what',img)
blurred = cv2.bilateralFilter(image, d=7, sigmaColor=200,sigmaSpace=200)
##cv2.imshow('what',blurred)
cartoon = cv2.bitwise_and(blurred, blurred, mask=edges)
##cv2.imshow('what',cartoon)
cv2.imwrite(str(count) + '.jpg', cartoon)
print("корректно сохранена " + str(count) + "-ая картинка")
count += 1
import cv2
import moviepy.editor as moviepy
from time import sleep
import os
print("фотографий:")
count = int(input())
print("кадров в секунду:")
fps = int(input())
counter = 1
img_array = []
for i in range(count):
img = cv2.imread(str(counter) + ".jpg")
height, width, layers = img.shape
size = (width,height)
img_array.append(img)
if os.path.isfile(str(counter) + ".jpg"):
os.remove(str(counter) + ".jpg")
counter += 1
if counter - 1 % 10 == 0:
print("успешно превращены в видео " + str(counter) + " из " + str(count) + " фотографий")
out = cv2.VideoWriter('cartoon.avi',cv2.VideoWriter_fourcc(*'DIVX'), fps, size)
for i in range(len(img_array)):
out.write(img_array[i])
out.release()
print("готово видео в формате .avi, но вы его нигде не воспроизведёте,")
print("сейчас произойдёт конвертация в .mp4")
print("конвертация...")
print()
clip = moviepy.VideoFileClip("cartoon.avi")
clip.write_videofile("result.mp4")
print()
print("программа завершена! спасибо, что воспользовались cartooner 1.2!")
print("терминал автоматически закроется через 60 секунд")
sleep(60)
Для полноценного использования кода вы можете запускать .exe файл даже без установки python и библиотек, инструкция по использованию в конце статьи.
Чтобы вы понимали, что происходит, для примера возьмём видео с ютуба.
Обозначим основные этапы:
Для каждого изображения из видео нужно превратить его в изображение типа «мультик»
Соединить фото в видео
Сделать видео воспроизводимым
Первое — импортировать необходимые библиотеки:
import cv2
import numpy as np
Далее необходимо создать функции:
def color_quantization(img, k):
# Transform the image
data = np.float32(img).reshape((-1, 3))
# Determine criteria
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 0.001)
# Implementing K-Means
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
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
Объяснение их работы вы найдёте в статье. Это главный ресурс, который я использовал для создания итоговой программы.
То же самое можно сказать про код сохранения и обработки:
print("количество цветов на видео (рекомендуется 10-100)")
total_color = int(input())
line_size = 7
blur_value = 7
print("создание изображений...")
count = 1
vidcap = cv2.VideoCapture('vid.mp4')
success, image = vidcap.read()
while success:
success, image = vidcap.read()
edges = edge_mask(image, line_size, blur_value)
image = color_quantization(image, total_color)
blurred = cv2.bilateralFilter(image, d=7, sigmaColor=200,sigmaSpace=200)
cartoon = cv2.bitwise_and(blurred, blurred, mask=edges)
cv2.imwrite(str(count) + '.jpg', cartoon)
print("корректно сохранена " + str(count) + "-ая картинка")
count += 1
Важно описать то, что есть в этом коде, но чего нет в вышеупомянутой статье. Это строка 26, отвечающая за сохранение изображения, а также 8, 9 и 12 строки, отвечающие за извлечение изображений из видео. Это — первая часть программы.
Второй файл отвечает за сборку фото в видео и удаление полученных фото. Впрочем, добавлена функция сборки с начала до определённой фотографии.
Как обычно, импорт библиотек:
import cv2
import moviepy.editor as moviepy
from time import sleep
import os
Приём данных от пользователя:
print("фотографий:")
count = int(input())
print("кадров в секунду:")
fps = int(input())
Далее — составление массива с фото и удаление этих фотографий, иначе вы получите полтысячи ненужных фотографий:
counter = 1
img_array = []
for i in range(count):
img = cv2.imread(str(counter) + ".jpg")
height, width, layers = img.shape
size = (width,height)
img_array.append(img)
if os.path.isfile(str(counter) + ".jpg"):
os.remove(str(counter) + ".jpg")
counter += 1
if counter - 1 % 10 == 0:
print("успешно превращены в видео " + str(counter) + " из " + str(count) + " фотографий")
Если вы хотите использовать полученные изображения, сотрите 8 и 9 строки.
Сборка видео из массива:
out = cv2.VideoWriter('cartoon.avi',cv2.VideoWriter_fourcc(*'DIVX'), fps, size)
for i in range(len(img_array)):
out.write(img_array[i])
out.release()
print("готово видео в формате .avi, но вы его нигде не воспроизведёте,")
Собственно, конвертация и сохранение:
print("сейчас произойдёт конвертация в .mp4")
print("конвертация...")
print()
clip = moviepy.VideoFileClip("cartoon.avi")
clip.write_videofile("result.mp4")
print()
print("программа завершена! спасибо, что воспользовались cartooner 1.2!")
print("терминал автоматически закроется через 60 секунд")
sleep(60)
Вот и всё!
Теперь проведём небольшое исследование модели, и получим видео:
https://disk.yandex.ru/d/fhhrK0KRp5UDTQ
Заметно, что чем больше цветов, тем лучше, но и время генерации увеличивается пропорционально.
Теперь рассмотрим использование файлов .exe из Яндекс диска. Скачиваем файлы, помещаем в отдельную папку. В эту же папку помещаем видео для превращения, переименовываем в vid.mp4, запускаем cartooner.exe, следуем инструкции. После окончания выполнения программы запускаем videoizer.exe и снова следуем инструкции. После выполнения программы вы получите: видео в формате avi, видео в формате mp4, возможно, несколько фотографий. Видео result.mp4 и есть результат работы программы. Помните, что при повторной генерации видео результата заместится новым.