26 Commits
4.7.0 ... 4.8.0

Author SHA1 Message Date
K4YT3X
4694c557ec added a none option for -tune to address #401 2020-12-13 17:13:03 -05:00
K4YT3X
33d96bcd4e added Discord server description 2020-12-13 16:55:37 -05:00
K4YT3X
eee43def3b redirected subprocess.Popen streams to system stdout and stderr 2020-12-13 16:53:55 -05:00
K4YT3X
f4be9cc596 BiLogger now inherits io.TextIOWrapper and has a fileno attribute 2020-12-13 16:52:58 -05:00
K4YT3X
cc89b0aac5 formatted setup script with black 2020-12-13 16:39:49 -05:00
K4YT3X
9e8e95803f setup script 2.4.1: fixed Gifski setup issues and enhanced garbage cleaning 2020-12-13 16:39:13 -05:00
K4YT3X
df0861ff5c Merge pull request #411 from konqiDAM/master
fix: windows installer fixed, now uses "zipball_url" for gifski
2020-11-18 20:24:54 +00:00
K4YT3X
706aeab03f updated setup script metadata 2020-11-18 20:24:17 +00:00
konqi
f850ca80f1 fix: windows installer fixed, now uses "zipball_url" for gifski 2020-11-18 20:56:56 +01:00
K4YT3X
608bf1a2ec added a link for @Felixkruemel 's name 2020-10-26 18:24:43 -04:00
K4YT3X
b1f7290c20 update Google Colab descriptions 2020-10-26 18:22:52 -04:00
K4YT3X
65d445c293 upscaler 4.4.1: use mimetypes to re-check python-magic's results 2020-10-26 18:14:49 -04:00
K4YT3X
43dbb134b6 Merge pull request #389 from jitsuCM/arr_fix
Quick fix for special case no-upscale 1.0 upscale
2020-10-26 22:09:04 +00:00
K4YT3X
84b0684d64 apply the smallest scaling ratio available instead of 1 2020-10-26 21:53:03 +00:00
K4YT3X
29b4153b63 Merge pull request #384 from Felixkruemel/master
Added Google Colab to readme
2020-10-26 21:47:43 +00:00
K4YT3X
3f1821f1ac Merge pull request #373 from donicrosby/master
Fixed issue where if hwaccel value in config is overwritten with auto
2020-10-26 21:47:16 +00:00
K4YT3X
4f8bb1be1c setup script 2.4.0: updated FFmpeg download URL and unpacking method 2020-10-26 13:13:54 -04:00
jitsuCM
c2f1e43656 Quick fix for special case no-upscale 1.0 upscale 2020-10-22 09:21:53 +02:00
Felixkruemel
914d5cdf87 fixed blank line 2020-10-13 19:27:36 +02:00
Felixkruemel
de77c90dd1 Updated Readme.md with Google Colab integration 2020-10-13 19:26:53 +02:00
donicrosby
458ce82644 Merge branch 'master' of https://github.com/k4yt3x/video2x into master 2020-09-29 17:18:37 -04:00
donicrosby
1d145a8690 Fixed issue where if hwaccel value is set to anything other auto it would be overwritten 2020-09-29 00:51:32 -04:00
K4YT3X
b37acfa31d setup script 2.3.0: changed FFmpeg build provider from zeranoe to gyan.dev 2020-09-28 20:31:22 -04:00
K4YT3X
a0522311e2 made custom intermediate frame format available for waifu2x/srmd/realsr 2020-09-21 15:14:00 -04:00
K4YT3X
7de9cc699a Merge pull request #363 from medram/waifu2x_ncnn_vulkan_args_update
Fixed supporting jpg format for waifu2x_ncnn_vulkan by updating its arguments.
2020-09-21 19:06:42 +00:00
medram
685648957f Update waifu2x_ncnn_vulkan arguments to the latest version! 2020-09-20 21:34:20 +01:00
15 changed files with 316 additions and 207 deletions

View File

