added arbitrary upscaling ratio/resolution support

This commit is contained in:
K4YT3X 2020-09-09 13:07:42 -04:00
parent 8b7e9f959b
commit 7059852586
16 changed files with 576 additions and 380 deletions

View File

@ -5,8 +5,8 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"POT-Creation-Date: 2020-05-22 17:51-0400\n"
"PO-Revision-Date: 2020-05-22 17:54-0400\n"
"POT-Creation-Date: 2020-09-09 13:04-0400\n"
"PO-Revision-Date: 2020-09-09 13:06-0400\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: zh_CN\n"
@ -14,234 +14,230 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: pygettext.py 1.5\n"
"X-Generator: Poedit 2.3.1\n"
"X-Generator: Poedit 2.4.1\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: progress_monitor.py:42
msgid "Upscaling Progress"
msgstr "放大进度"
#: progress_monitor.py:37
msgid "Processing: {} (pass {}/{})"
msgstr "正在处理:{}(进度)"
#: upscaler.py:110
#: upscaler.py:144
msgid "Specified or default cache directory is a file/link"
msgstr "指定或默认的缓存目录是文件/链接"
#: upscaler.py:116
#: upscaler.py:150
msgid "Creating cache directory {}"
msgstr "创建缓存目录 {}"
#: upscaler.py:119
#: upscaler.py:153
msgid "Unable to create {}"
msgstr "无法创建 {}"
#: upscaler.py:124
#: upscaler.py:158
msgid "Extracted frames are being saved to: {}"
msgstr "提取的帧将被保存到:{}"
#: upscaler.py:126
#: upscaler.py:160
msgid "Upscaled frames are being saved to: {}"
msgstr "已放大的帧将被保存到:{}"
#: upscaler.py:136
#: upscaler.py:170
msgid "Cleaning up cache directory: {}"
msgstr "清理缓存目录:{}"
#: upscaler.py:141
#: upscaler.py:175
msgid "Unable to delete: {}"
msgstr "无法删除:{}"
#: upscaler.py:147 upscaler.py:162 upscaler.py:173
#: upscaler.py:181 upscaler.py:196 upscaler.py:207
msgid "Input and output path type mismatch"
msgstr "输入和输出路径类型不匹配"
#: upscaler.py:148
#: upscaler.py:182
msgid "Input is multiple files but output is not directory"
msgstr "输入是多个文件,但输出不是目录"
#: upscaler.py:152
#: upscaler.py:186
msgid "Input path {} is neither a file nor a directory"
msgstr "输入路径 {} 既不是文件也不是目录"
#: upscaler.py:156 upscaler.py:178
#: upscaler.py:190 upscaler.py:212
msgid "Input directory and output directory cannot be the same"
msgstr "输入目录和输出目录不能相同"
#: upscaler.py:163
#: upscaler.py:197
msgid "Input is single file but output is directory"
msgstr "所选的输入路径是单个文件,但输出路径是目录"
#: upscaler.py:166
#: upscaler.py:200
msgid "No suffix found in output file path"
msgstr "在输出文件路径中未找到后缀"
#: upscaler.py:167
#: upscaler.py:201
msgid "Suffix must be specified"
msgstr "必须指定文件后缀"
#: upscaler.py:174
#: upscaler.py:208
msgid "Input is directory but output is existing single file"
msgstr "输入是目录,但输出是现有的单个文件"
#: upscaler.py:183
#: upscaler.py:217
msgid "Input path is neither a file nor a directory"
msgstr "输入路径既不是文件也不是目录"
#: upscaler.py:192
#: upscaler.py:226
msgid "FFmpeg or FFprobe cannot be found under the specified path"
msgstr "在指定的路径下找不到 FFmpeg 或 FFprobe"
#: upscaler.py:193 upscaler.py:203
#: upscaler.py:227 upscaler.py:237
msgid "Please check the configuration file settings"
msgstr "请检查配置文件设置"
#: upscaler.py:202
#: upscaler.py:236
msgid "Specified driver executable directory doesn't exist"
msgstr "指定驱动的可执行文件不存在"
#: upscaler.py:229
#: upscaler.py:263
msgid "Failed to parse driver argument: {}"
msgstr "解析驱动程序参数失败:{}"
#: upscaler.py:261
#: upscaler.py:283
msgid "Unrecognized driver: {}"
msgstr "无法识别的驱动名称:{}"
#: upscaler.py:301
#: upscaler.py:323
msgid "Starting progress monitor"
msgstr "启动进度监视器"
#: upscaler.py:306
#: upscaler.py:328
msgid "Starting upscaled image cleaner"
msgstr "启动已放大图像清理程序"
#: upscaler.py:315 upscaler.py:332
#: upscaler.py:337 upscaler.py:354
msgid "Killing progress monitor"
msgstr "终结进度监视器"
#: upscaler.py:318 upscaler.py:335
#: upscaler.py:340 upscaler.py:357
msgid "Killing upscaled image cleaner"
msgstr "终结已放大图像清理程序"
#: upscaler.py:339
#: upscaler.py:361
msgid "Terminating all processes"
msgstr "正在终止所有进程"
#: upscaler.py:346
#: upscaler.py:368
msgid "Main process waiting for subprocesses to exit"
msgstr "主进程开始等待子进程结束"
#: upscaler.py:365 upscaler.py:369
#: upscaler.py:387 upscaler.py:391
msgid "Subprocess {} exited with code {}"
msgstr "子进程 {} 结束,返回码 {}"
#: upscaler.py:375
#: upscaler.py:397
msgid "Stop signal received"
msgstr "收到停止信号"
#: upscaler.py:380
#: upscaler.py:402
msgid "Subprocess execution ran into an error"
msgstr "子进程执行遇到错误"
#: upscaler.py:410
#: upscaler.py:432
msgid "Loading files into processing queue"
msgstr "正在将文件添加到处理队列中"
#: upscaler.py:415
msgid "Loading files from multiple paths"
msgstr "正在从多个路径中导入文件"
#: upscaler.py:416 upscaler.py:435 upscaler.py:442
#: upscaler.py:433
msgid "Input path(s): {}"
msgstr "输入路径:{}"
#: upscaler.py:434
msgid "Loading single file"
msgstr "正在导入单个文件"
#: upscaler.py:441
msgid "Loading files from directory"
msgstr "正在从文件夹中导入文件"
#: upscaler.py:455
msgid "Loaded files into processing queue"
msgstr "文件已添加到处理队列"
#: upscaler.py:458
msgid "Input file: {}"
msgstr "输入文件:{}"
#: upscaler.py:485
msgid "Starting to upscale image"
msgstr "开始放大图像"
#: upscaler.py:488 upscaler.py:550
msgid "Upscaling completed"
msgstr "放大完成"
#: upscaler.py:502
msgid "Reading video information"
msgstr "读取视频信息"
#: upscaler.py:516
msgid "Aborting: No video stream found"
msgstr "程序中止:文件中未找到视频流"
#: upscaler.py:521
msgid "Framerate: {}"
msgstr "帧率:{}"
#: upscaler.py:538
msgid "Unsupported pixel format: {}"
msgstr "不支持的像素格式:{}"
#: upscaler.py:548
msgid "Starting to upscale extracted frames"
msgstr "开始对提取的帧进行放大"
#: upscaler.py:555
#: upscaler.py:495
msgid "File {} ({}) neither an image nor a video"
msgstr "文件 {} {} 既不是图片也不是视频"
#: upscaler.py:556
#: upscaler.py:496
msgid "Skipping this file"
msgstr "将跳过此文件"
#: upscaler.py:566
#: upscaler.py:521
msgid "Loaded files into processing queue"
msgstr "文件已添加到处理队列"
#: upscaler.py:524
msgid "Input file: {}"
msgstr "输入文件:{}"
#: upscaler.py:535
msgid "Starting to upscale image"
msgstr "开始放大图像"
#: upscaler.py:538 upscaler.py:689
msgid "Upscaling completed"
msgstr "放大完成"
#: upscaler.py:552
msgid "Reading video information"
msgstr "读取视频信息"
#: upscaler.py:564
msgid "Aborting: No video stream found"
msgstr "程序中止:文件中未找到视频流"
#: upscaler.py:571
msgid "Framerate: {}"
msgstr "帧率:{}"
#: upscaler.py:575
msgid "Getting total number of frames in the file"
msgstr "正在获取文件中的总帧数"
#: upscaler.py:650
msgid "Upscaling jobs queue: {}"
msgstr "放大工作队列:{}"
#: upscaler.py:666
msgid "Unsupported pixel format: {}"
msgstr "不支持的像素格式:{}"
#: upscaler.py:676
msgid "Starting to upscale extracted frames"
msgstr "开始对提取的帧进行放大"
#: upscaler.py:696
msgid "Converting extracted frames into GIF image"
msgstr "正在将提取的帧转换为 GIF"
#: upscaler.py:570 upscaler.py:579
#: upscaler.py:700 upscaler.py:709
msgid "Conversion completed"
msgstr "转换已完成"
#: upscaler.py:575
#: upscaler.py:705
msgid "Converting extracted frames into video"
msgstr "正在将提取的帧转换为视频"
#: upscaler.py:583
#: upscaler.py:713
msgid "Migrating audio, subtitles and other streams to upscaled video"
msgstr "正在将音频、字幕和其他流迁移到放大后的视频"
#: upscaler.py:593
#: upscaler.py:723
msgid "Failed to migrate streams"
msgstr "迁移流失败"
#: upscaler.py:594
#: upscaler.py:724
msgid "Trying to output video without additional streams"
msgstr "正在尝试输出不含其他流的视频"
#: upscaler.py:610
#: upscaler.py:740
msgid "Output video file exists"
msgstr "输出目标文件已存在"
#: upscaler.py:614
#: upscaler.py:744
msgid "Created temporary directory to contain file"
msgstr "为文件创建了临时目录"
#: upscaler.py:617
#: upscaler.py:747
msgid "Writing intermediate file to: {}"
msgstr "正在将中间视频文件写入至:{}"
#: video2x.py:85
#: video2x.py:86
msgid ""
"Video2X CLI Version: {}\n"
"Upscaler Version: {}\n"
@ -257,74 +253,108 @@ msgstr ""
"GitHub 主页https://github.com/k4yt3x/video2x\n"
"联系方式k4yt3x@k4yt3x.com"
#: video2x.py:108
#: video2x.py:109
msgid "Video2X Options"
msgstr "Video2X 选项"
#: video2x.py:109
#: video2x.py:110
msgid "show this help message and exit"
msgstr "显示此帮助消息并退出"
#: video2x.py:110
#: video2x.py:117
msgid "source video file/directory"
msgstr "源视频文件/目录"
#: video2x.py:111
#: video2x.py:118
msgid "output video file/directory"
msgstr "输出视频文件/目录"
#: video2x.py:112
#: video2x.py:120
msgid "video2x config file path"
msgstr "video2x 配置文件路径"
#: video2x.py:114
#: video2x.py:122
msgid "log file path"
msgstr "日志文件路径"
#: video2x.py:124
msgid "disable logging"
msgstr "禁用日志"
#: video2x.py:125
msgid "display version, lawful information and exit"
msgstr "显示版本和法律信息并退出"
#: video2x.py:117
#: video2x.py:128
msgid "Upscaling Options"
msgstr "视频放大选项"
#: video2x.py:118
msgid "upscaling driver"
msgstr "视频放大驱动"
#: video2x.py:119
#: video2x.py:129
msgid "scaling ratio"
msgstr "缩放比"
#: video2x.py:120
#: video2x.py:130
msgid "output width"
msgstr "输出宽度"
#: video2x.py:131
msgid "output height"
msgstr "输出高度"
#: video2x.py:132
msgid "upscaling driver"
msgstr "视频放大驱动"
#: video2x.py:133
msgid "number of processes to use for upscaling"
msgstr "并发进程数"
#: video2x.py:121
#: video2x.py:134
msgid "preserve extracted and upscaled frames"
msgstr "保留提取的和放大的帧"
#: video2x.py:161
#: video2x.py:174
msgid "This file cannot be imported"
msgstr "此文件无法被当作模块导入"
#: video2x.py:236
#: video2x.py:190
msgid "Specify either scaling ratio or scaling resolution, not both"
msgstr "您只能指定缩放比或输出分辨率两者之一"
#: video2x.py:194
msgid "Only one of scaling width and scaling height is specified"
msgstr "输出高度和宽度仅有其中一项被指定"
#: video2x.py:200
msgid "Redirecting console logs to {}"
msgstr "将控制台日志重定向到 {}"
#: video2x.py:276
msgid "Program completed, taking {} seconds"
msgstr "程序执行完毕,总计花费 {} 秒"
#: video2x.py:239
#: video2x.py:279
msgid "An exception has occurred"
msgstr "发生了异常"
#~ msgid "Upscaling Progress"
#~ msgstr "放大进度"
#~ msgid "Loading files from multiple paths"
#~ msgstr "正在从多个路径中导入文件"
#~ msgid "Loading single file"
#~ msgstr "正在导入单个文件"
#~ msgid "Loading files from directory"
#~ msgstr "正在从文件夹中导入文件"
#~ msgid "Anime4KCPP doesn't yet support GIF processing"
#~ msgstr "Anime4KCPP 尚不支持GIF处理"
#~ msgid "Starting to upscale video with Anime4KCPP"
#~ msgstr "开始用 Anime4KCPP 放大视频"
#~ msgid "output video width"
#~ msgstr "输出视频宽度"
#~ msgid "output video height"
#~ msgstr "输出视频高度"
#~ msgid "You must specify input video file/directory path"
#~ msgstr "您必须指定输入视频文件/目录路径"
@ -340,8 +370,5 @@ msgstr "发生了异常"
#~ msgid "Scaling ratio must be one of 2, 3 or 4 for srmd_ncnn_vulkan"
#~ msgstr "srmd_ncnn_vulkan 的缩放比必须为 2、3 或 4"
#~ msgid "You can only specify either scaling ratio or output width and height"
#~ msgstr "您只能指定缩放比或输出宽度和高度两者之一"
#~ msgid "You must specify both width and height"
#~ msgstr "您必须同时指定宽度和高度"

