mirror of
https://github.com/k4yt3x/video2x.git
synced 2026-02-09 22:34:48 +08:00
Compare commits
46 Commits
4.0.0-beta
...
4.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cf3271aad | ||
|
|
bcbead4d96 | ||
|
|
a3d0465e44 | ||
|
|
995fdec5c8 | ||
|
|
5c3ea51ccb | ||
|
|
a24b321088 | ||
|
|
a83249c670 | ||
|
|
ab2f982a84 | ||
|
|
91401977da | ||
|
|
99971bceb1 | ||
|
|
0c6de8af16 | ||
|
|
4def30f516 | ||
|
|
8d553ac575 | ||
|
|
e1a1cf578b | ||
|
|
4015617152 | ||
|
|
648bf4fd3d | ||
|
|
e3ed08ff40 | ||
|
|
90f807655a | ||
|
|
ab77d62c71 | ||
|
|
a64fabae87 | ||
|
|
26558c6159 | ||
|
|
4fbbb20258 | ||
|
|
4659a9a9f5 | ||
|
|
4c48af4fa4 | ||
|
|
4a6f90a1f0 | ||
|
|
2d9c5fe751 | ||
|
|
bef3861d3c | ||
|
|
bcb54b6d2c | ||
|
|
e82a26d44f | ||
|
|
14f7f34ee3 | ||
|
|
11ba334f16 | ||
|
|
c451b14bd7 | ||
|
|
80623a6bb7 | ||
|
|
a5dd87a72c | ||
|
|
9b20ef89c9 | ||
|
|
91efe2d684 | ||
|
|
0d9d5c4f43 | ||
|
|
e0e42b11c8 | ||
|
|
790bb54598 | ||
|
|
f2943802cb | ||
|
|
d12f2a3888 | ||
|
|
871d6386a8 | ||
|
|
589a68caf7 | ||
|
|
afacc48e1e | ||
|
|
4a3553607b | ||
|
|
988600a769 |
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,9 +1,3 @@
|
||||
# Runtime files
|
||||
upscaled/
|
||||
frames/
|
||||
waifu2x-caffe/
|
||||
testvid.mp4
|
||||
|
||||
# PyCharm
|
||||
.idea/
|
||||
|
||||
@@ -57,8 +51,8 @@ coverage.xml
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
#*.mo
|
||||
#*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
|
||||
341
README.md
341
README.md
@@ -1,3 +1,7 @@
|
||||
<p align="center">
|
||||
<img src="https://user-images.githubusercontent.com/21986859/81489504-c7d1f780-9265-11ea-86c8-cc0316e2082d.png"/>
|
||||
</p>
|
||||
|
||||

|
||||

|
||||

|
||||
@@ -5,35 +9,164 @@
|
||||

|
||||
<img alt="Become a Patron!"
|
||||
src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png"
|
||||
href="https://www.patreon.com/bePatron?u=34970782"
|
||||
href="https://www.patreon.com/bePatron?u=34970782"
|
||||
height=20 />
|
||||
|
||||
# Video2X Lossless Video Enlarger
|
||||
<!--# Video2X Lossless Video Enlarger-->
|
||||
|
||||
### Official Discussion Group (Telegram): https://t.me/video2x
|
||||
|
||||
## Download Builds (Windows)
|
||||
## [Download Builds](https://github.com/k4yt3x/video2x/releases) (Windows)
|
||||
|
||||
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. There are two editions available.
|
||||
|
||||
The **`full`** package provides all packages that will possibly be needed by `Video2X`, including `FFmpeg`, `waifu2x-caffe`, `waifu2x-converter-cpp`, `waifu2x-ncnn-vulkan`, `srmd-ncnn-vulkan` and `Anime4KCPP`. The config file (`video2x.yaml`) is also already configured for the environment. All you need to do is just to launch `video2x.exe`.
|
||||
- **`Full`**: full package comes pre-configured with **all** dependencies like `FFmpeg` and `waifu2x-caffe`.
|
||||
- **`Light`**: ligt package comes with only Video2X binaries and a template configuration file. The user will either have to run the setup script or install and configure dependencies themselves.
|
||||
|
||||
The **`light`** package provides only the most basic functions of `Video2X`. Only `video2x.exe`, `video2x_setup.exe` and `video2x.yaml` are included. To setup dependencies (e.g. `FFmpeg` and `Waifu2X`) automatically, simply launch `video2x_setup.exe`.
|
||||
Go to the [Quick Start](#quick-start) section for usages.
|
||||
|
||||
## Prerequisites
|
||||
## Introduction
|
||||
|
||||
Component names that are **bolded** can be automatically downloaded and configured with the `video2x_setup.py` script.
|
||||
Video2X is a video upscaling software based on Waifu2X, Anime4K and SRMD written in Python 3. It upscales videos and restores details from low-resolution videos. Below is a side-by-side preview.
|
||||
|
||||
1. Operating System: Windows / Linux
|
||||
2. AMD GPU / Nvidia GPU
|
||||
3. AMD GPU driver / Nvidia GPU driver / Nvidia CUDNN
|
||||
4. [**FFmpeg**](https://ffmpeg.zeranoe.com/builds/)
|
||||
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)
|
||||
- [**srmd-ncnn-vulkan**](https://github.com/nihui/srmd-ncnn-vulkan)
|
||||
- [**Anime4KCPP**](https://github.com/TianZerL/Anime4KCPP)
|
||||

|
||||
|
||||
*Upscale Comparison Demonstration*
|
||||
|
||||
**You can watch the whole demo video on YouTube: https://youtu.be/mGEfasQl2Zo**
|
||||
|
||||
Clip is from trailer of animated movie "千と千尋の神隠し". Copyright belongs to "株式会社スタジオジブリ (STUDIO GHIBLI INC.)". Will delete immediately if use of clip is in violation of copyright.
|
||||
|
||||
## Demo Videos
|
||||
|
||||
Below is a list of all the demo videos available.
|
||||
The list is sorted from new to old.
|
||||
|
||||
- **Bad Apple!!**
|
||||
- YouTube: https://youtu.be/-RKLdCELgkQ
|
||||
- Bilibili: https://www.bilibili.com/video/BV1s5411s7xV/
|
||||
- **The Pet Girl of Sakurasou 240P to 1080P 60FPS**
|
||||
- Original name: さくら荘のペットな彼女
|
||||
- YouTube: https://youtu.be/M0vDI1HH2_Y
|
||||
- Bilibili: https://www.bilibili.com/video/BV14k4y167KP/
|
||||
- **Spirited Away (360P to 4K)**
|
||||
- Original name: 千と千尋の神隠し
|
||||
- YouTube: https://youtu.be/mGEfasQl2Zo
|
||||
- Bilibili: https://www.bilibili.com/video/BV1V5411471i/
|
||||
|
||||
## Screenshots
|
||||
|
||||
### Video2X GUI
|
||||
|
||||

|
||||
|
||||
*Video2X GUI Screenshot*
|
||||
|
||||
### Video2X CLI
|
||||
|
||||

|
||||
|
||||
*Video2X CLI Screenshot*
|
||||
|
||||
---
|
||||
|
||||
## Documentations
|
||||
|
||||
### [Video2X Wiki](https://github.com/k4yt3x/video2x/wiki)
|
||||
|
||||
You can find all detailed user-facing and developer-facing documentations in the [Video2X Wiki](https://github.com/k4yt3x/video2x/wiki). It covers everything from step-by-step instructions for beginners, to the code structure of this program for advanced users and developers. If this README page doesn't answer all your questions, the wiki page is where you should head to.
|
||||
|
||||
### [Run From Source](https://github.com/k4yt3x/video2x/wiki/Run-From-Source)
|
||||
|
||||
Instructions for how to run this program from source code.
|
||||
|
||||
### [Step-By-Step Tutorial](https://github.com/k4yt3x/video2x/wiki/Step-By-Step-Tutorial)
|
||||
|
||||
For those who want a detailed walk-through of how to use Video2X, you can head to the [Step-By-Step Tutorial](https://github.com/k4yt3x/video2x/wiki/Step-By-Step-Tutorial) wiki page. It includes almost every step you need to perform in order to enlarge your first video.
|
||||
|
||||
### [Drivers](https://github.com/k4yt3x/video2x/wiki/Drivers)
|
||||
|
||||
Go to the [Drivers](https://github.com/k4yt3x/video2x/wiki/Drivers) wiki page if you want to see a detailed description on the different types of drivers implemented by Video2X. This wiki page contains detailed difference between different drivers, and how to download and set each of them up for Video2X.
|
||||
|
||||
### [Q&A](https://github.com/k4yt3x/video2x/wiki/Q&A)
|
||||
|
||||
If you have any questions, first try visiting our [Q&A](https://github.com/k4yt3x/video2x/wiki/Q&A) page to see if your question is answered there. If not, open an issue and we will respond to your questions ASAP. Alternatively, you can also join our [Telegram discussion group](https://t.me/video2x) and ask your questions there.
|
||||
|
||||
---
|
||||
|
||||
### Sample Videos
|
||||
|
||||
If you can't find a video clip to begin with, or if you want to see a before-after comparison, we have prepared some sample clips for you. The quick start guide down below will also be based on the name of the sample clips.
|
||||
|
||||

|
||||
|
||||
*Sample Upscale Videos*
|
||||
|
||||
- [Sample Video (240P) 4.54MB](https://files.k4yt3x.com/Resources/Videos/sample_input.mp4)
|
||||
- [Sample Video Upscaled (1080P) 4.54MB](https://files.k4yt3x.com/Resources/Videos/sample_output.mp4)
|
||||
- [Sample Video Original (1080P) 22.2MB](https://files.k4yt3x.com/Resources/Videos/sample_original.mp4)
|
||||
|
||||
Clip is from anime "さくら荘のペットな彼女". Copyright belongs to "株式会社アニプレックス (Aniplex Inc.)". Will delete immediately if use of clip is in violation of copyright.
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before running Video2X, you'll need to ensure you have installed the drivers' external dependencies such as GPU drivers.
|
||||
|
||||
- waifu2x-caffe
|
||||
- GPU mode: Nvidia graphics card driver
|
||||
- cuDNN mode: Nvidia CUDA and [cuDNN](https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html#install-windows)
|
||||
- Other Drivers
|
||||
- GPU driver if you want to use GPU for processing
|
||||
|
||||
### Running Video2X (GUI)
|
||||
|
||||
The easiest way to run Video2X is to use the full build. Extract the full release zip file and you'll get these files.
|
||||
|
||||

|
||||
|
||||
Simply double click on video2x_gui.exe to launch the GUI.
|
||||
|
||||

|
||||
|
||||
Then, drag the videos you wish to upscale into the window and select the appropriate output path.
|
||||
|
||||

|
||||
|
||||
Tweak the settings if you want to, then hit the start button at the bottom and the upscale will start. Now you'll just have to wait for it to complete.
|
||||
|
||||

|
||||
|
||||
### Running Video2X (CLI)
|
||||
|
||||
#### Basic Upscale Example
|
||||
|
||||
This example command below uses `waifu2x-caffe` to enlarge the video `sample-input.mp4` two double its original size.
|
||||
|
||||
```shell
|
||||
python video2x.py -i sample-input.mp4 -o sample-output.mp4 -r 2 -d waifu2x_caffe
|
||||
```
|
||||
|
||||
#### Advanced Upscale Example
|
||||
|
||||
If you would like to tweak engine-specific settings, either specify the corresponding argument after `--`, or edit the corresponding field in the configuration file `video2x.yaml`. **Command line arguments will overwrite default values in the config file.**
|
||||
|
||||
This example below adds enables TTA for `waifu2x-caffe`.
|
||||
|
||||
```shell
|
||||
python video2x.py -i sample-input.mp4 -o sample-output.mp4 -r 2 -d waifu2x_caffe -- --tta 1
|
||||
```
|
||||
|
||||
To see a help page for driver-specific settings, use `-d` to select the driver and append `-- --help` as demonstrated below. This will print all driver-specific settings and descriptions.
|
||||
|
||||
```shell
|
||||
python video2x.py -d waifu2x_caffe -- --help
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Recent Changes
|
||||
|
||||
@@ -62,148 +195,11 @@ Component names that are **bolded** can be automatically downloaded and configur
|
||||
|
||||
- Added support for Anime4KCPP
|
||||
|
||||
## Description
|
||||
|
||||
Video2X is an automation software based on waifu2x image enlarging engine. It extracts frames from a video, enlarge it by a number of times without losing any details or quality, keeping lines smooth and edges sharp.
|
||||
|
||||
For short: **Video2X enlarges your video without losing details**.
|
||||
|
||||
Watch for the sharper edges in this screenshot around the shadows:
|
||||
|
||||

|
||||
|
||||
*Upscale Comparison Demonstration*
|
||||
|
||||
**You can also watch the YouTube video Demo: https://www.youtube.com/watch?v=PG94iPoeoZk**
|
||||
|
||||
Clip is from trailer of animated movie "千と千尋の神隠し". Copyright belongs to "株式会社スタジオジブリ (STUDIO GHIBLI INC.)". Will delete immediately if use of clip is in violation of copyright.
|
||||
|
||||
## Screenshots
|
||||
|
||||
### Video2X GUI
|
||||
|
||||

|
||||
|
||||
*Video2X GUI Main Tab Screenshot*
|
||||
|
||||

|
||||
|
||||
*Video2X GUI Driver Settings Screenshot*
|
||||
|
||||
### Video2X CLI
|
||||
|
||||

|
||||
|
||||
*Video2X CLI Screenshot*
|
||||
|
||||
---
|
||||
|
||||
## Documentations
|
||||
|
||||
### [Video2X Wiki](https://github.com/k4yt3x/video2x/wiki)
|
||||
|
||||
You can find all detailed user-facing and developer-facing documentations in the [Video2X Wiki](https://github.com/k4yt3x/video2x/wiki). It covers everything from step-by-step instructions for beginners, to the code structure of this program for advanced users and developers. If this README page doesn't answer all your questions, the wiki page is where you should head to.
|
||||
|
||||
### [Step-By-Step Tutorial](https://github.com/k4yt3x/video2x/wiki/Step-By-Step-Tutorial)
|
||||
|
||||
For those who want a detailed walk-through of how to use `Video2X`, you can head to the [Step-By-Step Tutorial](https://github.com/k4yt3x/video2x/wiki/Step-By-Step-Tutorial) wiki page. It includes almost every step you need to perform in order to enlarge your first video.
|
||||
|
||||
### [Drivers](https://github.com/k4yt3x/video2x/wiki/Drivers)
|
||||
|
||||
Go to the [Drivers](https://github.com/k4yt3x/video2x/wiki/Drivers) wiki page if you want to see a detailed description on the different types of drivers implemented by `Video2X`. This wiki page contains detailed difference between different drivers, and how to download and set each of them up for `Video2X`.
|
||||
|
||||
### [Q&A](https://github.com/k4yt3x/video2x/wiki/Q&A)
|
||||
|
||||
If you have any questions, first try visiting our [Q&A](https://github.com/k4yt3x/video2x/wiki/Q&A) page to see if your question is answered there. If not, open an issue and we will respond to your questions ASAP.
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Python 3.8**
|
||||
Download: https://www.python.org/downloads/windows/
|
||||
- **FFmpeg Windows Build**
|
||||
Download: https://ffmpeg.org/download.html
|
||||
- **waifu2x-caffe** (designed for Nvidia CUDA/cuDNN)
|
||||
Download: https://github.com/lltcggie/waifu2x-caffe/releases
|
||||
- **waifu2x-converter-cpp**
|
||||
Download: https://github.com/DeadSix27/waifu2x-converter-cpp/releases
|
||||
- **waifu2x-ncnn-vulkan**
|
||||
Download: https://github.com/nihui/waifu2x-ncnn-vulkan/releases
|
||||
- **Anime4KCPP**
|
||||
Download: https://github.com/TianZerL/Anime4KCPP/releases
|
||||
- **srmd-ncnn-vulkan**
|
||||
Download: https://github.com/nihui/srmd-ncnn-vulkan/releases
|
||||
|
||||
### Installing Dependencies
|
||||
|
||||
First, clone the video2x repository.
|
||||
|
||||
```shell
|
||||
git clone https://github.com/k4yt3x/video2x.git
|
||||
cd video2x/src
|
||||
```
|
||||
|
||||
Then you may run the `video2x_setup.py` script to install and configure the dependencies automatically. This script is designed and tested on Windows 10.
|
||||
|
||||
This script will install the newest version of `ffmpeg`, and all upscaling drivers to `%LOCALAPPDATA%\\video2x` and all required python libraries.
|
||||
|
||||
```shell
|
||||
python video2x_setup.py
|
||||
```
|
||||
|
||||
Alternatively, you can also install the dependencies manually. Please refer to the prerequisites section to see what's needed.
|
||||
|
||||
Then you'll need to install python dependencies before start using video2x. Install simply by executing the following command.
|
||||
|
||||
```shell
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Sample Videos
|
||||
|
||||
If you can't find a video clip to begin with, or if you want to see a before-after comparison, we have prepared some sample clips for you. The quick start guide down below will also be based on the name of the sample clips.
|
||||
|
||||

|
||||
|
||||
*Sample Upscale Videos*
|
||||
|
||||
- [Sample Video Original (240P) 1.7MB](https://files.k4yt3x.com/Resources/Videos/sample_input.mp4)
|
||||
- [Sample Video Upscaled (1080P) 4.8MB](https://files.k4yt3x.com/Resources/Videos/sample_output.mp4)
|
||||
|
||||
Clip is from anime "さくら荘のペットな彼女". Copyright belongs to "株式会社アニプレックス (Aniplex Inc.)". Will delete immediately if use of clip is in violation of copyright.
|
||||
|
||||
### Basic Upscale Example
|
||||
|
||||
This example command below uses `waifu2x-caffe` to enlarge the video `sample-input.mp4` two double its original size.
|
||||
|
||||
```shell
|
||||
python video2x.py -i sample-input.mp4 -o sample-output.mp4 -r 2 -d waifu2x_caffe
|
||||
```
|
||||
|
||||
### Advanced Upscale Example
|
||||
|
||||
If you would like to tweak engine-specific settings, either specify the corresponding argument after `--`, or edit the corresponding field in the configuration file `video2x.yaml`. **Command line arguments will overwrite default values in the config file.**
|
||||
|
||||
This example below adds enables TTA for `waifu2x-caffe`.
|
||||
|
||||
```shell
|
||||
python video2x.py -i sample-input.mp4 -o sample-output.mp4 -r 2 -d waifu2x_caffe -- --tta 1
|
||||
```
|
||||
|
||||
To see a help page for driver-specific settings, use `-d` to select the driver and append `-- --help` as demonstrated below. This will print all driver-specific settings and descriptions.
|
||||
|
||||
```shell
|
||||
python video2x.py -d waifu2x_caffe -- --help
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Full Usage
|
||||
|
||||
## General Options:
|
||||
## Video2X Options
|
||||
|
||||
### -h, --help
|
||||
show this help message and exit
|
||||
@@ -217,25 +213,30 @@ python video2x.py -d waifu2x_caffe -- --help
|
||||
### -c CONFIG, --config CONFIG
|
||||
video2x config file path
|
||||
|
||||
### -d {waifu2x_caffe,waifu2x_converter_cpp,waifu2x_ncnn_vulkan,srmd_ncnn_vulkan,anime4kcpp}, --driver {waifu2x_caffe,waifu2x_converter_cpp,waifu2x_ncnn_vulkan,srmd_ncnn_vulkan,anime4kcpp}
|
||||
### -v, --version
|
||||
display version, lawful information and exit
|
||||
|
||||
## Upscaling Options
|
||||
|
||||
### -d DRIVER, --driver DRIVER
|
||||
upscaling driver (default: waifu2x_caffe)
|
||||
|
||||
Available options are:
|
||||
|
||||
- waifu2x_caffe
|
||||
- waifu2x_converter_cpp
|
||||
- waifu2x_ncnn_vulkan
|
||||
- srmd_ncnn_vulkan
|
||||
- anime4kcpp
|
||||
|
||||
### -r RATIO, --ratio RATIO
|
||||
scaling ratio
|
||||
|
||||
### -p PROCESSES, --processes PROCESSES
|
||||
number of processes to use for upscaling (default: 1)
|
||||
|
||||
### -v, --version
|
||||
display version, lawful information and exit
|
||||
|
||||
## Scaling Options
|
||||
|
||||
### --width WIDTH
|
||||
output video width
|
||||
|
||||
### --height HEIGHT
|
||||
output video height
|
||||
|
||||
### -r RATIO, --ratio RATIO
|
||||
scaling ratio
|
||||
### --preserve_frames
|
||||
preserve extracted and upscaled frames (default: False)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -12,12 +12,18 @@ To start a PowerShell session with execution policy bypass
|
||||
powershell –ExecutionPolicy Bypass
|
||||
#>
|
||||
|
||||
if ($args.count -ne 1){
|
||||
Write-Host -ForegroundColor White "Usage:`n .\build.ps1 VIDEO2X_VERSION"
|
||||
Exit
|
||||
}
|
||||
|
||||
# version number
|
||||
$SCRIPT_VERSION = "1.0.1"
|
||||
$VIDEO2X_VERSION = "4.0.0_beta2"
|
||||
$VIDEO2X_VERSION = $args[0]
|
||||
|
||||
Write-Host -ForegroundColor White "Video2X Building Script Version $($SCRIPT_VERSION)
|
||||
Starting to build Video2X release packages"
|
||||
Starting to build Video2X release packages
|
||||
Building Video2X release $($VIDEO2X_VERSION)"
|
||||
|
||||
# build Video2X CLI
|
||||
Write-Host -ForegroundColor White "`nBuilding Video2X CLI"
|
||||
|
||||
BIN
src/images/Video2X Banner.png
Normal file
BIN
src/images/Video2X Banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
BIN
src/images/Video2X GitHub Social Preview.png
Normal file
BIN
src/images/Video2X GitHub Social Preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
BIN
src/images/Video2X GitHub Social Preview.psd
Normal file
BIN
src/images/Video2X GitHub Social Preview.psd
Normal file
Binary file not shown.
BIN
src/images/Video2X Logo.psd
Normal file
BIN
src/images/Video2X Logo.psd
Normal file
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 298 KiB |
BIN
src/locale/zh_CN/LC_MESSAGES/video2x.mo
Normal file
BIN
src/locale/zh_CN/LC_MESSAGES/video2x.mo
Normal file
Binary file not shown.
BIN
src/locale/zh_CN/LC_MESSAGES/zh_CN.mo
Normal file
BIN
src/locale/zh_CN/LC_MESSAGES/zh_CN.mo
Normal file
Binary file not shown.
@@ -5,8 +5,8 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: 2020-05-07 15:54-0400\n"
|
||||
"PO-Revision-Date: 2020-05-07 15:55-0400\n"
|
||||
"POT-Creation-Date: 2020-05-11 04:39-0400\n"
|
||||
"PO-Revision-Date: 2020-05-11 04:40-0400\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
"Language: zh_CN\n"
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
"X-Generator: Poedit 2.3\n"
|
||||
"X-Generator: Poedit 2.3.1\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: progress_monitor.py:42
|
||||
@@ -49,127 +49,155 @@ msgstr "清理缓存目录:{}"
|
||||
msgid "Unable to delete: {}"
|
||||
msgstr "无法删除:{}"
|
||||
|
||||
#: upscaler.py:140 upscaler.py:151
|
||||
#: upscaler.py:139 upscaler.py:154 upscaler.py:165
|
||||
msgid "Input and output path type mismatch"
|
||||
msgstr "输入和输出路径类型不匹配"
|
||||
|
||||
#: upscaler.py:141
|
||||
#: upscaler.py:140
|
||||
msgid "Input is multiple files but output is not directory"
|
||||
msgstr "输入是多个文件,但输出不是目录"
|
||||
|
||||
#: upscaler.py:144
|
||||
msgid "Input path {} is neither a file nor a directory"
|
||||
msgstr "输入路径 {} 既不是文件也不是目录"
|
||||
|
||||
#: upscaler.py:148 upscaler.py:170
|
||||
msgid "Input directory and output directory cannot be the same"
|
||||
msgstr "输入目录和输出目录不能相同"
|
||||
|
||||
#: upscaler.py:155
|
||||
msgid "Input is single file but output is directory"
|
||||
msgstr "所选的输入路径是单个文件,但输出路径是目录"
|
||||
|
||||
#: upscaler.py:144
|
||||
#: upscaler.py:158
|
||||
msgid "No suffix found in output file path"
|
||||
msgstr "在输出文件路径中未找到后缀"
|
||||
|
||||
#: upscaler.py:145
|
||||
#: upscaler.py:159
|
||||
msgid "Suffix must be specified for FFmpeg"
|
||||
msgstr "必须为 FFmpeg 指定后缀"
|
||||
|
||||
#: upscaler.py:152
|
||||
#: upscaler.py:166
|
||||
msgid "Input is directory but output is existing single file"
|
||||
msgstr "输入是目录,但输出是现有的单个文件"
|
||||
|
||||
#: upscaler.py:157
|
||||
#: upscaler.py:175
|
||||
msgid "Input path is neither a file nor a directory"
|
||||
msgstr "输入路径既不是文件也不是目录"
|
||||
|
||||
#: upscaler.py:166
|
||||
#: upscaler.py:184
|
||||
msgid "FFmpeg or FFprobe cannot be found under the specified path"
|
||||
msgstr "在指定的路径下找不到 FFmpeg 或 FFprobe"
|
||||
|
||||
#: upscaler.py:167 upscaler.py:177
|
||||
#: upscaler.py:185 upscaler.py:195
|
||||
msgid "Please check the configuration file settings"
|
||||
msgstr "请检查配置文件设置"
|
||||
|
||||
#: upscaler.py:176
|
||||
#: upscaler.py:194
|
||||
msgid "Specified driver executable directory doesn't exist"
|
||||
msgstr "指定驱动的可执行文件不存在"
|
||||
|
||||
#: upscaler.py:203
|
||||
#: upscaler.py:221
|
||||
msgid "Failed to parse driver argument: {}"
|
||||
msgstr "解析驱动程序参数失败:{}"
|
||||
|
||||
#: upscaler.py:218
|
||||
#: upscaler.py:253
|
||||
msgid "Unrecognized driver: {}"
|
||||
msgstr "无法识别的驱动名称:{}"
|
||||
|
||||
#: upscaler.py:290
|
||||
#: upscaler.py:293
|
||||
msgid "Starting progress monitor"
|
||||
msgstr "启动进度监视器"
|
||||
|
||||
#: upscaler.py:295
|
||||
#: upscaler.py:298
|
||||
msgid "Starting upscaled image cleaner"
|
||||
msgstr "启动已放大图像清理程序"
|
||||
|
||||
#: upscaler.py:304 upscaler.py:321
|
||||
#: upscaler.py:307 upscaler.py:324
|
||||
msgid "Killing progress monitor"
|
||||
msgstr "终结进度监视器"
|
||||
|
||||
#: upscaler.py:307 upscaler.py:324
|
||||
#: upscaler.py:310 upscaler.py:327
|
||||
msgid "Killing upscaled image cleaner"
|
||||
msgstr "终结已放大图像清理程序"
|
||||
|
||||
#: upscaler.py:328
|
||||
#: upscaler.py:331
|
||||
msgid "Terminating all processes"
|
||||
msgstr "正在终止所有进程"
|
||||
|
||||
#: upscaler.py:335
|
||||
#: upscaler.py:338
|
||||
msgid "Main process waiting for subprocesses to exit"
|
||||
msgstr "主进程开始等待子进程结束"
|
||||
|
||||
#: upscaler.py:354 upscaler.py:358
|
||||
#: upscaler.py:357 upscaler.py:361
|
||||
msgid "Subprocess {} exited with code {}"
|
||||
msgstr "子进程 {} 结束,返回码 {}"
|
||||
|
||||
#: upscaler.py:364
|
||||
#: upscaler.py:367
|
||||
msgid "Stop signal received"
|
||||
msgstr "收到停止信号"
|
||||
|
||||
#: upscaler.py:369
|
||||
#: upscaler.py:372
|
||||
msgid "Subprocess execution ran into an error"
|
||||
msgstr "子进程执行遇到错误"
|
||||
|
||||
#: upscaler.py:395
|
||||
#: upscaler.py:421
|
||||
msgid "Upscaling single video file: {}"
|
||||
msgstr "放大单个视频文件:{}"
|
||||
|
||||
#: upscaler.py:414 upscaler.py:477
|
||||
#: upscaler.py:443 upscaler.py:502
|
||||
msgid "Starting to upscale extracted images"
|
||||
msgstr "开始对提取的帧进行放大"
|
||||
|
||||
#: upscaler.py:423 upscaler.py:479
|
||||
#: upscaler.py:448 upscaler.py:504
|
||||
msgid "Upscaling completed"
|
||||
msgstr "放大完成"
|
||||
|
||||
#: upscaler.py:432
|
||||
#: upscaler.py:457
|
||||
msgid "Reading video information"
|
||||
msgstr "读取视频信息"
|
||||
|
||||
#: upscaler.py:446
|
||||
#: upscaler.py:471
|
||||
msgid "Aborting: No video stream found"
|
||||
msgstr "程序中止:文件中未找到视频流"
|
||||
|
||||
#: upscaler.py:464
|
||||
#: upscaler.py:490
|
||||
msgid "Unsupported pixel format: {}"
|
||||
msgstr "不支持的像素格式:{}"
|
||||
|
||||
#: upscaler.py:467
|
||||
#: upscaler.py:493
|
||||
msgid "Framerate: {}"
|
||||
msgstr "帧率:{}"
|
||||
|
||||
#: upscaler.py:482
|
||||
#: upscaler.py:507
|
||||
msgid "Converting extracted frames into video"
|
||||
msgstr "将提取的帧转换为视频"
|
||||
msgstr "正在将提取的帧转换为视频"
|
||||
|
||||
#: upscaler.py:487
|
||||
#: upscaler.py:514
|
||||
msgid "Conversion completed"
|
||||
msgstr "转换已完成"
|
||||
|
||||
#: upscaler.py:490
|
||||
msgid "Migrating audio tracks and subtitles to upscaled video"
|
||||
msgstr "将音轨和字幕迁移到放大后的视频"
|
||||
#: upscaler.py:518
|
||||
msgid "Migrating audio, subtitles and other streams to upscaled video"
|
||||
msgstr "正在将音频、字幕和其他流迁移到放大后的视频"
|
||||
|
||||
#: video2x.py:87
|
||||
#: upscaler.py:527
|
||||
msgid "Failed to migrate streams"
|
||||
msgstr "迁移流失败"
|
||||
|
||||
#: upscaler.py:528
|
||||
msgid "Trying to output video without additional streams"
|
||||
msgstr "正在尝试输出不含其他流的视频"
|
||||
|
||||
#: upscaler.py:535
|
||||
msgid "Output video file exists, aborting"
|
||||
msgstr "输出目标文件已存在,取消输出"
|
||||
|
||||
#: upscaler.py:539
|
||||
msgid "Writing intermediate file to: {}"
|
||||
msgstr "正在将中间视频文件写入至:{}"
|
||||
|
||||
#: video2x.py:84
|
||||
msgid ""
|
||||
"Video2X Version: {}\n"
|
||||
"Author: K4YT3X\n"
|
||||
@@ -183,66 +211,68 @@ msgstr ""
|
||||
"GitHub 主页:https://github.com/k4yt3x/video2x\n"
|
||||
"联系方式:k4yt3x@k4yt3x.com"
|
||||
|
||||
#: video2x.py:109
|
||||
msgid "General Options"
|
||||
msgstr "通用选项"
|
||||
#: video2x.py:106
|
||||
msgid "Video2X Options"
|
||||
msgstr "Video2X 选项"
|
||||
|
||||
#: video2x.py:110
|
||||
#: video2x.py:107
|
||||
msgid "show this help message and exit"
|
||||
msgstr "显示此帮助消息并退出"
|
||||
|
||||
#: video2x.py:111
|
||||
#: video2x.py:108
|
||||
msgid "source video file/directory"
|
||||
msgstr "源视频文件/目录"
|
||||
|
||||
#: video2x.py:112
|
||||
#: video2x.py:109
|
||||
msgid "output video file/directory"
|
||||
msgstr "输出视频文件/目录"
|
||||
|
||||
#: video2x.py:113
|
||||
#: video2x.py:110
|
||||
msgid "video2x config file path"
|
||||
msgstr "video2x 配置文件路径"
|
||||
|
||||
#: video2x.py:115
|
||||
msgid "upscaling driver"
|
||||
msgstr "视频放大驱动"
|
||||
|
||||
#: video2x.py:116
|
||||
msgid "number of processes to use for upscaling"
|
||||
msgstr "并发进程数"
|
||||
|
||||
#: video2x.py:117
|
||||
#: video2x.py:112
|
||||
msgid "display version, lawful information and exit"
|
||||
msgstr "显示版本和法律信息并退出"
|
||||
|
||||
#: video2x.py:120
|
||||
msgid "Scaling Options"
|
||||
msgstr "缩放选项"
|
||||
#: video2x.py:115
|
||||
msgid "Upscaling Options"
|
||||
msgstr "视频放大选项"
|
||||
|
||||
#: video2x.py:121
|
||||
msgid "output video width"
|
||||
msgstr "输出视频宽度"
|
||||
#: video2x.py:116
|
||||
msgid "upscaling driver"
|
||||
msgstr "视频放大驱动"
|
||||
|
||||
#: video2x.py:122
|
||||
msgid "output video height"
|
||||
msgstr "输出视频高度"
|
||||
|
||||
#: video2x.py:123
|
||||
#: video2x.py:117
|
||||
msgid "scaling ratio"
|
||||
msgstr "缩放比"
|
||||
|
||||
#: video2x.py:163
|
||||
#: video2x.py:118
|
||||
msgid "number of processes to use for upscaling"
|
||||
msgstr "并发进程数"
|
||||
|
||||
#: video2x.py:119
|
||||
msgid "preserve extracted and upscaled frames"
|
||||
msgstr "保留提取的和放大的帧"
|
||||
|
||||
#: video2x.py:159
|
||||
msgid "This file cannot be imported"
|
||||
msgstr "此文件无法被当作模块导入"
|
||||
|
||||
#: video2x.py:224
|
||||
#: video2x.py:229
|
||||
msgid "Program completed, taking {} seconds"
|
||||
msgstr "程序执行完毕,总计花费 {} 秒"
|
||||
|
||||
#: video2x.py:227
|
||||
#: video2x.py:232
|
||||
msgid "An exception has occurred"
|
||||
msgstr "发生了异常"
|
||||
|
||||
#~ msgid "output video width"
|
||||
#~ msgstr "输出视频宽度"
|
||||
|
||||
#~ msgid "output video height"
|
||||
#~ msgstr "输出视频高度"
|
||||
|
||||
#~ msgid "You must specify input video file/directory path"
|
||||
#~ msgstr "您必须指定输入视频文件/目录路径"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Name: Video2X Upscale Progress Monitor
|
||||
Author: BrianPetkovsek
|
||||
Date Created: May 7, 2020
|
||||
Last Modified: May 7, 2020
|
||||
Last Modified: May 10, 2020
|
||||
"""
|
||||
|
||||
# built-in imports
|
||||
@@ -33,7 +33,7 @@ class ProgressMonitor(threading.Thread):
|
||||
|
||||
def run(self):
|
||||
self.running = True
|
||||
|
||||
|
||||
# get number of extracted frames
|
||||
self.upscaler.total_frames = 0
|
||||
for directory in self.extracted_frames_directories:
|
||||
@@ -47,7 +47,10 @@ class ProgressMonitor(threading.Thread):
|
||||
while self.running:
|
||||
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
self.upscaler.total_frames_upscaled = len([f for f in self.upscaler.upscaled_frames.iterdir() if str(f).lower().endswith(self.upscaler.image_format.lower())])
|
||||
upscaled_frames = [f for f in self.upscaler.upscaled_frames.iterdir() if str(f).lower().endswith(self.upscaler.image_format.lower())]
|
||||
if len(upscaled_frames) >= 1:
|
||||
self.upscaler.last_frame_upscaled = sorted(upscaled_frames)[-1]
|
||||
self.upscaler.total_frames_upscaled = len(upscaled_frames)
|
||||
|
||||
# update progress bar
|
||||
delta = self.upscaler.total_frames_upscaled - previous_cycle_frames
|
||||
|
||||
245
src/upscaler.py
245
src/upscaler.py
@@ -4,7 +4,7 @@
|
||||
Name: Video2X Upscaler
|
||||
Author: K4YT3X
|
||||
Date Created: December 10, 2018
|
||||
Last Modified: May 7, 2020
|
||||
Last Modified: May 10, 2020
|
||||
|
||||
Description: This file contains the Upscaler class. Each
|
||||
instance of the Upscaler class is an upscaler on an image or
|
||||
@@ -30,9 +30,7 @@ import queue
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
|
||||
@@ -71,15 +69,13 @@ class Upscaler:
|
||||
|
||||
def __init__(self, input_path, output_path, driver_settings, ffmpeg_settings):
|
||||
# mandatory arguments
|
||||
self.input_path = input_path
|
||||
self.output_path = output_path
|
||||
self.input = input_path
|
||||
self.output = output_path
|
||||
self.driver_settings = driver_settings
|
||||
self.ffmpeg_settings = ffmpeg_settings
|
||||
|
||||
# optional arguments
|
||||
self.driver = 'waifu2x_caffe'
|
||||
self.scale_width = None
|
||||
self.scale_height = None
|
||||
self.scale_ratio = None
|
||||
self.processes = 1
|
||||
self.video2x_cache_directory = pathlib.Path(tempfile.gettempdir()) / 'video2x'
|
||||
@@ -87,9 +83,13 @@ class Upscaler:
|
||||
self.preserve_frames = False
|
||||
|
||||
# other internal members and signals
|
||||
self.stop_signal = False
|
||||
self.running = False
|
||||
self.total_frames_upscaled = 0
|
||||
self.total_frames = 0
|
||||
self.total_videos = 0
|
||||
self.total_processed = 0
|
||||
self.current_input_video = pathlib.Path()
|
||||
self.last_frame_upscaled = pathlib.Path()
|
||||
|
||||
def create_temp_directories(self):
|
||||
"""create temporary directories
|
||||
@@ -103,7 +103,7 @@ class Upscaler:
|
||||
if self.video2x_cache_directory.exists() and not self.video2x_cache_directory.is_dir():
|
||||
Avalon.error(_('Specified or default cache directory is a file/link'))
|
||||
raise FileExistsError('Specified or default cache directory is a file/link')
|
||||
|
||||
|
||||
# if cache directory doesn't exist, try creating it
|
||||
if not self.video2x_cache_directory.exists():
|
||||
try:
|
||||
@@ -134,30 +134,48 @@ class Upscaler:
|
||||
traceback.print_exc()
|
||||
|
||||
def _check_arguments(self):
|
||||
if isinstance(self.input, list):
|
||||
if self.output.exists() and not self.output.is_dir():
|
||||
Avalon.error(_('Input and output path type mismatch'))
|
||||
Avalon.error(_('Input is multiple files but output is not directory'))
|
||||
raise ArgumentError('input output path type mismatch')
|
||||
for input_path in self.input:
|
||||
if not input_path.is_file() and not input_path.is_dir():
|
||||
Avalon.error(_('Input path {} is neither a file nor a directory').format(input_path))
|
||||
raise FileNotFoundError(f'{input_path} is neither file nor directory')
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
if input_path.samefile(self.output):
|
||||
Avalon.error(_('Input directory and output directory cannot be the same'))
|
||||
raise FileExistsError('input directory and output directory are the same')
|
||||
|
||||
# if input is a file
|
||||
if self.input_path.is_file():
|
||||
if self.output_path.is_dir():
|
||||
elif self.input.is_file():
|
||||
if self.output.is_dir():
|
||||
Avalon.error(_('Input and output path type mismatch'))
|
||||
Avalon.error(_('Input is single file but output is directory'))
|
||||
raise ArgumentError('input output path type mismatch')
|
||||
if not re.search(r'.*\..*$', str(self.output_path)):
|
||||
if not re.search(r'.*\..*$', str(self.output)):
|
||||
Avalon.error(_('No suffix found in output file path'))
|
||||
Avalon.error(_('Suffix must be specified for FFmpeg'))
|
||||
raise ArgumentError('no output video suffix specified')
|
||||
|
||||
# if input is a directory
|
||||
elif self.input_path.is_dir():
|
||||
if self.output_path.is_file():
|
||||
elif self.input.is_dir():
|
||||
if self.output.is_file():
|
||||
Avalon.error(_('Input and output path type mismatch'))
|
||||
Avalon.error(_('Input is directory but output is existing single file'))
|
||||
raise ArgumentError('input output path type mismatch')
|
||||
with contextlib.suppress(FileNotFoundError):
|
||||
if self.input.samefile(self.output):
|
||||
Avalon.error(_('Input directory and output directory cannot be the same'))
|
||||
raise FileExistsError('input directory and output directory are the same')
|
||||
|
||||
# if input is neither
|
||||
else:
|
||||
Avalon.error(_('Input path is neither a file nor a directory'))
|
||||
raise FileNotFoundError(f'{self.input_path} is neither file nor directory')
|
||||
|
||||
# check Fmpeg settings
|
||||
raise FileNotFoundError(f'{self.input} is neither file nor directory')
|
||||
|
||||
# check FFmpeg settings
|
||||
ffmpeg_path = pathlib.Path(self.ffmpeg_settings['ffmpeg_path'])
|
||||
if not ((pathlib.Path(ffmpeg_path / 'ffmpeg.exe').is_file() and
|
||||
pathlib.Path(ffmpeg_path / 'ffprobe.exe').is_file()) or
|
||||
@@ -203,6 +221,23 @@ class Upscaler:
|
||||
Avalon.error(_('Failed to parse driver argument: {}').format(e.args[0]))
|
||||
raise e
|
||||
|
||||
# waifu2x-caffe scale_ratio, scale_width and scale_height check
|
||||
if self.driver == 'waifu2x_caffe':
|
||||
if (driver_settings['scale_width'] != 0 and driver_settings['scale_height'] == 0 or
|
||||
driver_settings['scale_width'] == 0 and driver_settings['scale_height'] != 0):
|
||||
Avalon.error('Only one of scale_width and scale_height is specified for waifu2x-caffe')
|
||||
raise AttributeError('only one of scale_width and scale_height is specified for waifu2x-caffe')
|
||||
|
||||
# if scale_width and scale_height are specified, ensure scale_ratio is None
|
||||
elif self.driver_settings['scale_width'] != 0 and self.driver_settings['scale_height'] != 0:
|
||||
self.driver_settings['scale_ratio'] = None
|
||||
|
||||
# if scale_width and scale_height not specified
|
||||
# ensure they are None, not 0
|
||||
else:
|
||||
self.driver_settings['scale_width'] = None
|
||||
self.driver_settings['scale_height'] = None
|
||||
|
||||
def _upscale_frames(self):
|
||||
""" Upscale video frames with waifu2x-caffe
|
||||
|
||||
@@ -238,7 +273,7 @@ class Upscaler:
|
||||
process_directory.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# waifu2x-converter-cpp will perform multi-threading within its own process
|
||||
if self.driver == 'waifu2x_converter_cpp':
|
||||
if self.driver in ['waifu2x_converter_cpp', 'waifu2x_ncnn_vulkan', 'srmd_ncnn_vulkan']:
|
||||
process_directories = [self.extracted_frames]
|
||||
|
||||
else:
|
||||
@@ -250,41 +285,9 @@ class Upscaler:
|
||||
# rotate list
|
||||
process_directories = process_directories[-1:] + process_directories[:-1]
|
||||
|
||||
# create threads and start them
|
||||
# create driver processes and start them
|
||||
for process_directory in process_directories:
|
||||
|
||||
DriverWrapperMain = getattr(importlib.import_module(f'wrappers.{self.driver}'), 'WrapperMain')
|
||||
driver = DriverWrapperMain(copy.deepcopy(self.driver_settings))
|
||||
|
||||
# if the driver being used is waifu2x-caffe
|
||||
if self.driver == 'waifu2x_caffe':
|
||||
self.process_pool.append(driver.upscale(process_directory,
|
||||
self.upscaled_frames,
|
||||
self.scale_ratio,
|
||||
self.scale_width,
|
||||
self.scale_height,
|
||||
self.image_format,
|
||||
self.bit_depth))
|
||||
|
||||
# if the driver being used is waifu2x-converter-cpp
|
||||
elif self.driver == 'waifu2x_converter_cpp':
|
||||
self.process_pool.append(driver.upscale(process_directory,
|
||||
self.upscaled_frames,
|
||||
self.scale_ratio,
|
||||
self.processes,
|
||||
self.image_format))
|
||||
|
||||
# if the driver being used is waifu2x-ncnn-vulkan
|
||||
elif self.driver == 'waifu2x_ncnn_vulkan':
|
||||
self.process_pool.append(driver.upscale(process_directory,
|
||||
self.upscaled_frames,
|
||||
self.scale_ratio))
|
||||
|
||||
# if the driver being used is srmd_ncnn_vulkan
|
||||
elif self.driver == 'srmd_ncnn_vulkan':
|
||||
self.process_pool.append(driver.upscale(process_directory,
|
||||
self.upscaled_frames,
|
||||
self.scale_ratio))
|
||||
self.process_pool.append(self.driver_object.upscale(process_directory, self.upscaled_frames))
|
||||
|
||||
# start progress bar in a different thread
|
||||
Avalon.debug_info(_('Starting progress monitor'))
|
||||
@@ -305,7 +308,7 @@ class Upscaler:
|
||||
self.progress_monitor.stop()
|
||||
|
||||
Avalon.debug_info(_('Killing upscaled image cleaner'))
|
||||
self.image_cleaner.stop()
|
||||
self.image_cleaner.stop()
|
||||
raise e
|
||||
|
||||
# if the driver is waifu2x-converter-cpp
|
||||
@@ -337,9 +340,9 @@ class Upscaler:
|
||||
try:
|
||||
# while process pool not empty
|
||||
while self.process_pool:
|
||||
|
||||
|
||||
# if stop signal received, terminate all processes
|
||||
if self.stop_signal is True:
|
||||
if self.running is False:
|
||||
raise SystemExit
|
||||
|
||||
for process in self.process_pool:
|
||||
@@ -376,36 +379,62 @@ class Upscaler:
|
||||
This function controls the flow of video conversion
|
||||
and handles all necessary functions.
|
||||
"""
|
||||
|
||||
|
||||
# external stop signal when called in a thread
|
||||
self.stop_signal = False
|
||||
self.running = True
|
||||
|
||||
# define process pool to contain processes
|
||||
self.process_pool = []
|
||||
|
||||
# load driver modules
|
||||
DriverWrapperMain = getattr(importlib.import_module(f'wrappers.{self.driver}'), 'WrapperMain')
|
||||
self.driver_object = DriverWrapperMain(self.driver_settings)
|
||||
|
||||
# load options from upscaler class into driver settings
|
||||
self.driver_object.load_configurations(self)
|
||||
|
||||
# parse arguments for waifu2x
|
||||
# check argument sanity
|
||||
self._check_arguments()
|
||||
|
||||
# define processing queue
|
||||
processing_queue = queue.Queue()
|
||||
self.processing_queue = queue.Queue()
|
||||
|
||||
# if input is a list of files
|
||||
if isinstance(self.input, list):
|
||||
# make output directory if it doesn't exist
|
||||
self.output.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for input_path in self.input:
|
||||
|
||||
if input_path.is_file():
|
||||
output_video = self.output / input_path.name
|
||||
self.processing_queue.put((input_path.absolute(), output_video.absolute()))
|
||||
|
||||
elif input_path.is_dir():
|
||||
for input_video in [f for f in input_path.iterdir() if f.is_file()]:
|
||||
output_video = self.output / input_video.name
|
||||
self.processing_queue.put((input_video.absolute(), output_video.absolute()))
|
||||
|
||||
# if input specified is single file
|
||||
if self.input_path.is_file():
|
||||
Avalon.info(_('Upscaling single video file: {}').format(self.input_path))
|
||||
processing_queue.put((self.input_path.absolute(), self.output_path.absolute()))
|
||||
elif self.input.is_file():
|
||||
Avalon.info(_('Upscaling single video file: {}').format(self.input))
|
||||
self.processing_queue.put((self.input.absolute(), self.output.absolute()))
|
||||
|
||||
# if input specified is a directory
|
||||
elif self.input_path.is_dir():
|
||||
elif self.input.is_dir():
|
||||
|
||||
# make output directory if it doesn't exist
|
||||
self.output_path.mkdir(parents=True, exist_ok=True)
|
||||
for input_video in [f for f in self.input_path.iterdir() if f.is_file()]:
|
||||
output_video = self.output_path / input_video.name
|
||||
processing_queue.put((input_video.absolute(), output_video.absolute()))
|
||||
self.output.mkdir(parents=True, exist_ok=True)
|
||||
for input_video in [f for f in self.input.iterdir() if f.is_file()]:
|
||||
output_video = self.output / input_video.name
|
||||
self.processing_queue.put((input_video.absolute(), output_video.absolute()))
|
||||
|
||||
while not processing_queue.empty():
|
||||
input_video, output_video = processing_queue.get()
|
||||
# record video count for external calls
|
||||
self.total_videos = self.processing_queue.qsize()
|
||||
|
||||
while not self.processing_queue.empty():
|
||||
self.current_input_video, output_video = self.processing_queue.get()
|
||||
# drivers that have native support for video processing
|
||||
if self.driver == 'anime4kcpp':
|
||||
# append FFmpeg path to the end of PATH
|
||||
@@ -413,12 +442,8 @@ class Upscaler:
|
||||
os.environ['PATH'] += f';{self.ffmpeg_settings["ffmpeg_path"]}'
|
||||
Avalon.info(_('Starting to upscale extracted images'))
|
||||
|
||||
# import and initialize Anime4KCPP wrapper
|
||||
DriverWrapperMain = getattr(importlib.import_module('wrappers.anime4kcpp'), 'WrapperMain')
|
||||
driver = DriverWrapperMain(copy.deepcopy(self.driver_settings))
|
||||
|
||||
# run Anime4KCPP
|
||||
self.process_pool.append(driver.upscale(input_video, output_video, self.scale_ratio, self.processes))
|
||||
self.process_pool.append(self.driver_object.upscale(self.current_input_video, output_video))
|
||||
self._wait()
|
||||
Avalon.info(_('Upscaling completed'))
|
||||
|
||||
@@ -430,8 +455,8 @@ class Upscaler:
|
||||
fm = Ffmpeg(self.ffmpeg_settings, self.image_format)
|
||||
|
||||
Avalon.info(_('Reading video information'))
|
||||
video_info = fm.get_video_info(input_video)
|
||||
# analyze original video with ffprobe and retrieve framerate
|
||||
video_info = fm.get_video_info(self.current_input_video)
|
||||
# analyze original video with FFprobe and retrieve framerate
|
||||
# width, height = info['streams'][0]['width'], info['streams'][0]['height']
|
||||
|
||||
# find index of video stream
|
||||
@@ -447,31 +472,31 @@ class Upscaler:
|
||||
raise StreamNotFoundError('no video stream found')
|
||||
|
||||
# extract frames from video
|
||||
self.process_pool.append((fm.extract_frames(input_video, self.extracted_frames)))
|
||||
self.process_pool.append((fm.extract_frames(self.current_input_video, self.extracted_frames)))
|
||||
self._wait()
|
||||
|
||||
# get average frame rate of video stream
|
||||
framerate = float(Fraction(video_info['streams'][video_stream_index]['avg_frame_rate']))
|
||||
framerate = float(Fraction(video_info['streams'][video_stream_index]['r_frame_rate']))
|
||||
fm.pixel_format = video_info['streams'][video_stream_index]['pix_fmt']
|
||||
|
||||
# get a dict of all pixel formats and corresponding bit depth
|
||||
pixel_formats = fm.get_pixel_formats()
|
||||
if self.driver == 'waifu2x_caffe':
|
||||
# get a dict of all pixel formats and corresponding bit depth
|
||||
pixel_formats = fm.get_pixel_formats()
|
||||
|
||||
# try getting pixel format's corresponding bti depth
|
||||
try:
|
||||
self.bit_depth = pixel_formats[fm.pixel_format]
|
||||
except KeyError:
|
||||
Avalon.error(_('Unsupported pixel format: {}').format(fm.pixel_format))
|
||||
raise UnsupportedPixelError(f'unsupported pixel format {fm.pixel_format}')
|
||||
# try getting pixel format's corresponding bti depth
|
||||
try:
|
||||
self.driver_settings['output_depth'] = pixel_formats[fm.pixel_format]
|
||||
except KeyError:
|
||||
Avalon.error(_('Unsupported pixel format: {}').format(fm.pixel_format))
|
||||
raise UnsupportedPixelError(f'unsupported pixel format {fm.pixel_format}')
|
||||
|
||||
Avalon.info(_('Framerate: {}').format(framerate))
|
||||
|
||||
# width/height will be coded width/height x upscale factor
|
||||
if self.scale_ratio:
|
||||
original_width = video_info['streams'][video_stream_index]['width']
|
||||
original_height = video_info['streams'][video_stream_index]['height']
|
||||
self.scale_width = int(self.scale_ratio * original_width)
|
||||
self.scale_height = int(self.scale_ratio * original_height)
|
||||
original_width = video_info['streams'][video_stream_index]['width']
|
||||
original_height = video_info['streams'][video_stream_index]['height']
|
||||
scale_width = int(self.scale_ratio * original_width)
|
||||
scale_height = int(self.scale_ratio * original_height)
|
||||
|
||||
# upscale images one by one using waifu2x
|
||||
Avalon.info(_('Starting to upscale extracted images'))
|
||||
@@ -482,14 +507,37 @@ class Upscaler:
|
||||
Avalon.info(_('Converting extracted frames into video'))
|
||||
|
||||
# use user defined output size
|
||||
self.process_pool.append(fm.convert_video(framerate, f'{self.scale_width}x{self.scale_height}', self.upscaled_frames))
|
||||
self.process_pool.append(fm.assemble_video(framerate,
|
||||
f'{scale_width}x{scale_height}',
|
||||
self.upscaled_frames))
|
||||
self._wait()
|
||||
Avalon.info(_('Conversion completed'))
|
||||
|
||||
# migrate audio tracks and subtitles
|
||||
Avalon.info(_('Migrating audio tracks and subtitles to upscaled video'))
|
||||
self.process_pool.append(fm.migrate_audio_tracks_subtitles(input_video, output_video, self.upscaled_frames))
|
||||
self._wait()
|
||||
try:
|
||||
# migrate audio tracks and subtitles
|
||||
Avalon.info(_('Migrating audio, subtitles and other streams to upscaled video'))
|
||||
self.process_pool.append(fm.migrate_streams(self.current_input_video,
|
||||
output_video,
|
||||
self.upscaled_frames))
|
||||
self._wait()
|
||||
|
||||
# if failed to copy streams
|
||||
# use file with only video stream
|
||||
except subprocess.CalledProcessError:
|
||||
Avalon.error(_('Failed to migrate streams'))
|
||||
Avalon.warning(_('Trying to output video without additional streams'))
|
||||
|
||||
# construct output file path
|
||||
output_video_path = output_video.parent / f'{output_video.stem}{fm.intermediate_file_name.suffix}'
|
||||
|
||||
# if output file already exists, cancel
|
||||
if output_video_path.exists():
|
||||
Avalon.error(_('Output video file exists, aborting'))
|
||||
|
||||
# otherwise, rename intermediate file to the output file
|
||||
else:
|
||||
Avalon.info(_('Writing intermediate file to: {}').format(output_video_path.absolute()))
|
||||
(self.upscaled_frames / fm.intermediate_file_name).rename(output_video_path)
|
||||
|
||||
# destroy temp directories
|
||||
self.cleanup_temp_directories()
|
||||
@@ -497,4 +545,11 @@ class Upscaler:
|
||||
except (Exception, KeyboardInterrupt, SystemExit) as e:
|
||||
with contextlib.suppress(ValueError):
|
||||
self.cleanup_temp_directories()
|
||||
self.running = False
|
||||
raise e
|
||||
|
||||
# increment total number of videos processed
|
||||
self.total_processed += 1
|
||||
|
||||
# signal upscaling completion
|
||||
self.running = False
|
||||
|
||||
262
src/video2x.pot
Normal file
262
src/video2x.pot
Normal file
@@ -0,0 +1,262 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2020-05-11 04:39-0400\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=cp1252\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
#: progress_monitor.py:42
|
||||
msgid "Upscaling Progress"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:104
|
||||
msgid "Specified or default cache directory is a file/link"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:110
|
||||
msgid "Creating cache directory {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:113
|
||||
msgid "Unable to create {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:118
|
||||
msgid "Extracted frames are being saved to: {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:120
|
||||
msgid "Upscaled frames are being saved to: {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:130
|
||||
msgid "Cleaning up cache directory: {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:133
|
||||
msgid "Unable to delete: {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:139 upscaler.py:154 upscaler.py:165
|
||||
msgid "Input and output path type mismatch"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:140
|
||||
msgid "Input is multiple files but output is not directory"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:144
|
||||
msgid "Input path {} is neither a file nor a directory"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:148 upscaler.py:170
|
||||
msgid "Input directory and output directory cannot be the same"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:155
|
||||
msgid "Input is single file but output is directory"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:158
|
||||
msgid "No suffix found in output file path"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:159
|
||||
msgid "Suffix must be specified for FFmpeg"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:166
|
||||
msgid "Input is directory but output is existing single file"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:175
|
||||
msgid "Input path is neither a file nor a directory"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:184
|
||||
msgid "FFmpeg or FFprobe cannot be found under the specified path"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:185 upscaler.py:195
|
||||
msgid "Please check the configuration file settings"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:194
|
||||
msgid "Specified driver executable directory doesn't exist"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:221
|
||||
msgid "Failed to parse driver argument: {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:253
|
||||
msgid "Unrecognized driver: {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:293
|
||||
msgid "Starting progress monitor"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:298
|
||||
msgid "Starting upscaled image cleaner"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:307 upscaler.py:324
|
||||
msgid "Killing progress monitor"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:310 upscaler.py:327
|
||||
msgid "Killing upscaled image cleaner"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:331
|
||||
msgid "Terminating all processes"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:338
|
||||
msgid "Main process waiting for subprocesses to exit"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:357 upscaler.py:361
|
||||
msgid "Subprocess {} exited with code {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:367
|
||||
msgid "Stop signal received"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:372
|
||||
msgid "Subprocess execution ran into an error"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:421
|
||||
msgid "Upscaling single video file: {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:443 upscaler.py:502
|
||||
msgid "Starting to upscale extracted images"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:448 upscaler.py:504
|
||||
msgid "Upscaling completed"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:457
|
||||
msgid "Reading video information"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:471
|
||||
msgid "Aborting: No video stream found"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:490
|
||||
msgid "Unsupported pixel format: {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:493
|
||||
msgid "Framerate: {}"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:507
|
||||
msgid "Converting extracted frames into video"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:514
|
||||
msgid "Conversion completed"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:518
|
||||
msgid "Migrating audio, subtitles and other streams to upscaled video"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:527
|
||||
msgid "Failed to migrate streams"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:528
|
||||
msgid "Trying to output video without additional streams"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:535
|
||||
msgid "Output video file exists, aborting"
|
||||
msgstr ""
|
||||
|
||||
#: upscaler.py:539
|
||||
msgid "Writing intermediate file to: {}"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:84
|
||||
msgid ""
|
||||
"Video2X Version: {}\n"
|
||||
"Author: K4YT3X\n"
|
||||
"License: GNU GPL v3\n"
|
||||
"Github Page: https://github.com/k4yt3x/video2x\n"
|
||||
"Contact: k4yt3x@k4yt3x.com"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:106
|
||||
msgid "Video2X Options"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:107
|
||||
msgid "show this help message and exit"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:108
|
||||
msgid "source video file/directory"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:109
|
||||
msgid "output video file/directory"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:110
|
||||
msgid "video2x config file path"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:112
|
||||
msgid "display version, lawful information and exit"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:115
|
||||
msgid "Upscaling Options"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:116
|
||||
msgid "upscaling driver"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:117
|
||||
msgid "scaling ratio"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:118
|
||||
msgid "number of processes to use for upscaling"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:119
|
||||
msgid "preserve extracted and upscaled frames"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:159
|
||||
msgid "This file cannot be imported"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:229
|
||||
msgid "Program completed, taking {} seconds"
|
||||
msgstr ""
|
||||
|
||||
#: video2x.py:232
|
||||
msgid "An exception has occurred"
|
||||
msgstr ""
|
||||
|
||||
@@ -13,7 +13,7 @@ __ __ _ _ ___ __ __
|
||||
Name: Video2X Controller
|
||||
Creator: K4YT3X
|
||||
Date Created: Feb 24, 2018
|
||||
Last Modified: May 7, 2020
|
||||
Last Modified: May 10, 2020
|
||||
|
||||
Editor: BrianPetkovsek
|
||||
Last Modified: June 17, 2019
|
||||
@@ -54,14 +54,11 @@ from upscaler import Upscaler
|
||||
|
||||
# built-in imports
|
||||
import argparse
|
||||
import contextlib
|
||||
import gettext
|
||||
import importlib
|
||||
import locale
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
@@ -106,21 +103,20 @@ def parse_arguments():
|
||||
parser = argparse.ArgumentParser(prog='video2x', formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=False)
|
||||
|
||||
# video options
|
||||
general_options = parser.add_argument_group(_('General Options'))
|
||||
general_options.add_argument('-h', '--help', action='help', help=_('show this help message and exit'))
|
||||
general_options.add_argument('-i', '--input', type=pathlib.Path, help=_('source video file/directory'))
|
||||
general_options.add_argument('-o', '--output', type=pathlib.Path, help=_('output video file/directory'))
|
||||
general_options.add_argument('-c', '--config', type=pathlib.Path, help=_('video2x config file path'), action='store',
|
||||
video2x_options = parser.add_argument_group(_('Video2X Options'))
|
||||
video2x_options.add_argument('-h', '--help', action='help', help=_('show this help message and exit'))
|
||||
video2x_options.add_argument('-i', '--input', type=pathlib.Path, help=_('source video file/directory'))
|
||||
video2x_options.add_argument('-o', '--output', type=pathlib.Path, help=_('output video file/directory'))
|
||||
video2x_options.add_argument('-c', '--config', type=pathlib.Path, help=_('video2x config file path'), action='store',
|
||||
default=pathlib.Path(__file__).parent.absolute() / 'video2x.yaml')
|
||||
general_options.add_argument('-d', '--driver', help=_('upscaling driver'), choices=AVAILABLE_DRIVERS, default='waifu2x_caffe')
|
||||
general_options.add_argument('-p', '--processes', help=_('number of processes to use for upscaling'), action='store', type=int, default=1)
|
||||
general_options.add_argument('-v', '--version', help=_('display version, lawful information and exit'), action='store_true')
|
||||
video2x_options.add_argument('-v', '--version', help=_('display version, lawful information and exit'), action='store_true')
|
||||
|
||||
# scaling options
|
||||
scaling_options = parser.add_argument_group(_('Scaling Options'))
|
||||
scaling_options.add_argument('--width', help=_('output video width'), action='store', type=int)
|
||||
scaling_options.add_argument('--height', help=_('output video height'), action='store', type=int)
|
||||
scaling_options.add_argument('-r', '--ratio', help=_('scaling ratio'), action='store', type=float)
|
||||
upscaling_options = parser.add_argument_group(_('Upscaling Options'))
|
||||
upscaling_options.add_argument('-d', '--driver', help=_('upscaling driver'), choices=AVAILABLE_DRIVERS, default='waifu2x_caffe')
|
||||
upscaling_options.add_argument('-r', '--ratio', help=_('scaling ratio'), action='store', type=float, default=2.0)
|
||||
upscaling_options.add_argument('-p', '--processes', help=_('number of processes to use for upscaling'), action='store', type=int, default=1)
|
||||
upscaling_options.add_argument('--preserve_frames', help=_('preserve extracted and upscaled frames'), action='store_true')
|
||||
|
||||
# if no driver arguments are specified
|
||||
if '--' not in sys.argv:
|
||||
@@ -188,7 +184,18 @@ ffmpeg_settings['ffmpeg_path'] = os.path.expandvars(ffmpeg_settings['ffmpeg_path
|
||||
# load video2x settings
|
||||
image_format = config['video2x']['image_format'].lower()
|
||||
preserve_frames = config['video2x']['preserve_frames']
|
||||
video2x_cache_directory = config['video2x']['video2x_cache_directory']
|
||||
|
||||
# if preserve frames specified in command line
|
||||
# overwrite config file options
|
||||
if video2x_args.preserve_frames is True:
|
||||
preserve_frames = True
|
||||
|
||||
# if cache directory not specified
|
||||
# use default path: %TEMP%\video2x
|
||||
if config['video2x']['video2x_cache_directory'] is None:
|
||||
video2x_cache_directory = (pathlib.Path(tempfile.gettempdir()) / 'video2x')
|
||||
else:
|
||||
video2x_cache_directory = pathlib.Path(config['video2x']['video2x_cache_directory'])
|
||||
|
||||
# overwrite driver_settings with driver_args
|
||||
if driver_args is not None:
|
||||
@@ -210,8 +217,6 @@ try:
|
||||
|
||||
# set upscaler optional options
|
||||
upscaler.driver = video2x_args.driver
|
||||
upscaler.scale_width = video2x_args.width
|
||||
upscaler.scale_height = video2x_args.height
|
||||
upscaler.scale_ratio = video2x_args.ratio
|
||||
upscaler.processes = video2x_args.processes
|
||||
upscaler.video2x_cache_directory = video2x_cache_directory
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# Name: Video2X Configuration File
|
||||
# Creator: K4YT3X
|
||||
# Date Created: October 23, 2018
|
||||
# Last Modified: May 7, 2020
|
||||
# Items commented out are parameters handled by Video2x.
|
||||
# Last Modified: May 9, 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
|
||||
# or parameters handled by Video2X internally.
|
||||
waifu2x_caffe:
|
||||
path: '%LOCALAPPDATA%\video2x\waifu2x-caffe\waifu2x-caffe-cui'
|
||||
tta: 0 # <0|1> 8x slower and slightly high quality
|
||||
@@ -11,17 +14,17 @@ waifu2x_caffe:
|
||||
crop_h: null # input image split size(height)
|
||||
crop_w: null # input image split size(width)
|
||||
crop_size: 128 # input image split size
|
||||
output_depth: 8 # output image chaneel depth bit
|
||||
output_depth: 8 # output image chanel depth bit
|
||||
output_quality: -1 # output image quality
|
||||
process: gpu # <cpu|gpu|cudnn> process mode
|
||||
model_dir: null # path to custom model directory (don't append last / )
|
||||
#scale_height: null # custom scale height
|
||||
#scale_width: null # custom scale width
|
||||
scale_height: 0 # custom scale height (specifying this will overwrite scale_ratio)
|
||||
scale_width: 0 # custom scale width (specifying this will overwrite scale_ratio)
|
||||
#scale_ratio: null # custom scale ratio
|
||||
noise_level: 3 # <0|1|2|3> noise reduction level
|
||||
mode: noise_scale # <noise|scale|noise_scale|auto_scale> image processing mode
|
||||
output_extention: null # extention to output image file when output_path is (auto) or input_path is folder
|
||||
input_extention_list: null # extention to input image file when input_path is folder
|
||||
output_extention: null # extension to output image file when output_path is (auto) or input_path is folder
|
||||
input_extention_list: null # extension to input image file when input_path is folder
|
||||
#output_path: null # path to output image file (when input_path is folder, output_path must be folder)
|
||||
#input_path: null # (required) path to input image file
|
||||
waifu2x_converter_cpp:
|
||||
@@ -31,13 +34,13 @@ waifu2x_converter_cpp:
|
||||
#list-processor # dump processor list
|
||||
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 (0-101, 0 being smallest size and lowest quality), use 101 for lossless WebP
|
||||
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
|
||||
disable-gpu: false # disable GPU
|
||||
force-OpenCL: false # force to use OpenCL on Intel Platform
|
||||
processor: -1 # set target processor
|
||||
processor: -1 # set target processor (-1 uses default device)
|
||||
jobs: 0 # number of threads launching at the same time
|
||||
model-dir: null # path to custom model directory (don't append last / ) default: models_rgb
|
||||
model-dir: null # path to custom model directory (don't append last / ) default: models_rgb
|
||||
#scale-ratio: 2.0 # custom scale ratio
|
||||
noise-level: 1 # <0|1|2|3> noise reduction level
|
||||
mode: noise-scale # <noise|scale|noise-scale> image processing mode
|
||||
@@ -97,12 +100,17 @@ anime4kcpp:
|
||||
codec: mp4v # Specify the codec for encoding from mp4v(recommended in Windows), dxva(for Windows), avc1(H264, recommended in Linux), vp09(very slow), hevc(not support in Windowds), av01(not support in Windowds) (string [=mp4v])
|
||||
ffmpeg:
|
||||
ffmpeg_path: '%LOCALAPPDATA%\video2x\ffmpeg-latest-win64-static\bin'
|
||||
intermediate_file_name: 'intermediate.mkv'
|
||||
# step 1: extract all frames from original video
|
||||
# into temporary directory
|
||||
video_to_frames:
|
||||
output_options:
|
||||
'-qscale:v': null
|
||||
'-pix_fmt': rgba64be
|
||||
'-hwaccel': auto
|
||||
'-y': true
|
||||
# step 2: stitch all frames back into a video
|
||||
# with only a video track
|
||||
frames_to_video:
|
||||
input_options:
|
||||
'-qscale:v': null
|
||||
@@ -115,6 +123,8 @@ ffmpeg:
|
||||
'-pix_fmt': null
|
||||
'-hwaccel': auto
|
||||
'-y': true
|
||||
# step 3: migrate audio and subtitle tracks from original
|
||||
# video into the upscaled video
|
||||
migrating_tracks:
|
||||
output_options:
|
||||
'-map':
|
||||
@@ -125,6 +135,7 @@ ffmpeg:
|
||||
- '1:t?'
|
||||
'-c': copy
|
||||
'-pix_fmt': null
|
||||
'-metadata': 'comment=Upscaled by Video2X'
|
||||
'-hwaccel': auto
|
||||
'-y': true
|
||||
video2x:
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Creator: Video2X QT
|
||||
Creator: Video2X GUI
|
||||
Author: K4YT3X
|
||||
Date Created: May 5, 2020
|
||||
Last Modified: May 6, 2020
|
||||
Last Modified: May 10, 2020
|
||||
"""
|
||||
|
||||
# local imports
|
||||
@@ -14,25 +14,26 @@ from upscaler import Upscaler
|
||||
import contextlib
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
import urllib
|
||||
import yaml
|
||||
|
||||
# third-party imports
|
||||
from PyQt5 import QtWidgets, QtGui
|
||||
from PyQt5 import uic
|
||||
from PyQt5.QtCore import QObject, pyqtSlot, pyqtSignal, QRunnable, QThreadPool
|
||||
from PyQt5 import QtGui, uic
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtWidgets import *
|
||||
# QObject, pyqtSlot, pyqtSignal, QRunnable, QThreadPool, QAbstractTableModel, Qt
|
||||
|
||||
VERSION = '2.0.0'
|
||||
|
||||
LEGAL_INFO = f'''Video2X GUI Version: {VERSION}
|
||||
Author: K4YT3X
|
||||
License: GNU GPL v3
|
||||
Github Page: https://github.com/k4yt3x/video2x
|
||||
Contact: k4yt3x@k4yt3x.com'''
|
||||
LEGAL_INFO = f'''Video2X GUI Version: {VERSION}\\
|
||||
Author: K4YT3X\\
|
||||
License: GNU GPL v3\\
|
||||
Github Page: [https://github.com/k4yt3x/video2x](https://github.com/k4yt3x/video2x)\\
|
||||
Contact: [k4yt3x@k4yt3x.com](mailto:k4yt3x@k4yt3x.com)'''
|
||||
|
||||
AVAILABLE_DRIVERS = {
|
||||
'Waifu2X Caffe': 'waifu2x_caffe',
|
||||
@@ -42,6 +43,7 @@ AVAILABLE_DRIVERS = {
|
||||
'Anime4KCPP': 'anime4kcpp'
|
||||
}
|
||||
|
||||
|
||||
def resource_path(relative_path: str) -> pathlib.Path:
|
||||
try:
|
||||
base_path = pathlib.Path(sys._MEIPASS)
|
||||
@@ -52,13 +54,14 @@ def resource_path(relative_path: str) -> pathlib.Path:
|
||||
|
||||
class WorkerSignals(QObject):
|
||||
progress = pyqtSignal(tuple)
|
||||
error = pyqtSignal(str)
|
||||
error = pyqtSignal(Exception)
|
||||
interrupted = pyqtSignal()
|
||||
finished = pyqtSignal()
|
||||
|
||||
class ProgressBarWorker(QRunnable):
|
||||
|
||||
class ProgressMonitorWorkder(QRunnable):
|
||||
def __init__(self, fn, *args, **kwargs):
|
||||
super(ProgressBarWorker, self).__init__()
|
||||
super(ProgressMonitorWorkder, self).__init__()
|
||||
self.fn = fn
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
@@ -72,6 +75,7 @@ class ProgressBarWorker(QRunnable):
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
class UpscalerWorker(QRunnable):
|
||||
|
||||
def __init__(self, fn, *args, **kwargs):
|
||||
@@ -91,144 +95,253 @@ class UpscalerWorker(QRunnable):
|
||||
self.fn(*self.args, **self.kwargs)
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
self.signals.interrupted.emit()
|
||||
except Exception:
|
||||
error_message = traceback.format_exc()
|
||||
print(error_message, file=sys.stderr)
|
||||
self.signals.error.emit(error_message)
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
self.signals.error.emit(e)
|
||||
else:
|
||||
self.signals.finished.emit()
|
||||
|
||||
class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
class InputTableModel(QAbstractTableModel):
|
||||
def __init__(self, data):
|
||||
super(InputTableModel, self).__init__()
|
||||
self._data = data
|
||||
|
||||
def data(self, index, role):
|
||||
if role == Qt.DisplayRole:
|
||||
|
||||
if index.column() == 0:
|
||||
return str(self._data[index.row()].absolute())
|
||||
else:
|
||||
if self._data[index.row()].is_file():
|
||||
return 'File'
|
||||
elif self._data[index.row()].is_dir():
|
||||
return 'Folder'
|
||||
else:
|
||||
return 'Unknown'
|
||||
|
||||
def rowCount(self, index):
|
||||
return len(self._data)
|
||||
|
||||
def columnCount(self, index):
|
||||
return 2
|
||||
|
||||
def removeRow(self, index):
|
||||
self._data.pop(index)
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
# section is the index of the column/row.
|
||||
if role != Qt.DisplayRole:
|
||||
return None
|
||||
|
||||
horizontal_headers = ['File Path', 'Type']
|
||||
|
||||
# return the correspondign header
|
||||
if orientation == Qt.Horizontal:
|
||||
return horizontal_headers[section]
|
||||
|
||||
# simply return the line number
|
||||
if orientation == Qt.Vertical:
|
||||
return str(section)
|
||||
|
||||
|
||||
class Video2XMainWindow(QMainWindow):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
uic.loadUi(str(resource_path('video2x_gui.ui')), self)
|
||||
|
||||
# create thread pool for upscaler workers
|
||||
self.threadpool = QThreadPool()
|
||||
|
||||
# set window title and icon
|
||||
self.video2x_icon_path = str(resource_path('images/video2x.png'))
|
||||
self.setWindowTitle(f'Video2X GUI {VERSION}')
|
||||
self.setWindowIcon(QtGui.QIcon(self.video2x_icon_path))
|
||||
|
||||
# menu bar
|
||||
self.action_exit = self.findChild(QtWidgets.QAction, 'actionExit')
|
||||
self.action_exit = self.findChild(QAction, 'actionExit')
|
||||
self.action_exit.triggered.connect(sys.exit)
|
||||
|
||||
self.action_about = self.findChild(QtWidgets.QAction, 'actionAbout')
|
||||
self.action_about.triggered.connect(lambda: self.show_message(LEGAL_INFO, custom_icon=QtGui.QPixmap(self.video2x_icon_path)))
|
||||
self.action_about = self.findChild(QAction, 'actionAbout')
|
||||
self.action_about.triggered.connect(self.show_about)
|
||||
|
||||
# main tab
|
||||
# select input file/folder
|
||||
self.input_line_edit = self.findChild(QtWidgets.QLineEdit, 'inputLineEdit')
|
||||
self.input_select_file_button = self.findChild(QtWidgets.QPushButton, 'inputSelectFileButton')
|
||||
self.input_select_file_button.clicked.connect(self.select_input_file)
|
||||
self.input_select_folder_button = self.findChild(QtWidgets.QPushButton, 'inputSelectFolderButton')
|
||||
self.input_select_folder_button.clicked.connect(self.select_input_folder)
|
||||
self.input_table_view = self.findChild(QTableView, 'inputTableView')
|
||||
self.input_table_view.dragEnterEvent = self.dragEnterEvent
|
||||
self.input_table_view.dropEvent = self.dropEvent
|
||||
|
||||
# initialize data in table
|
||||
self.input_table_data = []
|
||||
self.input_table_model = InputTableModel(self.input_table_data)
|
||||
self.input_table_view.setModel(self.input_table_model)
|
||||
# stretch file path and fill columns horizontally
|
||||
self.input_table_view.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
|
||||
|
||||
# input table buttons
|
||||
self.input_select_file_button = self.findChild(QPushButton, 'inputSelectFileButton')
|
||||
self.input_select_file_button.clicked.connect(self.select_input_file)
|
||||
self.input_select_folder_button = self.findChild(QPushButton, 'inputSelectFolderButton')
|
||||
self.input_select_folder_button.clicked.connect(self.select_input_folder)
|
||||
self.input_delete_selected_button = self.findChild(QPushButton, 'inputDeleteSelectedButton')
|
||||
self.input_delete_selected_button.clicked.connect(self.input_table_delete_selected)
|
||||
self.input_clear_all_button = self.findChild(QPushButton, 'inputClearAllButton')
|
||||
self.input_clear_all_button.clicked.connect(self.input_table_clear_all)
|
||||
|
||||
# other paths selection
|
||||
# select output file/folder
|
||||
self.output_line_edit = self.findChild(QtWidgets.QLineEdit, 'outputLineEdit')
|
||||
self.output_select_file_button = self.findChild(QtWidgets.QPushButton, 'outputSelectFileButton')
|
||||
self.output_line_edit = self.findChild(QLineEdit, 'outputLineEdit')
|
||||
self.enable_line_edit_file_drop(self.output_line_edit)
|
||||
self.output_line_edit.setText(str((pathlib.Path().cwd() / 'output').absolute()))
|
||||
self.output_select_file_button = self.findChild(QPushButton, 'outputSelectFileButton')
|
||||
self.output_select_file_button.clicked.connect(self.select_output_file)
|
||||
self.output_select_folder_button = self.findChild(QtWidgets.QPushButton, 'outputSelectFolderButton')
|
||||
self.output_select_folder_button = self.findChild(QPushButton, 'outputSelectFolderButton')
|
||||
self.output_select_folder_button.clicked.connect(self.select_output_folder)
|
||||
|
||||
# config file
|
||||
self.config_line_edit = self.findChild(QtWidgets.QLineEdit, 'configLineEdit')
|
||||
self.config_line_edit = self.findChild(QLineEdit, 'configLineEdit')
|
||||
self.enable_line_edit_file_drop(self.config_line_edit)
|
||||
self.config_line_edit.setText(str((pathlib.Path(__file__).parent / 'video2x.yaml').absolute()))
|
||||
self.config_select_file_button = self.findChild(QtWidgets.QPushButton, 'configSelectButton')
|
||||
self.config_select_file_button = self.findChild(QPushButton, 'configSelectButton')
|
||||
self.config_select_file_button.clicked.connect(self.select_config_file)
|
||||
|
||||
# cache directory
|
||||
self.cache_line_edit = self.findChild(QtWidgets.QLineEdit, 'cacheLineEdit')
|
||||
self.cache_select_folder_button = self.findChild(QtWidgets.QPushButton, 'cacheSelectFolderButton')
|
||||
self.cache_line_edit = self.findChild(QLineEdit, 'cacheLineEdit')
|
||||
self.enable_line_edit_file_drop(self.cache_line_edit)
|
||||
self.cache_select_folder_button = self.findChild(QPushButton, 'cacheSelectFolderButton')
|
||||
self.cache_select_folder_button.clicked.connect(self.select_cache_folder)
|
||||
|
||||
# express settings
|
||||
self.driver_combo_box = self.findChild(QtWidgets.QComboBox, 'driverComboBox')
|
||||
self.driver_combo_box = self.findChild(QComboBox, 'driverComboBox')
|
||||
self.driver_combo_box.currentTextChanged.connect(self.update_gui_for_driver)
|
||||
self.processes_spin_box = self.findChild(QtWidgets.QSpinBox, 'processesSpinBox')
|
||||
self.scale_ratio_double_spin_box = self.findChild(QtWidgets.QDoubleSpinBox, 'scaleRatioDoubleSpinBox')
|
||||
self.preserve_frames_check_box = self.findChild(QtWidgets.QCheckBox, 'preserveFramesCheckBox')
|
||||
self.processes_spin_box = self.findChild(QSpinBox, 'processesSpinBox')
|
||||
self.scale_ratio_double_spin_box = self.findChild(QDoubleSpinBox, 'scaleRatioDoubleSpinBox')
|
||||
self.preserve_frames_check_box = self.findChild(QCheckBox, 'preserveFramesCheckBox')
|
||||
|
||||
# progress bar and start/stop controls
|
||||
self.progress_bar = self.findChild(QtWidgets.QProgressBar, 'progressBar')
|
||||
self.time_elapsed_label = self.findChild(QtWidgets.QLabel, 'timeElapsedLabel')
|
||||
self.time_remaining_label = self.findChild(QtWidgets.QLabel, 'timeRemainingLabel')
|
||||
self.rate_label = self.findChild(QtWidgets.QLabel, 'rateLabel')
|
||||
self.start_button = self.findChild(QtWidgets.QPushButton, 'startButton')
|
||||
# frame preview
|
||||
self.frame_preview_show_preview_check_box = self.findChild(QCheckBox, 'framePreviewShowPreviewCheckBox')
|
||||
self.frame_preview_keep_aspect_ratio_check_box = self.findChild(QCheckBox, 'framePreviewKeepAspectRatioCheckBox')
|
||||
self.frame_preview_label = self.findChild(QLabel, 'framePreviewLabel')
|
||||
|
||||
# currently processing
|
||||
self.currently_processing_label = self.findChild(QLabel, 'currentlyProcessingLabel')
|
||||
self.current_progress_bar = self.findChild(QProgressBar, 'currentProgressBar')
|
||||
self.time_elapsed_label = self.findChild(QLabel, 'timeElapsedLabel')
|
||||
self.time_remaining_label = self.findChild(QLabel, 'timeRemainingLabel')
|
||||
self.rate_label = self.findChild(QLabel, 'rateLabel')
|
||||
self.frames_label = self.findChild(QLabel, 'framesLabel')
|
||||
|
||||
# overall progress
|
||||
self.overall_progress_bar = self.findChild(QProgressBar, 'overallProgressBar')
|
||||
self.overall_progress_label = self.findChild(QLabel, 'overallProgressLabel')
|
||||
self.start_button = self.findChild(QPushButton, 'startButton')
|
||||
self.start_button.clicked.connect(self.start)
|
||||
self.stop_button = self.findChild(QtWidgets.QPushButton, 'stopButton')
|
||||
self.stop_button = self.findChild(QPushButton, 'stopButton')
|
||||
self.stop_button.clicked.connect(self.stop)
|
||||
|
||||
# driver settings
|
||||
# waifu2x-caffe
|
||||
self.waifu2x_caffe_path_line_edit = self.findChild(QtWidgets.QLineEdit, 'waifu2xCaffePathLineEdit')
|
||||
self.waifu2x_caffe_path_select_button = self.findChild(QtWidgets.QPushButton, 'waifu2xCaffePathSelectButton')
|
||||
self.waifu2x_caffe_path_line_edit = self.findChild(QLineEdit, 'waifu2xCaffePathLineEdit')
|
||||
self.enable_line_edit_file_drop(self.waifu2x_caffe_path_line_edit)
|
||||
self.waifu2x_caffe_path_select_button = self.findChild(QPushButton, 'waifu2xCaffePathSelectButton')
|
||||
self.waifu2x_caffe_path_select_button.clicked.connect(lambda: self.select_driver_binary_path(self.waifu2x_caffe_path_line_edit))
|
||||
self.waifu2x_caffe_mode_combo_box = self.findChild(QtWidgets.QComboBox, 'waifu2xCaffeModeComboBox')
|
||||
self.waifu2x_caffe_noise_level_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xCaffeNoiseLevelSpinBox')
|
||||
self.waifu2x_caffe_process_combo_box = self.findChild(QtWidgets.QComboBox, 'waifu2xCaffeProcessComboBox')
|
||||
self.waifu2x_caffe_model_combobox = self.findChild(QtWidgets.QComboBox, 'waifu2xCaffeModelComboBox')
|
||||
self.waifu2x_caffe_crop_size_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xCaffeCropSizeSpinBox')
|
||||
self.waifu2x_caffe_output_quality_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xCaffeOutputQualitySpinBox')
|
||||
self.waifu2x_caffe_output_depth_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xCaffeOutputDepthSpinBox')
|
||||
self.waifu2x_caffe_batch_size_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xCaffeBatchSizeSpinBox')
|
||||
self.waifu2x_caffe_gpu_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xCaffeGpuSpinBox')
|
||||
self.waifu2x_caffe_tta_check_box = self.findChild(QtWidgets.QCheckBox, 'waifu2xCaffeTtaCheckBox')
|
||||
self.waifu2x_caffe_scale_width_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeScaleWidthSpinBox')
|
||||
self.waifu2x_caffe_scale_height_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeScaleHeightSpinBox')
|
||||
self.waifu2x_caffe_mode_combo_box = self.findChild(QComboBox, 'waifu2xCaffeModeComboBox')
|
||||
self.waifu2x_caffe_noise_level_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeNoiseLevelSpinBox')
|
||||
self.waifu2x_caffe_process_combo_box = self.findChild(QComboBox, 'waifu2xCaffeProcessComboBox')
|
||||
self.waifu2x_caffe_model_combobox = self.findChild(QComboBox, 'waifu2xCaffeModelComboBox')
|
||||
self.waifu2x_caffe_crop_size_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeCropSizeSpinBox')
|
||||
self.waifu2x_caffe_output_quality_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeOutputQualitySpinBox')
|
||||
self.waifu2x_caffe_output_depth_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeOutputDepthSpinBox')
|
||||
self.waifu2x_caffe_batch_size_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeBatchSizeSpinBox')
|
||||
self.waifu2x_caffe_gpu_spin_box = self.findChild(QSpinBox, 'waifu2xCaffeGpuSpinBox')
|
||||
self.waifu2x_caffe_tta_check_box = self.findChild(QCheckBox, 'waifu2xCaffeTtaCheckBox')
|
||||
|
||||
# waifu2x-converter-cpp
|
||||
self.waifu2x_converter_cpp_path_line_edit = self.findChild(QtWidgets.QLineEdit, 'waifu2xConverterCppPathLineEdit')
|
||||
self.waifu2x_converter_cpp_path_edit_button = self.findChild(QtWidgets.QPushButton, 'waifu2xConverterCppPathSelectButton')
|
||||
self.waifu2x_converter_cpp_path_line_edit = self.findChild(QLineEdit, 'waifu2xConverterCppPathLineEdit')
|
||||
self.enable_line_edit_file_drop(self.waifu2x_converter_cpp_path_line_edit)
|
||||
self.waifu2x_converter_cpp_path_edit_button = self.findChild(QPushButton, 'waifu2xConverterCppPathSelectButton')
|
||||
self.waifu2x_converter_cpp_path_edit_button.clicked.connect(lambda: self.select_driver_binary_path(self.waifu2x_converter_cpp_path_line_edit))
|
||||
self.waifu2x_converter_cpp_png_compression_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xConverterCppPngCompressionSpinBox')
|
||||
self.waifu2x_converter_cpp_processor_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xConverterCppProcessorSpinBox')
|
||||
self.waifu2x_converter_cpp_model_combo_box = self.findChild(QtWidgets.QComboBox, 'waifu2xConverterCppModelComboBox')
|
||||
self.waifu2x_converter_cpp_mode_combo_box = self.findChild(QtWidgets.QComboBox, 'waifu2xConverterCppModeComboBox')
|
||||
self.waifu2x_converter_cpp_disable_gpu_check_box = self.findChild(QtWidgets.QCheckBox, 'disableGpuCheckBox')
|
||||
self.waifu2x_converter_cpp_tta_check_box = self.findChild(QtWidgets.QCheckBox, 'ttaCheckBox')
|
||||
self.waifu2x_converter_cpp_png_compression_spin_box = self.findChild(QSpinBox, 'waifu2xConverterCppPngCompressionSpinBox')
|
||||
self.waifu2x_converter_cpp_image_quality_spin_box = self.findChild(QSpinBox, 'waifu2xConverterCppImageQualitySpinBox')
|
||||
self.waifu2x_converter_cpp_block_size_spin_box = self.findChild(QSpinBox, 'waifu2xConverterCppBlockSizeSpinBox')
|
||||
self.waifu2x_converter_cpp_processor_spin_box = self.findChild(QSpinBox, 'waifu2xConverterCppProcessorSpinBox')
|
||||
self.waifu2x_converter_cpp_model_combo_box = self.findChild(QComboBox, 'waifu2xConverterCppModelComboBox')
|
||||
self.waifu2x_converter_cpp_noise_level_spin_box = self.findChild(QSpinBox, 'waifu2xConverterCppNoiseLevelSpinBox')
|
||||
self.waifu2x_converter_cpp_mode_combo_box = self.findChild(QComboBox, 'waifu2xConverterCppModeComboBox')
|
||||
self.waifu2x_converter_cpp_log_level_spin_box = self.findChild(QSpinBox, 'waifu2xConverterCppLogLevelSpinBox')
|
||||
self.waifu2x_converter_cpp_disable_gpu_check_box = self.findChild(QCheckBox, 'waifu2xConverterCppDisableGpuCheckBox')
|
||||
self.waifu2x_converter_cpp_force_opencl_check_box = self.findChild(QCheckBox, 'waifu2xConverterCppForceOpenclCheckBox')
|
||||
self.waifu2x_converter_cpp_tta_check_box = self.findChild(QCheckBox, 'waifu2xConverterCppTtaCheckBox')
|
||||
|
||||
# waifu2x-ncnn-vulkan
|
||||
self.waifu2x_ncnn_vulkan_path_line_edit = self.findChild(QtWidgets.QLineEdit, 'waifu2xNcnnVulkanPathLineEdit')
|
||||
self.waifu2x_ncnn_vulkan_path_select_button = self.findChild(QtWidgets.QPushButton, 'waifu2xNcnnVulkanPathSelectButton')
|
||||
self.waifu2x_ncnn_vulkan_path_line_edit = self.findChild(QLineEdit, 'waifu2xNcnnVulkanPathLineEdit')
|
||||
self.enable_line_edit_file_drop(self.waifu2x_ncnn_vulkan_path_line_edit)
|
||||
self.waifu2x_ncnn_vulkan_path_select_button = self.findChild(QPushButton, 'waifu2xNcnnVulkanPathSelectButton')
|
||||
self.waifu2x_ncnn_vulkan_path_select_button.clicked.connect(lambda: self.select_driver_binary_path(self.waifu2x_ncnn_vulkan_path_line_edit))
|
||||
self.waifu2x_ncnn_vulkan_noise_level_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xNcnnVulkanNoiseLevelSpinBox')
|
||||
self.waifu2x_ncnn_vulkan_tile_size_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xNcnnVulkanTileSizeSpinBox')
|
||||
self.waifu2x_ncnn_vulkan_model_combo_box = self.findChild(QtWidgets.QComboBox, 'waifu2xNcnnVulkanModelComboBox')
|
||||
self.waifu2x_ncnn_vulkan_gpu_id_spin_box = self.findChild(QtWidgets.QSpinBox, 'waifu2xNcnnVulkanGpuIdSpinBox')
|
||||
self.waifu2x_ncnn_vulkan_jobs_line_edit = self.findChild(QtWidgets.QLineEdit, 'waifu2xNcnnVulkanJobsLineEdit')
|
||||
self.waifu2x_ncnn_vulkan_tta_check_box = self.findChild(QtWidgets.QCheckBox, 'waifu2xNcnnVulkanTtaCheckBox')
|
||||
self.waifu2x_ncnn_vulkan_noise_level_spin_box = self.findChild(QSpinBox, 'waifu2xNcnnVulkanNoiseLevelSpinBox')
|
||||
self.waifu2x_ncnn_vulkan_tile_size_spin_box = self.findChild(QSpinBox, 'waifu2xNcnnVulkanTileSizeSpinBox')
|
||||
self.waifu2x_ncnn_vulkan_model_combo_box = self.findChild(QComboBox, 'waifu2xNcnnVulkanModelComboBox')
|
||||
self.waifu2x_ncnn_vulkan_gpu_id_spin_box = self.findChild(QSpinBox, 'waifu2xNcnnVulkanGpuIdSpinBox')
|
||||
self.waifu2x_ncnn_vulkan_jobs_line_edit = self.findChild(QLineEdit, 'waifu2xNcnnVulkanJobsLineEdit')
|
||||
self.waifu2x_ncnn_vulkan_tta_check_box = self.findChild(QCheckBox, 'waifu2xNcnnVulkanTtaCheckBox')
|
||||
|
||||
# srmd-ncnn-vulkan
|
||||
self.srmd_ncnn_vulkan_path_line_edit = self.findChild(QtWidgets.QLineEdit, 'srmdNcnnVulkanPathLineEdit')
|
||||
self.srmd_ncnn_vulkan_path_select_button = self.findChild(QtWidgets.QPushButton, 'srmdNcnnVulkanPathSelectButton')
|
||||
self.srmd_ncnn_vulkan_path_line_edit = self.findChild(QLineEdit, 'srmdNcnnVulkanPathLineEdit')
|
||||
self.enable_line_edit_file_drop(self.srmd_ncnn_vulkan_path_line_edit)
|
||||
self.srmd_ncnn_vulkan_path_select_button = self.findChild(QPushButton, 'srmdNcnnVulkanPathSelectButton')
|
||||
self.srmd_ncnn_vulkan_path_select_button.clicked.connect(lambda: self.select_driver_binary_path(self.srmd_ncnn_vulkan_path_line_edit))
|
||||
self.srmd_ncnn_vulkan_noise_level_spin_box = self.findChild(QtWidgets.QSpinBox, 'srmdNcnnVulkanNoiseLevelSpinBox')
|
||||
self.srmd_ncnn_vulkan_tile_size_spin_box = self.findChild(QtWidgets.QSpinBox, 'srmdNcnnVulkanTileSizeSpinBox')
|
||||
self.srmd_ncnn_vulkan_model_combo_box = self.findChild(QtWidgets.QComboBox, 'srmdNcnnVulkanModelComboBox')
|
||||
self.srmd_ncnn_vulkan_gpu_id_spin_box = self.findChild(QtWidgets.QSpinBox, 'srmdNcnnVulkanGpuIdSpinBox')
|
||||
self.srmd_ncnn_vulkan_jobs_line_edit = self.findChild(QtWidgets.QLineEdit, 'srmdNcnnVulkanJobsLineEdit')
|
||||
self.srmd_ncnn_vulkan_tta_check_box = self.findChild(QtWidgets.QCheckBox, 'srmdNcnnVulkanTtaCheckBox')
|
||||
self.srmd_ncnn_vulkan_noise_level_spin_box = self.findChild(QSpinBox, 'srmdNcnnVulkanNoiseLevelSpinBox')
|
||||
self.srmd_ncnn_vulkan_tile_size_spin_box = self.findChild(QSpinBox, 'srmdNcnnVulkanTileSizeSpinBox')
|
||||
self.srmd_ncnn_vulkan_model_combo_box = self.findChild(QComboBox, 'srmdNcnnVulkanModelComboBox')
|
||||
self.srmd_ncnn_vulkan_gpu_id_spin_box = self.findChild(QSpinBox, 'srmdNcnnVulkanGpuIdSpinBox')
|
||||
self.srmd_ncnn_vulkan_jobs_line_edit = self.findChild(QLineEdit, 'srmdNcnnVulkanJobsLineEdit')
|
||||
self.srmd_ncnn_vulkan_tta_check_box = self.findChild(QCheckBox, 'srmdNcnnVulkanTtaCheckBox')
|
||||
|
||||
# anime4k
|
||||
self.anime4kcpp_path_line_edit = self.findChild(QtWidgets.QLineEdit, 'anime4kCppPathLineEdit')
|
||||
self.anime4kcpp_path_select_button = self.findChild(QtWidgets.QPushButton, 'anime4kCppPathSelectButton')
|
||||
self.anime4kcpp_path_line_edit = self.findChild(QLineEdit, 'anime4kCppPathLineEdit')
|
||||
self.enable_line_edit_file_drop(self.anime4kcpp_path_line_edit)
|
||||
self.anime4kcpp_path_select_button = self.findChild(QPushButton, 'anime4kCppPathSelectButton')
|
||||
self.anime4kcpp_path_select_button.clicked.connect(lambda: self.select_driver_binary_path(self.anime4kcpp_path_line_edit))
|
||||
self.anime4kcpp_passes_spin_box = self.findChild(QtWidgets.QSpinBox, 'anime4kCppPassesSpinBox')
|
||||
self.anime4kcpp_push_color_count_spin_box = self.findChild(QtWidgets.QSpinBox, 'anime4kCppPushColorCountSpinBox')
|
||||
self.anime4kcpp_strength_color_spin_box = self.findChild(QtWidgets.QDoubleSpinBox, 'anime4kCppStrengthColorSpinBox')
|
||||
self.anime4kcpp_strength_gradient_spin_box = self.findChild(QtWidgets.QDoubleSpinBox, 'anime4kCppStrengthGradientSpinBox')
|
||||
self.anime4kcpp_threads_spin_box = self.findChild(QtWidgets.QSpinBox, 'anime4kCppThreadsSpinBox')
|
||||
self.anime4kcpp_pre_filters_spin_box = self.findChild(QtWidgets.QSpinBox, 'anime4kCppPreFiltersSpinBox')
|
||||
self.anime4kcpp_post_filters_spin_box = self.findChild(QtWidgets.QSpinBox, 'anime4kCppPostFiltersSpinBox')
|
||||
self.anime4kcpp_platform_id_spin_box = self.findChild(QtWidgets.QSpinBox, 'anime4kCppPlatformIdSpinBox')
|
||||
self.anime4kcpp_device_id_spin_box = self.findChild(QtWidgets.QSpinBox, 'anime4kCppDeviceIdSpinBox')
|
||||
self.anime4kcpp_codec_combo_box = self.findChild(QtWidgets.QComboBox, 'anime4kCppCodecComboBox')
|
||||
self.anime4kcpp_fast_mode_check_box = self.findChild(QtWidgets.QCheckBox, 'anime4kCppFastModeCheckBox')
|
||||
self.anime4kcpp_pre_processing_check_box = self.findChild(QtWidgets.QCheckBox, 'anime4kCppPreProcessingCheckBox')
|
||||
self.anime4kcpp_post_processing_check_box = self.findChild(QtWidgets.QCheckBox, 'anime4kCppPostProcessingCheckBox')
|
||||
self.anime4kcpp_gpu_mode_check_box = self.findChild(QtWidgets.QCheckBox, 'anime4kCppGpuModeCheckBox')
|
||||
self.anime4kcpp_passes_spin_box = self.findChild(QSpinBox, 'anime4kCppPassesSpinBox')
|
||||
self.anime4kcpp_push_color_count_spin_box = self.findChild(QSpinBox, 'anime4kCppPushColorCountSpinBox')
|
||||
self.anime4kcpp_strength_color_spin_box = self.findChild(QDoubleSpinBox, 'anime4kCppStrengthColorSpinBox')
|
||||
self.anime4kcpp_strength_gradient_spin_box = self.findChild(QDoubleSpinBox, 'anime4kCppStrengthGradientSpinBox')
|
||||
self.anime4kcpp_threads_spin_box = self.findChild(QSpinBox, 'anime4kCppThreadsSpinBox')
|
||||
self.anime4kcpp_pre_filters_spin_box = self.findChild(QSpinBox, 'anime4kCppPreFiltersSpinBox')
|
||||
self.anime4kcpp_post_filters_spin_box = self.findChild(QSpinBox, 'anime4kCppPostFiltersSpinBox')
|
||||
self.anime4kcpp_platform_id_spin_box = self.findChild(QSpinBox, 'anime4kCppPlatformIdSpinBox')
|
||||
self.anime4kcpp_device_id_spin_box = self.findChild(QSpinBox, 'anime4kCppDeviceIdSpinBox')
|
||||
self.anime4kcpp_codec_combo_box = self.findChild(QComboBox, 'anime4kCppCodecComboBox')
|
||||
self.anime4kcpp_fast_mode_check_box = self.findChild(QCheckBox, 'anime4kCppFastModeCheckBox')
|
||||
self.anime4kcpp_pre_processing_check_box = self.findChild(QCheckBox, 'anime4kCppPreProcessingCheckBox')
|
||||
self.anime4kcpp_post_processing_check_box = self.findChild(QCheckBox, 'anime4kCppPostProcessingCheckBox')
|
||||
self.anime4kcpp_gpu_mode_check_box = self.findChild(QCheckBox, 'anime4kCppGpuModeCheckBox')
|
||||
|
||||
# load configurations
|
||||
self.load_configurations()
|
||||
|
||||
def dragEnterEvent(self, event):
|
||||
if event.mimeData().hasUrls():
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
def dropEvent(self, event):
|
||||
input_paths = [pathlib.Path(u.toLocalFile()) for u in event.mimeData().urls()]
|
||||
for path in input_paths:
|
||||
if (path.is_file() or path.is_dir()) and not self.input_table_path_exists(path):
|
||||
self.input_table_data.append(path)
|
||||
|
||||
self.update_input_table()
|
||||
self.update_output_path()
|
||||
|
||||
def enable_line_edit_file_drop(self, line_edit: QLineEdit):
|
||||
line_edit.dragEnterEvent = self.dragEnterEvent
|
||||
line_edit.dropEvent = lambda event: line_edit.setText(str(pathlib.Path(event.mimeData().urls()[0].toLocalFile()).absolute()))
|
||||
|
||||
@staticmethod
|
||||
def read_config(config_file: pathlib.Path) -> dict:
|
||||
""" read video2x configurations from config file
|
||||
@@ -250,7 +363,7 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
# if file doesn't exist, return
|
||||
if not config_file_path.is_file():
|
||||
QtWidgets.QErrorMessage(self).showMessage('Video2X configuration file not found, please specify manually.')
|
||||
QErrorMessage(self).showMessage('Video2X configuration file not found, please specify manually.')
|
||||
return
|
||||
|
||||
# read configuration dict from config file
|
||||
@@ -262,8 +375,8 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
# set cache directory path
|
||||
if self.config['video2x']['video2x_cache_directory'] is None:
|
||||
video2x_cache_directory = str((pathlib.Path(tempfile.gettempdir()) / 'video2x').absolute())
|
||||
self.cache_line_edit.setText(video2x_cache_directory)
|
||||
self.config['video2x']['video2x_cache_directory'] = str((pathlib.Path(tempfile.gettempdir()) / 'video2x').absolute())
|
||||
self.cache_line_edit.setText(self.config['video2x']['video2x_cache_directory'])
|
||||
|
||||
# load preserve frames settings
|
||||
self.preserve_frames_check_box.setChecked(self.config['video2x']['preserve_frames'])
|
||||
@@ -271,6 +384,8 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
# waifu2x-caffe
|
||||
settings = self.config['waifu2x_caffe']
|
||||
self.waifu2x_caffe_scale_width_spin_box.setValue(settings['scale_width'])
|
||||
self.waifu2x_caffe_scale_height_spin_box.setValue(settings['scale_height'])
|
||||
self.waifu2x_caffe_path_line_edit.setText(str(pathlib.Path(os.path.expandvars(settings['path'])).absolute()))
|
||||
self.waifu2x_caffe_mode_combo_box.setCurrentText(settings['mode'])
|
||||
self.waifu2x_caffe_noise_level_spin_box.setValue(settings['noise_level'])
|
||||
@@ -286,9 +401,14 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
settings = self.config['waifu2x_converter_cpp']
|
||||
self.waifu2x_converter_cpp_path_line_edit.setText(str(pathlib.Path(os.path.expandvars(settings['path'])).absolute()))
|
||||
self.waifu2x_converter_cpp_png_compression_spin_box.setValue(settings['png-compression'])
|
||||
self.waifu2x_converter_cpp_image_quality_spin_box.setValue(settings['image-quality'])
|
||||
self.waifu2x_converter_cpp_block_size_spin_box.setValue(settings['block-size'])
|
||||
self.waifu2x_converter_cpp_processor_spin_box.setValue(settings['processor'])
|
||||
self.waifu2x_converter_cpp_noise_level_spin_box.setValue(settings['noise-level'])
|
||||
self.waifu2x_converter_cpp_mode_combo_box.setCurrentText(settings['mode'])
|
||||
self.waifu2x_converter_cpp_log_level_spin_box.setValue(settings['log-level'])
|
||||
self.waifu2x_converter_cpp_disable_gpu_check_box.setChecked(settings['disable-gpu'])
|
||||
self.waifu2x_converter_cpp_force_opencl_check_box.setChecked(settings['force-OpenCL'])
|
||||
self.waifu2x_converter_cpp_tta_check_box.setChecked(bool(settings['tta']))
|
||||
|
||||
# waifu2x-ncnn-vulkan
|
||||
@@ -328,8 +448,10 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
self.anime4kcpp_gpu_mode_check_box.setChecked(settings['GPUMode'])
|
||||
|
||||
def resolve_driver_settings(self):
|
||||
|
||||
|
||||
# waifu2x-caffe
|
||||
self.config['waifu2x_caffe']['scale_width'] = self.waifu2x_caffe_scale_width_spin_box.value()
|
||||
self.config['waifu2x_caffe']['scale_height'] = self.waifu2x_caffe_scale_height_spin_box.value()
|
||||
self.config['waifu2x_caffe']['path'] = os.path.expandvars(self.waifu2x_caffe_path_line_edit.text())
|
||||
self.config['waifu2x_caffe']['mode'] = self.waifu2x_caffe_mode_combo_box.currentText()
|
||||
self.config['waifu2x_caffe']['noise_level'] = self.waifu2x_caffe_noise_level_spin_box.value()
|
||||
@@ -340,16 +462,21 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
self.config['waifu2x_caffe']['output_depth'] = self.waifu2x_caffe_output_depth_spin_box.value()
|
||||
self.config['waifu2x_caffe']['batch_size'] = self.waifu2x_caffe_batch_size_spin_box.value()
|
||||
self.config['waifu2x_caffe']['gpu'] = self.waifu2x_caffe_gpu_spin_box.value()
|
||||
self.config['waifu2x_caffe']['tta'] = int(self.waifu2x_caffe_tta_check_box.checkState())
|
||||
self.config['waifu2x_caffe']['tta'] = int(self.waifu2x_caffe_tta_check_box.isChecked())
|
||||
|
||||
# waifu2x-converter-cpp
|
||||
self.config['waifu2x_converter_cpp']['path'] = os.path.expandvars(self.waifu2x_converter_cpp_path_line_edit.text())
|
||||
self.config['waifu2x_converter_cpp']['png-compression'] = self.waifu2x_converter_cpp_png_compression_spin_box.value()
|
||||
self.config['waifu2x_converter_cpp']['image-quality'] = self.waifu2x_converter_cpp_image_quality_spin_box.value()
|
||||
self.config['waifu2x_converter_cpp']['block-size'] = self.waifu2x_converter_cpp_block_size_spin_box.value()
|
||||
self.config['waifu2x_converter_cpp']['processor'] = self.waifu2x_converter_cpp_processor_spin_box.value()
|
||||
self.config['waifu2x_converter_cpp']['model-dir'] = str((pathlib.Path(self.config['waifu2x_converter_cpp']['path']).parent / self.waifu2x_converter_cpp_model_combo_box.currentText()).absolute())
|
||||
self.config['waifu2x_converter_cpp']['noise-level'] = self.waifu2x_converter_cpp_noise_level_spin_box.value()
|
||||
self.config['waifu2x_converter_cpp']['mode'] = self.waifu2x_converter_cpp_mode_combo_box.currentText()
|
||||
self.config['waifu2x_converter_cpp']['disable-gpu'] = bool(self.waifu2x_converter_cpp_disable_gpu_check_box.checkState())
|
||||
self.config['waifu2x_converter_cpp']['tta'] = int(self.waifu2x_converter_cpp_tta_check_box.checkState())
|
||||
self.config['waifu2x_converter_cpp']['log-level'] = self.waifu2x_converter_cpp_log_level_spin_box.value()
|
||||
self.config['waifu2x_converter_cpp']['disable-gpu'] = bool(self.waifu2x_converter_cpp_disable_gpu_check_box.isChecked())
|
||||
self.config['waifu2x_converter_cpp']['force-OpenCL'] = bool(self.waifu2x_converter_cpp_force_opencl_check_box.isChecked())
|
||||
self.config['waifu2x_converter_cpp']['tta'] = int(self.waifu2x_converter_cpp_tta_check_box.isChecked())
|
||||
|
||||
# waifu2x-ncnn-vulkan
|
||||
self.config['waifu2x_ncnn_vulkan']['path'] = os.path.expandvars(self.waifu2x_ncnn_vulkan_path_line_edit.text())
|
||||
@@ -358,7 +485,7 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
self.config['waifu2x_ncnn_vulkan']['m'] = str((pathlib.Path(self.config['waifu2x_ncnn_vulkan']['path']).parent / self.waifu2x_ncnn_vulkan_model_combo_box.currentText()).absolute())
|
||||
self.config['waifu2x_ncnn_vulkan']['g'] = self.waifu2x_ncnn_vulkan_gpu_id_spin_box.value()
|
||||
self.config['waifu2x_ncnn_vulkan']['j'] = self.waifu2x_ncnn_vulkan_jobs_line_edit.text()
|
||||
self.config['waifu2x_ncnn_vulkan']['x'] = self.waifu2x_ncnn_vulkan_tta_check_box.checkState()
|
||||
self.config['waifu2x_ncnn_vulkan']['x'] = self.waifu2x_ncnn_vulkan_tta_check_box.isChecked()
|
||||
|
||||
# srmd-ncnn-vulkan
|
||||
self.config['srmd_ncnn_vulkan']['path'] = os.path.expandvars(self.srmd_ncnn_vulkan_path_line_edit.text())
|
||||
@@ -367,7 +494,7 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
self.config['srmd_ncnn_vulkan']['m'] = str((pathlib.Path(self.config['srmd_ncnn_vulkan']['path']).parent / self.srmd_ncnn_vulkan_model_combo_box.currentText()).absolute())
|
||||
self.config['srmd_ncnn_vulkan']['g'] = self.srmd_ncnn_vulkan_gpu_id_spin_box.value()
|
||||
self.config['srmd_ncnn_vulkan']['j'] = self.srmd_ncnn_vulkan_jobs_line_edit.text()
|
||||
self.config['srmd_ncnn_vulkan']['x'] = self.srmd_ncnn_vulkan_tta_check_box.checkState()
|
||||
self.config['srmd_ncnn_vulkan']['x'] = self.srmd_ncnn_vulkan_tta_check_box.isChecked()
|
||||
|
||||
# anime4k
|
||||
self.config['anime4kcpp']['path'] = os.path.expandvars(self.anime4kcpp_path_line_edit.text())
|
||||
@@ -381,14 +508,14 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
self.config['anime4kcpp']['platformID'] = self.anime4kcpp_platform_id_spin_box.value()
|
||||
self.config['anime4kcpp']['deviceID'] = self.anime4kcpp_device_id_spin_box.value()
|
||||
self.config['anime4kcpp']['codec'] = self.anime4kcpp_codec_combo_box.currentText()
|
||||
self.config['anime4kcpp']['fastMode'] = bool(self.anime4kcpp_fast_mode_check_box.checkState())
|
||||
self.config['anime4kcpp']['preprocessing'] = bool(self.anime4kcpp_pre_processing_check_box.checkState())
|
||||
self.config['anime4kcpp']['postprocessing'] = bool(self.anime4kcpp_post_processing_check_box.checkState())
|
||||
self.config['anime4kcpp']['GPUMode'] = bool(self.anime4kcpp_gpu_mode_check_box.checkState())
|
||||
self.config['anime4kcpp']['fastMode'] = bool(self.anime4kcpp_fast_mode_check_box.isChecked())
|
||||
self.config['anime4kcpp']['preprocessing'] = bool(self.anime4kcpp_pre_processing_check_box.isChecked())
|
||||
self.config['anime4kcpp']['postprocessing'] = bool(self.anime4kcpp_post_processing_check_box.isChecked())
|
||||
self.config['anime4kcpp']['GPUMode'] = bool(self.anime4kcpp_gpu_mode_check_box.isChecked())
|
||||
|
||||
def update_gui_for_driver(self):
|
||||
current_driver = AVAILABLE_DRIVERS[self.driver_combo_box.currentText()]
|
||||
|
||||
|
||||
# update scale ratio constraints
|
||||
if current_driver in ['waifu2x_caffe', 'waifu2x_converter_cpp', 'anime4kcpp']:
|
||||
self.scale_ratio_double_spin_box.setMinimum(0.0)
|
||||
@@ -402,59 +529,93 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
self.scale_ratio_double_spin_box.setMinimum(2.0)
|
||||
self.scale_ratio_double_spin_box.setMaximum(4.0)
|
||||
self.scale_ratio_double_spin_box.setValue(2.0)
|
||||
|
||||
|
||||
# update preferred processes/threads count
|
||||
if current_driver == 'anime4kcpp':
|
||||
self.processes_spin_box.setValue(16)
|
||||
else:
|
||||
self.processes_spin_box.setValue(1)
|
||||
|
||||
|
||||
def update_input_table(self):
|
||||
# HACK: use insertRow, removeRow and signals
|
||||
del self.input_table_model
|
||||
self.input_table_model = InputTableModel(self.input_table_data)
|
||||
self.input_table_view.setModel(self.input_table_model)
|
||||
|
||||
def input_table_delete_selected(self):
|
||||
items_to_delete = []
|
||||
for index in [i.row() for i in self.input_table_view.selectedIndexes()]:
|
||||
items_to_delete.append(self.input_table_data[index])
|
||||
|
||||
for item in items_to_delete:
|
||||
self.input_table_data.remove(item)
|
||||
self.update_input_table()
|
||||
|
||||
def input_table_clear_all(self):
|
||||
self.input_table_data = []
|
||||
self.update_input_table()
|
||||
|
||||
def input_table_path_exists(self, input_path):
|
||||
for path in self.input_table_data:
|
||||
# not using Path.samefile since file may not exist
|
||||
if str(path.absolute()) == str(input_path.absolute()):
|
||||
return True
|
||||
return False
|
||||
|
||||
def select_file(self, *args, **kwargs) -> pathlib.Path:
|
||||
file_selected = QtWidgets.QFileDialog.getOpenFileName(self, *args, **kwargs)
|
||||
file_selected = QFileDialog.getOpenFileName(self, *args, **kwargs)
|
||||
if not isinstance(file_selected, tuple) or file_selected[0] == '':
|
||||
return None
|
||||
return pathlib.Path(file_selected[0])
|
||||
|
||||
def select_folder(self, *args, **kwargs) -> pathlib.Path:
|
||||
folder_selected = QtWidgets.QFileDialog.getExistingDirectory(self, *args, **kwargs)
|
||||
folder_selected = QFileDialog.getExistingDirectory(self, *args, **kwargs)
|
||||
if folder_selected == '':
|
||||
return None
|
||||
return pathlib.Path(folder_selected)
|
||||
|
||||
def select_input_file(self):
|
||||
|
||||
if (input_file := self.select_file('Select Input File')) is None:
|
||||
def update_output_path(self):
|
||||
# if there is more than one input
|
||||
if len(self.input_table_data) != 1:
|
||||
return
|
||||
self.input_line_edit.setText(str(input_file.absolute()))
|
||||
|
||||
# try to set an output file name automatically
|
||||
output_file = input_file.parent / f'{input_file.stem}_output.mp4'
|
||||
input_path = self.input_table_data[0]
|
||||
# give up if input path doesn't exist or isn't a file or a directory
|
||||
if not input_path.exists() or not (input_path.is_file() or input_path.is_dir()):
|
||||
return
|
||||
|
||||
output_file_id = 0
|
||||
while output_file.is_file() and output_file_id <= 10:
|
||||
output_file = input_file.parent / pathlib.Path(f'{input_file.stem}_output_{output_file_id}.mp4')
|
||||
output_file_id += 1
|
||||
if input_path.is_file():
|
||||
output_path = input_path.parent / f'{input_path.stem}_output.mp4'
|
||||
elif input_path.is_dir():
|
||||
output_path = input_path.parent / f'{input_path.stem}_output'
|
||||
|
||||
if not output_file.exists():
|
||||
self.output_line_edit.setText(str(output_file.absolute()))
|
||||
# try up to 1000 times
|
||||
output_path_id = 0
|
||||
while output_path.exists() and output_path_id <= 1000:
|
||||
if input_path.is_file():
|
||||
output_path = input_path.parent / pathlib.Path(f'{input_path.stem}_output_{output_path_id}.mp4')
|
||||
elif input_path.is_dir():
|
||||
output_path = input_path.parent / pathlib.Path(f'{input_path.stem}_output_{output_path_id}')
|
||||
output_path_id += 1
|
||||
|
||||
if not output_path.exists():
|
||||
self.output_line_edit.setText(str(output_path.absolute()))
|
||||
|
||||
def select_input_file(self):
|
||||
if ((input_file := self.select_file('Select Input File')) is None or
|
||||
self.input_table_path_exists(input_file)):
|
||||
return
|
||||
self.input_table_data.append(input_file)
|
||||
self.update_output_path()
|
||||
self.update_input_table()
|
||||
|
||||
def select_input_folder(self):
|
||||
|
||||
if (input_folder := self.select_folder('Select Input Folder')) is None:
|
||||
if ((input_folder := self.select_folder('Select Input Folder')) is None or
|
||||
self.input_table_path_exists(input_folder)):
|
||||
return
|
||||
|
||||
self.input_line_edit.setText(str(input_folder.absolute()))
|
||||
|
||||
# try to set an output file name automatically
|
||||
output_folder = input_folder.parent / f'{input_folder.stem}_output'
|
||||
|
||||
output_file_id = 0
|
||||
while output_folder.is_dir() and output_file_id <= 10:
|
||||
output_folder = input_folder.parent / pathlib.Path(f'{input_folder.stem}_output_{output_file_id}')
|
||||
output_file_id += 1
|
||||
|
||||
if not output_folder.exists():
|
||||
self.output_line_edit.setText(str(output_folder.absolute()))
|
||||
self.input_table_data.append(input_folder)
|
||||
self.update_output_path()
|
||||
self.update_input_table()
|
||||
|
||||
def select_output_file(self):
|
||||
if (output_file := self.select_file('Select Output File')) is None:
|
||||
@@ -476,58 +637,79 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
return
|
||||
self.config_line_edit.setText(str(config_file.absolute()))
|
||||
self.load_configurations()
|
||||
|
||||
|
||||
def select_driver_binary_path(self, driver_line_edit):
|
||||
if (driver_binary_path := self.select_file('Select Driver Binary File')) is None:
|
||||
return
|
||||
driver_line_edit.setText(str(driver_binary_path.absolute()))
|
||||
|
||||
def show_error(self, message: str):
|
||||
QtWidgets.QErrorMessage(self).showMessage(message.replace('\n', '<br>'))
|
||||
def show_about(self, message: str):
|
||||
message_box = QMessageBox(self)
|
||||
message_box.setWindowTitle('About Video2X')
|
||||
message_box.setIconPixmap(QtGui.QPixmap(self.video2x_icon_path).scaled(64, 64))
|
||||
message_box.setTextFormat(Qt.MarkdownText)
|
||||
message_box.setText(LEGAL_INFO)
|
||||
message_box.exec_()
|
||||
|
||||
def show_message(self, message: str, custom_icon=None):
|
||||
message_box = QtWidgets.QMessageBox()
|
||||
message_box.setWindowTitle('Message')
|
||||
if custom_icon:
|
||||
message_box.setIconPixmap(custom_icon.scaled(64, 64))
|
||||
else:
|
||||
message_box.setIcon(QtWidgets.QMessageBox.Information)
|
||||
def show_information(self, message: str):
|
||||
message_box = QMessageBox(self)
|
||||
message_box.setWindowTitle('Information')
|
||||
message_box.setIcon(QMessageBox.Information)
|
||||
message_box.setText(message)
|
||||
message_box.exec_()
|
||||
|
||||
def start_progress_bar(self, progress_callback):
|
||||
# wait for progress monitor to come online
|
||||
while 'progress_monitor' not in self.upscaler.__dict__:
|
||||
if self.upscaler.stop_signal:
|
||||
return
|
||||
time.sleep(0.1)
|
||||
def show_warning(self, message: str):
|
||||
message_box = QMessageBox(self)
|
||||
message_box.setWindowTitle('Warning')
|
||||
message_box.setIcon(QMessageBox.Warning)
|
||||
message_box.setText(message)
|
||||
message_box.exec_()
|
||||
|
||||
def show_error(self, exception: Exception):
|
||||
# QErrorMessage(self).showMessage(message.replace('\n', '<br>'))
|
||||
message_box = QMessageBox(self)
|
||||
message_box.setWindowTitle('Error')
|
||||
message_box.setIcon(QMessageBox.Critical)
|
||||
message_box.setTextFormat(Qt.MarkdownText)
|
||||
|
||||
error_message = '''Upscaler ran into an error:\\
|
||||
**{}**\\
|
||||
Check the console output for details.\\
|
||||
When reporting an error, please include console output.\\
|
||||
You can [submit an issue on GitHub](https://github.com/k4yt3x/video2x/issues/new?assignees=K4YT3X&labels=bug&template=bug-report.md&title={}) to report this error.'''
|
||||
message_box.setText(error_message.format(exception, urllib.parse.quote(str(exception))))
|
||||
message_box.exec_()
|
||||
|
||||
def progress_monitor(self, progress_callback):
|
||||
|
||||
# initialize progress bar values
|
||||
upscale_begin_time = time.time()
|
||||
progress_callback.emit((0, 0, 0, upscale_begin_time))
|
||||
progress_callback.emit((upscale_begin_time, 0, 0, 0, 0, pathlib.Path(), pathlib.Path()))
|
||||
|
||||
# keep querying upscaling process and feed information to callback signal
|
||||
while self.upscaler.progress_monitor.running:
|
||||
try:
|
||||
progress_percentage = int(100 * self.upscaler.total_frames_upscaled / self.upscaler.total_frames)
|
||||
except ZeroDivisionError:
|
||||
progress_percentage = 0
|
||||
while self.upscaler.running:
|
||||
|
||||
progress_callback.emit((progress_percentage,
|
||||
self.upscaler.total_frames_upscaled,
|
||||
self.upscaler.total_frames,
|
||||
upscale_begin_time))
|
||||
progress_callback.emit((upscale_begin_time,
|
||||
self.upscaler.total_frames_upscaled,
|
||||
self.upscaler.total_frames,
|
||||
self.upscaler.total_processed,
|
||||
self.upscaler.total_videos,
|
||||
self.upscaler.current_input_video,
|
||||
self.upscaler.last_frame_upscaled))
|
||||
time.sleep(1)
|
||||
|
||||
# upscale process will stop at 99%
|
||||
# so it's set to 100 manually when all is done
|
||||
progress_callback.emit((100, 0, 0, upscale_begin_time))
|
||||
progress_callback.emit((upscale_begin_time, 0, 0, 0, 0, pathlib.Path(), pathlib.Path()))
|
||||
|
||||
def set_progress(self, progress_information: tuple):
|
||||
progress_percentage = progress_information[0]
|
||||
upscale_begin_time = progress_information[0]
|
||||
total_frames_upscaled = progress_information[1]
|
||||
total_frames = progress_information[2]
|
||||
upscale_begin_time = progress_information[3]
|
||||
total_processed = progress_information[3]
|
||||
total_videos = progress_information[4]
|
||||
current_input_video = progress_information[5]
|
||||
last_frame_upscaled = progress_information[6]
|
||||
|
||||
# calculate fields based on frames and time elapsed
|
||||
time_elapsed = time.time() - upscale_begin_time
|
||||
@@ -539,10 +721,50 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
time_remaining = 0.0
|
||||
|
||||
# set calculated values in GUI
|
||||
self.progress_bar.setValue(progress_percentage)
|
||||
self.current_progress_bar.setMaximum(total_frames)
|
||||
self.current_progress_bar.setValue(total_frames_upscaled)
|
||||
self.frames_label.setText('Frames: {}/{}'.format(total_frames_upscaled, total_frames))
|
||||
self.time_elapsed_label.setText('Time Elapsed: {}'.format(time.strftime("%H:%M:%S", time.gmtime(time_elapsed))))
|
||||
self.time_remaining_label.setText('Time Remaining: {}'.format(time.strftime("%H:%M:%S", time.gmtime(time_remaining))))
|
||||
self.rate_label.setText('Rate (FPS): {}'.format(round(rate, 2)))
|
||||
self.overall_progress_label.setText('Overall Progress: {}/{}'.format(total_processed, total_videos))
|
||||
self.overall_progress_bar.setMaximum(total_videos)
|
||||
self.overall_progress_bar.setValue(total_processed)
|
||||
self.currently_processing_label.setText('Currently Processing: {}'.format(str(current_input_video.name)))
|
||||
|
||||
# if show frame is checked, show preview image
|
||||
if self.frame_preview_show_preview_check_box.isChecked() and last_frame_upscaled.is_file():
|
||||
last_frame_pixmap = QtGui.QPixmap(str(last_frame_upscaled.absolute()))
|
||||
# the -2 here behind geometry subtracts frame size from width and height
|
||||
self.frame_preview_label.setPixmap(last_frame_pixmap.scaled(self.frame_preview_label.width() - 2,
|
||||
self.frame_preview_label.height() - 2,
|
||||
Qt.KeepAspectRatio))
|
||||
|
||||
# if keep aspect ratio is checked, don't stretch image
|
||||
if self.frame_preview_keep_aspect_ratio_check_box.isChecked():
|
||||
self.frame_preview_label.setScaledContents(False)
|
||||
else:
|
||||
self.frame_preview_label.setScaledContents(True)
|
||||
|
||||
# display image in label
|
||||
self.frame_preview_label.show()
|
||||
|
||||
# if show frame is unchecked, clear image
|
||||
elif self.frame_preview_show_preview_check_box.isChecked() is False:
|
||||
self.frame_preview_label.clear()
|
||||
|
||||
def reset_progress_display(self):
|
||||
# reset progress display UI elements
|
||||
self.current_progress_bar.setMaximum(100)
|
||||
self.current_progress_bar.setValue(0)
|
||||
self.frames_label.setText('Frames: {}/{}'.format(0, 0))
|
||||
self.time_elapsed_label.setText('Time Elapsed: {}'.format(time.strftime("%H:%M:%S", time.gmtime(0))))
|
||||
self.time_remaining_label.setText('Time Remaining: {}'.format(time.strftime("%H:%M:%S", time.gmtime(0))))
|
||||
self.rate_label.setText('Rate (FPS): {}'.format(0.0))
|
||||
self.overall_progress_label.setText('Overall Progress: {}/{}'.format(0, 0))
|
||||
self.overall_progress_bar.setMaximum(100)
|
||||
self.overall_progress_bar.setValue(0)
|
||||
self.currently_processing_label.setText('Currently Processing:')
|
||||
|
||||
def start(self):
|
||||
|
||||
@@ -552,18 +774,20 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
self.begin_time = time.time()
|
||||
|
||||
# resolve input and output directories from GUI
|
||||
if self.input_line_edit.text().strip() == '':
|
||||
self.show_error('Input path not specified')
|
||||
if len(self.input_table_data) == 0:
|
||||
self.show_warning('Input path unspecified')
|
||||
return
|
||||
if self.output_line_edit.text().strip() == '':
|
||||
self.show_error('Output path not specified')
|
||||
self.show_warning('Output path unspecified')
|
||||
return
|
||||
|
||||
input_directory = pathlib.Path(os.path.expandvars(self.input_line_edit.text()))
|
||||
output_directory = pathlib.Path(os.path.expandvars(self.output_line_edit.text()))
|
||||
if len(self.input_table_data) == 1:
|
||||
input_directory = self.input_table_data[0]
|
||||
else:
|
||||
input_directory = self.input_table_data
|
||||
|
||||
# create thread pool for upscaler workers
|
||||
self.threadpool = QThreadPool()
|
||||
# resolve output directory
|
||||
output_directory = pathlib.Path(os.path.expandvars(self.output_line_edit.text()))
|
||||
|
||||
# load driver settings from GUI
|
||||
self.resolve_driver_settings()
|
||||
@@ -582,44 +806,52 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
self.upscaler.processes = self.processes_spin_box.value()
|
||||
self.upscaler.video2x_cache_directory = pathlib.Path(os.path.expandvars(self.cache_line_edit.text()))
|
||||
self.upscaler.image_format = self.config['video2x']['image_format'].lower()
|
||||
self.upscaler.preserve_frames = bool(self.preserve_frames_check_box.checkState())
|
||||
|
||||
# start progress bar
|
||||
if AVAILABLE_DRIVERS[self.driver_combo_box.currentText()] != 'anime4kcpp':
|
||||
progress_bar_worker = ProgressBarWorker(self.start_progress_bar)
|
||||
progress_bar_worker.signals.progress.connect(self.set_progress)
|
||||
self.threadpool.start(progress_bar_worker)
|
||||
self.upscaler.preserve_frames = bool(self.preserve_frames_check_box.isChecked())
|
||||
|
||||
# run upscaler
|
||||
worker = UpscalerWorker(self.upscaler.run)
|
||||
worker.signals.error.connect(self.upscale_errored)
|
||||
worker.signals.finished.connect(self.upscale_completed)
|
||||
worker.signals.interrupted.connect(self.upscale_interrupted)
|
||||
worker.signals.finished.connect(self.upscale_successful)
|
||||
self.threadpool.start(worker)
|
||||
|
||||
# start progress monitoring
|
||||
progress_bar_worker = ProgressMonitorWorkder(self.progress_monitor)
|
||||
progress_bar_worker.signals.progress.connect(self.set_progress)
|
||||
self.threadpool.start(progress_bar_worker)
|
||||
|
||||
self.start_button.setEnabled(False)
|
||||
self.stop_button.setEnabled(True)
|
||||
|
||||
except Exception:
|
||||
self.upscale_errored(traceback.format_exc())
|
||||
|
||||
def upscale_errored(self, error_message):
|
||||
self.show_error(f'Upscaler ran into an error:\n{error_message}')
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
self.upscale_errored(e)
|
||||
|
||||
def upscale_completed(self):
|
||||
# if all threads have finished
|
||||
if self.threadpool.activeThreadCount() == 0:
|
||||
self.show_message('Program completed, taking {} seconds'.format(round((time.time() - self.begin_time), 5)))
|
||||
self.start_button.setEnabled(True)
|
||||
self.stop_button.setEnabled(False)
|
||||
|
||||
def upscale_interrupted(self):
|
||||
self.show_message('Upscale has been interrupted')
|
||||
def upscale_errored(self, exception: Exception):
|
||||
self.show_error(exception)
|
||||
self.threadpool.waitForDone(5)
|
||||
self.start_button.setEnabled(True)
|
||||
self.stop_button.setEnabled(False)
|
||||
self.reset_progress_display()
|
||||
|
||||
def upscale_interrupted(self):
|
||||
self.show_information('Upscale has been interrupted')
|
||||
self.threadpool.waitForDone(5)
|
||||
self.start_button.setEnabled(True)
|
||||
self.stop_button.setEnabled(False)
|
||||
self.reset_progress_display()
|
||||
|
||||
def upscale_successful(self):
|
||||
# if all threads have finished
|
||||
self.threadpool.waitForDone(5)
|
||||
self.show_information('Upscale finished successfully, taking {} seconds'.format(round((time.time() - self.begin_time), 5)))
|
||||
self.start_button.setEnabled(True)
|
||||
self.stop_button.setEnabled(False)
|
||||
self.reset_progress_display()
|
||||
|
||||
def stop(self):
|
||||
with contextlib.suppress(AttributeError):
|
||||
self.upscaler.stop_signal = True
|
||||
self.upscaler.running = False
|
||||
|
||||
def closeEvent(self, event):
|
||||
# try cleaning up temp directories
|
||||
@@ -629,7 +861,14 @@ class Video2XMainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
# this file shouldn't be imported
|
||||
if __name__ == '__main__':
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
window = Video2XMainWindow()
|
||||
window.show()
|
||||
app.exec_()
|
||||
try:
|
||||
app = QApplication(sys.argv)
|
||||
window = Video2XMainWindow()
|
||||
window.show()
|
||||
app.exec_()
|
||||
|
||||
# on GUI exception, print error message in console
|
||||
# and hold window open using input()
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
input('Press enter to close')
|
||||
|
||||
190
src/video2x_gui.pyproject.user
Normal file
190
src/video2x_gui.pyproject.user
Normal file
@@ -0,0 +1,190 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.12.0, 2020-05-11T04:13:22. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
<value type="QByteArray">{25c1e4a4-6b4a-4828-883b-6f32c3f7eba0}</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.ActiveTarget</variable>
|
||||
<value type="int">0</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.EditorSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
|
||||
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
|
||||
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
|
||||
<value type="QString" key="language">Cpp</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
|
||||
<value type="QString" key="language">QmlJS</value>
|
||||
<valuemap type="QVariantMap" key="value">
|
||||
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
|
||||
<value type="QByteArray" key="EditorConfiguration.Codec">UTF-8</value>
|
||||
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.IndentSize">4</value>
|
||||
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
|
||||
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
|
||||
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
|
||||
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
|
||||
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">true</value>
|
||||
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
|
||||
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">0</value>
|
||||
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
|
||||
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
|
||||
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
|
||||
<value type="int" key="EditorConfiguration.TabSize">8</value>
|
||||
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
|
||||
<value type="int" key="EditorConfiguration.Utf8BomBehavior">1</value>
|
||||
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
|
||||
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
|
||||
<value type="bool" key="EditorConfiguration.inEntireDocument">false</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuelist type="QVariantList" key="ClangCodeModel.CustomCommandLineKey">
|
||||
<value type="QString">-fno-delayed-template-parsing</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="ClangCodeModel.UseGlobalConfig">true</value>
|
||||
<value type="QString" key="ClangCodeModel.WarningConfigId">Builtin.Questionable</value>
|
||||
<valuemap type="QVariantMap" key="ClangTools">
|
||||
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
|
||||
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
|
||||
<value type="int" key="ClangTools.ParallelJobs">8</value>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
|
||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
<valuemap type="QVariantMap">
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop (x86-windows-msvc2019-pe-64bit)</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop (x86-windows-msvc2019-pe-64bit)</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{5450e32e-f498-4c15-a0a5-7456f3375388}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">-1</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Deploy</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
|
||||
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
<value type="QString" key="Analyzer.Perf.CallgraphMode">dwarf</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.Events">
|
||||
<value type="QString">cpu-cycles</value>
|
||||
</valuelist>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.ExtraArguments"/>
|
||||
<value type="int" key="Analyzer.Perf.Frequency">250</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Perf.RecordArguments">
|
||||
<value type="QString">-e</value>
|
||||
<value type="QString">cpu-cycles</value>
|
||||
<value type="QString">--call-graph</value>
|
||||
<value type="QString">dwarf,4096</value>
|
||||
<value type="QString">-F</value>
|
||||
<value type="QString">250</value>
|
||||
</valuelist>
|
||||
<value type="QString" key="Analyzer.Perf.SampleMode">-F</value>
|
||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||
<value type="int" key="Analyzer.Perf.StackSize">4096</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.AggregateTraces">false</value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
|
||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
|
||||
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.KCachegrindExecutable">kcachegrind</value>
|
||||
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
|
||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
||||
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
||||
<value type="int">0</value>
|
||||
<value type="int">1</value>
|
||||
<value type="int">2</value>
|
||||
<value type="int">3</value>
|
||||
<value type="int">4</value>
|
||||
<value type="int">5</value>
|
||||
<value type="int">6</value>
|
||||
<value type="int">7</value>
|
||||
<value type="int">8</value>
|
||||
<value type="int">9</value>
|
||||
<value type="int">10</value>
|
||||
<value type="int">11</value>
|
||||
<value type="int">12</value>
|
||||
<value type="int">13</value>
|
||||
<value type="int">14</value>
|
||||
</valuelist>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">video2x_gui</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">PythonEditor.RunConfiguration.C:/Users/k4yt3x/Documents/Projects/video2x/src/video2x_gui.py</value>
|
||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">C:/Users/k4yt3x/Documents/Projects/video2x/src/video2x_gui.py</value>
|
||||
<value type="bool" key="PythonEditor.RunConfiguation.Buffered">false</value>
|
||||
<value type="QString" key="PythonEditor.RunConfiguation.Interpreter">{ffc39ed5-fbe0-4af8-8b16-9a60c393bdb8}</value>
|
||||
<value type="QString" key="PythonEditor.RunConfiguation.Script">C:\Users\k4yt3x\Documents\Projects\video2x\src\video2x_gui.py</value>
|
||||
<value type="QString" key="RunConfiguration.Arguments"></value>
|
||||
<value type="bool" key="RunConfiguration.Arguments.multi">false</value>
|
||||
<value type="QString" key="RunConfiguration.OverrideDebuggerStartup"></value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory"></value>
|
||||
<value type="QString" key="RunConfiguration.WorkingDirectory.default"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||
<value type="int">1</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
<data>
|
||||
<variable>Version</variable>
|
||||
<value type="int">22</value>
|
||||
</data>
|
||||
</qtcreator>
|
||||
1173
src/video2x_gui.ui
1173
src/video2x_gui.ui
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
Name: Video2X Setup Script
|
||||
Creator: K4YT3X
|
||||
Date Created: November 28, 2018
|
||||
Last Modified: May 7, 2020
|
||||
Last Modified: May 8, 2020
|
||||
|
||||
Editor: BrianPetkovsek
|
||||
Editor: SAT3LL
|
||||
@@ -261,7 +261,7 @@ class Video2xSetup:
|
||||
# configure only the specified drivers
|
||||
if self.driver == 'all':
|
||||
template_dict['waifu2x_caffe']['path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-caffe' / 'waifu2x-caffe-cui')
|
||||
template_dict['waifu2x_converter_cpp']['path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-converter-cpp')
|
||||
template_dict['waifu2x_converter_cpp']['path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-converter-cpp' / 'waifu2x-converter-cpp')
|
||||
template_dict['waifu2x_ncnn_vulkan']['path'] = str(LOCALAPPDATA / 'video2x' / 'waifu2x-ncnn-vulkan' / 'waifu2x-ncnn-vulkan')
|
||||
template_dict['srmd_ncnn_vulkan']['path'] = str(LOCALAPPDATA / 'video2x' / 'srmd-ncnn-vulkan' / 'srmd-ncnn-vulkan')
|
||||
template_dict['anime4kcpp']['path'] = str(LOCALAPPDATA / 'video2x' / 'anime4kcpp' / 'CLI' / 'Anime4KCPP_CLI' / 'Anime4KCPP_CLI')
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Name: Waifu2x Caffe Driver
|
||||
Author: K4YT3X
|
||||
Date Created: May 3, 2020
|
||||
Last Modified: May 7, 2020
|
||||
Last Modified: May 11, 2020
|
||||
|
||||
Description: This class is a high-level wrapper
|
||||
for waifu2x-caffe.
|
||||
@@ -31,21 +31,28 @@ class WrapperMain:
|
||||
self.driver_settings = driver_settings
|
||||
self.print_lock = threading.Lock()
|
||||
|
||||
@staticmethod
|
||||
def zero_to_one_float(value):
|
||||
value = float(value)
|
||||
if value < 0.0 or value > 1.0:
|
||||
raise argparse.ArgumentTypeError(f'{value} is not between 0.0 and 1.0')
|
||||
return value
|
||||
|
||||
@staticmethod
|
||||
def parse_arguments(arguments):
|
||||
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter, add_help=False)
|
||||
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('-i', '--input', type=pathlib.Path, help='File for loading')
|
||||
# parser.add_argument('-o', '--output', type=pathlib.Path, help='File for outputting')
|
||||
parser.add_argument('-i', '--input', type=str, help=argparse.SUPPRESS) # help='File for loading')
|
||||
parser.add_argument('-o', '--output', type=str, help=argparse.SUPPRESS) # help='File for outputting')
|
||||
parser.add_argument('-p', '--passes', type=int, help='Passes for processing')
|
||||
parser.add_argument('-n', '--pushColorCount', type=int, help='Limit the number of color pushes')
|
||||
parser.add_argument('-c', '--strengthColor', type=float, help='Strength for pushing color,range 0 to 1,higher for thinner')
|
||||
parser.add_argument('-g', '--strengthGradient', type=float, help='Strength for pushing gradient,range 0 to 1,higher for sharper')
|
||||
parser.add_argument('-c', '--strengthColor', type=WrapperMain.zero_to_one_float, help='Strength for pushing color,range 0 to 1,higher for thinner')
|
||||
parser.add_argument('-g', '--strengthGradient', type=WrapperMain.zero_to_one_float, help='Strength for pushing gradient,range 0 to 1,higher for sharper')
|
||||
parser.add_argument('-z', '--zoomFactor', type=float, help='zoom factor for resizing')
|
||||
parser.add_argument('-t', '--threads', type=int, help='Threads count for video processing')
|
||||
parser.add_argument('-f', '--fastMode', action='store_true', help='Faster but maybe low quality')
|
||||
# parser.add_argument('-v', '--videoMode', action='store_true', help='Video process')
|
||||
parser.add_argument('-v', '--videoMode', action='store_true', help='Video process')
|
||||
parser.add_argument('-s', '--preview', action='store_true', help='Preview image')
|
||||
parser.add_argument('-b', '--preprocessing', action='store_true', help='Enable pre processing')
|
||||
parser.add_argument('-a', '--postprocessing', action='store_true', help='Enable post processing')
|
||||
@@ -58,7 +65,11 @@ class WrapperMain:
|
||||
parser.add_argument('-C', '--codec', type=str, help='Specify the codec for encoding from mp4v(recommended in Windows), dxva(for Windows), avc1(H264, recommended in Linux), vp09(very slow), hevc(not support in Windowds), av01(not support in Windowds) (string [=mp4v])')
|
||||
return parser.parse_args(arguments)
|
||||
|
||||
def upscale(self, input_file, output_file, zoom_factor, threads):
|
||||
def load_configurations(self, upscaler):
|
||||
self.driver_settings['zoomFactor'] = upscaler.scale_ratio
|
||||
self.driver_settings['threads'] = upscaler.processes
|
||||
|
||||
def upscale(self, input_file, output_file):
|
||||
"""This is the core function for WAIFU2X class
|
||||
|
||||
Arguments:
|
||||
@@ -71,9 +82,7 @@ class WrapperMain:
|
||||
# overwrite config file settings
|
||||
self.driver_settings['input'] = input_file
|
||||
self.driver_settings['output'] = output_file
|
||||
self.driver_settings['zoomFactor'] = zoom_factor
|
||||
self.driver_settings['threads'] = threads
|
||||
|
||||
|
||||
# Anime4KCPP will look for Anime4KCPPKernel.cl under the current working directory
|
||||
# change the CWD to its containing directory so it will find it
|
||||
if platform.system() == 'Windows':
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Name: Video2X FFmpeg Controller
|
||||
Author: K4YT3X
|
||||
Date Created: Feb 24, 2018
|
||||
Last Modified: May 7, 2020
|
||||
Last Modified: May 9, 2020
|
||||
|
||||
Description: This class handles all FFmpeg related operations.
|
||||
"""
|
||||
@@ -32,7 +32,10 @@ class Ffmpeg:
|
||||
self.ffmpeg_path = pathlib.Path(self.ffmpeg_settings['ffmpeg_path'])
|
||||
self.ffmpeg_binary = self.ffmpeg_path / 'ffmpeg'
|
||||
self.ffmpeg_probe_binary = self.ffmpeg_path / 'ffprobe'
|
||||
|
||||
# video metadata
|
||||
self.image_format = image_format
|
||||
self.intermediate_file_name = pathlib.Path(self.ffmpeg_settings['intermediate_file_name'])
|
||||
self.pixel_format = None
|
||||
|
||||
def get_pixel_formats(self):
|
||||
@@ -133,7 +136,7 @@ class Ffmpeg:
|
||||
|
||||
return(self._execute(execute))
|
||||
|
||||
def convert_video(self, framerate, resolution, upscaled_frames):
|
||||
def assemble_video(self, framerate, resolution, upscaled_frames):
|
||||
"""Converts images into videos
|
||||
|
||||
This method converts a set of images into a video
|
||||
@@ -177,12 +180,12 @@ class Ffmpeg:
|
||||
|
||||
# specify output file location
|
||||
execute.extend([
|
||||
upscaled_frames / 'no_audio.mp4'
|
||||
upscaled_frames / self.intermediate_file_name
|
||||
])
|
||||
|
||||
return(self._execute(execute))
|
||||
|
||||
def migrate_audio_tracks_subtitles(self, input_video, output_video, upscaled_frames):
|
||||
def migrate_streams(self, input_video, output_video, upscaled_frames):
|
||||
""" Migrates audio tracks and subtitles from input video to output video
|
||||
|
||||
Arguments:
|
||||
@@ -198,7 +201,7 @@ class Ffmpeg:
|
||||
|
||||
execute.extend([
|
||||
'-i',
|
||||
upscaled_frames / 'no_audio.mp4',
|
||||
upscaled_frames / self.intermediate_file_name,
|
||||
'-i',
|
||||
input_video
|
||||
])
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Name: SRMD NCNN Vulkan Driver
|
||||
Creator: K4YT3X
|
||||
Date Created: April 26, 2020
|
||||
Last Modified: May 7, 2020
|
||||
Last Modified: May 11, 2020
|
||||
|
||||
Description: This class is a high-level wrapper
|
||||
for srmd_ncnn_vulkan.
|
||||
@@ -42,8 +42,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=pathlib.Path, help='input image path (jpg/png) or directory')
|
||||
# parser.add_argument('-o', type=pathlib.Path, help='output image path (png) or directory')
|
||||
parser.add_argument('-i', type=str, help=argparse.SUPPRESS) # help='input image path (jpg/png) or directory')
|
||||
parser.add_argument('-o', type=str, help=argparse.SUPPRESS) # help='output image path (png) or directory')
|
||||
parser.add_argument('-n', type=int, choices=range(-1, 11), help='denoise level')
|
||||
parser.add_argument('-s', type=int, choices=range(2, 5), help='upscale ratio')
|
||||
parser.add_argument('-t', type=int, help='tile size (>=32)')
|
||||
@@ -53,7 +53,11 @@ class WrapperMain:
|
||||
parser.add_argument('-x', action='store_true', help='enable tta mode')
|
||||
return parser.parse_args(arguments)
|
||||
|
||||
def upscale(self, input_directory, output_directory, scale_ratio):
|
||||
def load_configurations(self, upscaler):
|
||||
self.driver_settings['s'] = int(upscaler.scale_ratio)
|
||||
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
|
||||
|
||||
def upscale(self, input_directory, output_directory):
|
||||
"""This is the core function for SRMD ncnn Vulkan class
|
||||
|
||||
Arguments:
|
||||
@@ -65,7 +69,6 @@ class WrapperMain:
|
||||
# overwrite config file settings
|
||||
self.driver_settings['i'] = input_directory
|
||||
self.driver_settings['o'] = output_directory
|
||||
self.driver_settings['s'] = scale_ratio
|
||||
|
||||
# by default, srmd-ncnn-vulkan will look for the models under the current working directory
|
||||
# change the working directory to its containing folder if model directory not specified
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Name: Waifu2x Caffe Driver
|
||||
Author: K4YT3X
|
||||
Date Created: Feb 24, 2018
|
||||
Last Modified: May 7, 2020
|
||||
Last Modified: May 11, 2020
|
||||
|
||||
Description: This class is a high-level wrapper
|
||||
for waifu2x-caffe.
|
||||
@@ -53,36 +53,30 @@ class WrapperMain:
|
||||
parser.add_argument('-w', '--scale_width', type=int, help='custom scale width')
|
||||
parser.add_argument('-s', '--scale_ratio', type=float, help='custom scale ratio')
|
||||
parser.add_argument('-n', '--noise_level', type=int, choices=range(4), help='noise reduction level')
|
||||
parser.add_argument('-m', '--mode', choices=['noise', 'scale', 'noise_scale'], help='image processing mode')
|
||||
parser.add_argument('-e', '--output_extension', type=str, help='extention to output image file when output_path is (auto) or input_path is folder')
|
||||
parser.add_argument('-m', '--mode', choices=['noise', 'scale', 'noise_scale', 'auto_scale'], help='image processing mode')
|
||||
parser.add_argument('-e', '--output_extention', type=str, help='extention to output image file when output_path is (auto) or input_path is folder')
|
||||
parser.add_argument('-l', '--input_extention_list', type=str, help='extention to input image file when input_path is folder')
|
||||
# parser.add_argument('-o', '--output', type=pathlib.Path, help='path to output image file (when input_path is folder, output_path must be folder)')
|
||||
# parser.add_argument('-i', '--input_file', type=pathlib.Path, help='(required) path to input image file')
|
||||
parser.add_argument('-o', '--output', type=str, help=argparse.SUPPRESS) # help='path to output image file (when input_path is folder, output_path must be folder)')
|
||||
parser.add_argument('-i', '--input_file', type=str, help=argparse.SUPPRESS) # help='(required) path to input image file')
|
||||
return parser.parse_args(arguments)
|
||||
|
||||
def upscale(self, input_directory, output_directory, scale_ratio, scale_width, scale_height, image_format, bit_depth):
|
||||
"""This is the core function for WAIFU2X class
|
||||
def load_configurations(self, upscaler):
|
||||
# use scale width and scale height if specified
|
||||
self.driver_settings['scale_ratio'] = upscaler.scale_ratio
|
||||
self.driver_settings['output_extention'] = upscaler.image_format
|
||||
|
||||
Arguments:
|
||||
input_directory {string} -- source directory path
|
||||
output_directory {string} -- output directory path
|
||||
width {int} -- output video width
|
||||
height {int} -- output video height
|
||||
# bit_depth will be 12 at this point
|
||||
# it will up updated later
|
||||
self.driver_settings['output_depth'] = 12
|
||||
|
||||
def upscale(self, input_directory, output_directory):
|
||||
""" start upscaling process
|
||||
"""
|
||||
|
||||
# overwrite config file settings
|
||||
self.driver_settings['input_path'] = input_directory
|
||||
self.driver_settings['output_path'] = output_directory
|
||||
|
||||
if scale_ratio:
|
||||
self.driver_settings['scale_ratio'] = scale_ratio
|
||||
elif scale_width and scale_height:
|
||||
self.driver_settings['scale_width'] = scale_width
|
||||
self.driver_settings['scale_height'] = scale_height
|
||||
|
||||
self.driver_settings['output_extention'] = image_format
|
||||
self.driver_settings['output_depth'] = bit_depth
|
||||
|
||||
# list to be executed
|
||||
# initialize the list with waifu2x binary path as the first element
|
||||
execute = [self.driver_settings.pop('path')]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Name: Waifu2x Converter CPP Driver
|
||||
Author: K4YT3X
|
||||
Date Created: February 8, 2019
|
||||
Last Modified: May 7, 2020
|
||||
Last Modified: May 11, 2020
|
||||
|
||||
Description: This class is a high-level wrapper
|
||||
for waifu2x-converter-cpp.
|
||||
@@ -45,7 +45,7 @@ class WrapperMain:
|
||||
parser.add_argument('-l', '--list-processor', action='store_true', help='dump processor list')
|
||||
parser.add_argument('-f', '--output-format', choices=['png', 'jpg'], help='The format used when running in recursive/folder mode\nSee --list-supported-formats for a list of supported formats/extensions.')
|
||||
parser.add_argument('-c', '--png-compression', type=int, choices=range(10), help='Set PNG compression level (0-9), 9 = Max compression (slowest & smallest)')
|
||||
parser.add_argument('-q', '--image-quality', type=int, choices=range(100), help='JPEG & WebP Compression quality (0-101, 0 being smallest size and lowest quality), use 101 for lossless WebP')
|
||||
parser.add_argument('-q', '--image-quality', type=int, choices=range(-1, 102), help='JPEG & WebP Compression quality (0-101, 0 being smallest size and lowest quality), use 101 for lossless WebP')
|
||||
parser.add_argument('--block-size', type=int, help='block size')
|
||||
parser.add_argument('--disable-gpu', action='store_true', help='disable GPU')
|
||||
parser.add_argument('--force-OpenCL', action='store_true', help='force to use OpenCL on Intel Platform')
|
||||
@@ -61,12 +61,17 @@ class WrapperMain:
|
||||
parser.add_argument('-g', '--generate-subdir', type=int, choices=range(2), help='Generate sub folder when recursive directory is enabled.')
|
||||
parser.add_argument('-a', '--auto-naming', type=int, choices=range(2), help='Add postfix to output name when output path is not specified.\nSet 0 to disable this.')
|
||||
parser.add_argument('-r', '--recursive-directory', type=int, choices=range(2), help='Search recursively through directories to find more images to process.')
|
||||
# parser.add_argument('-o', '--output', type=pathlib.Pathh, help='path to output image file or directory (you should use the full path)')
|
||||
# parser.add_argument('-i', '--input', type=pathlib.Path, help='(required) path to input image file or directory (you should use the full path)')
|
||||
parser.add_argument('-o', '--output', type=str, help=argparse.SUPPRESS) # help='path to output image file or directory (you should use the full path)')
|
||||
parser.add_argument('-i', '--input', type=str, help=argparse.SUPPRESS) # help='(required) path to input image file or directory (you should use the full path)')
|
||||
parser.add_argument('--version', action='store_true', help='Displays version information and exits.')
|
||||
return parser.parse_args(arguments)
|
||||
|
||||
def upscale(self, input_directory, output_directory, scale_ratio, jobs, image_format):
|
||||
def load_configurations(self, upscaler):
|
||||
self.driver_settings['scale-ratio'] = upscaler.scale_ratio
|
||||
self.driver_settings['jobs'] = upscaler.processes
|
||||
self.driver_settings['output-format'] = upscaler.image_format.lower()
|
||||
|
||||
def upscale(self, input_directory, output_directory):
|
||||
""" Waifu2x Converter Driver Upscaler
|
||||
This method executes the upscaling of extracted frames.
|
||||
|
||||
@@ -80,9 +85,6 @@ class WrapperMain:
|
||||
# overwrite config file settings
|
||||
self.driver_settings['input'] = input_directory
|
||||
self.driver_settings['output'] = output_directory
|
||||
self.driver_settings['scale-ratio'] = scale_ratio
|
||||
self.driver_settings['jobs'] = jobs
|
||||
self.driver_settings['output-format'] = image_format
|
||||
|
||||
# models_rgb must be specified manually for waifu2x-converter-cpp
|
||||
# if it's not specified in the arguments, create automatically
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Name: Waifu2x NCNN Vulkan Driver
|
||||
Creator: SAT3LL
|
||||
Date Created: June 26, 2019
|
||||
Last Modified: May 7, 2020
|
||||
Last Modified: May 11, 2020
|
||||
|
||||
Editor: K4YT3X
|
||||
Last Modified: February 22, 2020
|
||||
@@ -45,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=pathlib.Path, help='input image path (jpg/png) or directory')
|
||||
# parser.add_argument('-o', type=pathlib.Path, help='output image path (png) or directory')
|
||||
parser.add_argument('-i', type=str, help=argparse.SUPPRESS) # help='input image path (jpg/png) or directory')
|
||||
parser.add_argument('-o', type=str, help=argparse.SUPPRESS) # help='output image path (png) or directory')
|
||||
parser.add_argument('-n', type=int, choices=range(-1, 4), help='denoise level')
|
||||
parser.add_argument('-s', type=int, choices=range(1, 3), help='upscale ratio')
|
||||
parser.add_argument('-t', type=int, help='tile size (>=32)')
|
||||
@@ -56,7 +56,11 @@ class WrapperMain:
|
||||
parser.add_argument('-x', action='store_true', help='enable tta mode')
|
||||
return parser.parse_args(arguments)
|
||||
|
||||
def upscale(self, input_directory, output_directory, scale_ratio):
|
||||
def load_configurations(self, upscaler):
|
||||
self.driver_settings['s'] = int(upscaler.scale_ratio)
|
||||
self.driver_settings['j'] = '{}:{}:{}'.format(upscaler.processes, upscaler.processes, upscaler.processes)
|
||||
|
||||
def upscale(self, input_directory, output_directory):
|
||||
"""This is the core function for WAIFU2X class
|
||||
|
||||
Arguments:
|
||||
@@ -68,7 +72,6 @@ class WrapperMain:
|
||||
# overwrite config file settings
|
||||
self.driver_settings['i'] = input_directory
|
||||
self.driver_settings['o'] = output_directory
|
||||
self.driver_settings['s'] = int(scale_ratio)
|
||||
|
||||
# by default, waifu2x-ncnn-vulkan will look for the models under the current working directory
|
||||
# change the working directory to its containing folder if model directory not specified
|
||||
|
||||
Reference in New Issue
Block a user