@@ -14,6 +14,8 @@
### Official Discussion Group (Telegram): https://t.me/video2x
A [Discord server](https://discord.gg/Pwf6Ht) is also available. Please note that most developers are only on Telegram. If you join the Discord server, the developers might not be able to see your questions and help you. It is mostly for user-user interactions and those who do not want to use Telegram.
## [Download Stable/Beta Builds](https://github.com/k4yt3x/video2x/releases/latest) (Windows)
- **`Full`**: full package comes pre-configured with **all** dependencies like `FFmpeg` and `waifu2x-caffe`.
@@ -37,6 +39,12 @@ To download the latest nightly build, go to the [GitHub Actions](https://github.
Video2X Docker images are available on Docker Hub for easy and rapid Video2X deployment on Linux and macOS. If you already have Docker installed, then only one command is needed to start upscaling a video. For more information on how to use Video2X's Docker image, please refer to the [documentations](https://github.com/K4YT3X/video2x/wiki/Docker).
## [Google Colab](https://colab.research.google.com/drive/1xqeZvoJXaBBPP6UyVwErnhwrnth0br0u)
You can use Video2X on [Google Colab](https://colab.research.google.com/) for free. Colab allows you too use a GPU on Google's Servers (Tesla K80, T4, P4, P100). Please bare in mind that Colab can only be provided for free if all users know that they shouldn't abuse it. A single free-tier tier session can last up to 12 hours. Please do not abuse the platform by creating sessions back-to-back and running upscaling 24/7. This might result in you getting banned.
Here is an exmaple Notebook written by [@Felixkruemel](https://github.com/Felixkruemel): [Video2X_on_Colab.ipynb](https://colab.research.google.com/drive/1xqeZvoJXaBBPP6UyVwErnhwrnth0br0u). This file can be used in combination of the following modified configuration file: [@Felixkruemel's Video2X configuration for Google Colab](https://gist.githubusercontent.com/Felixkruemel/71e62de4bb38965ead2e0f4bae7ef4ee/raw/video2x.yaml).
## Introduction
Video2X is a video/GIF/image upscaling software based on Waifu2X, Anime4K, SRMD and RealSR written in Python 3. It upscales videos, GIFs and images, restoring details from low-resolution inputs. Video2X also accepts GIF input to video output and video input to GIF output.

View File

@@ -4,21 +4,21 @@
Creator: Video2X Bidirectional Logger
Author: K4YT3X
Date Created: June 4, 2020
Last Modified: September 13, 2020
Last Modified: December 13, 2020
"""
# built-in imports
import _io
import io
class BiLogger(object):
class BiLogger(io.TextIOWrapper):
""" A bidirectional logger that both prints the output
and log all output to file.
Original code from: https://stackoverflow.com/a/14906787
"""
def __init__(self, terminal: _io.TextIOWrapper, log_file: _io.BufferedRandom):
def __init__(self, terminal: io.TextIOWrapper, log_file: io.BufferedRandom):
""" initialize BiLogger
Args:
@@ -27,6 +27,7 @@ class BiLogger(object):
"""
self.terminal = terminal
self.log_file = log_file
self.fileno = self.log_file.fileno
def write(self, message: str):
""" write message to original terminal output and log file

View File

@@ -4,7 +4,7 @@
Name: Video2X Upscaler
Author: K4YT3X
Date Created: December 10, 2018
Last Modified: September 13, 2020
Last Modified: October 26, 2020
Description: This file contains the Upscaler class. Each
instance of the Upscaler class is an upscaler on an image or
@@ -53,7 +53,7 @@ language.install()
_ = language.gettext
# version information
UPSCALER_VERSION = '4.4.0'
UPSCALER_VERSION = '4.4.1'
# these names are consistent for
# - driver selection in command line
@@ -474,7 +474,11 @@ class Upscaler:
input_file_type = input_file_mime_type.split('/')[0]
input_file_subtype = input_file_mime_type.split('/')[1]
except Exception:
input_file_mime_type = input_file_type = input_file_subtype = ''
# if python-magic doesn't determine the file to be an image/video file
# fall back to mimetypes to guess the file type based on the extension
if input_file_type not in ['image', 'video']:
# in case python-magic fails to detect file type
# try guessing file mime type with mimetypes
input_file_mime_type = mimetypes.guess_type(input_path.name)[0]
@@ -625,29 +629,33 @@ class Upscaler:
remaining_scaling_ratio = math.ceil(output_scale)
self.scaling_jobs = []
while remaining_scaling_ratio > 1:
for ratio in supported_scaling_ratios:
if ratio >= remaining_scaling_ratio:
self.scaling_jobs.append(ratio)
remaining_scaling_ratio /= ratio
break
else:
found = False
for i in supported_scaling_ratios:
for j in supported_scaling_ratios:
if i * j >= remaining_scaling_ratio:
self.scaling_jobs.extend([i, j])
remaining_scaling_ratio /= i * j
found = True
break
if found is True:
# if the scaling ratio is 1.0
# apply the smallest scaling ratio available
if remaining_scaling_ratio == 1:
self.scaling_jobs.append(supported_scaling_ratios[0])
else:
while remaining_scaling_ratio > 1:
for ratio in supported_scaling_ratios:
if ratio >= remaining_scaling_ratio:
self.scaling_jobs.append(ratio)
remaining_scaling_ratio /= ratio
break
if found is False:
self.scaling_jobs.append(supported_scaling_ratios[-1])
remaining_scaling_ratio /= supported_scaling_ratios[-1]
else:
found = False
for i in supported_scaling_ratios:
for j in supported_scaling_ratios:
if i * j >= remaining_scaling_ratio:
self.scaling_jobs.extend([i, j])
remaining_scaling_ratio /= i * j
found = True
break
if found is True:
break
if found is False:
self.scaling_jobs.append(supported_scaling_ratios[-1])
remaining_scaling_ratio /= supported_scaling_ratios[-1]
else:
self.scaling_jobs = [output_scale]

View File

@@ -1,7 +1,7 @@
# Name: Video2X Configuration File
# Creator: K4YT3X
# Date Created: October 23, 2018
# Last Modified: September 13, 2020
# Last Modified: September 28, 2020
# Values here are the default values. Change the value here to
# save the default value permanently.
# Items commented out are parameters irrelevant to this context
@@ -32,7 +32,7 @@ waifu2x_converter_cpp:
#list-supported-formats: null # dump currently supported format list
#list-opencv-formats: null # (deprecated. Use --list-supported-formats) dump opencv supported format list
#list-processor # dump processor list
output-format: null # The format used when running in recursive/folder mode
#output-format: null # The format used when running in recursive/folder mode
png-compression: 5 # Set PNG compression level (0-9), 9 = Max compression (slowest & smallest)
image-quality: -1 # JPEG & WebP Compression quality (-1-101, 0 being smallest size and lowest quality, -1 being default), use 101 for lossless WebP
block-size: 0 # block size
@@ -55,15 +55,16 @@ waifu2x_converter_cpp:
waifu2x_ncnn_vulkan:
path: '%LOCALAPPDATA%\video2x\waifu2x-ncnn-vulkan\waifu2x-ncnn-vulkan'
v: null # verbose output
#i: null # input-path: input image path (jpg/png) or directory
#o: null # output-path: output image path (png) or directory
#i: null # input-path: input image path (jpg/png/webp) or directory
#o: null # output-path: output image path (jpg/png/webp) or directory
'n': 2 # noise-level: denoise level (-1/0/1/2/3, default=0)
s: 2 # scale: upscale ratio (1/2, default=2)
t: 400 # tile-size: tile size (>=32, default=400)
m: null # model-path: waifu2x model path (default=models-cunet)
g: 0 # gpu-id: gpu device to use (default=0)
j: '1:2:2' # thread count for load/proc/save (default=1:2:2)
j: '1:2:2' # thread count for load/proc/save (default=1:2:2) can be 1:2,2,2:2 for multi-gpu
x: false # enable tta mode
#f: png # output image format (jpg/png/webp, default=ext/png)
srmd_ncnn_vulkan:
path: '%LOCALAPPDATA%\video2x\srmd-ncnn-vulkan\srmd-ncnn-vulkan'
v: null # verbose output
@@ -76,6 +77,7 @@ srmd_ncnn_vulkan:
g: 0 # gpu device to use (default=0)
j: '1:2:2' # thread count for load/proc/save (default=1:2:2)
x: false # enable tta mode
#f: png # output image format (jpg/png/webp, default=ext/png)
realsr_ncnn_vulkan:
path: '%LOCALAPPDATA%\video2x\realsr-ncnn-vulkan\realsr-ncnn-vulkan'
v: null # verbose output
@@ -87,6 +89,7 @@ realsr_ncnn_vulkan:
g: 0 # gpu device to use (default=0)
j: '1:2:2' # thread count for load/proc/save (default=1:2:2)
x: false # enable tta mode
#f: png # output image format (jpg/png/webp, default=ext/png)
anime4kcpp:
path: '%LOCALAPPDATA%\video2x\anime4kcpp\CLI\Anime4KCPP_CLI\Anime4KCPP_CLI'
#input: null # File for loading (string [=./pic/p1.png])
@@ -117,7 +120,7 @@ anime4kcpp:
webVideo: null # process the video from URL
alpha: false # preserve the Alpha channel for transparent image
ffmpeg:
ffmpeg_path: '%LOCALAPPDATA%\video2x\ffmpeg-latest-win64-static\bin'
ffmpeg_path: '%LOCALAPPDATA%\video2x\ffmpeg\bin'
intermediate_file_name: 'intermediate.mkv'
# Step 1: Frame Extraction
# extract all frames from original input into temporary directory

View File

@@ -4,7 +4,7 @@
Creator: Video2X GUI
Author: K4YT3X
Date Created: May 5, 2020
Last Modified: September 13, 2020
Last Modified: December 13, 2020
"""
# local imports
@@ -33,7 +33,7 @@ from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import magic
GUI_VERSION = '2.8.0'
GUI_VERSION = '2.8.1'
LEGAL_INFO = f'''Video2X GUI Version: {GUI_VERSION}\\
Upscaler Version: {UPSCALER_VERSION}\\
@@ -684,9 +684,7 @@ class Video2XMainWindow(QMainWindow):
# extract frames
self.config['ffmpeg']['extract_frames']['output_options']['-pix_fmt'] = self.ffmpeg_extract_frames_output_options_pixel_format_line_edit.text()
if self.ffmpeg_extract_frames_hardware_acceleration_check_box.isChecked():
self.config['ffmpeg']['extract_frames']['-hwaccel'] = 'auto'
else:
if not self.ffmpeg_extract_frames_hardware_acceleration_check_box.isChecked():
self.config['ffmpeg']['extract_frames'].pop('-hwaccel', None)
# assemble video
@@ -694,7 +692,10 @@ class Video2XMainWindow(QMainWindow):
self.config['ffmpeg']['assemble_video']['output_options']['-vcodec'] = self.ffmpeg_assemble_video_output_options_video_codec_line_edit.text()
self.config['ffmpeg']['assemble_video']['output_options']['-pix_fmt'] = self.ffmpeg_assemble_video_output_options_pixel_format_line_edit.text()
self.config['ffmpeg']['assemble_video']['output_options']['-crf'] = self.ffmpeg_assemble_video_output_options_crf_spin_box.value()
self.config['ffmpeg']['assemble_video']['output_options']['-tune'] = self.ffmpeg_assemble_video_output_options_tune_combo_box.currentText()
if self.ffmpeg_assemble_video_output_options_tune_combo_box.currentText() == 'none':
self.config['ffmpeg']['assemble_video']['output_options']['-tune'] = None
else:
self.config['ffmpeg']['assemble_video']['output_options']['-tune'] = self.ffmpeg_assemble_video_output_options_tune_combo_box.currentText()
if self.ffmpeg_assemble_video_output_options_bitrate_line_edit.text() != '':
self.config['ffmpeg']['assemble_video']['output_options']['-b:v'] = self.ffmpeg_assemble_video_output_options_bitrate_line_edit.text()
else:
@@ -712,9 +713,7 @@ class Video2XMainWindow(QMainWindow):
else:
self.config['ffmpeg']['assemble_video']['output_options'].pop('-vf', None)
if self.ffmpeg_assemble_video_hardware_acceleration_check_box.isChecked():
self.config['ffmpeg']['assemble_video']['-hwaccel'] = 'auto'
else:
if not self.ffmpeg_assemble_video_hardware_acceleration_check_box.isChecked():
self.config['ffmpeg']['assemble_video'].pop('-hwaccel', None)
# migrate streams
@@ -768,9 +767,7 @@ class Video2XMainWindow(QMainWindow):
self.config['ffmpeg']['migrate_streams']['output_options'].pop('-movflags', None)
# hardware acceleration
if self.ffmpeg_migrate_streams_hardware_acceleration_check_box.isChecked():
self.config['ffmpeg']['migrate_streams']['-hwaccel'] = 'auto'
else:
if not self.ffmpeg_migrate_streams_hardware_acceleration_check_box.isChecked():
self.config['ffmpeg']['migrate_streams'].pop('-hwaccel', None)
# Gifski

View File

@@ -2289,6 +2289,11 @@
<string>ssim</string>
</property>
</item>
<item>
<property name="text">
<string>none</string>
</property>
</item>
</widget>
</item>
</layout>

View File

@@ -4,10 +4,11 @@
Name: Video2X Setup Script
Creator: K4YT3X
Date Created: November 28, 2018
Last Modified: May 30, 2020
Last Modified: December 13, 2020
Editor: BrianPetkovsek
Editor: SAT3LL
Editor: konqiDAM
Description: This script helps installing all dependencies of video2x
and generates a configuration for it.
@@ -44,33 +45,47 @@ import zipfile
# Therefore, they will be installed during the Python dependency
# installation step and imported later in the script.
SETUP_VERSION = '2.2.1'
SETUP_VERSION = "2.4.1"
# global static variables
LOCALAPPDATA = pathlib.Path(os.getenv('localappdata'))
DRIVER_OPTIONS = ['all',
'ffmpeg',
'gifski',
'waifu2x_caffe',
'waifu2x_converter_cpp',
'waifu2x_ncnn_vulkan',
'srmd_ncnn_vulkan',
'realsr_ncnn_vulkan',
'anime4kcpp']
LOCALAPPDATA = pathlib.Path(os.getenv("localappdata"))
DRIVER_OPTIONS = [
"all",
"ffmpeg",
"gifski",
"waifu2x_caffe",
"waifu2x_converter_cpp",
"waifu2x_ncnn_vulkan",
"srmd_ncnn_vulkan",
"realsr_ncnn_vulkan",
"anime4kcpp",
]
def parse_arguments():
""" parse command line arguments
"""
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-d', '--driver', help='driver to download and configure', choices=DRIVER_OPTIONS, default='all')
parser.add_argument('-u', '--uninstall', help='uninstall Video2X dependencies from default location', action='store_true')
"""parse command line arguments"""
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"-d",
"--driver",
help="driver to download and configure",
choices=DRIVER_OPTIONS,
default="all",
)
parser.add_argument(
"-u",
"--uninstall",
help="uninstall Video2X dependencies from default location",
action="store_true",
)
# parse arguments
return parser.parse_args()
class Video2xSetup:
""" install dependencies for video2x video enlarger
"""install dependencies for video2x video enlarger
This library is meant to be executed as a stand-alone
script. All files will be installed under %LOCALAPPDATA%\\video2x.
@@ -85,187 +100,232 @@ class Video2xSetup:
# regardless of which driver to install
# always ensure Python modules are installed and up-to-date
if self.download_python_modules:
print('\nInstalling Python libraries')
print("\nInstalling Python libraries")
self._install_python_requirements()
# if all drivers are to be installed
if self.driver == 'all':
DRIVER_OPTIONS.remove('all')
if self.driver == "all":
DRIVER_OPTIONS.remove("all")
for driver in DRIVER_OPTIONS:
getattr(self, f'_install_{driver}')()
getattr(self, f"_install_{driver}")()
# install only the selected driver
else:
getattr(self, f'_install_{self.driver}')()
getattr(self, f"_install_{self.driver}")()
print('\nCleaning up temporary files')
self._cleanup()
# self._cleanup()
def _install_python_requirements(self):
""" Read requirements.txt and return its content
"""
pip_install('requirements.txt')
"""Read requirements.txt and return its content"""
pip_install("requirements.txt")
def _cleanup(self):
""" Cleanup all the temp files downloaded
"""
"""Cleanup all the temp files downloaded"""
print("\nCleaning up temporary files")
for file in self.trash:
try:
if file.is_dir():
print(f'Deleting directory: {file}')
print(f"Deleting directory: {file}")
shutil.rmtree(file)
else:
print(f'Deleting file: {file}')
print(f"Deleting file: {file}")
file.unlink()
except Exception:
print(f'Error deleting: {file}')
print(f"Error deleting: {file}")
traceback.print_exc()
def _install_ffmpeg(self):
""" Install FFMPEG
"""
print('\nInstalling FFmpeg')
"""Install FFMPEG"""
print("\nInstalling FFmpeg")
latest_release = 'https://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-latest-win64-static.zip'
import patoolib
ffmpeg_zip = download(latest_release, tempfile.gettempdir())
self.trash.append(ffmpeg_zip)
latest_release = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z"
with zipfile.ZipFile(ffmpeg_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x')
ffmpeg_7z = download(latest_release, tempfile.gettempdir())
self.trash.append(ffmpeg_7z)
# if running in PyInstaller, add sys._MEIPASS\7z to path
# this directory contains 7za.exe and its DLL files
with contextlib.suppress(AttributeError):
os.environ["PATH"] += f";{sys._MEIPASS}\\7z"
ffmpeg_directory = LOCALAPPDATA / "video2x" / "ffmpeg"
# (ffmpeg_directory).mkdir(parents=True, exist_ok=True)
# pyunpack.Archive(ffmpeg_7z).extractall(ffmpeg_directory)
if (ffmpeg_directory).exists():
shutil.rmtree(ffmpeg_directory)
patoolib.extract_archive(str(ffmpeg_7z), outdir=str(LOCALAPPDATA / "video2x"))
(LOCALAPPDATA / "video2x" / ffmpeg_7z.stem).rename(ffmpeg_directory)
def _install_gifski(self):
print('\nInstalling Gifski')
print("\nInstalling Gifski")
import requests
# Get latest release of Gifski via Github API
latest_release = requests.get('https://api.github.com/repos/ImageOptim/gifski/releases/latest').json()
releases = requests.get(
"https://api.github.com/repos/ImageOptim/gifski/releases"
).json()
for release in releases:
for asset in release["assets"]:
if re.search(r"gifski-.*\.tar\.xz", asset["browser_download_url"]):
gifski_tar_xz = download(
asset["browser_download_url"], tempfile.gettempdir()
)
self.trash.append(gifski_tar_xz)
for a in latest_release['assets']:
if re.search(r'gifski-.*\.tar\.xz', a['browser_download_url']):
gifski_tar_gz = download(a['browser_download_url'], tempfile.gettempdir())
self.trash.append(gifski_tar_gz)
# extract and rename
with tarfile.open(gifski_tar_xz) as archive:
archive.extractall(LOCALAPPDATA / "video2x" / "gifski")
# extract and rename
with tarfile.open(gifski_tar_gz) as archive:
archive.extractall(LOCALAPPDATA / 'video2x' / 'gifski')
return
def _install_waifu2x_caffe(self):
""" Install waifu2x_caffe
"""
print('\nInstalling waifu2x-caffe')
"""Install waifu2x_caffe"""
print("\nInstalling waifu2x-caffe")
import requests
# Get latest release of waifu2x-caffe via GitHub API
latest_release = requests.get('https://api.github.com/repos/lltcggie/waifu2x-caffe/releases/latest').json()
latest_release = requests.get(
"https://api.github.com/repos/lltcggie/waifu2x-caffe/releases/latest"
).json()
for a in latest_release['assets']:
if 'waifu2x-caffe.zip' in a['browser_download_url']:
waifu2x_caffe_zip = download(a['browser_download_url'], tempfile.gettempdir())
for a in latest_release["assets"]:
if "waifu2x-caffe.zip" in a["browser_download_url"]:
waifu2x_caffe_zip = download(
a["browser_download_url"], tempfile.gettempdir()
)
self.trash.append(waifu2x_caffe_zip)
with zipfile.ZipFile(waifu2x_caffe_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x')
zipf.extractall(LOCALAPPDATA / "video2x")
def _install_waifu2x_converter_cpp(self):
""" Install waifu2x_caffe
"""
print('\nInstalling waifu2x-converter-cpp')
"""Install waifu2x_caffe"""
print("\nInstalling waifu2x-converter-cpp")
import requests
# Get latest release of waifu2x-caffe via GitHub API
latest_release = requests.get('https://api.github.com/repos/DeadSix27/waifu2x-converter-cpp/releases/latest').json()
latest_release = requests.get(
"https://api.github.com/repos/DeadSix27/waifu2x-converter-cpp/releases/latest"
).json()
for a in latest_release['assets']:
if re.search(r'waifu2x-DeadSix27-win64_v[0-9]*\.zip', a['browser_download_url']):
waifu2x_converter_cpp_zip = download(a['browser_download_url'], tempfile.gettempdir())
for a in latest_release["assets"]:
if re.search(
r"waifu2x-DeadSix27-win64_v[0-9]*\.zip", a["browser_download_url"]
):
waifu2x_converter_cpp_zip = download(
a["browser_download_url"], tempfile.gettempdir()
)
self.trash.append(waifu2x_converter_cpp_zip)
with zipfile.ZipFile(waifu2x_converter_cpp_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x' / 'waifu2x-converter-cpp')
zipf.extractall(LOCALAPPDATA / "video2x" / "waifu2x-converter-cpp")
def _install_waifu2x_ncnn_vulkan(self):
""" Install waifu2x-ncnn-vulkan
"""
print('\nInstalling waifu2x-ncnn-vulkan')
"""Install waifu2x-ncnn-vulkan"""
print("\nInstalling waifu2x-ncnn-vulkan")
import requests
# Get latest release of waifu2x-ncnn-vulkan via Github API
latest_release = requests.get('https://api.github.com/repos/nihui/waifu2x-ncnn-vulkan/releases/latest').json()
latest_release = requests.get(
"https://api.github.com/repos/nihui/waifu2x-ncnn-vulkan/releases/latest"
).json()
for a in latest_release['assets']:
if re.search(r'waifu2x-ncnn-vulkan-\d*-windows\.zip', a['browser_download_url']):
waifu2x_ncnn_vulkan_zip = download(a['browser_download_url'], tempfile.gettempdir())
for a in latest_release["assets"]:
if re.search(
r"waifu2x-ncnn-vulkan-\d*-windows\.zip", a["browser_download_url"]
):
waifu2x_ncnn_vulkan_zip = download(
a["browser_download_url"], tempfile.gettempdir()
)
self.trash.append(waifu2x_ncnn_vulkan_zip)
# extract and rename
waifu2x_ncnn_vulkan_directory = LOCALAPPDATA / 'video2x' / 'waifu2x-ncnn-vulkan'
waifu2x_ncnn_vulkan_directory = LOCALAPPDATA / "video2x" / "waifu2x-ncnn-vulkan"
with zipfile.ZipFile(waifu2x_ncnn_vulkan_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x')
zipf.extractall(LOCALAPPDATA / "video2x")
# if directory already exists, remove it
if waifu2x_ncnn_vulkan_directory.exists():
shutil.rmtree(waifu2x_ncnn_vulkan_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_srmd_ncnn_vulkan(self):
""" Install srmd-ncnn-vulkan
"""
print('\nInstalling srmd-ncnn-vulkan')
"""Install srmd-ncnn-vulkan"""
print("\nInstalling srmd-ncnn-vulkan")
import requests
# Get latest release of srmd-ncnn-vulkan via Github API
latest_release = requests.get('https://api.github.com/repos/nihui/srmd-ncnn-vulkan/releases/latest').json()
latest_release = requests.get(
"https://api.github.com/repos/nihui/srmd-ncnn-vulkan/releases/latest"
).json()
for a in latest_release['assets']:
if re.search(r'srmd-ncnn-vulkan-\d*-windows\.zip', a['browser_download_url']):
srmd_ncnn_vulkan_zip = download(a['browser_download_url'], tempfile.gettempdir())
for a in latest_release["assets"]:
if re.search(
r"srmd-ncnn-vulkan-\d*-windows\.zip", a["browser_download_url"]
):
srmd_ncnn_vulkan_zip = download(
a["browser_download_url"], tempfile.gettempdir()
)
self.trash.append(srmd_ncnn_vulkan_zip)
# extract and rename
srmd_ncnn_vulkan_directory = LOCALAPPDATA / 'video2x' / 'srmd-ncnn-vulkan'
srmd_ncnn_vulkan_directory = LOCALAPPDATA / "video2x" / "srmd-ncnn-vulkan"
with zipfile.ZipFile(srmd_ncnn_vulkan_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x')
zipf.extractall(LOCALAPPDATA / "video2x")
# if directory already exists, remove it
if srmd_ncnn_vulkan_directory.exists():
shutil.rmtree(srmd_ncnn_vulkan_directory)
# rename the newly extracted directory
(LOCALAPPDATA / 'video2x' / zipf.namelist()[0]).rename(srmd_ncnn_vulkan_directory)
(LOCALAPPDATA / "video2x" / zipf.namelist()[0]).rename(
srmd_ncnn_vulkan_directory
)
def _install_realsr_ncnn_vulkan(self):
""" Install realsr-ncnn-vulkan
"""
print('\nInstalling realsr-ncnn-vulkan')
"""Install realsr-ncnn-vulkan"""
print("\nInstalling realsr-ncnn-vulkan")
import requests
# Get latest release of realsr-ncnn-vulkan via Github API
latest_release = requests.get('https://api.github.com/repos/nihui/realsr-ncnn-vulkan/releases/latest').json()
latest_release = requests.get(
"https://api.github.com/repos/nihui/realsr-ncnn-vulkan/releases/latest"
).json()
for a in latest_release['assets']:
if re.search(r'realsr-ncnn-vulkan-\d*-windows\.zip', a['browser_download_url']):
realsr_ncnn_vulkan_zip = download(a['browser_download_url'], tempfile.gettempdir())
for a in latest_release["assets"]:
if re.search(
r"realsr-ncnn-vulkan-\d*-windows\.zip", a["browser_download_url"]
):
realsr_ncnn_vulkan_zip = download(
a["browser_download_url"], tempfile.gettempdir()
)
self.trash.append(realsr_ncnn_vulkan_zip)
# extract and rename
realsr_ncnn_vulkan_directory = LOCALAPPDATA / 'video2x' / 'realsr-ncnn-vulkan'
realsr_ncnn_vulkan_directory = LOCALAPPDATA / "video2x" / "realsr-ncnn-vulkan"
with zipfile.ZipFile(realsr_ncnn_vulkan_zip) as zipf:
zipf.extractall(LOCALAPPDATA / 'video2x')
zipf.extractall(LOCALAPPDATA / "video2x")
# if directory already exists, remove it
if realsr_ncnn_vulkan_directory.exists():
shutil.rmtree(realsr_ncnn_vulkan_directory)
# rename the newly extracted directory
(LOCALAPPDATA / 'video2x' / zipf.namelist()[0]).rename(realsr_ncnn_vulkan_directory)
(LOCALAPPDATA / "video2x" / zipf.namelist()[0]).rename(
realsr_ncnn_vulkan_directory
)
def _install_anime4kcpp(self):
""" Install Anime4KCPP
"""
print('\nInstalling Anime4KCPP')
"""Install Anime4KCPP"""
print("\nInstalling Anime4KCPP")
import patoolib
import requests
@@ -273,28 +333,35 @@ class Video2xSetup:
# get latest release of Anime4KCPP via Github API
# at the time of writing this portion, Anime4KCPP doesn't yet have a stable release
# therefore releases/latest won't work
latest_release = requests.get('https://api.github.com/repos/TianZerL/Anime4KCPP/releases/latest').json()
latest_release = requests.get(
"https://api.github.com/repos/TianZerL/Anime4KCPP/releases/latest"
).json()
for a in latest_release['assets']:
if re.search(r'Anime4KCPP_CLI-.*-Win64-msvc\.7z', a['browser_download_url']):
anime4kcpp_7z = download(a['browser_download_url'], tempfile.gettempdir())
for a in latest_release["assets"]:
if re.search(
r"Anime4KCPP_CLI-.*-Win64-msvc\.7z", a["browser_download_url"]
):
anime4kcpp_7z = download(
a["browser_download_url"], tempfile.gettempdir()
)
self.trash.append(anime4kcpp_7z)
# if running in PyInstaller, add sys._MEIPASS\7z to path
# this directory contains 7za.exe and its DLL files
with contextlib.suppress(AttributeError):
os.environ['PATH'] += f';{sys._MEIPASS}\\7z'
os.environ["PATH"] += f";{sys._MEIPASS}\\7z"
# (LOCALAPPDATA / 'video2x' / 'anime4kcpp').mkdir(parents=True, exist_ok=True)
# pyunpack.Archive(anime4kcpp_7z).extractall(LOCALAPPDATA / 'video2x' / 'anime4kcpp')
if (LOCALAPPDATA / 'video2x' / 'anime4kcpp').exists():
shutil.rmtree(LOCALAPPDATA / 'video2x' / 'anime4kcpp')
patoolib.extract_archive(str(anime4kcpp_7z), outdir=str(LOCALAPPDATA / 'video2x' / 'anime4kcpp'))
if (LOCALAPPDATA / "video2x" / "anime4kcpp").exists():
shutil.rmtree(LOCALAPPDATA / "video2x" / "anime4kcpp")
patoolib.extract_archive(
str(anime4kcpp_7z), outdir=str(LOCALAPPDATA / "video2x" / "anime4kcpp")
)
def download(url, save_path, chunk_size=4096):
""" Download file to local with requests library
"""
"""Download file to local with requests library"""
from tqdm import tqdm
import requests
@@ -308,14 +375,14 @@ def download(url, save_path, chunk_size=4096):
# get file name
file_name = None
if 'content-disposition' in stream.headers:
disposition = stream.headers['content-disposition']
if "content-disposition" in stream.headers:
disposition = stream.headers["content-disposition"]
with contextlib.suppress(IndexError):
file_name = re.findall("filename=(.+)", disposition)[0].strip('"')
if file_name is None:
# output_file = f'{save_path}\\{stream.url.split("/")[-1]}'
output_file = save_path / stream.url.split('/')[-1]
output_file = save_path / stream.url.split("/")[-1]
else:
output_file = save_path / file_name
@@ -324,17 +391,17 @@ def download(url, save_path, chunk_size=4096):
# get total size for progress bar if provided in headers
total_size = 0
if 'content-length' in stream.headers:
total_size = int(stream.headers['content-length'])
if "content-length" in stream.headers:
total_size = int(stream.headers["content-length"])
# print download information summary
print(f'Downloading: {url}')
print(f'Total size: {total_size}')
print(f'Chunk size: {chunk_size}')
print(f'Saving to: {output_file}')
print(f"Downloading: {url}")
print(f"Total size: {total_size}")
print(f"Chunk size: {chunk_size}")
print(f"Saving to: {output_file}")
# Write content into file
with open(output_file, 'wb') as output:
with open(output_file, "wb") as output:
with tqdm(total=total_size, ascii=True) as progress_bar:
for chunk in stream.iter_content(chunk_size=chunk_size):
if chunk:
@@ -346,16 +413,18 @@ def download(url, save_path, chunk_size=4096):
def pip_install(file):
""" Install python package via python pip module
"""Install python package via python pip module
pip.main() is not available after pip 9.0.1, thus
pip module is not used in this case.
"""
return subprocess.run([sys.executable, '-m', 'pip', 'install', '-U', '-r', file]).returncode
return subprocess.run(
[sys.executable, "-m", "pip", "install", "-U", "-r", file]
).returncode
if __name__ != '__main__':
raise ImportError('video2x_setup cannot be imported')
if __name__ != "__main__":
raise ImportError("video2x_setup cannot be imported")
try:
# set default exit code
@@ -365,42 +434,47 @@ try:
start_time = time.time()
# check platform
if platform.system() != 'Windows':
print('This script is currently only compatible with Windows')
if platform.system() != "Windows":
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: {SETUP_VERSION}')
print("Video2X Setup Script")
print(f"Version: {SETUP_VERSION}")
# uninstall video2x dependencies
if args.uninstall:
if input('Are you sure you want to uninstall all Video2X dependencies? [y/N]: ').lower() == 'y':
if (
input(
"Are you sure you want to uninstall all Video2X dependencies? [y/N]: "
).lower()
== "y"
):
try:
print(f'Removing: {LOCALAPPDATA / "video2x"}')
shutil.rmtree(LOCALAPPDATA / 'video2x')
print('Successfully uninstalled all dependencies')
shutil.rmtree(LOCALAPPDATA / "video2x")
print("Successfully uninstalled all dependencies")
except FileNotFoundError:
print(f'Dependency folder does not exist: {LOCALAPPDATA / "video2x"}')
else:
print('Uninstallation aborted')
print("Uninstallation aborted")
# run installation
else:
# do not install pip modules if script
# is packaged in exe format
download_python_modules = True
if sys.argv[0].endswith('.exe'):
print('\nScript is packaged as exe, skipping pip module download')
if sys.argv[0].endswith(".exe"):
print("\nScript is packaged as exe, skipping pip module download")
download_python_modules = False
# create setup install instance and run installer
setup = Video2xSetup(args.driver, download_python_modules)
setup.run()
print('\nScript finished successfully')
print("\nScript finished successfully")
# let SystemExit signals pass through
except SystemExit as e:
@@ -410,35 +484,35 @@ except SystemExit as e:
# 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')
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')
# in case of a failure, try cleaning up temp files
try:
setup._cleanup()
except Exception:
traceback.print_exc()
print('An error occurred while trying to cleanup files')
print("An error has occurred")
print("Video2X Automatic Setup has failed")
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))}')
# always try cleaning up trash
try:
setup._cleanup()
except Exception:
traceback.print_exc()
print("An error occurred while trying to cleanup files")
print("Script finished")
print(f"Time taken: {timedelta(seconds=round(time.time() - start_time))}")
# if the program is launched as an Windows PE file
# it might be launched from double clicking
# pause the window before it closes automatically
if sys.argv[0].endswith('.exe'):
input('Press [ENTER] to exit script')
if sys.argv[0].endswith(".exe"):
input("Press [ENTER] to exit script")
sys.exit(EXIT_CODE)

View File

@@ -130,4 +130,4 @@ class WrapperMain:
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {" ".join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)

View File

@@ -13,6 +13,7 @@ Description: This class handles all FFmpeg related operations.
import json
import pathlib
import subprocess
import sys
# third-party imports
from avalon_framework import Avalon
@@ -316,4 +317,4 @@ class Ffmpeg:
# turn all list elements into string to avoid errors
execute = [str(e) for e in execute]
Avalon.debug_info(f'Executing: {" ".join(execute)}')
return subprocess.Popen(execute)
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)

View File

@@ -12,6 +12,7 @@ Description: High-level wrapper for Gifski.
# built-in imports
import pathlib
import subprocess
import sys
# third-party imports
from avalon_framework import Avalon
@@ -71,4 +72,4 @@ class Gifski:
Avalon.debug_info(f'Executing: {execute}')
return subprocess.Popen(execute)
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)

View File

@@ -4,7 +4,7 @@
Name: RealSR NCNN Vulkan Driver
Creator: K4YT3X
Date Created: May 26, 2020
Last Modified: September 9, 2020
Last Modified: September 21, 2020
Description: This class is a high-level wrapper
for realsr_ncnn_vulkan.
@@ -16,6 +16,7 @@ import os
import pathlib
import platform
import subprocess
import sys
import threading
# third-party imports
@@ -49,11 +50,13 @@ class WrapperMain:
parser.add_argument('-g', type=int, help='gpu device to use')
parser.add_argument('-j', type=str, help='thread count for load/proc/save')
parser.add_argument('-x', action='store_true', help='enable tta mode')
parser.add_argument('-f', type=str, help=argparse.SUPPRESS) # help='output image format (jpg/png/webp, default=ext/png)')
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
# self.driver_settings['s'] = int(upscaler.scale_ratio)
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
self.driver_settings['f'] = upscaler.extracted_frame_format.lower()
def set_scale_ratio(self, scale_ratio: int):
self.driver_settings['s'] = int(scale_ratio)
@@ -105,4 +108,4 @@ class WrapperMain:
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {" ".join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)

View File

@@ -4,7 +4,7 @@
Name: SRMD NCNN Vulkan Driver
Creator: K4YT3X
Date Created: April 26, 2020
Last Modified: September 9, 2020
Last Modified: September 21, 2020
Description: This class is a high-level wrapper
for srmd_ncnn_vulkan.
@@ -16,6 +16,7 @@ import os
import pathlib
import platform
import subprocess
import sys
import threading
# third-party imports
@@ -50,11 +51,13 @@ class WrapperMain:
parser.add_argument('-g', type=int, help='gpu device to use')
parser.add_argument('-j', type=str, help='thread count for load/proc/save')
parser.add_argument('-x', action='store_true', help='enable tta mode')
parser.add_argument('-f', type=str, help=argparse.SUPPRESS) # help='output image format (jpg/png/webp, default=ext/png)')
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
# self.driver_settings['s'] = int(upscaler.scale_ratio)
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
self.driver_settings['f'] = upscaler.extracted_frame_format.lower()
def set_scale_ratio(self, scale_ratio: int):
self.driver_settings['s'] = int(scale_ratio)
@@ -106,4 +109,4 @@ class WrapperMain:
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {" ".join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)

View File

@@ -15,6 +15,7 @@ import argparse
import os
import pathlib
import subprocess
import sys
import threading
# third-party imports
@@ -116,4 +117,4 @@ class WrapperMain:
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {" ".join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)

View File

@@ -15,6 +15,7 @@ import argparse
import os
import pathlib
import subprocess
import sys
import threading
# third-party imports
@@ -122,4 +123,4 @@ class WrapperMain:
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {" ".join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)

View File

@@ -7,7 +7,7 @@ Date Created: June 26, 2019
Last Modified: May 11, 2020
Editor: K4YT3X
Last Modified: September 9, 2020
Last Modified: September 21, 2020
Description: This class is a high-level wrapper
for waifu2x_ncnn_vulkan.
@@ -19,6 +19,7 @@ import os
import pathlib
import platform
import subprocess
import sys
import threading
# third-party imports
@@ -44,8 +45,8 @@ class WrapperMain:
parser.error = lambda message: (_ for _ in ()).throw(AttributeError(message))
parser.add_argument('--help', action='help', help='show this help message and exit')
parser.add_argument('-v', action='store_true', help='verbose output')
parser.add_argument('-i', type=str, help=argparse.SUPPRESS) # help='input image path (jpg/png) or directory')
parser.add_argument('-o', type=str, help=argparse.SUPPRESS) # help='output image path (png) or directory')
parser.add_argument('-i', type=str, help=argparse.SUPPRESS) # help='input image path (jpg/png/webp) or directory')
parser.add_argument('-o', type=str, help=argparse.SUPPRESS) # help='output image path (jpg/png/webp) or directory')
parser.add_argument('-n', type=int, choices=range(-1, 4), help='denoise level')
parser.add_argument('-s', type=int, help='upscale ratio')
parser.add_argument('-t', type=int, help='tile size (>=32)')
@@ -53,11 +54,13 @@ class WrapperMain:
parser.add_argument('-g', type=int, help='gpu device to use')
parser.add_argument('-j', type=str, help='thread count for load/proc/save')
parser.add_argument('-x', action='store_true', help='enable tta mode')
parser.add_argument('-f', type=str, help=argparse.SUPPRESS) # help='output image format (jpg/png/webp, default=ext/png)')
return parser.parse_args(arguments)
def load_configurations(self, upscaler):
# self.driver_settings['s'] = int(upscaler.scale_ratio)
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
self.driver_settings['f'] = upscaler.extracted_frame_format.lower()
def set_scale_ratio(self, scale_ratio: int):
self.driver_settings['s'] = int(scale_ratio)
@@ -109,4 +112,4 @@ class WrapperMain:
self.print_lock.acquire()
Avalon.debug_info(f'[upscaler] Subprocess {os.getpid()} executing: {" ".join(execute)}')
self.print_lock.release()
return subprocess.Popen(execute)
return subprocess.Popen(execute, stdout=sys.stdout, stderr=sys.stderr)