View File

@ -4,7 +4,7 @@
Name: Video2X Upscale Progress Monitor
Author: K4YT3X
Date Created: May 7, 2020
Last Modified: June 7, 2020
Last Modified: September 9, 2020
"""
# built-in imports
@ -34,12 +34,7 @@ class ProgressMonitor(threading.Thread):
def run(self):
self.running = True
# get number of extracted frames
self.upscaler.total_frames = 0
for directory in self.extracted_frames_directories:
self.upscaler.total_frames += len([f for f in directory.iterdir() if str(f).lower().endswith(self.upscaler.extracted_frame_format.lower())])
with tqdm(total=self.upscaler.total_frames, ascii=True, desc=_('Upscaling Progress')) as progress_bar:
with tqdm(total=self.upscaler.total_frames, ascii=True, desc=_('Processing: {} (pass {}/{})').format(self.upscaler.current_input_file.name, self.upscaler.current_pass, len(self.upscaler.scaling_jobs))) as progress_bar:
# tqdm update method adds the value to the progress
# bar instead of setting the value. Therefore, a delta
# needs to be calculated.

View File

@ -4,7 +4,7 @@
Name: Video2X Upscaler
Author: K4YT3X
Date Created: December 10, 2018
Last Modified: June 29, 2020
Last Modified: September 9, 2020
Description: This file contains the Upscaler class. Each
instance of the Upscaler class is an upscaler on an image or
@ -25,6 +25,7 @@ import copy
import gettext
import importlib
import locale
import math
import mimetypes
import pathlib
import queue
@ -50,7 +51,7 @@ language.install()
_ = language.gettext
# version information
UPSCALER_VERSION = '4.2.2'
UPSCALER_VERSION = '4.3.0'
# these names are consistent for
# - driver selection in command line
@ -63,6 +64,12 @@ AVAILABLE_DRIVERS = ['waifu2x_caffe',
'realsr_ncnn_vulkan',
'anime4kcpp']
DRIVER_FIXED_SCALING_RATIOS = {
'waifu2x_ncnn_vulkan': [1, 2],
'srmd_ncnn_vulkan': [2, 3, 4],
'realsr_ncnn_vulkan': [4],
}
class Upscaler:
""" An instance of this class is a upscaler that will
@ -82,6 +89,8 @@ class Upscaler:
gifski_settings: dict,
driver: str = 'waifu2x_caffe',
scale_ratio: float = None,
scale_width: int = None,
scale_height: int = None,
processes: int = 1,
video2x_cache_directory: pathlib.Path = pathlib.Path(tempfile.gettempdir()) / 'video2x',
extracted_frame_format: str = 'png',
@ -101,6 +110,8 @@ class Upscaler:
# optional parameters
self.driver = driver
self.scale_ratio = scale_ratio
self.scale_width = scale_width
self.scale_height = scale_height
self.processes = processes
self.video2x_cache_directory = video2x_cache_directory
self.extracted_frame_format = extracted_frame_format
@ -115,6 +126,8 @@ class Upscaler:
self.total_frames = 0
self.total_files = 0
self.total_processed = 0
self.scaling_jobs = []
self.current_pass = 0
self.current_input_file = pathlib.Path()
self.last_frame_upscaled = pathlib.Path()
@ -250,31 +263,19 @@ class Upscaler:
Avalon.error(_('Failed to parse driver argument: {}').format(e.args[0]))
raise e
# waifu2x-caffe scale_ratio, scale_width and scale_height check
if self.driver == 'waifu2x_caffe':
if (driver_settings['scale_width'] != 0 and driver_settings['scale_height'] == 0 or
driver_settings['scale_width'] == 0 and driver_settings['scale_height'] != 0):
Avalon.error(_('Only one of scale_width and scale_height is specified for waifu2x-caffe'))
raise AttributeError('only one of scale_width and scale_height is specified for waifu2x-caffe')
# if scale_width and scale_height are specified, ensure scale_ratio is None
elif self.driver_settings['scale_width'] != 0 and self.driver_settings['scale_height'] != 0:
self.driver_settings['scale_ratio'] = None
# if scale_width and scale_height not specified
# ensure they are None, not 0
else:
self.driver_settings['scale_width'] = None
self.driver_settings['scale_height'] = None
def _upscale_frames(self):
def _upscale_frames(self, input_directory: pathlib.Path, output_directory: pathlib.Path):
""" Upscale video frames with waifu2x-caffe
This function upscales all the frames extracted
by ffmpeg using the waifu2x-caffe binary.
Arguments:
w2 {Waifu2x Object} -- initialized waifu2x object
Args:
input_directory (pathlib.Path): directory containing frames to upscale
output_directory (pathlib.Path): directory which upscaled frames should be exported to
Raises:
UnrecognizedDriverError: raised when the given driver is not recognized
e: re-raised exception after an exception has been captured and finished processing in this scope
"""
# initialize waifu2x driver
@ -282,7 +283,7 @@ class Upscaler:
raise UnrecognizedDriverError(_('Unrecognized driver: {}').format(self.driver))
# list all images in the extracted frames
frames = [(self.extracted_frames / f) for f in self.extracted_frames.iterdir() if f.is_file]
frames = [(input_directory / f) for f in input_directory.iterdir() if f.is_file]
# if we have less images than processes,
# create only the processes necessary
@ -293,7 +294,7 @@ class Upscaler:
# name into a list
process_directories = []
for process_id in range(self.processes):
process_directory = self.extracted_frames / str(process_id)
process_directory = input_directory / str(process_id)
process_directories.append(process_directory)
# delete old directories and create new directories
@ -303,7 +304,7 @@ class Upscaler:
# waifu2x-converter-cpp will perform multi-threading within its own process
if self.driver in ['waifu2x_converter_cpp', 'waifu2x_ncnn_vulkan', 'srmd_ncnn_vulkan', 'realsr_ncnn_vulkan', 'anime4kcpp']:
process_directories = [self.extracted_frames]
process_directories = [input_directory]
else:
# evenly distribute images into each directory
@ -316,7 +317,7 @@ class Upscaler:
# create driver processes and start them
for process_directory in process_directories:
self.process_pool.append(self.driver_object.upscale(process_directory, self.upscaled_frames))
self.process_pool.append(self.driver_object.upscale(process_directory, output_directory))
# start progress bar in a different thread
Avalon.debug_info(_('Starting progress monitor'))
@ -325,7 +326,7 @@ class Upscaler:
# create the clearer and start it
Avalon.debug_info(_('Starting upscaled image cleaner'))
self.image_cleaner = ImageCleaner(self.extracted_frames, self.upscaled_frames, len(self.process_pool))
self.image_cleaner = ImageCleaner(input_directory, output_directory, len(self.process_pool))
self.image_cleaner.start()
# wait for all process to exit
@ -343,11 +344,11 @@ class Upscaler:
# if the driver is waifu2x-converter-cpp
# images need to be renamed to be recognizable for FFmpeg
if self.driver == 'waifu2x_converter_cpp':
for image in [f for f in self.upscaled_frames.iterdir() if f.is_file()]:
for image in [f for f in output_directory.iterdir() if f.is_file()]:
renamed = re.sub(f'_\\[.*\\]\\[x(\\d+(\\.\\d+)?)\\]\\.{self.extracted_frame_format}',
f'.{self.extracted_frame_format}',
str(image.name))
(self.upscaled_frames / image).rename(self.upscaled_frames / renamed)
(output_directory / image).rename(output_directory / renamed)
# upscaling done, kill helper threads
Avalon.debug_info(_('Killing progress monitor'))
@ -550,8 +551,6 @@ class Upscaler:
# get video information JSON using FFprobe
Avalon.info(_('Reading video information'))
video_info = self.ffmpeg_object.probe_file_info(self.current_input_file)
# analyze original video with FFprobe and retrieve framerate
# width, height = info['streams'][0]['width'], info['streams'][0]['height']
# find index of video stream
video_stream_index = None
@ -567,9 +566,89 @@ class Upscaler:
# get average frame rate of video stream
framerate = float(Fraction(video_info['streams'][video_stream_index]['r_frame_rate']))
width = int(video_info['streams'][video_stream_index]['width'])
height = int(video_info['streams'][video_stream_index]['height'])
Avalon.info(_('Framerate: {}').format(framerate))
# self.ffmpeg_object.pixel_format = video_info['streams'][video_stream_index]['pix_fmt']
# get total number of frames
Avalon.info(_('Getting total number of frames in the file'))
# if container stores total number of frames in nb_frames, fetch it directly
if 'nb_frames' in video_info['streams'][video_stream_index]:
self.total_frames = int(video_info['streams'][video_stream_index]['nb_frames'])
# otherwise call FFprobe to count the total number of frames
else:
self.total_frames = self.ffmpeg_object.get_number_of_frames(self.current_input_file, video_stream_index)
# if driver is one of the drivers that doesn't support arbitrary scaling ratio
# TODO: more documentations on this block
if self.driver in DRIVER_FIXED_SCALING_RATIOS:
# if user specified output resolution
# calculate number of passes needed
if self.scale_width is not None and self.scale_height is not None:
self.scale_ratio = 2
# when scaled output resolution is smaller than target output resolution
# increase scaling ratio
while (self.scale_ratio * width) < self.scale_width:
self.scale_ratio += 1
while (self.scale_ratio * height) < self.scale_height:
self.scale_ratio += 1
# select the optimal driver scaling ratio to use
supported_scaling_ratios = sorted(DRIVER_FIXED_SCALING_RATIOS[self.driver])
remaining_scaling_ratio = math.ceil(self.scale_ratio)
self.scaling_jobs = []
while remaining_scaling_ratio > 1:
for ratio in supported_scaling_ratios:
if ratio >= remaining_scaling_ratio:
self.scaling_jobs.append(ratio)
remaining_scaling_ratio /= ratio
break
else:
found = False
for i in supported_scaling_ratios:
for j in supported_scaling_ratios:
if i * j >= remaining_scaling_ratio:
self.scaling_jobs.extend([i, j])
remaining_scaling_ratio /= i * j
found = True
break
if found is True:
break
if found is False:
self.scaling_jobs.append(supported_scaling_ratios[-1])
remaining_scaling_ratio /= supported_scaling_ratios[-1]
# calculate and set output bicubic downscaling filter
# always ensure that the output resolution is divisible by 2
if self.scale_width is not None and self.scale_height is not None:
output_width = math.ceil(self.scale_width / 2.0) * 2
output_height = math.ceil(self.scale_height / 2.0) * 2
else:
output_width = math.ceil(width * self.scale_ratio / 2.0) * 2
output_height = math.ceil(height * self.scale_ratio / 2.0) * 2
# append scaling filter to video assembly command
if self.ffmpeg_settings['assemble_video']['output_options'].get('-vf') is None:
self.ffmpeg_settings['assemble_video']['output_options']['-vf'] = f'scale={output_width}:{output_height}'
else:
self.ffmpeg_settings['assemble_video']['output_options']['-vf'] += f',scale={output_width}:{output_height}'
else:
self.scaling_jobs = [self.scale_ratio]
Avalon.debug_info(_('Upscaling jobs queue: {}').format(self.scaling_jobs))
# extract frames from video
self.process_pool.append((self.ffmpeg_object.extract_frames(self.current_input_file, self.extracted_frames)))
self._wait()
@ -595,7 +674,18 @@ class Upscaler:
# upscale images one by one using waifu2x
Avalon.info(_('Starting to upscale extracted frames'))
self._upscale_frames()
self.current_pass = 1
self.driver_object.set_scale_ratio(self.scaling_jobs[0])
self._upscale_frames(self.extracted_frames, self.upscaled_frames)
for job in self.scaling_jobs[1:]:
self.current_pass += 1
self.driver_object.set_scale_ratio(job)
shutil.rmtree(self.extracted_frames)
shutil.move(self.upscaled_frames, self.extracted_frames)
self.upscaled_frames.mkdir(parents=True, exist_ok=True)
self._upscale_frames(self.extracted_frames, self.upscaled_frames)
Avalon.info(_('Upscaling completed'))
# start handling output

