mirror of
https://github.com/maciej3031/comixify.git
synced 2026-03-11 08:54:35 +00:00
parent
b6416e6ac9
commit
6a2be40ea0
6 changed files with 57 additions and 11 deletions
|
|
@ -11,13 +11,14 @@ from api.exceptions import TooLargeFile
|
||||||
from comic_layout.comic_layout import LayoutGenerator
|
from comic_layout.comic_layout import LayoutGenerator
|
||||||
from keyframes.keyframes import KeyFramesExtractor
|
from keyframes.keyframes import KeyFramesExtractor
|
||||||
from style_transfer.style_transfer import StyleTransfer
|
from style_transfer.style_transfer import StyleTransfer
|
||||||
from utils import jj
|
from utils import jj, profile
|
||||||
|
|
||||||
|
|
||||||
class Video(models.Model):
|
class Video(models.Model):
|
||||||
file = models.FileField(blank=False, null=False, upload_to="raw_videos")
|
file = models.FileField(blank=False, null=False, upload_to="raw_videos")
|
||||||
timestamp = models.DateTimeField(auto_now_add=True)
|
timestamp = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
|
@profile
|
||||||
def download_from_youtube(self, yt_url):
|
def download_from_youtube(self, yt_url):
|
||||||
yt_pafy = pafy.new(yt_url)
|
yt_pafy = pafy.new(yt_url)
|
||||||
|
|
||||||
|
|
@ -34,10 +35,16 @@ class Video(models.Model):
|
||||||
raise TooLargeFile()
|
raise TooLargeFile()
|
||||||
|
|
||||||
def create_comic(self, frames_mode=0, rl_mode=0):
|
def create_comic(self, frames_mode=0, rl_mode=0):
|
||||||
keyframes = KeyFramesExtractor.get_keyframes(video=self, frames_mode=frames_mode, rl_mode=rl_mode)
|
keyframes, keyframes_extraction_time = KeyFramesExtractor.get_keyframes(video=self,
|
||||||
stylized_keyframes = StyleTransfer.get_stylized_frames(frames=keyframes)
|
frames_mode=frames_mode,
|
||||||
comic_image = LayoutGenerator.get_layout(frames=stylized_keyframes)
|
rl_mode=rl_mode)
|
||||||
return comic_image
|
stylized_keyframes, stylization_time = StyleTransfer.get_stylized_frames(frames=keyframes)
|
||||||
|
comic_image, layout_generation_time = LayoutGenerator.get_layout(frames=stylized_keyframes)
|
||||||
|
|
||||||
|
timings = {'keyframes_extraction_time': keyframes_extraction_time,
|
||||||
|
'stylization_time': stylization_time,
|
||||||
|
'layout_generation_time': layout_generation_time}
|
||||||
|
return comic_image, timings
|
||||||
|
|
||||||
|
|
||||||
class Comic(models.Model):
|
class Comic(models.Model):
|
||||||
|
|
@ -45,6 +52,7 @@ class Comic(models.Model):
|
||||||
video = models.ForeignKey(Video, on_delete=models.CASCADE, related_name="comic")
|
video = models.ForeignKey(Video, on_delete=models.CASCADE, related_name="comic")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@profile
|
||||||
def create_from_nparray(cls, nparray_file, video):
|
def create_from_nparray(cls, nparray_file, video):
|
||||||
if nparray_file.max() <= 1:
|
if nparray_file.max() <= 1:
|
||||||
nparray_file = (nparray_file * 255).astype(int)
|
nparray_file = (nparray_file * 255).astype(int)
|
||||||
|
|
|
||||||
15
api/views.py
15
api/views.py
|
|
@ -19,15 +19,17 @@ class Comixify(APIView):
|
||||||
|
|
||||||
video_file = serializer.validated_data["file"]
|
video_file = serializer.validated_data["file"]
|
||||||
video = Video.objects.create(file=video_file)
|
video = Video.objects.create(file=video_file)
|
||||||
comic_image = video.create_comic(
|
comic_image, timings = video.create_comic(
|
||||||
frames_mode=serializer.validated_data["frames_mode"],
|
frames_mode=serializer.validated_data["frames_mode"],
|
||||||
rl_mode=serializer.validated_data["rl_mode"]
|
rl_mode=serializer.validated_data["rl_mode"]
|
||||||
)
|
)
|
||||||
comic = Comic.create_from_nparray(comic_image, video)
|
comic, from_nparray_time = Comic.create_from_nparray(comic_image, video)
|
||||||
|
timings['from_nparray_time'] = from_nparray_time
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
"status_message": "ok",
|
"status_message": "ok",
|
||||||
"comic": comic.file.url,
|
"comic": comic.file.url,
|
||||||
|
"timings": timings,
|
||||||
}
|
}
|
||||||
# Remove to spare storage
|
# Remove to spare storage
|
||||||
video.file.delete()
|
video.file.delete()
|
||||||
|
|
@ -46,17 +48,20 @@ class ComixifyFromYoutube(APIView):
|
||||||
yt_url = serializer.validated_data["url"]
|
yt_url = serializer.validated_data["url"]
|
||||||
|
|
||||||
video = Video()
|
video = Video()
|
||||||
video.download_from_youtube(yt_url)
|
_, yt_download_time = video.download_from_youtube(yt_url)
|
||||||
video.save()
|
video.save()
|
||||||
comic_image = video.create_comic(
|
comic_image, timings = video.create_comic(
|
||||||
frames_mode=serializer.validated_data["frames_mode"],
|
frames_mode=serializer.validated_data["frames_mode"],
|
||||||
rl_mode=serializer.validated_data["rl_mode"]
|
rl_mode=serializer.validated_data["rl_mode"]
|
||||||
)
|
)
|
||||||
comic = Comic.create_from_nparray(comic_image, video)
|
comic, from_nparray_time = Comic.create_from_nparray(comic_image, video)
|
||||||
|
timings['from_nparray_time'] = from_nparray_time
|
||||||
|
timings['yt_download_time'] = yt_download_time
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
"status_message": "ok",
|
"status_message": "ok",
|
||||||
"comic": comic.file.url,
|
"comic": comic.file.url,
|
||||||
|
"timings": timings,
|
||||||
}
|
}
|
||||||
# Remove to spare storage
|
# Remove to spare storage
|
||||||
video.file.delete()
|
video.file.delete()
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
from utils import profile
|
||||||
|
|
||||||
|
|
||||||
class LayoutGenerator():
|
class LayoutGenerator():
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@profile
|
||||||
def get_layout(cls, frames):
|
def get_layout(cls, frames):
|
||||||
result_imgs = cls._pad_images(frames)
|
result_imgs = cls._pad_images(frames)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ from django.core.cache import cache
|
||||||
from skimage import img_as_ubyte
|
from skimage import img_as_ubyte
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from utils import jj
|
from utils import jj, profile
|
||||||
from keyframes_rl.models import DSN
|
from keyframes_rl.models import DSN
|
||||||
from popularity.models import PopularityPredictor
|
from popularity.models import PopularityPredictor
|
||||||
from keyframes.kts import cpd_auto
|
from keyframes.kts import cpd_auto
|
||||||
|
|
@ -26,6 +26,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class KeyFramesExtractor:
|
class KeyFramesExtractor:
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@profile
|
||||||
def get_keyframes(cls, video, gpu=settings.GPU, features_batch_size=settings.FEATURE_BATCH_SIZE,
|
def get_keyframes(cls, video, gpu=settings.GPU, features_batch_size=settings.FEATURE_BATCH_SIZE,
|
||||||
frames_mode=0, rl_mode=0):
|
frames_mode=0, rl_mode=0):
|
||||||
frames_paths, all_frames_tmp_dir = cls._get_all_frames(video, mode=frames_mode)
|
frames_paths, all_frames_tmp_dir = cls._get_all_frames(video, mode=frames_mode)
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,12 @@ from django.core.cache import cache
|
||||||
from torch.autograd import Variable
|
from torch.autograd import Variable
|
||||||
|
|
||||||
from CartoonGAN.network.Transformer import Transformer
|
from CartoonGAN.network.Transformer import Transformer
|
||||||
|
from utils import profile
|
||||||
|
|
||||||
|
|
||||||
class StyleTransfer():
|
class StyleTransfer():
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@profile
|
||||||
def get_stylized_frames(cls, frames, method="cartoon_gan", gpu=settings.GPU, **kwargs):
|
def get_stylized_frames(cls, frames, method="cartoon_gan", gpu=settings.GPU, **kwargs):
|
||||||
if method == "cartoon_gan":
|
if method == "cartoon_gan":
|
||||||
return cls._cartoon_gan_stylize(frames, gpu=gpu, **kwargs)
|
return cls._cartoon_gan_stylize(frames, gpu=gpu, **kwargs)
|
||||||
|
|
|
||||||
27
utils.py
27
utils.py
|
|
@ -1,5 +1,32 @@
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
|
||||||
def jj(*args):
|
def jj(*args):
|
||||||
return os.path.join(*args)
|
return os.path.join(*args)
|
||||||
|
|
||||||
|
|
||||||
|
class Timer(object):
|
||||||
|
def __init__(self, verbose=False):
|
||||||
|
self.verbose = verbose
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.start = time.time()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *args):
|
||||||
|
self.end = time.time()
|
||||||
|
self.secs = self.end - self.start
|
||||||
|
self.msecs = self.secs * 1000 # millisecs
|
||||||
|
|
||||||
|
|
||||||
|
def profile(fn):
|
||||||
|
@wraps(fn)
|
||||||
|
def with_profiling(*args, **kwargs):
|
||||||
|
with Timer() as t:
|
||||||
|
ret = fn(*args, **kwargs)
|
||||||
|
|
||||||
|
return ret, t.secs
|
||||||
|
|
||||||
|
return with_profiling
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue