29 Commits

Author SHA1 Message Date
k4yt3x
6180ccd9b2 fixing folder upscaling function 2019-08-29 16:03:15 -04:00
k4yt3x
e10315f89e using contextlib instead of try-catch 2019-08-25 23:03:37 -04:00
k4yt3x
6521e071ce enhanced logo-printing 2019-08-25 23:03:18 -04:00
k4yt3x
a685e91b14 removed unused dependencies 2019-08-25 23:02:59 -04:00
k4yt3x
9d72bad314 temporary fix for Anime4K download 2019-08-20 22:40:26 -04:00
k4yt3x
2b63b5f0a6 added total time display 2019-08-17 23:28:37 -04:00
k4yt3x
9c84228c17 added screenshot for video2x gui 2019-08-17 23:19:47 -04:00
k4yt3x
f9bb191336 fixed gui compatibility with anime4k, added constraints for a4k 2019-08-17 18:16:47 -04:00
K4YT3X
7a3af366f8 Merge pull request #137 from k4yt3x/2.10.0-anime4k
2.10.0 anime4k
2019-08-16 15:49:33 +00:00
k4yt3x
d4223f93ec fixed a4k not installed bug 2019-08-16 02:53:07 -04:00
k4yt3x
c5c764a91f GUI 1.1.1: Added support for Anime4K 2019-08-16 02:49:38 -04:00
k4yt3x
ba6472c9fc exe build is out of beta 2019-08-16 02:49:22 -04:00
k4yt3x
dc1244580f updated README for 2.10.0 2019-08-16 00:46:43 -04:00
k4yt3x
0347d05127 setup script 1.5.0: added support for Anime4K 2019-08-16 00:36:45 -04:00
k4yt3x
45f5bf91e6 updated anime4k path 2019-08-16 00:36:22 -04:00
k4yt3x
5e78beabcf added thread dialog for anime4k 2019-08-16 00:19:36 -04:00
k4yt3x
6c5b7ea17f moved constants into one single place 2019-08-15 23:57:24 -04:00
k4yt3x
d9610abae0 fixed thread-unsafe printing 2019-08-15 23:56:55 -04:00
k4yt3x
47471352ba 2.10.0 added anime4k support 2019-08-15 23:34:24 -04:00
k4yt3x
969cfe5c0d fixing issue #134 2019-08-11 23:57:10 -04:00
k4yt3x
e12db41213 updated bug report template for newest version of v2x 2019-08-07 23:07:55 -04:00
k4yt3x
7a69d58e28 placed version number into window title 2019-08-07 22:56:41 -04:00
k4yt3x
ad6308d385 relocated docstrings 2019-08-07 22:54:39 -04:00
k4yt3x
8c3a85ac42 GUI 1.1.0 added basic menu bar and better output file naming check 2019-08-07 22:54:33 -04:00
k4yt3x
db603062e9 updated main file date 2019-08-03 23:15:36 -04:00
k4yt3x
807276fcc3 fixing converter frame filename issues 2019-08-03 23:15:19 -04:00
k4yt3x
9be46f7d62 fixing support for waifu2x_ncnn_vulkan 2019-08-03 23:15:03 -04:00
k4yt3x
f42a8ab71f fixed waifu2x-ncnn-vulkan argument errors 2019-08-03 21:29:13 -04:00
k4yt3x
e3b2624977 fixed the issue where subprocess tries to execute pathlib.Path 2019-08-03 19:45:22 -04:00
13 changed files with 364 additions and 162 deletions

View File

@@ -11,10 +11,11 @@ assignees: K4YT3X
|Module|Version| |Module|Version|
|-|-| |-|-|
|`video2x`|| |`Video2X`||
|`ffmpeg`|| |`FFmpeg`||
|`waifu2x-caffe`|| |`waifu2x-caffe`||
|`waifu2x-converter-cpp`|| |`waifu2x-converter-cpp`||
|`waifu2x-ncnn-vulkan`||
## Symptom ## Symptom

View File