View File

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2020-05-22 17:51-0400\n"
"POT-Creation-Date: 2020-09-09 13:04-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -15,231 +15,227 @@ msgstr ""
"Generated-By: pygettext.py 1.5\n"
#: progress_monitor.py:42
msgid "Upscaling Progress"
#: progress_monitor.py:37
msgid "Processing: {} (pass {}/{})"
msgstr ""
#: upscaler.py:110
#: upscaler.py:144
msgid "Specified or default cache directory is a file/link"
msgstr ""
#: upscaler.py:116
#: upscaler.py:150
msgid "Creating cache directory {}"
msgstr ""
#: upscaler.py:119
#: upscaler.py:153
msgid "Unable to create {}"
msgstr ""
#: upscaler.py:124
#: upscaler.py:158
msgid "Extracted frames are being saved to: {}"
msgstr ""
#: upscaler.py:126
#: upscaler.py:160
msgid "Upscaled frames are being saved to: {}"
msgstr ""
#: upscaler.py:136
#: upscaler.py:170
msgid "Cleaning up cache directory: {}"
msgstr ""
#: upscaler.py:141
#: upscaler.py:175
msgid "Unable to delete: {}"
msgstr ""
#: upscaler.py:147 upscaler.py:162 upscaler.py:173
#: upscaler.py:181 upscaler.py:196 upscaler.py:207
msgid "Input and output path type mismatch"
msgstr ""
#: upscaler.py:148
#: upscaler.py:182
msgid "Input is multiple files but output is not directory"
msgstr ""
#: upscaler.py:152
#: upscaler.py:186
msgid "Input path {} is neither a file nor a directory"
msgstr ""
#: upscaler.py:156 upscaler.py:178
#: upscaler.py:190 upscaler.py:212
msgid "Input directory and output directory cannot be the same"
msgstr ""
#: upscaler.py:163
#: upscaler.py:197
msgid "Input is single file but output is directory"
msgstr ""
#: upscaler.py:166
#: upscaler.py:200
msgid "No suffix found in output file path"
msgstr ""
#: upscaler.py:167
#: upscaler.py:201
msgid "Suffix must be specified"
msgstr ""
#: upscaler.py:174
#: upscaler.py:208
msgid "Input is directory but output is existing single file"
msgstr ""
#: upscaler.py:183
#: upscaler.py:217
msgid "Input path is neither a file nor a directory"
msgstr ""
#: upscaler.py:192
#: upscaler.py:226
msgid "FFmpeg or FFprobe cannot be found under the specified path"
msgstr ""
#: upscaler.py:193 upscaler.py:203
#: upscaler.py:227 upscaler.py:237
msgid "Please check the configuration file settings"
msgstr ""
#: upscaler.py:202
#: upscaler.py:236
msgid "Specified driver executable directory doesn't exist"
msgstr ""
#: upscaler.py:229
#: upscaler.py:263
msgid "Failed to parse driver argument: {}"
msgstr ""
#: upscaler.py:261
#: upscaler.py:283
msgid "Unrecognized driver: {}"
msgstr ""
#: upscaler.py:301
#: upscaler.py:323
msgid "Starting progress monitor"
msgstr ""
#: upscaler.py:306
#: upscaler.py:328
msgid "Starting upscaled image cleaner"
msgstr ""
#: upscaler.py:315 upscaler.py:332
#: upscaler.py:337 upscaler.py:354
msgid "Killing progress monitor"
msgstr ""
#: upscaler.py:318 upscaler.py:335
#: upscaler.py:340 upscaler.py:357
msgid "Killing upscaled image cleaner"
msgstr ""
#: upscaler.py:339
#: upscaler.py:361
msgid "Terminating all processes"
msgstr ""
#: upscaler.py:346
#: upscaler.py:368
msgid "Main process waiting for subprocesses to exit"
msgstr ""
#: upscaler.py:365 upscaler.py:369
#: upscaler.py:387 upscaler.py:391
msgid "Subprocess {} exited with code {}"
msgstr ""
#: upscaler.py:375
#: upscaler.py:397
msgid "Stop signal received"
msgstr ""
#: upscaler.py:380
#: upscaler.py:402
msgid "Subprocess execution ran into an error"
msgstr ""
#: upscaler.py:410
#: upscaler.py:432
msgid "Loading files into processing queue"
msgstr ""
#: upscaler.py:415
msgid "Loading files from multiple paths"
msgstr ""
#: upscaler.py:416 upscaler.py:435 upscaler.py:442
#: upscaler.py:433
msgid "Input path(s): {}"
msgstr ""
#: upscaler.py:434
msgid "Loading single file"
msgstr ""
#: upscaler.py:441
msgid "Loading files from directory"
msgstr ""
#: upscaler.py:455
msgid "Loaded files into processing queue"
msgstr ""
#: upscaler.py:458
msgid "Input file: {}"
msgstr ""
#: upscaler.py:485
msgid "Starting to upscale image"
msgstr ""
#: upscaler.py:488 upscaler.py:550
msgid "Upscaling completed"
msgstr ""
#: upscaler.py:502
msgid "Reading video information"
msgstr ""
#: upscaler.py:516
msgid "Aborting: No video stream found"
msgstr ""
#: upscaler.py:521
msgid "Framerate: {}"
msgstr ""
#: upscaler.py:538
msgid "Unsupported pixel format: {}"
msgstr ""
#: upscaler.py:548
msgid "Starting to upscale extracted frames"
msgstr ""
#: upscaler.py:555
#: upscaler.py:495
msgid "File {} ({}) neither an image nor a video"
msgstr ""
#: upscaler.py:556
#: upscaler.py:496
msgid "Skipping this file"
msgstr ""
#: upscaler.py:566
msgid "Converting extracted frames into GIF image"
#: upscaler.py:521
msgid "Loaded files into processing queue"
msgstr ""
#: upscaler.py:570 upscaler.py:579
msgid "Conversion completed"
#: upscaler.py:524
msgid "Input file: {}"
msgstr ""
#: upscaler.py:535
msgid "Starting to upscale image"
msgstr ""
#: upscaler.py:538 upscaler.py:689
msgid "Upscaling completed"
msgstr ""
#: upscaler.py:552
msgid "Reading video information"
msgstr ""
#: upscaler.py:564
msgid "Aborting: No video stream found"
msgstr ""
#: upscaler.py:571
msgid "Framerate: {}"
msgstr ""
#: upscaler.py:575
msgid "Getting total number of frames in the file"
msgstr ""
#: upscaler.py:650
msgid "Upscaling jobs queue: {}"
msgstr ""
#: upscaler.py:666
msgid "Unsupported pixel format: {}"
msgstr ""
#: upscaler.py:676
msgid "Starting to upscale extracted frames"
msgstr ""
#: upscaler.py:696
msgid "Converting extracted frames into GIF image"
msgstr ""
#: upscaler.py:700 upscaler.py:709
msgid "Conversion completed"
msgstr ""
#: upscaler.py:705
msgid "Converting extracted frames into video"
msgstr ""
#: upscaler.py:583
#: upscaler.py:713
msgid "Migrating audio, subtitles and other streams to upscaled video"
msgstr ""
#: upscaler.py:593
#: upscaler.py:723
msgid "Failed to migrate streams"
msgstr ""
#: upscaler.py:594
#: upscaler.py:724
msgid "Trying to output video without additional streams"
msgstr ""
#: upscaler.py:610
#: upscaler.py:740
msgid "Output video file exists"
msgstr ""
#: upscaler.py:614
#: upscaler.py:744
msgid "Created temporary directory to contain file"
msgstr ""
#: upscaler.py:617
#: upscaler.py:747
msgid "Writing intermediate file to: {}"
msgstr ""
#: video2x.py:85
#: video2x.py:86
msgid ""
"Video2X CLI Version: {}\n"
"Upscaler Version: {}\n"
@ -249,59 +245,87 @@ msgid ""
"Contact: k4yt3x@k4yt3x.com"
msgstr ""
#: video2x.py:108
#: video2x.py:109
msgid "Video2X Options"
msgstr ""
#: video2x.py:109
#: video2x.py:110
msgid "show this help message and exit"
msgstr ""
#: video2x.py:110
#: video2x.py:117
msgid "source video file/directory"
msgstr ""
#: video2x.py:111
#: video2x.py:118
msgid "output video file/directory"
msgstr ""
#: video2x.py:112
#: video2x.py:120
msgid "video2x config file path"
msgstr ""
#: video2x.py:114
#: video2x.py:122
msgid "log file path"
msgstr ""
#: video2x.py:124
msgid "disable logging"
msgstr ""
#: video2x.py:125
msgid "display version, lawful information and exit"
msgstr ""
#: video2x.py:117
#: video2x.py:128
msgid "Upscaling Options"
msgstr ""
#: video2x.py:118
msgid "upscaling driver"
msgstr ""
#: video2x.py:119
#: video2x.py:129
msgid "scaling ratio"
msgstr ""
#: video2x.py:120
#: video2x.py:130
msgid "output width"
msgstr ""
#: video2x.py:131
msgid "output height"
msgstr ""
#: video2x.py:132
msgid "upscaling driver"
msgstr ""
#: video2x.py:133
msgid "number of processes to use for upscaling"
msgstr ""
#: video2x.py:121
#: video2x.py:134
msgid "preserve extracted and upscaled frames"
msgstr ""
#: video2x.py:161
#: video2x.py:174
msgid "This file cannot be imported"
msgstr ""
#: video2x.py:236
#: video2x.py:190
msgid "Specify either scaling ratio or scaling resolution, not both"
msgstr ""
#: video2x.py:194
msgid "Only one of scaling width and scaling height is specified"
msgstr ""
#: video2x.py:200
msgid "Redirecting console logs to {}"
msgstr ""
#: video2x.py:276
msgid "Program completed, taking {} seconds"
msgstr ""
#: video2x.py:239
#: video2x.py:279
msgid "An exception has occurred"
msgstr ""

