mirror of
https://github.com/k4yt3x/video2x.git
synced 2024-12-29 16:09:10 +00:00
Merge branch '3.0.0'
This commit is contained in:
commit
65cc4c6afb
21
README.md
21
README.md
@ -26,6 +26,13 @@ Component names that are **bolded** can be automatically downloaded and configur
|
||||
|
||||
## Recent Changes
|
||||
|
||||
### 3.0.0 (November 26, 2019)
|
||||
|
||||
- Linux compatibility
|
||||
- Configuration file changed to YAML format
|
||||
- You may still use a JSON-formatted config file. To do so, please specify `-c video2x.json`.
|
||||
- Other code clean-up and optimization
|
||||
|
||||
### 2.10.0 (August 16, 2019)
|
||||
|
||||
- **Added support for [Anime4K](https://github.com/bloc97/Anime4K)**
|
||||
@ -36,18 +43,10 @@ Component names that are **bolded** can be automatically downloaded and configur
|
||||
- Removed f_string dependency and support for legacy versions of Python
|
||||
- Organized file import statements
|
||||
|
||||
### 2.8.1 (July 9, 2019)
|
||||
### Setup Script 1.6.0 (November 26, 2019)
|
||||
|
||||
- Added automatic pixel format detection
|
||||
- Added automatic color bit depth detection
|
||||
|
||||
### 2.8.0 (June 25, 2019)
|
||||
|
||||
- **Added support for [waifu2x-ncnn-vulkan](https://github.com/nihui/waifu2x-ncnn-vulkan)**
|
||||
|
||||
### Setup Script 1.5.0 (August 16, 2019)
|
||||
|
||||
- Added automatic installation support for `Anime4K`
|
||||
- Added compatibility for new YAML configuration file
|
||||
- Added better exception handling
|
||||
|
||||
## Description
|
||||
|
||||
|
10
bin/anime4k.py → src/anime4k.py
Normal file → Executable file
10
bin/anime4k.py → src/anime4k.py
Normal file → Executable file
@ -4,7 +4,7 @@
|
||||
Name: Anime4K Driver
|
||||
Author: K4YT3X
|
||||
Date Created: August 15, 2019
|
||||
Last Modified: August 15, 2019
|
||||
Last Modified: November 15, 2019
|
||||
|
||||
Description: This class is a high-level wrapper
|
||||
for Anime4k.
|
||||
@ -27,8 +27,8 @@ class Anime4k:
|
||||
the upscale function.
|
||||
"""
|
||||
|
||||
def __init__(self, waifu2x_settings):
|
||||
self.waifu2x_settings = waifu2x_settings
|
||||
def __init__(self, driver_settings):
|
||||
self.driver_settings = driver_settings
|
||||
self.print_lock = threading.Lock()
|
||||
|
||||
def upscale(self, input_directory, output_directory, scale_ratio, upscaler_exceptions, push_strength=None, push_grad_strength=None):
|
||||
@ -57,9 +57,9 @@ class Anime4k:
|
||||
for image in extracted_frame_files:
|
||||
|
||||
execute = [
|
||||
self.waifu2x_settings['java_path'],
|
||||
self.driver_settings['java_path'],
|
||||
'-jar',
|
||||
self.waifu2x_settings['anime4k_path'],
|
||||
self.driver_settings['path'],
|
||||
str(image.absolute()),
|
||||
str(output_directory / image.name),
|
||||
str(scale_ratio)
|
0
bin/exceptions.py → src/exceptions.py
Normal file → Executable file
0
bin/exceptions.py → src/exceptions.py
Normal file → Executable file
10
bin/ffmpeg.py → src/ffmpeg.py
Normal file → Executable file
10
bin/ffmpeg.py → src/ffmpeg.py
Normal file → Executable file
@ -4,7 +4,7 @@
|
||||
Name: Video2X FFmpeg Controller
|
||||
Author: K4YT3X
|
||||
Date Created: Feb 24, 2018
|
||||
Last Modified: August 15, 2019
|
||||
Last Modified: November 15, 2019
|
||||
|
||||
Description: This class handles all FFmpeg related operations.
|
||||
"""
|
||||
@ -30,8 +30,8 @@ class Ffmpeg:
|
||||
self.ffmpeg_settings = ffmpeg_settings
|
||||
|
||||
self.ffmpeg_path = pathlib.Path(self.ffmpeg_settings['ffmpeg_path'])
|
||||
self.ffmpeg_binary = self.ffmpeg_path / 'ffmpeg.exe'
|
||||
self.ffmpeg_probe_binary = self.ffmpeg_path / 'ffprobe.exe'
|
||||
self.ffmpeg_binary = self.ffmpeg_path / 'ffmpeg'
|
||||
self.ffmpeg_probe_binary = self.ffmpeg_path / 'ffprobe'
|
||||
self.image_format = image_format
|
||||
self.pixel_format = None
|
||||
|
||||
@ -67,7 +67,7 @@ class Ffmpeg:
|
||||
pass
|
||||
|
||||
# print pixel formats for debugging
|
||||
Avalon.debug_info(pixel_formats)
|
||||
Avalon.debug_info(str(pixel_formats))
|
||||
|
||||
return pixel_formats
|
||||
|
||||
@ -284,4 +284,4 @@ class Ffmpeg:
|
||||
|
||||
Avalon.debug_info(f'Executing: {execute}')
|
||||
|
||||
return subprocess.run(execute, shell=True, check=True).returncode
|
||||
return subprocess.run(execute, check=True).returncode
|
0
bin/image_cleaner.py → src/image_cleaner.py
Normal file → Executable file
0
bin/image_cleaner.py → src/image_cleaner.py
Normal file → Executable file
@ -2,5 +2,6 @@ avalon_framework
|
||||
colorama
|
||||
GPUtil
|
||||
psutil
|
||||
pyyaml
|
||||
requests
|
||||
tqdm
|
14
bin/upscaler.py → src/upscaler.py
Normal file → Executable file
14
bin/upscaler.py → src/upscaler.py
Normal file → Executable file
@ -4,7 +4,7 @@
|
||||
Name: Video2X Upscaler
|
||||
Author: K4YT3X
|
||||
Date Created: December 10, 2018
|
||||
Last Modified: August 21, 2019
|
||||
Last Modified: October 6, 2019
|
||||
|
||||
Dev: SAT3LL
|
||||
|
||||
@ -51,12 +51,12 @@ class Upscaler:
|
||||
ArgumentError -- if argument is not valid
|
||||
"""
|
||||
|
||||
def __init__(self, input_video, output_video, method, waifu2x_settings, ffmpeg_settings):
|
||||
def __init__(self, input_video, output_video, method, driver_settings, ffmpeg_settings):
|
||||
# mandatory arguments
|
||||
self.input_video = input_video
|
||||
self.output_video = output_video
|
||||
self.method = method
|
||||
self.waifu2x_settings = waifu2x_settings
|
||||
self.driver_settings = driver_settings
|
||||
self.ffmpeg_settings = ffmpeg_settings
|
||||
|
||||
# optional arguments
|
||||
@ -165,7 +165,7 @@ class Upscaler:
|
||||
# it's easier to do multi-threading with waifu2x_converter
|
||||
# the number of threads can be passed directly to waifu2x_converter
|
||||
if self.waifu2x_driver == 'waifu2x_converter':
|
||||
w2 = Waifu2xConverter(self.waifu2x_settings, self.model_dir)
|
||||
w2 = Waifu2xConverter(self.driver_settings, self.model_dir)
|
||||
|
||||
progress_bar = threading.Thread(target=self._progress_bar, args=([self.extracted_frames],))
|
||||
progress_bar.start()
|
||||
@ -222,7 +222,7 @@ class Upscaler:
|
||||
|
||||
# create a separate w2 instance for each thread
|
||||
if self.waifu2x_driver == 'waifu2x_caffe':
|
||||
w2 = Waifu2xCaffe(copy.deepcopy(self.waifu2x_settings), self.method, self.model_dir, self.bit_depth)
|
||||
w2 = Waifu2xCaffe(copy.deepcopy(self.driver_settings), self.method, self.model_dir, self.bit_depth)
|
||||
if self.scale_ratio:
|
||||
thread = threading.Thread(target=w2.upscale,
|
||||
args=(thread_info[0],
|
||||
@ -244,7 +244,7 @@ class Upscaler:
|
||||
|
||||
# if the driver being used is waifu2x_ncnn_vulkan
|
||||
elif self.waifu2x_driver == 'waifu2x_ncnn_vulkan':
|
||||
w2 = Waifu2xNcnnVulkan(copy.deepcopy(self.waifu2x_settings))
|
||||
w2 = Waifu2xNcnnVulkan(copy.deepcopy(self.driver_settings))
|
||||
thread = threading.Thread(target=w2.upscale,
|
||||
args=(thread_info[0],
|
||||
self.upscaled_frames,
|
||||
@ -253,7 +253,7 @@ class Upscaler:
|
||||
|
||||
# if the driver being used is anime4k
|
||||
elif self.waifu2x_driver == 'anime4k':
|
||||
w2 = Anime4k(copy.deepcopy(self.waifu2x_settings))
|
||||
w2 = Anime4k(copy.deepcopy(self.driver_settings))
|
||||
thread = threading.Thread(target=w2.upscale,
|
||||
args=(thread_info[0],
|
||||
self.upscaled_frames,
|
100
bin/video2x.py → src/video2x.py
Normal file → Executable file
100
bin/video2x.py → src/video2x.py
Normal file → Executable file
@ -11,12 +11,12 @@ __ __ _ _ ___ __ __
|
||||
|
||||
|
||||
Name: Video2X Controller
|
||||
Author: K4YT3X
|
||||
Creator: K4YT3X
|
||||
Date Created: Feb 24, 2018
|
||||
Last Modified: August 29, 2019
|
||||
Last Modified: November 15, 2019
|
||||
|
||||
Dev: BrianPetkovsek
|
||||
Dev: SAT3LL
|
||||
Editor: BrianPetkovsek
|
||||
Editor: SAT3LL
|
||||
|
||||
Licensed under the GNU General Public License Version 3 (GNU GPL v3),
|
||||
available at: https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
@ -50,7 +50,6 @@ from upscaler import Upscaler
|
||||
# built-in imports
|
||||
import argparse
|
||||
import contextlib
|
||||
import json
|
||||
import pathlib
|
||||
import re
|
||||
import shutil
|
||||
@ -58,13 +57,18 @@ import sys
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
import yaml
|
||||
|
||||
# third-party imports
|
||||
from avalon_framework import Avalon
|
||||
import GPUtil
|
||||
import psutil
|
||||
|
||||
VERSION = '2.10.0'
|
||||
# platform-specific imports
|
||||
if sys.platform == 'win32':
|
||||
import GPUtil
|
||||
|
||||
|
||||
VERSION = '3.0.0'
|
||||
|
||||
LEGAL_INFO = f'''Video2X Version: {VERSION}
|
||||
Author: K4YT3X
|
||||
@ -87,7 +91,7 @@ SYS_MEM_PER_THREAD = 2.5
|
||||
GPU_MEM_PER_THREAD = 3.5
|
||||
|
||||
|
||||
def process_arguments():
|
||||
def parse_arguments():
|
||||
"""Processes CLI arguments
|
||||
|
||||
This function parses all arguments
|
||||
@ -107,7 +111,7 @@ def process_arguments():
|
||||
upscaler_options.add_argument('-d', '--driver', help='upscaling driver', action='store', default='waifu2x_caffe', choices=AVAILABLE_DRIVERS)
|
||||
upscaler_options.add_argument('-y', '--model_dir', type=pathlib.Path, help='directory containing model JSON files', action='store')
|
||||
upscaler_options.add_argument('-t', '--threads', help='number of threads to use for upscaling', action='store', type=int, default=1)
|
||||
upscaler_options.add_argument('-c', '--config', type=pathlib.Path, help='video2x config file location', action='store', default=pathlib.Path(sys.argv[0]).parent.absolute() / 'video2x.json')
|
||||
upscaler_options.add_argument('-c', '--config', type=pathlib.Path, help='video2x config file location', action='store', default=pathlib.Path(sys.argv[0]).parent.absolute() / 'video2x.yaml')
|
||||
upscaler_options.add_argument('-b', '--batch', help='enable batch mode (select all default values to questions)', action='store_true')
|
||||
|
||||
# scaling options
|
||||
@ -186,14 +190,18 @@ def check_memory():
|
||||
Avalon.warning('Proceed with caution')
|
||||
|
||||
|
||||
def read_config(config_file):
|
||||
""" Reads configuration file
|
||||
def read_config(config_file: pathlib.Path) -> dict:
|
||||
""" read video2x configurations from config file
|
||||
|
||||
Returns a dictionary read by JSON.
|
||||
Arguments:
|
||||
config_file {pathlib.Path} -- video2x configuration file pathlib.Path
|
||||
|
||||
Returns:
|
||||
dict -- dictionary of video2x configuration
|
||||
"""
|
||||
with open(config_file, 'r') as raw_config:
|
||||
config = json.load(raw_config)
|
||||
return config
|
||||
|
||||
with open(config_file, 'r') as config:
|
||||
return yaml.load(config, Loader=yaml.FullLoader)
|
||||
|
||||
|
||||
def absolutify_paths(config):
|
||||
@ -248,13 +256,13 @@ if __name__ != '__main__':
|
||||
# print video2x logo
|
||||
print_logo()
|
||||
|
||||
# process CLI arguments
|
||||
args = process_arguments()
|
||||
# parse command line arguments
|
||||
args = parse_arguments()
|
||||
|
||||
# display version and lawful informaition
|
||||
if args.version:
|
||||
print(LEGAL_INFO)
|
||||
exit(0)
|
||||
sys.exit(0)
|
||||
|
||||
# arguments sanity check
|
||||
if not args.input:
|
||||
@ -277,54 +285,44 @@ if (args.width and not args.height) or (not args.width and args.height):
|
||||
raise ArgumentError('only one of width or height is specified')
|
||||
|
||||
# check available memory if driver is waifu2x-based
|
||||
if args.driver in ['waifu2x_caffe', 'waifu2x_converter', 'waifu2x_ncnn_vulkan']:
|
||||
if args.driver in ['waifu2x_caffe', 'waifu2x_converter', 'waifu2x_ncnn_vulkan'] and sys.platform == 'win32':
|
||||
check_memory()
|
||||
|
||||
# anime4k runs significantly faster with more threads
|
||||
if args.driver == 'anime4k' and args.threads <= 1:
|
||||
Avalon.warning('Anime4K runs significantly faster with more threads')
|
||||
if Avalon.ask('Use more threads of Anime4K?', True):
|
||||
if Avalon.ask('Use more threads of Anime4K?', default=True, batch=args.batch):
|
||||
while True:
|
||||
try:
|
||||
threads = Avalon.gets('Amount of threads to use [5]: ')
|
||||
threads = Avalon.gets('Amount of threads to use [5]: ', default=5, batch=args.batch)
|
||||
args.threads = int(threads)
|
||||
break
|
||||
except ValueError:
|
||||
if threads == '':
|
||||
args.threads = 5
|
||||
break
|
||||
else:
|
||||
Avalon.error(f'{threads} is not a valid integer')
|
||||
Avalon.error(f'{threads} is not a valid integer')
|
||||
|
||||
# read configurations from JSON
|
||||
# read configurations from configuration file
|
||||
config = read_config(args.config)
|
||||
config = absolutify_paths(config)
|
||||
|
||||
# config = absolutify_paths(config)
|
||||
|
||||
# load waifu2x configuration
|
||||
if args.driver == 'waifu2x_caffe':
|
||||
waifu2x_settings = config['waifu2x_caffe']
|
||||
if not pathlib.Path(waifu2x_settings['waifu2x_caffe_path']).is_file():
|
||||
Avalon.error('Specified waifu2x-caffe directory doesn\'t exist')
|
||||
driver_settings = config[args.driver]
|
||||
|
||||
# check if driver path exists
|
||||
if not pathlib.Path(driver_settings['path']).is_file():
|
||||
if not pathlib.Path(f'{driver_settings["path"]}.exe').is_file():
|
||||
Avalon.error('Specified driver executable directory doesn\'t exist')
|
||||
Avalon.error('Please check the configuration file settings')
|
||||
raise FileNotFoundError(waifu2x_settings['waifu2x_caffe_path'])
|
||||
elif args.driver == 'waifu2x_converter':
|
||||
waifu2x_settings = config['waifu2x_converter']
|
||||
if not pathlib.Path(waifu2x_settings['waifu2x_converter_path']).is_dir():
|
||||
Avalon.error('Specified waifu2x-converter-cpp directory doesn\'t exist')
|
||||
Avalon.error('Please check the configuration file settings')
|
||||
raise FileNotFoundError(waifu2x_settings['waifu2x_converter_path'])
|
||||
elif args.driver == 'waifu2x_ncnn_vulkan':
|
||||
waifu2x_settings = config['waifu2x_ncnn_vulkan']
|
||||
if not pathlib.Path(waifu2x_settings['waifu2x_ncnn_vulkan_path']).is_file():
|
||||
Avalon.error('Specified waifu2x_ncnn_vulkan directory doesn\'t exist')
|
||||
Avalon.error('Please check the configuration file settings')
|
||||
raise FileNotFoundError(waifu2x_settings['waifu2x_ncnn_vulkan_path'])
|
||||
elif args.driver == 'anime4k':
|
||||
waifu2x_settings = config['anime4k']
|
||||
if not pathlib.Path(waifu2x_settings['anime4k_path']).is_file():
|
||||
Avalon.error('Specified anime4k directory doesn\'t exist')
|
||||
Avalon.error('Please check the configuration file settings')
|
||||
raise FileNotFoundError(waifu2x_settings['anime4k_path'])
|
||||
raise FileNotFoundError(driver_settings['path'])
|
||||
|
||||
# if the driver is Anime4K, check if JDK 12 is installed
|
||||
if args.driver == 'anime4k':
|
||||
if not pathlib.Path('C:/Program Files/Java/jdk-12.0.2/bin/java.exe').is_file():
|
||||
Avalon.warning('Cannot find JDK 12 at its default installation location')
|
||||
Avalon.warning('Please ensure you have JDK 12 installed and configured')
|
||||
|
||||
# read FFmpeg configuration
|
||||
ffmpeg_settings = config['ffmpeg']
|
||||
@ -385,7 +383,7 @@ try:
|
||||
Avalon.error('Suffix must be specified for FFmpeg')
|
||||
raise Exception('No suffix specified')
|
||||
|
||||
upscaler = Upscaler(input_video=args.input, output_video=args.output, method=args.method, waifu2x_settings=waifu2x_settings, ffmpeg_settings=ffmpeg_settings)
|
||||
upscaler = Upscaler(input_video=args.input, output_video=args.output, method=args.method, driver_settings=driver_settings, ffmpeg_settings=ffmpeg_settings)
|
||||
|
||||
# set optional options
|
||||
upscaler.waifu2x_driver = args.driver
|
||||
@ -413,7 +411,7 @@ try:
|
||||
|
||||
for input_video in [f for f in args.input.iterdir() if f.is_file()]:
|
||||
output_video = args.output / input_video.name
|
||||
upscaler = Upscaler(input_video=input_video, output_video=output_video, method=args.method, waifu2x_settings=waifu2x_settings, ffmpeg_settings=ffmpeg_settings)
|
||||
upscaler = Upscaler(input_video=input_video, output_video=output_video, method=args.method, driver_settings=driver_settings, ffmpeg_settings=ffmpeg_settings)
|
||||
|
||||
# set optional options
|
||||
upscaler.waifu2x_driver = args.driver
|
||||
@ -435,9 +433,11 @@ try:
|
||||
raise FileNotFoundError(f'{args.input} is neither file nor directory')
|
||||
|
||||
Avalon.info(f'Program completed, taking {round((time.time() - begin_time), 5)} seconds')
|
||||
|
||||
except Exception:
|
||||
Avalon.error('An exception has occurred')
|
||||
traceback.print_exc()
|
||||
|
||||
finally:
|
||||
# remove Video2X cache directory
|
||||
with contextlib.suppress(FileNotFoundError):
|
89
src/video2x.yaml
Normal file
89
src/video2x.yaml
Normal file
@ -0,0 +1,89 @@
|
||||
---
|
||||
waifu2x_caffe:
|
||||
path: C:\Users\K4YT3X\AppData\Local\video2x\waifu2x-caffe\waifu2x-caffe-cui
|
||||
input_extention_list:
|
||||
output_extention:
|
||||
mode: noise_scale
|
||||
scale_ratio:
|
||||
scale_width:
|
||||
scale_height:
|
||||
noise_level: 3
|
||||
process: gpu
|
||||
crop_size: 128
|
||||
output_quality: -1
|
||||
output_depth: 8
|
||||
batch_size: 1
|
||||
gpu: 0
|
||||
tta: 0
|
||||
input_path:
|
||||
output_path:
|
||||
model_dir:
|
||||
crop_w:
|
||||
crop_h:
|
||||
waifu2x_converter:
|
||||
path: C:\Users\K4YT3X\AppData\Local\video2x\waifu2x-converter-cpp
|
||||
output-format:
|
||||
png-compression:
|
||||
image-quality:
|
||||
block-size:
|
||||
disable-gpu:
|
||||
force-OpenCL:
|
||||
processor:
|
||||
jobs:
|
||||
model-dir:
|
||||
scale-ratio:
|
||||
noise-level: 3
|
||||
mode: noise-scale
|
||||
silent: true
|
||||
output:
|
||||
input:
|
||||
waifu2x_ncnn_vulkan:
|
||||
path: C:\Users\K4YT3X\AppData\Local\video2x\waifu2x-ncnn-vulkan\waifu2x-ncnn-vulkan
|
||||
v:
|
||||
i:
|
||||
o:
|
||||
n: 2
|
||||
s: 2
|
||||
t: 400
|
||||
m: models-cunet
|
||||
g: 0
|
||||
j: "1:2:2"
|
||||
anime4k:
|
||||
path: C:\Users\K4YT3X\AppData\Local\video2x\anime4k\Anime4K.jar
|
||||
java_path: C:\Program Files\Java\jdk-12.0.2\bin\java.exe
|
||||
ffmpeg:
|
||||
ffmpeg_path: C:\Users\K4YT3X\AppData\Local\video2x\ffmpeg-latest-win64-static\bin
|
||||
video_to_frames:
|
||||
output_options:
|
||||
"-qscale:v":
|
||||
"-pix_fmt": rgba64be
|
||||
"-hwaccel": auto
|
||||
"-y": true
|
||||
frames_to_video:
|
||||
input_options:
|
||||
"-qscale:v":
|
||||
"-qscale:a":
|
||||
"-f": image2
|
||||
output_options:
|
||||
"-vcodec": libx264
|
||||
"-crf": 17
|
||||
"-b:v":
|
||||
"-pix_fmt":
|
||||
"-hwaccel": auto
|
||||
"-y": true
|
||||
migrating_tracks:
|
||||
output_options:
|
||||
"-map":
|
||||
- 0:v?
|
||||
- 1:a?
|
||||
- 1:s?
|
||||
- 1:d?
|
||||
- 1:t?
|
||||
"-c": copy
|
||||
"-pix_fmt":
|
||||
"-hwaccel": auto
|
||||
"-y": true
|
||||
video2x:
|
||||
video2x_cache_directory:
|
||||
image_format: png
|
||||
preserve_frames: false
|
69
bin/video2x_gui.py → src/video2x_gui.py
Normal file → Executable file
69
bin/video2x_gui.py → src/video2x_gui.py
Normal file → Executable file
@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Name: Video2x GUI
|
||||
Creator: Video2X GUI
|
||||
Author: K4YT3X
|
||||
Date Created: July 27, 2019
|
||||
Last Modified: August 17, 2019
|
||||
Last Modified: November 16, 2019
|
||||
|
||||
Description: GUI for Video2X
|
||||
Description: A simple GUI for Video2X made with tkinter.
|
||||
"""
|
||||
|
||||
# local imports
|
||||
@ -18,13 +18,16 @@ from tkinter import *
|
||||
from tkinter import messagebox
|
||||
from tkinter import ttk
|
||||
from tkinter.filedialog import *
|
||||
import json
|
||||
import pathlib
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
import yaml
|
||||
|
||||
VERSION = '1.1.1'
|
||||
VERSION = '1.1.2'
|
||||
|
||||
VIDEO2X_CONFIG = pathlib.Path(sys.argv[0]).parent.absolute() / 'video2x.yaml'
|
||||
|
||||
LEGAL_INFO = f'''Video2X GUI Version: {VERSION}
|
||||
Author: K4YT3X
|
||||
@ -48,6 +51,46 @@ AVAILABLE_DRIVERS = {
|
||||
|
||||
IMAGE_FORMATS = {'PNG', 'JPG'}
|
||||
|
||||
DEMUXER_EXTENSIONS = {'3dostr', '4xm', 'aa', 'aac', 'ac3', 'acm', 'act',
|
||||
'adf', 'adp', 'ads', 'adx', 'aea', 'afc', 'aiff', 'aix', 'alaw',
|
||||
'alias_pix', 'alsa', 'amr', 'amrnb', 'amrwb', 'anm', 'apc', 'ape',
|
||||
'apng', 'aptx', 'aptx_hd', 'aqtitle', 'asf', 'asf_o', 'ass', 'ast',
|
||||
'au', 'avi', 'avisynth', 'avr', 'avs', 'avs2', 'bethsoftvid', 'bfi',
|
||||
'bfstm', 'bin', 'bink', 'bit', 'bmp_pipe', 'bmv', 'boa', 'brender_pix',
|
||||
'brstm', 'c93', 'caf', 'cavsvideo', 'cdg', 'cdxl', 'cine', 'codec2',
|
||||
'codec2raw', 'concat', 'dash', 'data', 'daud', 'dcstr', 'dds_pipe',
|
||||
'dfa', 'dirac', 'dnxhd', 'dpx_pipe', 'dsf', 'dsicin', 'dss', 'dts',
|
||||
'dtshd', 'dv', 'dvbsub', 'dvbtxt', 'dxa', 'ea', 'ea_cdata', 'eac3',
|
||||
'epaf', 'exr_pipe', 'f32be', 'f32le', 'f64be', 'f64le', 'fbdev',
|
||||
'ffmetadata', 'film_cpk', 'filmstrip', 'fits', 'flac', 'flic', 'flv',
|
||||
'frm', 'fsb', 'g722', 'g723_1', 'g726', 'g726le', 'g729', 'gdv', 'genh',
|
||||
'gif', 'gsm', 'gxf', 'h261', 'h263', 'h264', 'hevc', 'hls', 'applehttp',
|
||||
'hnm', 'ico', 'idcin', 'idf', 'iec61883', 'iff', 'ilbc', 'image2',
|
||||
'image2pipe', 'ingenient', 'ipmovie', 'ircam', 'iss', 'iv8', 'ivf',
|
||||
'ivr', 'j2k_pipe', 'jack', 'jacosub', 'jpeg_pipe', 'jpegls_pipe',
|
||||
'jv', 'kmsgrab', 'lavfi', 'libcdio', 'libdc1394', 'libgme', 'libopenmpt',
|
||||
'live_flv', 'lmlm4', 'loas', 'lrc', 'lvf', 'lxf', 'm4v', 'matroska', 'webm',
|
||||
'mgsts', 'microdvd', 'mjpeg', 'mjpeg_2000', 'mlp', 'mlv', 'mm', 'mmf',
|
||||
'mov', 'mp4', 'm4a', '3gp', '3g2', 'mj2', 'mp3', 'mpc', 'mpc8', 'mpeg',
|
||||
'mpegts', 'mpegtsraw', 'mpegvideo', 'mpjpeg', 'mpl2', 'mpsub', 'msf',
|
||||
'msnwctcp', 'mtaf', 'mtv', 'mulaw', 'musx', 'mv', 'mvi', 'mxf', 'mxg',
|
||||
'nc', 'nistsphere', 'nsp', 'nsv', 'nut', 'nuv', 'ogg', 'oma', 'openal',
|
||||
'oss', 'paf', 'pam_pipe', 'pbm_pipe', 'pcx_pipe', 'pgm_pipe', 'pgmyuv_pipe',
|
||||
'pictor_pipe', 'pjs', 'pmp', 'png_pipe', 'ppm_pipe', 'psd_pipe', 'psxstr',
|
||||
'pulse', 'pva', 'pvf', 'qcp', 'qdraw_pipe', 'r3d', 'rawvideo', 'realtext',
|
||||
'redspark', 'rl2', 'rm', 'roq', 'rpl', 'rsd', 'rso', 'rtp', 'rtsp',
|
||||
's16be', 's16le', 's24be', 's24le', 's32be', 's32le', 's337m', 's8',
|
||||
'sami', 'sap', 'sbc', 'sbg', 'scc', 'sdp', 'sdr2', 'sds', 'sdx', 'ser',
|
||||
'sgi_pipe', 'shn', 'siff', 'sln', 'smjpeg', 'smk', 'smush', 'sndio',
|
||||
'sol', 'sox', 'spdif', 'srt', 'stl', 'subviewer', 'subviewer1', 'sunrast_pipe',
|
||||
'sup', 'svag', 'svg_pipe', 'swf', 'tak', 'tedcaptions', 'thp', 'tiertexseq',
|
||||
'tiff_pipe', 'tmv', 'truehd', 'tta', 'tty', 'txd', 'ty', 'u16be', 'u16le',
|
||||
'u24be', 'u24le', 'u32be', 'u32le', 'u8', 'v210', 'v210x', 'vag', 'vc1',
|
||||
'vc1test', 'vidc', 'video4linux2', 'v4l2', 'vivo', 'vmd', 'vobsub', 'voc',
|
||||
'vpk', 'vplayer', 'vqf', 'w64', 'wav', 'wc3movie', 'webm_dash_manifest',
|
||||
'webp_pipe', 'webvtt', 'wsaud', 'wsd', 'wsvqa', 'wtv', 'wv', 'wve', 'x11grab',
|
||||
'xa', 'xbin', 'xmv', 'xpm_pipe', 'xvag', 'xwd_pipe', 'xwma', 'yop', 'yuv4mpegpipe'}
|
||||
|
||||
|
||||
class Video2xGui():
|
||||
|
||||
@ -228,7 +271,7 @@ class Video2xGui():
|
||||
begin_time = time.time()
|
||||
|
||||
# read configuration file
|
||||
config = read_config('video2x.json')
|
||||
config = read_config(VIDEO2X_CONFIG)
|
||||
config = absolutify_paths(config)
|
||||
|
||||
input_file = pathlib.Path(self.input_file.get())
|
||||
@ -350,12 +393,18 @@ class Video2xGui():
|
||||
def _select_input(self):
|
||||
self.input_file.set(askopenfilename(title='Select Input File'))
|
||||
|
||||
# remove input file extension
|
||||
input_filename = str(self.input_file.get())
|
||||
for extension in DEMUXER_EXTENSIONS:
|
||||
if input_filename.endswith(f'.{extension}'):
|
||||
input_filename = input_filename[:-1 - len(extension)]
|
||||
|
||||
# try to set an output file name automatically
|
||||
output_file = pathlib.Path(f'{self.input_file.get()}_output.mp4')
|
||||
output_file = pathlib.Path(f'{input_filename}_output.mp4')
|
||||
|
||||
output_file_id = 0
|
||||
while output_file.is_file() and output_file_id <= 10:
|
||||
output_file = pathlib.Path(f'{self.input_file.get()}_output_{output_file_id}.mp4')
|
||||
output_file = pathlib.Path(f'{input_filename}_output_{output_file_id}.mp4')
|
||||
output_file_id += 1
|
||||
|
||||
if not output_file.exists():
|
||||
@ -368,10 +417,10 @@ class Video2xGui():
|
||||
def read_config(config_file):
|
||||
""" Reads configuration file
|
||||
|
||||
Returns a dictionary read by JSON.
|
||||
Returns a dictionary read by parsing Video2X config.
|
||||
"""
|
||||
with open(config_file, 'r') as raw_config:
|
||||
config = json.load(raw_config)
|
||||
config = yaml.load(raw_config, Loader=yaml.FullLoader)
|
||||
return config
|
||||
|
||||
|
75
bin/video2x_setup.py → src/video2x_setup.py
Normal file → Executable file
75
bin/video2x_setup.py → src/video2x_setup.py
Normal file → Executable file
@ -2,17 +2,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Name: Video2X Setup Script
|
||||
Author: K4YT3X
|
||||
Author: BrianPetkovsek
|
||||
Creator: K4YT3X
|
||||
Date Created: November 28, 2018
|
||||
Last Modified: August 20, 2019
|
||||
Last Modified: November 26, 2019
|
||||
|
||||
Dev: SAT3LL
|
||||
|
||||
Licensed under the GNU General Public License Version 3 (GNU GPL v3),
|
||||
available at: https://www.gnu.org/licenses/gpl-3.0.txt
|
||||
|
||||
(C) 2018-2019 K4YT3X
|
||||
Editor: BrianPetkovsek
|
||||
Editor: SAT3LL
|
||||
|
||||
Description: This script helps installing all dependencies of video2x
|
||||
and generates a configuration for it.
|
||||
@ -26,9 +21,9 @@ Installation Details:
|
||||
"""
|
||||
|
||||
# built-in imports
|
||||
from datetime import timedelta
|
||||
import argparse
|
||||
import contextlib
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
@ -36,6 +31,7 @@ import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
import urllib
|
||||
import zipfile
|
||||
@ -45,14 +41,15 @@ import zipfile
|
||||
# later in the script.
|
||||
# import requests
|
||||
|
||||
VERSION = '1.5.0'
|
||||
VERSION = '1.6.0'
|
||||
|
||||
# global static variables
|
||||
LOCALAPPDATA = pathlib.Path(os.getenv('localappdata'))
|
||||
VIDEO2X_CONFIG = pathlib.Path(sys.argv[0]).parent.absolute() / 'video2x.yaml'
|
||||
DRIVER_OPTIONS = ['all', 'waifu2x_caffe', 'waifu2x_converter', 'waifu2x_ncnn_vulkan', 'anime4k']
|
||||
|
||||
|
||||
def process_arguments():
|
||||
def parse_arguments():
|
||||
"""Processes CLI arguments
|
||||
"""
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
@ -227,9 +224,11 @@ class Video2xSetup:
|
||||
def _generate_config(self):
|
||||
""" Generate video2x config
|
||||
"""
|
||||
# Open current video2x.json file as template
|
||||
with open('video2x.json', 'r') as template:
|
||||
template_dict = json.load(template)
|
||||
import yaml
|
||||
|
||||
# open current video2x configuration file as template
|
||||
with open(VIDEO2X_CONFIG, 'r') as template:
|
||||
template_dict = yaml.load(template, Loader=yaml.FullLoader)
|
||||
template.close()
|
||||
|
||||
# configure only the specified drivers
|
||||
@ -251,10 +250,9 @@ class Video2xSetup:
|
||||
template_dict['video2x']['video2x_cache_directory'] = None
|
||||
template_dict['video2x']['preserve_frames'] = False
|
||||
|
||||
# Write configuration into file
|
||||
with open('video2x.json', 'w') as config:
|
||||
json.dump(template_dict, config, indent=2)
|
||||
config.close()
|
||||
# write configuration into file
|
||||
with open(VIDEO2X_CONFIG, 'w') as config:
|
||||
yaml.dump(template_dict, config)
|
||||
|
||||
|
||||
def download(url, save_path, chunk_size=4096):
|
||||
@ -321,7 +319,20 @@ def pip_install(file):
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
args = process_arguments()
|
||||
# set default exit code
|
||||
EXIT_CODE = 0
|
||||
|
||||
# get start time
|
||||
start_time = time.time()
|
||||
|
||||
# check platform
|
||||
if sys.platform == 'win32':
|
||||
print('This script is currently only compatible with Windows')
|
||||
EXIT_CODE = 1
|
||||
sys.exit(1)
|
||||
|
||||
# parse command line arguments
|
||||
args = parse_arguments()
|
||||
print('Video2X Setup Script')
|
||||
print(f'Version: {VERSION}')
|
||||
|
||||
@ -335,8 +346,20 @@ if __name__ == '__main__':
|
||||
setup = Video2xSetup(args.driver, download_python_modules)
|
||||
setup.run()
|
||||
print('\nScript finished successfully')
|
||||
except Exception:
|
||||
|
||||
except SystemExit:
|
||||
pass
|
||||
|
||||
# if PermissionError is raised
|
||||
# user needs to run this with higher privilege
|
||||
except PermissionError:
|
||||
traceback.print_exc()
|
||||
print('You might have insufficient privilege for this script to run')
|
||||
print('Try running this script with Administrator privileges')
|
||||
EXIT_CODE = 1
|
||||
|
||||
# for any exception in the script
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
print('An error has occurred')
|
||||
print('Video2X Automatic Setup has failed')
|
||||
@ -348,4 +371,12 @@ if __name__ == '__main__':
|
||||
traceback.print_exc()
|
||||
print('An error occurred while trying to cleanup files')
|
||||
|
||||
exit(1)
|
||||
EXIT_CODE = 1
|
||||
|
||||
# regardless if script finishes successfully or not
|
||||
# print script execution summary
|
||||
finally:
|
||||
print('Script finished')
|
||||
print(f'Time taken: {timedelta(seconds=round(time.time() - start_time))}')
|
||||
input('Press [ENTER] to exit script')
|
||||
sys.exit(EXIT_CODE)
|
32
bin/waifu2x_caffe.py → src/waifu2x_caffe.py
Normal file → Executable file
32
bin/waifu2x_caffe.py → src/waifu2x_caffe.py
Normal file → Executable file
@ -4,7 +4,7 @@
|
||||
Name: Waifu2x Caffe Driver
|
||||
Author: K4YT3X
|
||||
Date Created: Feb 24, 2018
|
||||
Last Modified: August 3, 2019
|
||||
Last Modified: October 6, 2019
|
||||
|
||||
Description: This class is a high-level wrapper
|
||||
for waifu2x-caffe.
|
||||
@ -27,11 +27,11 @@ class Waifu2xCaffe:
|
||||
the upscale function.
|
||||
"""
|
||||
|
||||
def __init__(self, waifu2x_settings, process, model_dir, bit_depth):
|
||||
self.waifu2x_settings = waifu2x_settings
|
||||
self.waifu2x_settings['process'] = process
|
||||
self.waifu2x_settings['model_dir'] = model_dir
|
||||
self.waifu2x_settings['output_depth'] = bit_depth
|
||||
def __init__(self, driver_settings, process, model_dir, bit_depth):
|
||||
self.driver_settings = driver_settings
|
||||
self.driver_settings['process'] = process
|
||||
self.driver_settings['model_dir'] = model_dir
|
||||
self.driver_settings['output_depth'] = bit_depth
|
||||
|
||||
# arguments passed through command line overwrites config file values
|
||||
self.process = process
|
||||
@ -50,16 +50,16 @@ class Waifu2xCaffe:
|
||||
|
||||
try:
|
||||
# overwrite config file settings
|
||||
self.waifu2x_settings['input_path'] = input_directory
|
||||
self.waifu2x_settings['output_path'] = output_directory
|
||||
self.driver_settings['input_path'] = input_directory
|
||||
self.driver_settings['output_path'] = output_directory
|
||||
|
||||
if scale_ratio:
|
||||
self.waifu2x_settings['scale_ratio'] = scale_ratio
|
||||
self.driver_settings['scale_ratio'] = scale_ratio
|
||||
elif scale_width and scale_height:
|
||||
self.waifu2x_settings['scale_width'] = scale_width
|
||||
self.waifu2x_settings['scale_height'] = scale_height
|
||||
self.driver_settings['scale_width'] = scale_width
|
||||
self.driver_settings['scale_height'] = scale_height
|
||||
|
||||
self.waifu2x_settings['output_extention'] = image_format
|
||||
self.driver_settings['output_extention'] = image_format
|
||||
|
||||
# print thread start message
|
||||
self.print_lock.acquire()
|
||||
@ -68,14 +68,14 @@ class Waifu2xCaffe:
|
||||
|
||||
# list to be executed
|
||||
# initialize the list with waifu2x binary path as the first element
|
||||
execute = [str(self.waifu2x_settings['waifu2x_caffe_path'])]
|
||||
execute = [str(self.driver_settings['path'])]
|
||||
|
||||
for key in self.waifu2x_settings.keys():
|
||||
for key in self.driver_settings.keys():
|
||||
|
||||
value = self.waifu2x_settings[key]
|
||||
value = self.driver_settings[key]
|
||||
|
||||
# is executable key or null or None means that leave this option out (keep default)
|
||||
if key == 'waifu2x_caffe_path' or value is None or value is False:
|
||||
if key == 'path' or value is None or value is False:
|
||||
continue
|
||||
else:
|
||||
if len(key) == 1:
|
30
bin/waifu2x_converter.py → src/waifu2x_converter.py
Normal file → Executable file
30
bin/waifu2x_converter.py → src/waifu2x_converter.py
Normal file → Executable file
@ -4,7 +4,7 @@
|
||||
Name: Waifu2x Converter CPP Driver
|
||||
Author: K4YT3X
|
||||
Date Created: February 8, 2019
|
||||
Last Modified: August 3, 2019
|
||||
Last Modified: October 6, 2019
|
||||
|
||||
Description: This class is a high-level wrapper
|
||||
for waifu2x-converter-cpp.
|
||||
@ -28,9 +28,9 @@ class Waifu2xConverter:
|
||||
the upscale function.
|
||||
"""
|
||||
|
||||
def __init__(self, waifu2x_settings, model_dir):
|
||||
self.waifu2x_settings = waifu2x_settings
|
||||
self.waifu2x_settings['model_dir'] = model_dir
|
||||
def __init__(self, driver_settings, model_dir):
|
||||
self.driver_settings = driver_settings
|
||||
self.driver_settings['model_dir'] = model_dir
|
||||
self.print_lock = threading.Lock()
|
||||
|
||||
def upscale(self, input_directory, output_directory, scale_ratio, jobs, image_format, upscaler_exceptions):
|
||||
@ -46,16 +46,16 @@ class Waifu2xConverter:
|
||||
|
||||
try:
|
||||
# overwrite config file settings
|
||||
self.waifu2x_settings['input'] = input_directory
|
||||
self.waifu2x_settings['output'] = output_directory
|
||||
self.waifu2x_settings['scale-ratio'] = scale_ratio
|
||||
self.waifu2x_settings['jobs'] = jobs
|
||||
self.waifu2x_settings['output-format'] = image_format
|
||||
self.driver_settings['input'] = input_directory
|
||||
self.driver_settings['output'] = output_directory
|
||||
self.driver_settings['scale-ratio'] = scale_ratio
|
||||
self.driver_settings['jobs'] = jobs
|
||||
self.driver_settings['output-format'] = image_format
|
||||
|
||||
# models_rgb must be specified manually for waifu2x-converter-cpp
|
||||
# if it's not specified in the arguments, create automatically
|
||||
if self.waifu2x_settings['model-dir'] is None:
|
||||
self.waifu2x_settings['model-dir'] = pathlib.Path(self.waifu2x_settings['waifu2x_converter_path']) / 'models_rgb'
|
||||
if self.driver_settings['model-dir'] is None:
|
||||
self.driver_settings['model-dir'] = pathlib.Path(self.driver_settings['waifu2x_converter_path']) / 'models_rgb'
|
||||
|
||||
# print thread start message
|
||||
self.print_lock.acquire()
|
||||
@ -64,14 +64,14 @@ class Waifu2xConverter:
|
||||
|
||||
# list to be executed
|
||||
# initialize the list with waifu2x binary path as the first element
|
||||
execute = [str(pathlib.Path(self.waifu2x_settings['waifu2x_converter_path']) / 'waifu2x-converter-cpp.exe')]
|
||||
execute = [str(pathlib.Path(self.driver_settings['path']) / 'waifu2x-converter-cpp.exe')]
|
||||
|
||||
for key in self.waifu2x_settings.keys():
|
||||
for key in self.driver_settings.keys():
|
||||
|
||||
value = self.waifu2x_settings[key]
|
||||
value = self.driver_settings[key]
|
||||
|
||||
# the key doesn't need to be passed in this case
|
||||
if key == 'waifu2x_converter_path':
|
||||
if key == 'path':
|
||||
continue
|
||||
|
||||
# null or None means that leave this option out (keep default)
|
22
bin/waifu2x_ncnn_vulkan.py → src/waifu2x_ncnn_vulkan.py
Normal file → Executable file
22
bin/waifu2x_ncnn_vulkan.py → src/waifu2x_ncnn_vulkan.py
Normal file → Executable file
@ -4,7 +4,7 @@
|
||||
Name: Waifu2x NCNN Vulkan Driver
|
||||
Author: SAT3LL
|
||||
Date Created: June 26, 2019
|
||||
Last Modified: October 24, 2019
|
||||
Last Modified: November 15, 2019
|
||||
|
||||
Dev: K4YT3X
|
||||
|
||||
@ -30,14 +30,14 @@ class Waifu2xNcnnVulkan:
|
||||
the upscale function.
|
||||
"""
|
||||
|
||||
def __init__(self, waifu2x_settings):
|
||||
self.waifu2x_settings = waifu2x_settings
|
||||
def __init__(self, driver_settings):
|
||||
self.driver_settings = driver_settings
|
||||
|
||||
# arguments passed through command line overwrites config file values
|
||||
|
||||
# waifu2x_ncnn_vulkan can't find its own model directory if its not in the current dir
|
||||
# so change to it
|
||||
os.chdir(os.path.join(self.waifu2x_settings['waifu2x_ncnn_vulkan_path'], '..'))
|
||||
os.chdir(os.path.join(self.driver_settings['waifu2x_ncnn_vulkan_path'], '..'))
|
||||
|
||||
self.print_lock = threading.Lock()
|
||||
|
||||
@ -52,9 +52,9 @@ class Waifu2xNcnnVulkan:
|
||||
|
||||
try:
|
||||
# overwrite config file settings
|
||||
self.waifu2x_settings['i'] = input_directory
|
||||
self.waifu2x_settings['o'] = output_directory
|
||||
self.waifu2x_settings['s'] = int(scale_ratio)
|
||||
self.driver_settings['i'] = input_directory
|
||||
self.driver_settings['o'] = output_directory
|
||||
self.driver_settings['s'] = int(scale_ratio)
|
||||
|
||||
# print thread start message
|
||||
self.print_lock.acquire()
|
||||
@ -63,14 +63,14 @@ class Waifu2xNcnnVulkan:
|
||||
|
||||
# list to be executed
|
||||
# initialize the list with waifu2x binary path as the first element
|
||||
execute = [str(self.waifu2x_settings['waifu2x_ncnn_vulkan_path'])]
|
||||
execute = [str(self.driver_settings['path'])]
|
||||
|
||||
for key in self.waifu2x_settings.keys():
|
||||
for key in self.driver_settings.keys():
|
||||
|
||||
value = self.waifu2x_settings[key]
|
||||
value = self.driver_settings[key]
|
||||
|
||||
# is executable key or null or None means that leave this option out (keep default)
|
||||
if key == 'waifu2x_ncnn_vulkan_path' or value is None or value is False:
|
||||
if key == 'path' or value is None or value is False:
|
||||
continue
|
||||
else:
|
||||
if len(key) == 1:
|
Loading…
Reference in New Issue
Block a user