@@ -2,11 +2,11 @@
### Official Discussion Group (Telegram): https://t.me/video2x ### Official Discussion Group (Telegram): https://t.me/video2x
## Download Builds (beta) ## Download Builds
You can go to the [releases page](https://github.com/k4yt3x/video2x/releases) to download the latest builds of `Video2X`. The exe files will require no Python or Python module installation. You can go to the [releases page](https://github.com/k4yt3x/video2x/releases) to download the latest builds of `Video2X`. The exe files will require no Python or Python module installation.
The **`full`** package provides all packages that will possibly be needed by `Video2X`, including `FFmpeg`, `waifu2x-caffe`, `waifu2x-converter-cpp`, and `waifu2x-ncnn-vulkan`. The config file (`video2x.json`) is also already configured for the environment. All you need to do is just to launch `video2x.exe`. The **`full`** package provides all packages that will possibly be needed by `Video2X`, including `FFmpeg`, `waifu2x-caffe`, `waifu2x-converter-cpp`, `waifu2x-ncnn-vulkan`, and `Anime4K`. The config file (`video2x.json`) is also already configured for the environment. All you need to do is just to launch `video2x.exe`.
The **`light`** package provides only the most basic functions of `Video2X`. Only `video2x.exe`, `video2x_setup.exe` and `video2x.json` are included. To setup dependencies (e.g. `FFmpeg` and `Waifu2X`) automatically, simply launch `video2x_setup.exe`. The **`light`** package provides only the most basic functions of `Video2X`. Only `video2x.exe`, `video2x_setup.exe` and `video2x.json` are included. To setup dependencies (e.g. `FFmpeg` and `Waifu2X`) automatically, simply launch `video2x_setup.exe`.
@@ -18,10 +18,18 @@ Component names that are **bolded** can be automatically downloaded and configur
2. AMD GPU / Nvidia GPU 2. AMD GPU / Nvidia GPU
3. AMD GPU driver / Nvidia GPU driver / Nvidia CUDNN 3. AMD GPU driver / Nvidia GPU driver / Nvidia CUDNN
4. [**FFmpeg**](https://ffmpeg.zeranoe.com/builds/) 4. [**FFmpeg**](https://ffmpeg.zeranoe.com/builds/)
5. [**waifu2x-caffe**](https://github.com/lltcggie/waifu2x-caffe/releases) / [**waifu2x-converter-cpp**](https://github.com/DeadSix27/waifu2x-converter-cpp/releases) / [**waifu2x-ncnn-vulkan**](https://github.com/nihui/waifu2x-ncnn-vulkan) 5. One of the following drivers
- [**waifu2x-caffe**](https://github.com/lltcggie/waifu2x-caffe/releases)
- [**waifu2x-converter-cpp**](https://github.com/DeadSix27/waifu2x-converter-cpp/releases)
- [**waifu2x-ncnn-vulkan**](https://github.com/nihui/waifu2x-ncnn-vulkan)
- [**Anime4K**](https://github.com/bloc97/Anime4K)
## Recent Changes ## Recent Changes
### 2.10.0 (August 16, 2019)
- **Added support for [Anime4K](https://github.com/bloc97/Anime4K)**
### 2.9.0 (July 27, 2019) ### 2.9.0 (July 27, 2019)
- Changed file handling method from `os` to `pathlib` - Changed file handling method from `os` to `pathlib`
@@ -35,15 +43,11 @@ Component names that are **bolded** can be automatically downloaded and configur
### 2.8.0 (June 25, 2019) ### 2.8.0 (June 25, 2019)
- Added support for [waifu2x-ncnn-vulkan](https://github.com/nihui/waifu2x-ncnn-vulkan) - **Added support for [waifu2x-ncnn-vulkan](https://github.com/nihui/waifu2x-ncnn-vulkan)**
### 2.7.1 (April 18, 2019) ### Setup Script 1.5.0 (August 16, 2019)
- Fixed video2x custom temp folder bug found by @cr08 . - Added automatic installation support for `Anime4K`
### Setup Script 1.3.0 (June 25, 2019)
- Added automatic installation support for `waifu2x-ncnn-vulkan`
## Description ## Description
@@ -61,6 +65,8 @@ Clip is from trailer of animated movie "千と千尋の神隠し". Copyright bel
## Screenshot ## Screenshot
![video2x_gui](https://user-images.githubusercontent.com/21986859/63219691-ee478400-c166-11e9-8c15-dcf59228bd96.png)
![screenshot](https://user-images.githubusercontent.com/21986859/40265170-39c0caae-5b01-11e8-8371-8b6c24769639.png) ![screenshot](https://user-images.githubusercontent.com/21986859/40265170-39c0caae-5b01-11e8-8371-8b6c24769639.png)
--- ---
@@ -89,14 +95,18 @@ If you have any questions, first try visiting our [Q&A](https://github.com/k4yt3
### Prerequisites ### Prerequisites
- **Python 3** - **Python 3**
Download: https://www.python.org/downloads/windows/ Download: https://www.python.org/downloads/windows/
- **FFmpeg Windows Build** - **FFmpeg Windows Build**
Download: https://ffmpeg.org/download.html Download: https://ffmpeg.org/download.html
- **waifu2x-caffe** (for Nvidia CUDA/CUDNN) - **waifu2x-caffe** (for Nvidia CUDA/CUDNN)
Download: https://github.com/lltcggie/waifu2x-caffe/releases Download: https://github.com/lltcggie/waifu2x-caffe/releases
- **waifu2x-converter-cpp** (required for AMD, OpenCL and OpenGL processing) - **waifu2x-converter-cpp** (required for AMD, OpenCL and OpenGL processing)
Download: https://github.com/DeadSix27/waifu2x-converter-cpp/releases Download: https://github.com/DeadSix27/waifu2x-converter-cpp/releases
- **waifu2x-ncnn-vulkan**
Download: https://github.com/nihui/waifu2x-ncnn-vulkan/releases
- **Anime4K**
Download: https://github.com/bloc97/Anime4K/releases
### Installing Dependencies ### Installing Dependencies
@@ -144,7 +154,7 @@ Enlarge the video to 1920x1080 using CUDA. You may also use the `-r/--ratio` opt
python video2x.py -i sample_input.mp4 -o sample_output.mp4 -m gpu --width=1920 --height=1080 python video2x.py -i sample_input.mp4 -o sample_output.mp4 -m gpu --width=1920 --height=1080
``` ```
### Nvidia CNDNN ### Nvidia CUDNN
Enlarge the video to 1920x1080 using CUDNN. You may also use the `-r/--ratio` option. Enlarge the video to 1920x1080 using CUDNN. You may also use the `-r/--ratio` option.
@@ -168,7 +178,7 @@ python video2x.py -i sample_input.mp4 -o sample_output.mp4 -m gpu -r 2 -d waifu2
### CPU ### CPU
Enlarge the video to 1920x1080 using the CPU. You may also use the `-r/--ratio` option. This is potentially much slower than using a GPU. The configuration file for this method is similar to the previous methods. Enlarge the video to 1920x1080 using the CPU. You may also use the `-r/--ratio` option. **waifu2x-based upscalers potentially run much slower than using a GPU, but Anime4K is more CPU-dependant**. The configuration file for this method is similar to the previous methods.
```shell ```shell
python video2x.py -i sample_input.mp4 -o sample_output.mp4 -m cpu --width=1920 --height=1080 python video2x.py -i sample_input.mp4 -o sample_output.mp4 -m cpu --width=1920 --height=1080
@@ -241,6 +251,7 @@ This project relies on the following software and projects.
- [waifu2x-caffe](https://github.com/lltcggie/waifu2x-caffe) - [waifu2x-caffe](https://github.com/lltcggie/waifu2x-caffe)
- [waifu2x-converter-cpp](https://github.com/DeadSix27/waifu2x-converter-cpp) - [waifu2x-converter-cpp](https://github.com/DeadSix27/waifu2x-converter-cpp)
- [waifu2x-ncnn-vulkan](https://github.com/nihui/waifu2x-ncnn-vulkan) - [waifu2x-ncnn-vulkan](https://github.com/nihui/waifu2x-ncnn-vulkan)
- [Anime4K](https://github.com/bloc97/Anime4K)
## Special Thanks ## Special Thanks

92
bin/anime4k.py Normal file
View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Name: Anime4K Driver
Author: K4YT3X
Date Created: August 15, 2019
Last Modified: August 15, 2019
Description: This class is a high-level wrapper
for Anime4k.
"""
# built-in imports
import subprocess
import threading
# third-party imports
from avalon_framework import Avalon
class Anime4k:
"""This class communicates with Anime4K engine
An object will be created for this class, containing information
about the binary address and the processing method. When being called
by the main program, other detailed information will be passed to
the upscale function.
"""
def __init__(self, waifu2x_settings):
self.waifu2x_settings = waifu2x_settings
self.print_lock = threading.Lock()
def upscale(self, input_directory, output_directory, scale_ratio, upscaler_exceptions, push_strength=None, push_grad_strength=None):
""" Anime4K wrapper
Arguments:
file_in {string} -- input file path
file_out {string} -- output file path
Keyword Arguments:
scale {int} -- scale ratio (default: {None})
push_strength {int} -- residual push strength (default: {None})
push_grad_strength {int} -- residual gradient push strength (default: {None})
Returns:
subprocess.Popen.returncode -- command line return value of execution
"""
try:
# return value is the sum of all execution return codes
return_value = 0
# get a list lof all image files in input_directory
extracted_frame_files = [f for f in input_directory.iterdir() if str(f).lower().endswith('.png') or str(f).lower().endswith('.jpg')]
# upscale each image in input_directory
for image in extracted_frame_files:
execute = [
self.waifu2x_settings['java_path'],
'-jar',
self.waifu2x_settings['anime4k_path'],
str(image.absolute()),
str(output_directory / image.name),
str(scale_ratio)
]
# optional arguments
kwargs = [
'push_strength',
'push_grad_strength'
]
# if optional argument specified, append value to execution list
for arg in kwargs:
if locals()[arg] is not None:
execute.extend([locals([arg])])
self.print_lock.acquire()
Avalon.debug_info(f'Executing: {execute}', )
self.print_lock.release()
return_value += subprocess.run(execute, check=True).returncode
# print thread exiting message
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Thread {threading.current_thread().name} exiting')
self.print_lock.release()
# return command execution return code
return return_value
except Exception as e:
upscaler_exceptions.append(e)

View File

@@ -4,14 +4,13 @@
Name: Video2X FFmpeg Controller Name: Video2X FFmpeg Controller
Author: K4YT3X Author: K4YT3X
Date Created: Feb 24, 2018 Date Created: Feb 24, 2018
Last Modified: July 27, 2019 Last Modified: August 15, 2019
Description: This class handles all FFmpeg related operations. Description: This class handles all FFmpeg related operations.
""" """
# built-in imports # built-in imports
import json import json
import os
import pathlib import pathlib
import subprocess import subprocess
@@ -119,6 +118,8 @@ class Ffmpeg:
self.ffmpeg_binary self.ffmpeg_binary
] ]
execute.extend(self._read_configuration(phase='video_to_frames'))
execute.extend([ execute.extend([
'-i', '-i',
input_video input_video
@@ -130,8 +131,6 @@ class Ffmpeg:
extracted_frames / f'extracted_%0d.{self.image_format}' extracted_frames / f'extracted_%0d.{self.image_format}'
]) ])
execute.extend(self._read_configuration(phase='video_to_frames'))
self._execute(execute) self._execute(execute)
def convert_video(self, framerate, resolution, upscaled_frames): def convert_video(self, framerate, resolution, upscaled_frames):
@@ -152,6 +151,9 @@ class Ffmpeg:
resolution resolution
] ]
# read other options
execute.extend(self._read_configuration(phase='frames_to_video'))
# read FFmpeg input options # read FFmpeg input options
execute.extend(self._read_configuration(phase='frames_to_video', section='input_options')) execute.extend(self._read_configuration(phase='frames_to_video', section='input_options'))
@@ -159,8 +161,7 @@ class Ffmpeg:
# Dev: SAT3LL # Dev: SAT3LL
# rename all .png.png suffixes to .png # rename all .png.png suffixes to .png
import re import re
import shutil regex = re.compile(r'\.png\.png$', re.IGNORECASE)
regex = re.compile(r'\.png\.png$')
for frame_name in upscaled_frames.iterdir(): for frame_name in upscaled_frames.iterdir():
(upscaled_frames / frame_name).rename(upscaled_frames / regex.sub('.png', str(frame_name))) (upscaled_frames / frame_name).rename(upscaled_frames / regex.sub('.png', str(frame_name)))
# END WORKAROUND # END WORKAROUND
@@ -174,9 +175,6 @@ class Ffmpeg:
# read FFmpeg output options # read FFmpeg output options
execute.extend(self._read_configuration(phase='frames_to_video', section='output_options')) execute.extend(self._read_configuration(phase='frames_to_video', section='output_options'))
# read other options
execute.extend(self._read_configuration(phase='frames_to_video'))
# specify output file location # specify output file location
execute.extend([ execute.extend([
upscaled_frames / 'no_audio.mp4' upscaled_frames / 'no_audio.mp4'
@@ -193,12 +191,17 @@ class Ffmpeg:
upscaled_frames {string} -- directory containing upscaled frames upscaled_frames {string} -- directory containing upscaled frames
""" """
execute = [ execute = [
self.ffmpeg_binary, self.ffmpeg_binary
]
execute.extend(self._read_configuration(phase='migrating_tracks'))
execute.extend([
'-i', '-i',
upscaled_frames / 'no_audio.mp4', upscaled_frames / 'no_audio.mp4',
'-i', '-i',
input_video input_video
] ])
execute.extend(self._read_configuration(phase='migrating_tracks', section='output_options')) execute.extend(self._read_configuration(phase='migrating_tracks', section='output_options'))
@@ -206,8 +209,6 @@ class Ffmpeg:
output_video output_video
]) ])
execute.extend(self._read_configuration(phase='migrating_tracks'))
self._execute(execute) self._execute(execute)
def _read_configuration(self, phase, section=None): def _read_configuration(self, phase, section=None):
@@ -278,9 +279,9 @@ class Ffmpeg:
Returns: Returns:
int -- execution return code int -- execution return code
""" """
Avalon.debug_info(f'Executing: {execute}')
# turn all list elements into string to avoid errors # turn all list elements into string to avoid errors
execute = [str(e) for e in execute] execute = [str(e) for e in execute]
Avalon.debug_info(f'Executing: {execute}')
return subprocess.run(execute, shell=True, check=True).returncode return subprocess.run(execute, shell=True, check=True).returncode

View File

@@ -12,7 +12,6 @@ that have already been upscaled.
""" """
# built-in imports # built-in imports
import os
import threading import threading
import time import time

View File

@@ -4,7 +4,7 @@
Name: Video2X Upscaler Name: Video2X Upscaler
Author: K4YT3X Author: K4YT3X
Date Created: December 10, 2018 Date Created: December 10, 2018
Last Modified: July 27, 2019 Last Modified: August 21, 2019
Dev: SAT3LL Dev: SAT3LL
@@ -15,6 +15,7 @@ Licensed under the GNU General Public License Version 3 (GNU GPL v3),
""" """
# local imports # local imports
from anime4k import Anime4k
from exceptions import * from exceptions import *
from ffmpeg import Ffmpeg from ffmpeg import Ffmpeg
from image_cleaner import ImageCleaner from image_cleaner import ImageCleaner
@@ -24,6 +25,7 @@ from waifu2x_ncnn_vulkan import Waifu2xNcnnVulkan
# built-in imports # built-in imports
from fractions import Fraction from fractions import Fraction
import contextlib
import copy import copy
import pathlib import pathlib
import re import re
@@ -37,6 +39,8 @@ import traceback
from avalon_framework import Avalon from avalon_framework import Avalon
from tqdm import tqdm from tqdm import tqdm
AVAILABLE_DRIVERS = ['waifu2x_caffe', 'waifu2x_converter', 'waifu2x_ncnn_vulkan', 'anime4k']
class Upscaler: class Upscaler:
""" An instance of this class is a upscaler that will """ An instance of this class is a upscaler that will
@@ -122,7 +126,7 @@ class Upscaler:
previous_cycle_frames = 0 previous_cycle_frames = 0
while not self.progress_bar_exit_signal: while not self.progress_bar_exit_signal:
try: with contextlib.suppress(FileNotFoundError):
self.total_frames_upscaled = len([f for f in self.upscaled_frames.iterdir() if str(f)[-4:] == f'.{self.image_format}']) self.total_frames_upscaled = len([f for f in self.upscaled_frames.iterdir() if str(f)[-4:] == f'.{self.image_format}'])
delta = self.total_frames_upscaled - previous_cycle_frames delta = self.total_frames_upscaled - previous_cycle_frames
previous_cycle_frames = self.total_frames_upscaled previous_cycle_frames = self.total_frames_upscaled
@@ -131,10 +135,8 @@ class Upscaler:
if self.total_frames_upscaled >= self.total_frames: if self.total_frames_upscaled >= self.total_frames:
return return
# adds the detla into the progress bar # adds the delta into the progress bar
progress_bar.update(delta) progress_bar.update(delta)
except FileNotFoundError:
pass
time.sleep(1) time.sleep(1)
@@ -156,7 +158,7 @@ class Upscaler:
self.upscaler_exceptions = [] self.upscaler_exceptions = []
# initialize waifu2x driver # initialize waifu2x driver
drivers = ['waifu2x_caffe', 'waifu2x_converter', 'waifu2x_ncnn_vulkan'] drivers = AVAILABLE_DRIVERS
if self.waifu2x_driver not in drivers: if self.waifu2x_driver not in drivers:
raise UnrecognizedDriverError(f'Unrecognized waifu2x driver: {self.waifu2x_driver}') raise UnrecognizedDriverError(f'Unrecognized waifu2x driver: {self.waifu2x_driver}')
@@ -170,12 +172,14 @@ class Upscaler:
w2.upscale(self.extracted_frames, self.upscaled_frames, self.scale_ratio, self.threads, self.image_format, self.upscaler_exceptions) w2.upscale(self.extracted_frames, self.upscaled_frames, self.scale_ratio, self.threads, self.image_format, self.upscaler_exceptions)
for image in [f for f in self.upscaled_frames.iterdir() if f.is_file()]: for image in [f for f in self.upscaled_frames.iterdir() if f.is_file()]:
renamed = re.sub(f'_\[.*-.*\]\[x(\d+(\.\d+)?)\]\.{self.image_format}', f'.{self.image_format}', image) renamed = re.sub(f'_\[.*-.*\]\[x(\d+(\.\d+)?)\]\.{self.image_format}', f'.{self.image_format}', str(image))
(self.upscaled_frames / image).rename(self.upscaled_frames / renamed) (self.upscaled_frames / image).rename(self.upscaled_frames / renamed)
self.progress_bar_exit_signal = True self.progress_bar_exit_signal = True
progress_bar.join() progress_bar.join()
return return
# drivers that are to be multi-threaded by video2x
else: else:
# create a container for all upscaler threads # create a container for all upscaler threads
upscaler_threads = [] upscaler_threads = []
@@ -247,6 +251,15 @@ class Upscaler:
self.scale_ratio, self.scale_ratio,
self.upscaler_exceptions)) self.upscaler_exceptions))
# if the driver being used is anime4k
elif self.waifu2x_driver == 'anime4k':
w2 = Anime4k(copy.deepcopy(self.waifu2x_settings))
thread = threading.Thread(target=w2.upscale,
args=(thread_info[0],
self.upscaled_frames,
self.scale_ratio,
self.upscaler_exceptions))
# create thread # create thread
thread.name = thread_info[1] thread.name = thread_info[1]

View File

@@ -41,15 +41,19 @@
}, },
"waifu2x_ncnn_vulkan": { "waifu2x_ncnn_vulkan": {
"waifu2x_ncnn_vulkan_path": "C:\\Users\\K4YT3X\\AppData\\Local\\video2x\\waifu2x-ncnn-vulkan\\waifu2x-ncnn-vulkan.exe", "waifu2x_ncnn_vulkan_path": "C:\\Users\\K4YT3X\\AppData\\Local\\video2x\\waifu2x-ncnn-vulkan\\waifu2x-ncnn-vulkan.exe",
"input": null, "v": null,
"output": null, "i": null,
"noise-level": 2, "o": null,
"scale-ratio": null, "n": 2,
"tile-size": 200, "s": 2,
"model-path": null, "t": 400,
"gpu": 0, "m": "models-cunet",
"load-proc-save_threads": null, "g": 0,
"verbose": null "j": "1:2:2"
},
"anime4k": {
"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": {
"ffmpeg_path": "C:\\Users\\K4YT3X\\AppData\\Local\\video2x\\ffmpeg-latest-win64-static\\bin", "ffmpeg_path": "C:\\Users\\K4YT3X\\AppData\\Local\\video2x\\ffmpeg-latest-win64-static\\bin",
@@ -73,6 +77,7 @@
"-b:v": null, "-b:v": null,
"-pix_fmt": null "-pix_fmt": null
}, },
"-hwaccel": "auto",
"-y": true "-y": true
}, },
"migrating_tracks": { "migrating_tracks": {
@@ -85,6 +90,7 @@
"-c": "copy", "-c": "copy",
"-pix_fmt": null "-pix_fmt": null
}, },
"-hwaccel": "auto",
"-y": true "-y": true
} }
}, },

View File

@@ -13,7 +13,7 @@ __ __ _ _ ___ __ __
Name: Video2X Controller Name: Video2X Controller
Author: K4YT3X Author: K4YT3X
Date Created: Feb 24, 2018 Date Created: Feb 24, 2018
Last Modified: July 27, 2019 Last Modified: August 29, 2019
Dev: BrianPetkovsek Dev: BrianPetkovsek
Dev: SAT3LL Dev: SAT3LL
@@ -44,13 +44,13 @@ smooth and edges sharp.
# local imports # local imports
from exceptions import * from exceptions import *
from upscaler import AVAILABLE_DRIVERS
from upscaler import Upscaler from upscaler import Upscaler
# built-in imports # built-in imports
import argparse import argparse
import glob import contextlib
import json import json
import os
import pathlib import pathlib
import re import re
import shutil import shutil
@@ -64,7 +64,22 @@ from avalon_framework import Avalon
import GPUtil import GPUtil
import psutil import psutil
VERSION = '2.9.0' VERSION = '2.10.0'
LEGAL_INFO = f'''Video2X Version: {VERSION}
Author: K4YT3X
License: GNU GPL v3
Github Page: https://github.com/k4yt3x/video2x
Contact: k4yt3x@k4yt3x.com'''
LOGO = r'''
__ __ _ _ ___ __ __
\ \ / / (_) | | |__ \ \ \ / /
\ \ / / _ __| | ___ ___ ) | \ V /
\ \/ / | | / _` | / _ \ / _ \ / / > <
\ / | | | (_| | | __/ | (_) | / /_ / . \
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
'''
# each thread might take up to 2.5 GB during initialization. # each thread might take up to 2.5 GB during initialization.
# (system memory, not to be confused with GPU memory) # (system memory, not to be confused with GPU memory)
@@ -89,7 +104,7 @@ def process_arguments():
# upscaler options # upscaler options
upscaler_options = parser.add_argument_group('Upscaler Options') upscaler_options = parser.add_argument_group('Upscaler Options')
upscaler_options.add_argument('-m', '--method', help='upscaling method', action='store', default='gpu', choices=['cpu', 'gpu', 'cudnn']) upscaler_options.add_argument('-m', '--method', help='upscaling method', action='store', default='gpu', choices=['cpu', 'gpu', 'cudnn'])
upscaler_options.add_argument('-d', '--driver', help='waifu2x driver', action='store', default='waifu2x_caffe', choices=['waifu2x_caffe', 'waifu2x_converter', 'waifu2x_ncnn_vulkan']) 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('-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('-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.json')
@@ -111,18 +126,9 @@ def process_arguments():
def print_logo(): def print_logo():
"""print video2x logo""" """print video2x logo"""
logo = r''' print(LOGO)
__ __ _ _ ___ __ __ print(f'\n{"Video2X Video Enlarger".rjust(40, " ")}')
\ \ / / (_) | | |__ \ \ \ / / print(f'\n{Avalon.FM.BD}{f"Version {VERSION}".rjust(36, " ")}{Avalon.FM.RST}\n')
\ \ / / _ __| | ___ ___ ) | \ V /
\ \/ / | | / _` | / _ \ / _ \ / / > <
\ / | | | (_| | | __/ | (_) | / /_ / . \
\/ |_| \__,_| \___| \___/ |____| /_/ \_\
'''
print(logo)
print('\n Video2X Video Enlarger')
spaces = ((44 - len(f'Version {VERSION}')) // 2) * ' '
print(f'{Avalon.FM.BD}\n{spaces} Version {VERSION}\n{Avalon.FM.RST}')
def check_memory(): def check_memory():
@@ -145,12 +151,10 @@ def check_memory():
Avalon.warning('Nvidia-smi not available, skipping available memory check') Avalon.warning('Nvidia-smi not available, skipping available memory check')
Avalon.warning('If you experience error \"cudaSuccess out of memory\", try reducing number of threads you\'re using') Avalon.warning('If you experience error \"cudaSuccess out of memory\", try reducing number of threads you\'re using')
else: else:
try: with contextlib.suppress(ValueError):
# "0" is GPU ID. Both waifu2x drivers use the first GPU available, therefore only 0 makes sense # "0" is GPU ID. Both waifu2x drivers use the first GPU available, therefore only 0 makes sense
gpu_memory_available = (GPUtil.getGPUs()[0].memoryTotal - GPUtil.getGPUs()[0].memoryUsed) / 1024 gpu_memory_available = (GPUtil.getGPUs()[0].memoryTotal - GPUtil.getGPUs()[0].memoryUsed) / 1024
memory_status.append(('GPU', gpu_memory_available)) memory_status.append(('GPU', gpu_memory_available))
except ValueError:
pass
# go though each checkable memory type and check availability # go though each checkable memory type and check availability
for memory_type, memory_available in memory_status: for memory_type, memory_available in memory_status:
@@ -218,6 +222,10 @@ def absolutify_paths(config):
if not re.match('^[a-z]:', config['waifu2x_ncnn_vulkan']['waifu2x_ncnn_vulkan_path'], re.IGNORECASE): if not re.match('^[a-z]:', config['waifu2x_ncnn_vulkan']['waifu2x_ncnn_vulkan_path'], re.IGNORECASE):
config['waifu2x_ncnn_vulkan']['waifu2x_ncnn_vulkan_path'] = current_directory / config['waifu2x_ncnn_vulkan']['waifu2x_ncnn_vulkan_path'] config['waifu2x_ncnn_vulkan']['waifu2x_ncnn_vulkan_path'] = current_directory / config['waifu2x_ncnn_vulkan']['waifu2x_ncnn_vulkan_path']
# check anime4k path
if not re.match('^[a-z]:', config['anime4k']['anime4k_path'], re.IGNORECASE):
config['anime4k']['anime4k_path'] = current_directory / config['anime4k']['anime4k_path']
# check ffmpeg path # check ffmpeg path
if not re.match('^[a-z]:', config['ffmpeg']['ffmpeg_path'], re.IGNORECASE): if not re.match('^[a-z]:', config['ffmpeg']['ffmpeg_path'], re.IGNORECASE):
config['ffmpeg']['ffmpeg_path'] = current_directory / config['ffmpeg']['ffmpeg_path'] config['ffmpeg']['ffmpeg_path'] = current_directory / config['ffmpeg']['ffmpeg_path']
@@ -245,11 +253,7 @@ args = process_arguments()
# display version and lawful informaition # display version and lawful informaition
if args.version: if args.version:
print(f'Video2X Version: {VERSION}') print(LEGAL_INFO)
print('Author: K4YT3X')
print('License: GNU GPL v3')
print('Github Page: https://github.com/k4yt3x/video2x')
print('Contact: k4yt3x@k4yt3x.com')
exit(0) exit(0)
# arguments sanity check # arguments sanity check
@@ -259,9 +263,9 @@ if not args.input:
if not args.output: if not args.output:
Avalon.error('You must specify output video file/directory path') Avalon.error('You must specify output video file/directory path')
raise ArgumentError('output video path not specified') raise ArgumentError('output video path not specified')
if (args.driver == 'waifu2x_converter' or args.driver == 'waifu2x_ncnn_vulkan') and args.width and args.height: if (args.driver in ['waifu2x_converter', 'waifu2x_ncnn_vulkan', 'anime4k']) and args.width and args.height:
Avalon.error('Waifu2x Converter CPP/NCNN accepts only scaling ratio') Avalon.error('Selected driver accepts only scaling ratio')
raise ArgumentError('waifu2x-converter supports only scaling ratio') raise ArgumentError('selected driver supports only scaling ratio')
if args.driver == 'waifu2x_ncnn_vulkan' and (args.ratio > 2 or not args.ratio.is_integer()): if args.driver == 'waifu2x_ncnn_vulkan' and (args.ratio > 2 or not args.ratio.is_integer()):
Avalon.error('Scaling ratio must be 1 or 2 for waifu2x_ncnn_vulkan') Avalon.error('Scaling ratio must be 1 or 2 for waifu2x_ncnn_vulkan')
raise ArgumentError('scaling ratio must be 1 or 2 for waifu2x_ncnn_vulkan') raise ArgumentError('scaling ratio must be 1 or 2 for waifu2x_ncnn_vulkan')
@@ -272,8 +276,25 @@ if (args.width and not args.height) or (not args.width and args.height):
Avalon.error('You must specify both width and height') Avalon.error('You must specify both width and height')
raise ArgumentError('only one of width or height is specified') raise ArgumentError('only one of width or height is specified')
# check available memory # check available memory if driver is waifu2x-based
check_memory() if args.driver in ['waifu2x_caffe', 'waifu2x_converter', 'waifu2x_ncnn_vulkan']:
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):
while True:
try:
threads = Avalon.gets('Amount of threads to use [5]: ')
args.threads = int(threads)
break
except ValueError:
if threads == '':
args.threads = 5
break
else:
Avalon.error(f'{threads} is not a valid integer')
# read configurations from JSON # read configurations from JSON
config = read_config(args.config) config = read_config(args.config)
@@ -298,6 +319,12 @@ elif args.driver == 'waifu2x_ncnn_vulkan':
Avalon.error('Specified waifu2x_ncnn_vulkan directory doesn\'t exist') Avalon.error('Specified waifu2x_ncnn_vulkan directory doesn\'t exist')
Avalon.error('Please check the configuration file settings') Avalon.error('Please check the configuration file settings')
raise FileNotFoundError(waifu2x_settings['waifu2x_ncnn_vulkan_path']) 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'])
# read FFmpeg configuration # read FFmpeg configuration
ffmpeg_settings = config['ffmpeg'] ffmpeg_settings = config['ffmpeg']
@@ -353,7 +380,7 @@ try:
Avalon.error('Input and output path type mismatch') Avalon.error('Input and output path type mismatch')
Avalon.error('Input is single file but output is directory') Avalon.error('Input is single file but output is directory')
raise Exception('input output path type mismatch') raise Exception('input output path type mismatch')
if not re.search('.*\..*$', str(args.output)): if not re.search(r'.*\..*$', str(args.output)):
Avalon.error('No suffix found in output file path') Avalon.error('No suffix found in output file path')
Avalon.error('Suffix must be specified for FFmpeg') Avalon.error('Suffix must be specified for FFmpeg')
raise Exception('No suffix specified') raise Exception('No suffix specified')
@@ -380,9 +407,13 @@ try:
elif args.input.is_dir(): elif args.input.is_dir():
# upscale videos in a directory # upscale videos in a directory
Avalon.info(f'Upscaling videos in directory: {args.input}') Avalon.info(f'Upscaling videos in directory: {args.input}')
# make output directory if it doesn't exist
args.output.mkdir(parents=True, exist_ok=True)
for input_video in [f for f in args.input.iterdir() if f.is_file()]: for input_video in [f for f in args.input.iterdir() if f.is_file()]:
output_video = args.output / input_video output_video = args.output / input_video.name
upscaler = Upscaler(input_video=args.input / 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, waifu2x_settings=waifu2x_settings, ffmpeg_settings=ffmpeg_settings)
# set optional options # set optional options
upscaler.waifu2x_driver = args.driver upscaler.waifu2x_driver = args.driver
@@ -409,8 +440,6 @@ except Exception:
traceback.print_exc() traceback.print_exc()
finally: finally:
# remove Video2X cache directory # remove Video2X cache directory
try: with contextlib.suppress(FileNotFoundError):
if not preserve_frames: if not preserve_frames:
shutil.rmtree(video2x_cache_directory) shutil.rmtree(video2x_cache_directory)
except FileNotFoundError:
pass

View File

@@ -4,7 +4,7 @@
Name: Video2x GUI Name: Video2x GUI
Author: K4YT3X Author: K4YT3X
Date Created: July 27, 2019 Date Created: July 27, 2019
Last Modified: July 27, 2019 Last Modified: August 17, 2019
Description: GUI for Video2X Description: GUI for Video2X
""" """
@@ -23,14 +23,18 @@ import pathlib
import tempfile import tempfile
import threading import threading
import time import time
import tkinter as tk
VERSION = '1.0.0' VERSION = '1.1.1'
LEGAL_INFO = f'''Video2X GUI Version: {VERSION}
Author: K4YT3X
License: GNU GPL v3
Github Page: https://github.com/k4yt3x/video2x
Contact: k4yt3x@k4yt3x.com'''
# global static variables # global static variables
AVAILABLE_METHODS = {
AVAILABLE_METHODS = {'GPU': 'gpu', 'GPU': 'gpu',
'CUDNN': 'cudnn', 'CUDNN': 'cudnn',
'CPU': 'cpu' 'CPU': 'cpu'
} }
@@ -38,7 +42,8 @@ AVAILABLE_METHODS = {'GPU': 'gpu',
AVAILABLE_DRIVERS = { AVAILABLE_DRIVERS = {
'Waifu2X Caffe': 'waifu2x_caffe', 'Waifu2X Caffe': 'waifu2x_caffe',
'Waifu2X Converter CPP': 'waifu2x_converter', 'Waifu2X Converter CPP': 'waifu2x_converter',
'Waifu2x NCNN Vulkan': 'waifu2x_ncnn_vulkan' 'Waifu2x NCNN Vulkan': 'waifu2x_ncnn_vulkan',
'Anime4K': 'anime4k'
} }
IMAGE_FORMATS = {'PNG', 'JPG'} IMAGE_FORMATS = {'PNG', 'JPG'}
@@ -52,10 +57,25 @@ class Video2xGui():
# create main window # create main window
self.main_window = Tk() self.main_window = Tk()
self.main_window.title('Video2X GUI') self.main_window.title(f'Video2X GUI {VERSION}')
self.main_frame = Frame() self.main_frame = Frame()
self.main_frame.pack(fill=BOTH, expand=True) self.main_frame.pack(fill=BOTH, expand=True)
# add menu bar
self.menu_bar = Menu(self.main_frame)
# file menu
self.file_menu = Menu(self.menu_bar, tearoff=0)
self.file_menu.add_command(label='Exit', command=self.main_frame.quit)
self.menu_bar.add_cascade(label='File', menu=self.file_menu)
# help menu
self.help_menu = Menu(self.menu_bar, tearoff=0)
self.help_menu.add_command(label='About', command=self._display_help)
self.menu_bar.add_cascade(label='Help', menu=self.help_menu)
self.main_window.config(menu=self.menu_bar)
# file frame # file frame
self.file_frame = Frame(self.main_frame) self.file_frame = Frame(self.main_frame)
self.file_frame.pack(fill=X, padx=5, pady=5, expand=True) self.file_frame.pack(fill=X, padx=5, pady=5, expand=True)
@@ -164,6 +184,9 @@ class Video2xGui():
self.main_frame.mainloop() self.main_frame.mainloop()
def _display_help(self):
messagebox.showinfo('About', LEGAL_INFO)
def _launch_upscaling(self): def _launch_upscaling(self):
# prevent launching multiple instances # prevent launching multiple instances
@@ -178,8 +201,8 @@ class Video2xGui():
if self.output_file.get() == '': if self.output_file.get() == '':
messagebox.showerror('Error', 'You must specify output video file/directory path') messagebox.showerror('Error', 'You must specify output video file/directory path')
return return
if (self.driver.get() == 'waifu2x_converter' or self.driver.get() == 'waifu2x_ncnn_vulkan') and self.width.get() and self.height.get(): if (self.driver.get() in ['Waifu2X Converter CPP', 'Waifu2x NCNN Vulkan', 'Anime4K']) and self.width.get() and self.height.get():
messagebox.showerror('Error', 'Waifu2x Converter CPP/NCNN accepts only scaling ratio') messagebox.showerror('Error', f'Selected driver \"{self.driver.get()}\" accepts only scaling ratio')
return return
if self.driver.get() == 'waifu2x_ncnn_vulkan' and (self.scale_ratio.get() > 2 or not self.scale_ratio.get().is_integer()): if self.driver.get() == 'waifu2x_ncnn_vulkan' and (self.scale_ratio.get() > 2 or not self.scale_ratio.get().is_integer()):
messagebox.showerror('Error', 'Scaling ratio must be 1 or 2 for waifu2x_ncnn_vulkan') messagebox.showerror('Error', 'Scaling ratio must be 1 or 2 for waifu2x_ncnn_vulkan')
@@ -201,6 +224,9 @@ class Video2xGui():
def _upscale(self): def _upscale(self):
# start timer
begin_time = time.time()
# read configuration file # read configuration file
config = read_config('video2x.json') config = read_config('video2x.json')
config = absolutify_paths(config) config = absolutify_paths(config)
@@ -218,14 +244,21 @@ class Video2xGui():
waifu2x_settings = config['waifu2x_converter'] waifu2x_settings = config['waifu2x_converter']
if not pathlib.Path(waifu2x_settings['waifu2x_converter_path']).is_dir(): if not pathlib.Path(waifu2x_settings['waifu2x_converter_path']).is_dir():
messagebox.showerror('Error', 'Specified waifu2x-converter-cpp directory doesn\'t exist\nPlease check the configuration file settings') messagebox.showerror('Error', 'Specified waifu2x-converter-cpp directory doesn\'t exist\nPlease check the configuration file settings')
raise FileNotFoundError(waifu2x_settings['waifu2x_converter_path'])
elif driver == 'waifu2x_ncnn_vulkan': elif driver == 'waifu2x_ncnn_vulkan':
waifu2x_settings = config['waifu2x_ncnn_vulkan'] waifu2x_settings = config['waifu2x_ncnn_vulkan']
if not pathlib.Path(waifu2x_settings['waifu2x_ncnn_vulkan_path']).is_file(): if not pathlib.Path(waifu2x_settings['waifu2x_ncnn_vulkan_path']).is_file():
messagebox.showerror('Error', 'Specified waifu2x_ncnn_vulkan directory doesn\'t exist\nPlease check the configuration file settings') messagebox.showerror('Error', 'Specified waifu2x_ncnn_vulkan directory doesn\'t exist\nPlease check the configuration file settings')
raise FileNotFoundError(waifu2x_settings['waifu2x_ncnn_vulkan_path']) raise FileNotFoundError(waifu2x_settings['waifu2x_ncnn_vulkan_path'])
elif driver == 'anime4k':
waifu2x_settings = config['anime4k']
if not pathlib.Path(waifu2x_settings['anime4k_path']).is_file():
messagebox.showerror('Error', 'Specified Anime4K directory doesn\'t exist\nPlease check the configuration file settings')
raise FileNotFoundError(waifu2x_settings['anime4k_path'])
# read FFmpeg configuration # read FFmpeg configuration
ffmpeg_settings = config['ffmpeg'] ffmpeg_settings = config['ffmpeg']
# load video2x settings # load video2x settings
image_format = config['video2x']['image_format'].lower() image_format = config['video2x']['image_format'].lower()
preserve_frames = config['video2x']['preserve_frames'] preserve_frames = config['video2x']['preserve_frames']
@@ -289,12 +322,11 @@ class Video2xGui():
self.upscaler.cleanup_temp_directories() self.upscaler.cleanup_temp_directories()
# show message when upscaling completes # show message when upscaling completes
messagebox.showinfo('Info', 'Upscaling Completed') messagebox.showinfo('Info', f'Upscaling Completed\nTime Taken: {round((time.time() - begin_time), 5)} seconds')
self.progress_bar['value'] = 100 self.progress_bar['value'] = 100
self.running = False self.running = False
self.start_button_text.set('Start') self.start_button_text.set('Start')
def _progress_bar(self): def _progress_bar(self):
""" This method prints a progress bar """ This method prints a progress bar
@@ -317,7 +349,17 @@ class Video2xGui():
def _select_input(self): def _select_input(self):
self.input_file.set(askopenfilename(title='Select Input File')) self.input_file.set(askopenfilename(title='Select Input File'))
self.output_file.set(f'{self.input_file.get()}_output.mp4')
# try to set an output file name automatically
output_file = pathlib.Path(f'{self.input_file.get()}_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_id += 1
if not output_file.exists():
self.output_file.set(str(output_file))
def _select_output(self): def _select_output(self):
self.output_file.set(asksaveasfilename(title='Select Output File')) self.output_file.set(asksaveasfilename(title='Select Output File'))

View File

@@ -5,7 +5,7 @@ Name: Video2X Setup Script
Author: K4YT3X Author: K4YT3X
Author: BrianPetkovsek Author: BrianPetkovsek
Date Created: November 28, 2018 Date Created: November 28, 2018
Last Modified: July 30, 2019 Last Modified: August 20, 2019
Dev: SAT3LL Dev: SAT3LL
@@ -22,10 +22,12 @@ Installation Details:
- waifu2x-caffe: %LOCALAPPDATA%\\video2x\\waifu2x-caffe - waifu2x-caffe: %LOCALAPPDATA%\\video2x\\waifu2x-caffe
- waifu2x-cpp-converter: %LOCALAPPDATA%\\video2x\\waifu2x-converter-cpp - waifu2x-cpp-converter: %LOCALAPPDATA%\\video2x\\waifu2x-converter-cpp
- waifu2x_ncnn_vulkan: %LOCALAPPDATA%\\video2x\\waifu2x-ncnn-vulkan - waifu2x_ncnn_vulkan: %LOCALAPPDATA%\\video2x\\waifu2x-ncnn-vulkan
- anime4k: %LOCALAPPDATA%\\video2x\\anime4k
""" """
# built-in imports # built-in imports
import argparse import argparse
import contextlib
import json import json
import os import os
import pathlib import pathlib
@@ -43,10 +45,11 @@ import zipfile
# later in the script. # later in the script.
# import requests # import requests
VERSION = '1.4.0' VERSION = '1.5.0'
# global static variables # global static variables
LOCALAPPDATA = pathlib.Path(os.getenv('localappdata')) LOCALAPPDATA = pathlib.Path(os.getenv('localappdata'))
DRIVER_OPTIONS = ['all', 'waifu2x_caffe', 'waifu2x_converter', 'waifu2x_ncnn_vulkan', 'anime4k']
def process_arguments(): def process_arguments():
@@ -56,7 +59,7 @@ def process_arguments():
# video options # video options
general_options = parser.add_argument_group('General Options') general_options = parser.add_argument_group('General Options')
general_options.add_argument('-d', '--driver', help='driver to download and configure', action='store', choices=['all', 'waifu2x_caffe', 'waifu2x_converter', 'waifu2x_ncnn_vulkan'], default='all') general_options.add_argument('-d', '--driver', help='driver to download and configure', action='store', choices=DRIVER_OPTIONS, default='all')
# parse arguments # parse arguments
return parser.parse_args() return parser.parse_args()
@@ -79,19 +82,22 @@ class Video2xSetup:
print('\nInstalling Python libraries') print('\nInstalling Python libraries')
self._install_python_requirements() self._install_python_requirements()
print('\nInstalling FFMPEG') print('\nInstalling FFmpeg')
self._install_ffmpeg() self._install_ffmpeg()
if self.driver == 'all': if self.driver == 'all':
self._install_waifu2x_caffe() self._install_waifu2x_caffe()
self._install_waifu2x_converter_cpp() self._install_waifu2x_converter_cpp()
self._install_waifu2x_ncnn_vulkan() self._install_waifu2x_ncnn_vulkan()
self._install_anime4k()
elif self.driver == 'waifu2x_caffe': elif self.driver == 'waifu2x_caffe':
self._install_waifu2x_caffe() self._install_waifu2x_caffe()
elif self.driver == 'waifu2x_converter': elif self.driver == 'waifu2x_converter':
self._install_waifu2x_converter_cpp() self._install_waifu2x_converter_cpp()
elif self.driver == 'waifu2x_ncnn_vulkan': elif self.driver == 'waifu2x_ncnn_vulkan':
self._install_waifu2x_ncnn_vulkan() self._install_waifu2x_ncnn_vulkan()
elif self.driver == 'anime4k':
self._install_anime4k()
print('\nGenerating Video2X configuration file') print('\nGenerating Video2X configuration file')
self._generate_config() self._generate_config()
@@ -137,7 +143,7 @@ class Video2xSetup:
import requests import requests
# Get latest release of waifu2x-caffe via GitHub API # Get latest release of waifu2x-caffe via GitHub API
latest_release = json.loads(requests.get('https://api.github.com/repos/lltcggie/waifu2x-caffe/releases/latest').content.decode('utf-8')) latest_release = requests.get('https://api.github.com/repos/lltcggie/waifu2x-caffe/releases/latest').json()
for a in latest_release['assets']: for a in latest_release['assets']:
if 'waifu2x-caffe.zip' in a['browser_download_url']: if 'waifu2x-caffe.zip' in a['browser_download_url']:
@@ -154,7 +160,7 @@ class Video2xSetup:
import requests import requests
# Get latest release of waifu2x-caffe via GitHub API # Get latest release of waifu2x-caffe via GitHub API
latest_release = json.loads(requests.get('https://api.github.com/repos/DeadSix27/waifu2x-converter-cpp/releases/latest').content.decode('utf-8')) latest_release = requests.get('https://api.github.com/repos/DeadSix27/waifu2x-converter-cpp/releases/latest').json()
for a in latest_release['assets']: for a in latest_release['assets']:
if re.search(r'waifu2x-DeadSix27-win64_v[0-9]*\.zip', a['browser_download_url']): if re.search(r'waifu2x-DeadSix27-win64_v[0-9]*\.zip', a['browser_download_url']):
@@ -171,7 +177,7 @@ class Video2xSetup:
import requests import requests
# Get latest release of waifu2x-ncnn-vulkan via Github API # Get latest release of waifu2x-ncnn-vulkan via Github API
latest_release = json.loads(requests.get('https://api.github.com/repos/nihui/waifu2x-ncnn-vulkan/releases/latest').content.decode('utf-8')) latest_release = requests.get('https://api.github.com/repos/nihui/waifu2x-ncnn-vulkan/releases/latest').json()
for a in latest_release['assets']: for a in latest_release['assets']:
if re.search(r'waifu2x-ncnn-vulkan-\d*\.zip', a['browser_download_url']): if re.search(r'waifu2x-ncnn-vulkan-\d*\.zip', a['browser_download_url']):
@@ -190,6 +196,34 @@ class Video2xSetup:
# rename the newly extracted directory # rename the newly extracted directory
(LOCALAPPDATA / 'video2x' / zipf.namelist()[0]).rename(waifu2x_ncnn_vulkan_directory) (LOCALAPPDATA / 'video2x' / zipf.namelist()[0]).rename(waifu2x_ncnn_vulkan_directory)
def _install_anime4k(self):
""" Install Anime4K
"""
print('\nInstalling Anime4K')
"""
import requests
# get latest release of Anime4K via Github API
# at the time of writing this portion, Anime4K doesn't yet have a stable release
# therefore releases/latest won't work
latest_release = requests.get('https://api.github.com/repos/bloc97/Anime4K/releases').json()[0]
for a in latest_release['assets']:
if 'Anime4K_Java.zip' in a['browser_download_url']:
anime4k_zip = download(a['browser_download_url'], tempfile.gettempdir())
self.trash.append(anime4k_zip)
"""
# since Java pre-compiled release has been removed from download
# page, we use this cached version as a temporary solution
anime4k_zip = download('https://files.flexio.org/Resources/anime4k.zip', tempfile.gettempdir())
self.trash.append(anime4k_zip)
# extract and rename
with zipfile.ZipFile(anime4k_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x' / 'anime4k')
def _generate_config(self): def _generate_config(self):
""" Generate video2x config """ Generate video2x config
""" """
@@ -203,12 +237,15 @@ class Video2xSetup:
template_dict['waifu2x_caffe']['waifu2x_caffe_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-caffe' / 'waifu2x-caffe-cui.exe') template_dict['waifu2x_caffe']['waifu2x_caffe_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-caffe' / 'waifu2x-caffe-cui.exe')
template_dict['waifu2x_converter']['waifu2x_converter_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-converter-cpp') template_dict['waifu2x_converter']['waifu2x_converter_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-converter-cpp')
template_dict['waifu2x_ncnn_vulkan']['waifu2x_ncnn_vulkan_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-ncnn-vulkan' / 'waifu2x-ncnn-vulkan.exe') template_dict['waifu2x_ncnn_vulkan']['waifu2x_ncnn_vulkan_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-ncnn-vulkan' / 'waifu2x-ncnn-vulkan.exe')
template_dict['anime4k']['anime4k_path'] = str(LOCALAPPDATA / 'video2x' / 'anime4k' / 'Anime4K.jar')
elif self.driver == 'waifu2x_caffe': elif self.driver == 'waifu2x_caffe':
template_dict['waifu2x_caffe']['waifu2x_caffe_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-caffe' / 'waifu2x-caffe-cui.exe') template_dict['waifu2x_caffe']['waifu2x_caffe_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-caffe' / 'waifu2x-caffe-cui.exe')
elif self.driver == 'waifu2x_converter': elif self.driver == 'waifu2x_converter':
template_dict['waifu2x_converter']['waifu2x_converter_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-converter-cpp') template_dict['waifu2x_converter']['waifu2x_converter_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-converter-cpp')
elif self.driver == 'waifu2x_ncnn_vulkan': elif self.driver == 'waifu2x_ncnn_vulkan':
template_dict['waifu2x_ncnn_vulkan']['waifu2x_ncnn_vulkan_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-ncnn-vulkan' / 'waifu2x-ncnn-vulkan.exe') template_dict['waifu2x_ncnn_vulkan']['waifu2x_ncnn_vulkan_path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-ncnn-vulkan' / 'waifu2x-ncnn-vulkan.exe')
elif self.driver == 'anime4k':
template_dict['anime4k']['anime4k_path'] = str(LOCALAPPDATA / 'video2x' / 'anime4k' / 'Anime4K.jar')
template_dict['ffmpeg']['ffmpeg_path'] = str(LOCALAPPDATA / 'video2x' / 'ffmpeg-latest-win64-static' / 'bin') template_dict['ffmpeg']['ffmpeg_path'] = str(LOCALAPPDATA / 'video2x' / 'ffmpeg-latest-win64-static' / 'bin')
template_dict['video2x']['video2x_cache_directory'] = None template_dict['video2x']['video2x_cache_directory'] = None
@@ -216,7 +253,7 @@ class Video2xSetup:
# Write configuration into file # Write configuration into file
with open('video2x.json', 'w') as config: with open('video2x.json', 'w') as config:
json.dump(template_dict, config, indent=4) json.dump(template_dict, config, indent=2)
config.close() config.close()
@@ -238,10 +275,8 @@ def download(url, save_path, chunk_size=4096):
file_name = None file_name = None
if 'content-disposition' in stream.headers: if 'content-disposition' in stream.headers:
disposition = stream.headers['content-disposition'] disposition = stream.headers['content-disposition']
try: with contextlib.suppress(IndexError):
file_name = re.findall("filename=(.+)", disposition)[0].strip('"') file_name = re.findall("filename=(.+)", disposition)[0].strip('"')
except IndexError:
pass
if file_name is None: if file_name is None:
# output_file = f'{save_path}\\{stream.url.split("/")[-1]}' # output_file = f'{save_path}\\{stream.url.split("/")[-1]}'

View File

@@ -4,7 +4,7 @@
Name: Waifu2x Caffe Driver Name: Waifu2x Caffe Driver
Author: K4YT3X Author: K4YT3X
Date Created: Feb 24, 2018 Date Created: Feb 24, 2018
Last Modified: July 27, 2019 Last Modified: August 3, 2019
Description: This class is a high-level wrapper Description: This class is a high-level wrapper
for waifu2x-caffe. for waifu2x-caffe.
@@ -67,9 +67,9 @@ class Waifu2xCaffe:
self.print_lock.release() self.print_lock.release()
# list to be executed # list to be executed
execute = [] # initialize the list with waifu2x binary path as the first element
execute = [str(self.waifu2x_settings['waifu2x_caffe_path'])]
execute.append(self.waifu2x_settings['waifu2x_caffe_path'])
for key in self.waifu2x_settings.keys(): for key in self.waifu2x_settings.keys():
value = self.waifu2x_settings[key] value = self.waifu2x_settings[key]

View File

@@ -4,7 +4,7 @@
Name: Waifu2x Converter CPP Driver Name: Waifu2x Converter CPP Driver
Author: K4YT3X Author: K4YT3X
Date Created: February 8, 2019 Date Created: February 8, 2019
Last Modified: July 27, 2019 Last Modified: August 3, 2019
Description: This class is a high-level wrapper Description: This class is a high-level wrapper
for waifu2x-converter-cpp. for waifu2x-converter-cpp.
@@ -48,15 +48,6 @@ class Waifu2xConverter:
# overwrite config file settings # overwrite config file settings
self.waifu2x_settings['input'] = input_directory self.waifu2x_settings['input'] = input_directory
self.waifu2x_settings['output'] = output_directory self.waifu2x_settings['output'] = output_directory
# temporary fix for https://github.com/DeadSix27/waifu2x-converter-cpp/issues/109
"""
self.waifu2x_settings['i'] = input_directory
self.waifu2x_settings['o'] = output_directory
self.waifu2x_settings['input'] = None
self.waifu2x_settings['output'] = None
"""
self.waifu2x_settings['scale-ratio'] = scale_ratio self.waifu2x_settings['scale-ratio'] = scale_ratio
self.waifu2x_settings['jobs'] = jobs self.waifu2x_settings['jobs'] = jobs
self.waifu2x_settings['output-format'] = image_format self.waifu2x_settings['output-format'] = image_format
@@ -72,7 +63,8 @@ class Waifu2xConverter:
self.print_lock.release() self.print_lock.release()
# list to be executed # list to be executed
execute = [] # 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')]
for key in self.waifu2x_settings.keys(): for key in self.waifu2x_settings.keys():
@@ -80,7 +72,7 @@ class Waifu2xConverter:
# the key doesn't need to be passed in this case # the key doesn't need to be passed in this case
if key == 'waifu2x_converter_path': if key == 'waifu2x_converter_path':
execute.append(pathlib.Path(str(value)) / 'waifu2x-converter-cpp.exe') continue
# null or None means that leave this option out (keep default) # null or None means that leave this option out (keep default)
elif value is None or value is False: elif value is None or value is False:

View File

@@ -4,7 +4,7 @@
Name: Waifu2x NCNN Vulkan Driver Name: Waifu2x NCNN Vulkan Driver
Author: SAT3LL Author: SAT3LL
Date Created: June 26, 2019 Date Created: June 26, 2019
Last Modified: July 27, 2019 Last Modified: August 3, 2019
Dev: K4YT3X Dev: K4YT3X
@@ -52,61 +52,42 @@ class Waifu2xNcnnVulkan:
try: try:
# overwrite config file settings # overwrite config file settings
self.waifu2x_settings['input'] = input_directory self.waifu2x_settings['i'] = input_directory
self.waifu2x_settings['output'] = output_directory self.waifu2x_settings['o'] = output_directory
self.waifu2x_settings['s'] = scale_ratio
# print thread start message # print thread start message
self.print_lock.acquire() self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Thread {threading.current_thread().name} started') Avalon.debug_info(f'[upscaler] Thread {threading.current_thread().name} started')
self.print_lock.release() self.print_lock.release()
# waifu2x_ncnn_vulkan does not have long-opts, we'll have a dictionary that maps "our" config long-opt # list to be executed
# names to their short opts # initialize the list with waifu2x binary path as the first element
waifu2x_ncnn_vulkan_opt_flag = { execute = [str(self.waifu2x_settings['waifu2x_ncnn_vulkan_path'])]
'input': '-i',
'output': '-o',
'noise-level': '-n',
'scale-ratio': '-s',
'tile-size': '-t',
'model-path': '-m',
'gpu': '-g',
'load-proc-save_threads': '-j',
'verbose': '-v'
}
execute = [self.waifu2x_settings['waifu2x_ncnn_vulkan_path']]
for key in self.waifu2x_settings.keys(): for key in self.waifu2x_settings.keys():
value = self.waifu2x_settings[key] value = self.waifu2x_settings[key]
if key == 'waifu2x_ncnn_vulkan_path':
continue # is executable key or null or None means that leave this option out (keep default)
elif key == 'input': if key == 'waifu2x_ncnn_vulkan_path' or value is None or value is False:
execute.append(waifu2x_ncnn_vulkan_opt_flag[key])
execute.append(input_directory)
elif key == 'output':
execute.append(waifu2x_ncnn_vulkan_opt_flag[key])
execute.append(output_directory)
elif key == 'scale-ratio':
execute.append(waifu2x_ncnn_vulkan_opt_flag[key])
# waifu2x_ncnn_vulkan does not accept an arbitrary scale ratio, max is 2
if scale_ratio == 1:
execute.append('1')
else:
execute.append('2')
# allow upper if cases to take precedence
elif value is None or value is False:
continue continue
else: else:
execute.append(waifu2x_ncnn_vulkan_opt_flag[key]) if len(key) == 1:
execute.append(f'-{key}')
else:
execute.append(f'--{key}')
execute.append(str(value)) execute.append(str(value))
Avalon.debug_info(f'Executing: {execute}') Avalon.debug_info(f'Executing: {execute}')
subprocess.run(execute, check=True, stderr=subprocess.DEVNULL) completed_command = subprocess.run(execute, check=True)
# print thread exiting message # print thread exiting message
self.print_lock.acquire() self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Thread {threading.current_thread().name} exiting') Avalon.debug_info(f'[upscaler] Thread {threading.current_thread().name} exiting')
self.print_lock.release() self.print_lock.release()
return 0 # return command execution return code
return completed_command.returncode
except Exception as e: except Exception as e:
upscaler_exceptions.append(e) upscaler_exceptions.append(e)