View File

@ -13,7 +13,7 @@ __ __ _ _ ___ __ __
Name: Video2X Controller
Creator: K4YT3X
Date Created: Feb 24, 2018
Last Modified: June 29, 2020
Last Modified: September 9, 2020
Editor: BrianPetkovsek
Last Modified: June 17, 2019
@ -81,7 +81,7 @@ language = gettext.translation(DOMAIN, LOCALE_DIRECTORY, [default_locale], fallb
language.install()
_ = language.gettext
CLI_VERSION = '4.2.0'
CLI_VERSION = '4.3.0'
LEGAL_INFO = _('''Video2X CLI Version: {}
Upscaler Version: {}
@ -107,7 +107,7 @@ def parse_arguments():
# video options
video2x_options = parser.add_argument_group(_('Video2X Options'))
video2x_options.add_argument('-h', '--help', action='help', help=_('show this help message and exit'))
video2x_options.add_argument('--help', action='help', help=_('show this help message and exit'))
# if help is in arguments list
# do not require input and output path to be specified
@ -126,8 +126,10 @@ def parse_arguments():
# scaling options
upscaling_options = parser.add_argument_group(_('Upscaling Options'))
upscaling_options.add_argument('-d', '--driver', help=_('upscaling driver'), choices=AVAILABLE_DRIVERS, default='waifu2x_caffe')
upscaling_options.add_argument('-r', '--ratio', help=_('scaling ratio'), action='store', type=float, default=2.0)
upscaling_options.add_argument('-r', '--ratio', help=_('scaling ratio'), action='store', type=float)
upscaling_options.add_argument('-w', '--width', help=_('output width'), action='store', type=float)
upscaling_options.add_argument('-h', '--height', help=_('output height'), action='store', type=float)
upscaling_options.add_argument('-d', '--driver', help=_('upscaling driver'), choices=AVAILABLE_DRIVERS, default='waifu2x_ncnn_vulkan')
upscaling_options.add_argument('-p', '--processes', help=_('number of processes to use for upscaling'), action='store', type=int, default=1)
upscaling_options.add_argument('--preserve_frames', help=_('preserve extracted and upscaled frames'), action='store_true')
@ -183,6 +185,15 @@ if video2x_args.version:
print(LEGAL_INFO)
sys.exit(0)
# additional checks on upscaling arguments
if video2x_args.ratio is not None and (video2x_args.width is not None or video2x_args.height is not None):
Avalon.error(_('Specify either scaling ratio or scaling resolution, not both'))
sys.exit(1)
if bool(video2x_args.width) ^ bool(video2x_args.height):
Avalon.error(_('Only one of scaling width and scaling height is specified'))
sys.exit(1)
# redirect output to both terminal and log file
if video2x_args.disable_logging is False:
LOGFILE = video2x_args.log
@ -248,6 +259,8 @@ try:
# optional parameters
driver=video2x_args.driver,
scale_ratio=video2x_args.ratio,
scale_width=video2x_args.width,
scale_height=video2x_args.height,
processes=video2x_args.processes,
video2x_cache_directory=video2x_cache_directory,
extracted_frame_format=extracted_frame_format,

View File

@ -4,7 +4,7 @@
Creator: Video2X GUI
Author: K4YT3X
Date Created: May 5, 2020
Last Modified: September 4, 2020
Last Modified: September 9, 2020
"""
# local imports
@ -34,7 +34,7 @@ from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import magic
GUI_VERSION = '2.7.3'
GUI_VERSION = '2.8.0'
LEGAL_INFO = f'''Video2X GUI Version: {GUI_VERSION}\\
Upscaler Version: {UPSCALER_VERSION}\\
@ -277,6 +277,10 @@ class Video2XMainWindow(QMainWindow):
self.driver_combo_box.currentTextChanged.connect(self.update_gui_for_driver)
self.processes_spin_box = self.findChild(QSpinBox, 'processesSpinBox')
self.scale_ratio_double_spin_box = self.findChild(QDoubleSpinBox, 'scaleRatioDoubleSpinBox')
self.output_width_spin_box = self.findChild(QSpinBox, 'outputWidthSpinBox')
self.output_width_spin_box.valueChanged.connect(self.mutually_exclude_scale_ratio_resolution)
self.output_height_spin_box = self.findChild(QSpinBox, 'outputHeightSpinBox')
self.output_height_spin_box.valueChanged.connect(self.mutually_exclude_scale_ratio_resolution)
self.output_file_name_format_string_line_edit = self.findChild(QLineEdit, 'outputFileNameFormatStringLineEdit')
self.image_output_extension_line_edit = self.findChild(QLineEdit, 'imageOutputExtensionLineEdit')
self.video_output_extension_line_edit = self.findChild(QLineEdit, 'videoOutputExtensionLineEdit')
@ -310,8 +314,6 @@ class Video2XMainWindow(QMainWindow):
self.enable_line_edit_file_drop(self.waifu2x_caffe_path_line_edit)
self.waifu2x_caffe_path_select_button = self.findChild(QPushButton, 'waifu2xCaffePathSelectButton')
self.waifu2x_caffe_path_select_button.clicked.connect(lambda: self.select_driver_binary_path(self.waifu2x_caffe_path_line_edit))
self.waifu2x_caffe_scale_width_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeScaleWidthSpinBox')
self.waifu2x_caffe_scale_height_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeScaleHeightSpinBox')
self.waifu2x_caffe_mode_combo_box = self.findChild(QComboBox, 'waifu2xCaffeModeComboBox')
self.waifu2x_caffe_noise_level_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeNoiseLevelSpinBox')
self.waifu2x_caffe_process_combo_box = self.findChild(QComboBox, 'waifu2xCaffeProcessComboBox')
@ -491,8 +493,6 @@ class Video2XMainWindow(QMainWindow):
# waifu2x-caffe
settings = self.config['waifu2x_caffe']
self.waifu2x_caffe_scale_width_spin_box.setValue(settings['scale_width'])
self.waifu2x_caffe_scale_height_spin_box.setValue(settings['scale_height'])
self.waifu2x_caffe_path_line_edit.setText(str(pathlib.Path(os.path.expandvars(settings['path'])).absolute()))
self.waifu2x_caffe_mode_combo_box.setCurrentText(settings['mode'])
self.waifu2x_caffe_noise_level_spin_box.setValue(settings['noise_level'])
@ -605,8 +605,6 @@ class Video2XMainWindow(QMainWindow):
def resolve_driver_settings(self):
# waifu2x-caffe
self.config['waifu2x_caffe']['scale_width'] = self.waifu2x_caffe_scale_width_spin_box.value()
self.config['waifu2x_caffe']['scale_height'] = self.waifu2x_caffe_scale_height_spin_box.value()
self.config['waifu2x_caffe']['path'] = os.path.expandvars(self.waifu2x_caffe_path_line_edit.text())
self.config['waifu2x_caffe']['mode'] = self.waifu2x_caffe_mode_combo_box.currentText()
self.config['waifu2x_caffe']['noise_level'] = self.waifu2x_caffe_noise_level_spin_box.value()
@ -831,6 +829,12 @@ class Video2XMainWindow(QMainWindow):
with open(config_file, 'r') as config:
return yaml.load(config, Loader=yaml.FullLoader)
def mutually_exclude_scale_ratio_resolution(self):
if self.output_width_spin_box.value() != 0 or self.output_height_spin_box.value() != 0:
self.scale_ratio_double_spin_box.setDisabled(True)
elif self.output_width_spin_box.value() == 0 and self.output_height_spin_box.value() == 0:
self.scale_ratio_double_spin_box.setDisabled(False)
def mutually_exclude_frame_interpolation_stream_copy(self):
if self.ffmpeg_migrate_streams_output_options_frame_interpolation_spin_box.value() > 0:
self.ffmpeg_migrate_streams_output_options_copy_streams_check_box.setChecked(False)
@ -842,24 +846,6 @@ class Video2XMainWindow(QMainWindow):
def update_gui_for_driver(self):
current_driver = AVAILABLE_DRIVERS[self.driver_combo_box.currentText()]
# update scale ratio constraints
if current_driver in ['waifu2x_caffe', 'waifu2x_converter_cpp', 'anime4kcpp']:
self.scale_ratio_double_spin_box.setMinimum(0.0)
self.scale_ratio_double_spin_box.setMaximum(999.0)
self.scale_ratio_double_spin_box.setValue(2.0)
elif current_driver == 'waifu2x_ncnn_vulkan':
self.scale_ratio_double_spin_box.setMinimum(1.0)
self.scale_ratio_double_spin_box.setMaximum(2.0)
self.scale_ratio_double_spin_box.setValue(2.0)
elif current_driver == 'srmd_ncnn_vulkan':
self.scale_ratio_double_spin_box.setMinimum(2.0)
self.scale_ratio_double_spin_box.setMaximum(4.0)
self.scale_ratio_double_spin_box.setValue(2.0)
elif current_driver == 'realsr_ncnn_vulkan':
self.scale_ratio_double_spin_box.setMinimum(4.0)
self.scale_ratio_double_spin_box.setMaximum(4.0)
self.scale_ratio_double_spin_box.setValue(4.0)
# update preferred processes/threads count
if current_driver == 'anime4kcpp':
self.processes_spin_box.setValue(16)
@ -1074,7 +1060,7 @@ It\'s also highly recommended for you to attach the [log file]({}) under the pro
# initialize progress bar values
upscale_begin_time = time.time()
progress_callback.emit((upscale_begin_time, 0, 0, 0, 0, pathlib.Path(), pathlib.Path()))
progress_callback.emit((upscale_begin_time, 0, 0, 0, 0, 0, [], pathlib.Path(), pathlib.Path()))
# keep querying upscaling process and feed information to callback signal
while self.upscaler.running:
@ -1084,6 +1070,8 @@ It\'s also highly recommended for you to attach the [log file]({}) under the pro
self.upscaler.total_frames,
self.upscaler.total_processed,
self.upscaler.total_files,
self.upscaler.current_pass,
self.upscaler.scaling_jobs,
self.upscaler.current_input_file,
self.upscaler.last_frame_upscaled))
time.sleep(1)
@ -1098,8 +1086,10 @@ It\'s also highly recommended for you to attach the [log file]({}) under the pro
total_frames = progress_information[2]
total_processed = progress_information[3]
total_files = progress_information[4]
current_input_file = progress_information[5]
last_frame_upscaled = progress_information[6]
current_pass = progress_information[5]
scaling_jobs = progress_information[6]
current_input_file = progress_information[7]
last_frame_upscaled = progress_information[8]
# calculate fields based on frames and time elapsed
time_elapsed = time.time() - upscale_begin_time
@ -1120,7 +1110,7 @@ It\'s also highly recommended for you to attach the [log file]({}) under the pro
self.overall_progress_label.setText('Overall Progress: {}/{}'.format(total_processed, total_files))
self.overall_progress_bar.setMaximum(total_files)
self.overall_progress_bar.setValue(total_processed)
self.currently_processing_label.setText('Currently Processing: {}'.format(str(current_input_file.name)))
self.currently_processing_label.setText('Currently Processing: {} (pass {}/{})'.format(str(current_input_file.name), current_pass, len(scaling_jobs)))
# if show frame is checked, show preview image
if self.frame_preview_show_preview_check_box.isChecked() and last_frame_upscaled.is_file():
@ -1190,6 +1180,16 @@ It\'s also highly recommended for you to attach the [log file]({}) under the pro
# load driver settings for the current driver
self.driver_settings = self.config[AVAILABLE_DRIVERS[self.driver_combo_box.currentText()]]
# get scale ratio or resolution
if self.scale_ratio_double_spin_box.isEnabled():
scale_ratio = self.scale_ratio_double_spin_box.value()
scale_width = scale_height = None
else:
scale_ratio = None
scale_width = self.output_width_spin_box.value()
scale_height = self.output_height_spin_box.value()
self.upscaler = Upscaler(
# required parameters
input_path=input_directory,
@ -1200,7 +1200,9 @@ It\'s also highly recommended for you to attach the [log file]({}) under the pro
# optional parameters
driver=AVAILABLE_DRIVERS[self.driver_combo_box.currentText()],
scale_ratio=self.scale_ratio_double_spin_box.value(),
scale_ratio=scale_ratio,
scale_width=scale_width,
scale_height=scale_height,
processes=self.processes_spin_box.value(),
video2x_cache_directory=pathlib.Path(os.path.expandvars(self.cache_line_edit.text())),
extracted_frame_format=self.config['video2x']['extracted_frame_format'].lower(),

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>756</width>
<height>954</height>
<width>737</width>
<height>1020</height>
</rect>
</property>
<property name="acceptDrops">
@ -40,8 +40,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>744</width>
<height>696</height>
<width>725</width>
<height>762</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_36">
@ -376,6 +376,11 @@
&lt;/li&gt;
&lt;/ul&gt;</string>
</property>
<item>
<property name="text">
<string>Waifu2X NCNN Vulkan</string>
</property>
</item>
<item>
<property name="text">
<string>Waifu2X Caffe</string>
@ -386,11 +391,6 @@
<string>Waifu2X Converter CPP</string>
</property>
</item>
<item>
<property name="text">
<string>Waifu2X NCNN Vulkan</string>
</property>
</item>
<item>
<property name="text">
<string>SRMD NCNN Vulkan</string>
@ -461,6 +461,42 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="outputWidthHorizontalLayout">
<item>
<widget class="QLabel" name="outputWidthLabel">
<property name="text">
<string>Output Width</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="outputWidthSpinBox">
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="outputHeightHorizontalLayout">
<item>
<widget class="QLabel" name="outputHeightLabel">
<property name="text">
<string>Output Height</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="outputHeightSpinBox">
<property name="maximum">
<number>99999</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="imageOutputExtensionHorizontalLayout">
<item>
@ -628,48 +664,6 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="waifu2xCaffeScaleWidthHorizontalLayout">
<item>
<widget class="QLabel" name="waifu2xCaffeScaleWidthLabel">
<property name="text">
<string>Scale Width</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="waifu2xCaffeScaleWidthSpinBox">
<property name="toolTip">
<string>custom scale width (specifying this will overwrite scale_ratio)</string>
</property>
<property name="maximum">
<number>999999</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="waifu2xCaffeScaleHeightHorizontalLayout">
<item>
<widget class="QLabel" name="waifu2xCaffeScaleHeightLabel">
<property name="text">
<string>Scale Height</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="waifu2xCaffeScaleHeightSpinBox">
<property name="toolTip">
<string>custom scale height (specifying this will overwrite scale_ratio)</string>
</property>
<property name="maximum">
<number>999999</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="waifu2xCaffeModeHorizontalLayout">
<item>
@ -2946,7 +2940,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>756</width>
<width>737</width>
<height>21</height>
</rect>
</property>

View File

@ -4,7 +4,7 @@
Name: Anime4KCPP Driver
Author: K4YT3X
Date Created: May 3, 2020
Last Modified: September 1, 2020
Last Modified: September 9, 2020
Description: This class is a high-level wrapper
for Anime4KCPP.
@ -73,13 +73,16 @@ class WrapperMain:
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
self.driver_settings['zoomFactor'] = upscaler.scale_ratio
# self.driver_settings['zoomFactor'] = upscaler.scale_ratio
self.driver_settings['threads'] = upscaler.processes
# append FFmpeg path to the end of PATH
# Anime4KCPP will then use FFmpeg to migrate audio tracks
os.environ['PATH'] += f';{upscaler.ffmpeg_settings["ffmpeg_path"]}'
def set_scale_ratio(self, scale_ratio: float):
self.driver_settings['zoomFactor'] = scale_ratio
def upscale(self, input_file, output_file):
"""This is the core function for WAIFU2X class

View File

@ -75,6 +75,37 @@ class Ffmpeg:
return pixel_formats
def get_number_of_frames(self, input_file: str, video_stream_index: int) -> int:
""" Count the number of frames in a video
Args:
input_file (str): input file path
video_stream_index (int): index number of the video stream
Returns:
int: number of frames in the video
"""
execute = [
self.ffmpeg_probe_binary,
'-v',
'quiet',
'-count_frames',
'-select_streams',
f'v:{video_stream_index}',
'-show_entries',
'stream=nb_read_frames',
'-of',
'default=nokey=1:noprint_wrappers=1',
input_file
]
# turn elements into str
execute = [str(e) for e in execute]
Avalon.debug_info(f'Executing: {shlex.join(execute)}')
return int(subprocess.run(execute, check=True, stdout=subprocess.PIPE).stdout.decode().strip())
def probe_file_info(self, input_video):
""" Gets input video information
@ -134,6 +165,7 @@ class Ffmpeg:
# specify output file
execute.extend([
extracted_frames / f'extracted_%0d.{self.extracted_frame_format}'
# extracted_frames / f'frame_%06d.{self.extracted_frame_format}'
])
return(self._execute(execute))
@ -175,6 +207,7 @@ class Ffmpeg:
execute.extend([
'-i',
upscaled_frames / f'extracted_%d.{self.extracted_frame_format}'
# upscaled_frames / f'%06d.{self.extracted_frame_format}'
])
# read FFmpeg output options

View File

@ -4,7 +4,7 @@
Name: RealSR NCNN Vulkan Driver
Creator: K4YT3X
Date Created: May 26, 2020
Last Modified: May 26, 2020
Last Modified: September 9, 2020
Description: This class is a high-level wrapper
for realsr_ncnn_vulkan.
@ -44,7 +44,7 @@ class WrapperMain:
parser.add_argument('-v', action='store_true', help='verbose output')
parser.add_argument('-i', type=str, help=argparse.SUPPRESS) # help='input image path (jpg/png) or directory')
parser.add_argument('-o', type=str, help=argparse.SUPPRESS) # help='output image path (png) or directory')
parser.add_argument('-s', type=int, choices=[4], help='upscale ratio')
parser.add_argument('-s', type=int, help='upscale ratio')
parser.add_argument('-t', type=int, help='tile size (>=32/0=auto)')
parser.add_argument('-m', type=str, help='realsr model path')
parser.add_argument('-g', type=int, help='gpu device to use')
@ -53,9 +53,12 @@ class WrapperMain:
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
self.driver_settings['s'] = int(upscaler.scale_ratio)
# self.driver_settings['s'] = int(upscaler.scale_ratio)
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
def set_scale_ratio(self, scale_ratio: int):
self.driver_settings['s'] = int(scale_ratio)
def upscale(self, input_directory, output_directory):
"""This is the core function for RealSR NCNN Vulkan class

View File

@ -4,7 +4,7 @@
Name: SRMD NCNN Vulkan Driver
Creator: K4YT3X
Date Created: April 26, 2020
Last Modified: May 11, 2020
Last Modified: September 9, 2020
Description: This class is a high-level wrapper
for srmd_ncnn_vulkan.
@ -45,7 +45,7 @@ class WrapperMain:
parser.add_argument('-i', type=str, help=argparse.SUPPRESS) # help='input image path (jpg/png) or directory')
parser.add_argument('-o', type=str, help=argparse.SUPPRESS) # help='output image path (png) or directory')
parser.add_argument('-n', type=int, choices=range(-1, 11), help='denoise level')
parser.add_argument('-s', type=int, choices=range(2, 5), help='upscale ratio')
parser.add_argument('-s', type=int, help='upscale ratio')
parser.add_argument('-t', type=int, help='tile size (>=32)')
parser.add_argument('-m', type=str, help='srmd model path')
parser.add_argument('-g', type=int, help='gpu device to use')
@ -54,9 +54,12 @@ class WrapperMain:
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
self.driver_settings['s'] = int(upscaler.scale_ratio)
# self.driver_settings['s'] = int(upscaler.scale_ratio)
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
def set_scale_ratio(self, scale_ratio: int):
self.driver_settings['s'] = int(scale_ratio)
def upscale(self, input_directory, output_directory):
"""This is the core function for SRMD ncnn Vulkan class

View File

@ -4,7 +4,7 @@
Name: Waifu2x Caffe Driver
Author: K4YT3X
Date Created: Feb 24, 2018
Last Modified: June 7, 2020
Last Modified: September 9, 2020
Description: This class is a high-level wrapper
for waifu2x-caffe.
@ -63,13 +63,16 @@ class WrapperMain:
def load_configurations(self, upscaler):
# use scale width and scale height if specified
self.driver_settings['scale_ratio'] = upscaler.scale_ratio
# self.driver_settings['scale_ratio'] = upscaler.scale_ratio
self.driver_settings['output_extention'] = upscaler.extracted_frame_format
# bit_depth will be 12 at this point
# it will up updated later
self.driver_settings['output_depth'] = 12
def set_scale_ratio(self, scale_ratio: float):
self.driver_settings['scale_ratio'] = scale_ratio
def upscale(self, input_directory, output_directory):
""" start upscaling process
"""

View File

@ -4,7 +4,7 @@
Name: Waifu2x Converter CPP Driver
Author: K4YT3X
Date Created: February 8, 2019
Last Modified: June 13, 2020
Last Modified: September 9, 2020
Description: This class is a high-level wrapper
for waifu2x-converter-cpp.
@ -67,10 +67,13 @@ class WrapperMain:
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
self.driver_settings['scale-ratio'] = upscaler.scale_ratio
# self.driver_settings['scale-ratio'] = upscaler.scale_ratio
self.driver_settings['jobs'] = upscaler.processes
self.driver_settings['output-format'] = upscaler.extracted_frame_format.lower()
def set_scale_ratio(self, scale_ratio: float):
self.driver_settings['scale-ratio'] = scale_ratio
def upscale(self, input_directory, output_directory):
""" Waifu2x Converter Driver Upscaler
This method executes the upscaling of extracted frames.

View File

@ -7,7 +7,7 @@ Date Created: June 26, 2019
Last Modified: May 11, 2020
Editor: K4YT3X
Last Modified: February 22, 2020
Last Modified: September 9, 2020
Description: This class is a high-level wrapper
for waifu2x_ncnn_vulkan.
@ -48,7 +48,7 @@ class WrapperMain:
parser.add_argument('-i', type=str, help=argparse.SUPPRESS) # help='input image path (jpg/png) or directory')
parser.add_argument('-o', type=str, help=argparse.SUPPRESS) # help='output image path (png) or directory')
parser.add_argument('-n', type=int, choices=range(-1, 4), help='denoise level')
parser.add_argument('-s', type=int, choices=range(1, 3), help='upscale ratio')
parser.add_argument('-s', type=int, help='upscale ratio')
parser.add_argument('-t', type=int, help='tile size (>=32)')
parser.add_argument('-m', type=str, help='waifu2x model path')
parser.add_argument('-g', type=int, help='gpu device to use')
@ -57,11 +57,14 @@ class WrapperMain:
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
self.driver_settings['s'] = int(upscaler.scale_ratio)
# self.driver_settings['s'] = int(upscaler.scale_ratio)
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
def set_scale_ratio(self, scale_ratio: int):
self.driver_settings['s'] = int(scale_ratio)
def upscale(self, input_directory, output_directory):
"""This is the core function for WAIFU2X class
""" This is the core function for waifu2x class
Arguments:
input_directory {string} -- source directory path