Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > VapourSynth

Reply
 
Thread Tools Search this Thread Display Modes
Old 2nd May 2017, 23:07   #1  |  Link
Frechdachs
Registered User
 
Frechdachs's Avatar
 
Join Date: May 2014
Posts: 20
Descale

https://github.com/Frechdachs/vapoursynth-descale

This plugin undoes upscaling.

Included Filters: Debilinear, Debicubic, Delanczos, Despline16, and Despline36

The code can probably be improved. This is literally babby's first C++ program.

Look at the GitHub page for an explanation of how the algorithm works.

Currently works only on GrayS, YUV444PS, and RGBS, but for convenience I've included a python wrapper which does conversion automatically and accepts YUV (every subsampling), Gray, and RGB of every bitdepth. Chroma is scaled with a normal kernel, since it almost never makes sense to use this on chroma.
As of now, if you want to use this on subsampled non center-aligned chroma, you would have to do the shifting manually with src_left.

Although it works pretty well, this is still work in progress. Currently, the vertical pass limits the speed a bit on some systems. I have to figure out how to access columns on a plane efficiently. Hints are appreciated.

TODO:

- Improve the vertical pass
- Decide wether to do the horizontal or vertical pass first depending on cost
- Clean up this mess of a code
- Maybe handle subsampled chroma

Last edited by Frechdachs; 9th May 2017 at 11:11.
Frechdachs is offline   Reply With Quote
Old 3rd May 2017, 02:45   #2  |  Link
feisty2
I'm Siri
 
feisty2's Avatar
 
Join Date: Oct 2012
Location: void
Posts: 2,633
Quote:
Currently, the vertical pass limits the speed a bit on some systems. I have to figure out how to access columns on a plane efficiently. Hints are appreciated.
probably generate a pre-transposed version of the entire frame before the actual processing,,, if u don't mind about memory usage
feisty2 is offline   Reply With Quote
Old 9th May 2017, 10:24   #3  |  Link
Frechdachs
Registered User
 
Frechdachs's Avatar
 
Join Date: May 2014
Posts: 20
https://github.com/Frechdachs/vapour...scale/releases

r2
  • Fixed a small but nasty bug in the python wrapper of Debicubic that caused c to always equal b
  • Added native support for YUV444PS and RGBS to the plugin
  • Added some sanity checks
Frechdachs is offline   Reply With Quote
Old 9th May 2017, 12:03   #4  |  Link
ChaosKing
Registered User
 
Join Date: Dec 2005
Location: Germany
Posts: 1,795
Is there a way to find out the original resolution programmatically?
__________________
AVSRepoGUI // VSRepoGUI - Package Manager for AviSynth // VapourSynth
VapourSynth Portable FATPACK || VapourSynth Database
ChaosKing is offline   Reply With Quote
Old 9th May 2017, 14:01   #5  |  Link
jackoneill
unsigned int
 
jackoneill's Avatar
 
Join Date: Oct 2012
Location: 🇪🇺
Posts: 760
Hi.

Parameters passed by reference but not modified in the function should be const. It helps readability and keeps you from accidentally modifying the parameter later.

You can sprinkle "static" over every single function except VapourSynthPluginInit. That way the compiler won't generate a public symbol. See: https://gcc.gnu.org/wiki/Visibility

https://github.com/Frechdachs/vapour...scale.cpp#L350
What is this for?

https://github.com/Frechdachs/vapour...scale.cpp#L440
You can pass NULL instead of src here. This frame doesn't need the frame properties from src. dst needs them so they're passed on to the next filter in the chain, but intermediate doesn't make it out of your filter, so it's an unnecessary allocation and copying.

https://github.com/Frechdachs/vapour...scale.cpp#L482
You can free intermediate before this if-else.

https://github.com/Frechdachs/vapour...scale.cpp#L501
The vi_dst member doesn't have to be a pointer. If you make it a plain struct and get rid of DescaleData's width and height members, vi_dst will actually be what its name suggests.

https://github.com/Frechdachs/vapour....cpp#L631-L633
This code never runs. Parameters not marked with "opt" will always be available. The VapourSynth core checks their presence before calling debilinear_create. You can safely pass NULL instead of &err.

https://github.com/Frechdachs/vapour...scale.cpp#L960
You can avoid the code duplication in all those *_create functions by using just one create function and passing the appropriate DescaleMode here instead of that nullptr. You will receive the value in the function's userData parameter.

You can make the parameter lists more readable like so:
Code:
"src:clip;"
"width:int;"
"height:int;"
"src_left:float:opt;"
"src_top:float:opt"
__________________
Buy me a "coffee" and/or hire me to write code!
jackoneill is offline   Reply With Quote
Old 11th May 2017, 02:41   #6  |  Link
Frechdachs
Registered User
 
Frechdachs's Avatar
 
Join Date: May 2014
Posts: 20
@jackoneill

Thank you! This helped a lot.

Quote:
What is this for?
That was a left-over of code that was previously there.

Quote:
You can avoid the code duplication in all those *_create functions by using just one create function and passing the appropriate DescaleMode here instead of that nullptr.
Thanks, this was really bugging me. I hope I'm doing it right™ now.



@ChaosKing

Quote:
Is there a way to find out the original resolution programmatically?
Yes. The simplest and in my opinion most reliable way is looking at the luma average of the diff between the source frame and the downscaled and upscaled version of that frame.

You can use this script for that: https://gist.github.com/kageru/549e0...09e567ed081799

Usage example:
Code:
python getnative.py --input C:/path/to/file.m2ts --frame 15000 --kernel bicubic --bicubic-b 0 --bicubic-c 0.5 --min-height 700 --max-height 1000
Make sure you read the header before trying to use it. This script uses fmtconv's resample with invks=True which is not as accurate as this plugin, but it's good enough for resolution guessing.

After the script finishes, you will get a graph like this:



You are basically looking for negative spikes.
In this example it is very obvious that the show was produced in 873p.

Keep in mind that the graph does not show the actual error, since very low values in the diff image are set to zero.

Also, this will NOT help you with finding the right kernel, even if a wrong kernel is used, these spikes are usually still there.

Last edited by Frechdachs; 11th May 2017 at 03:08.
Frechdachs is offline   Reply With Quote
Old 11th May 2017, 10:45   #7  |  Link
Myrsloik
Professional Code Monkey
 
Myrsloik's Avatar
 
Join Date: Jun 2003
Location: Kinnarps Chair
Posts: 2,554
If there's (sometimes?) such a clear spike, why can't we have a function that helps with the guessing? Or a function that can make such a nice plot at least? Seems like a useful thing to have easily available.
__________________
VapourSynth - proving that scripting languages and video processing isn't dead yet
Myrsloik is offline   Reply With Quote
Old 12th May 2017, 11:23   #8  |  Link
Frechdachs
Registered User
 
Frechdachs's Avatar
 
Join Date: May 2014
Posts: 20
What do you mean exactly? The script that I've linked does try to guess the resolution. It outputs a text file with the guessed resolution and a plot image.

Or do you mean having this script's functionality as a simple function instead of a callable script?
Frechdachs is offline   Reply With Quote
Old 12th May 2017, 20:10   #9  |  Link
MonoS
Registered User
 
Join Date: Aug 2012
Posts: 203
How does it compare against punedtree's debicubic/debilinear and firesledge's invks?
MonoS is offline   Reply With Quote
Old 12th May 2017, 20:11   #10  |  Link
Myrsloik
Professional Code Monkey
 
Myrsloik's Avatar
 
Join Date: Jun 2003
Location: Kinnarps Chair
Posts: 2,554
Quote:
Originally Posted by Frechdachs View Post
What do you mean exactly? The script that I've linked does try to guess the resolution. It outputs a text file with the guessed resolution and a plot image.

Or do you mean having this script's functionality as a simple function instead of a callable script?
Never mind, I didn't read stuff.
__________________
VapourSynth - proving that scripting languages and video processing isn't dead yet
Myrsloik is offline   Reply With Quote
Old 13th May 2017, 10:26   #11  |  Link
Frechdachs
Registered User
 
Frechdachs's Avatar
 
Join Date: May 2014
Posts: 20
Quote:
Originally Posted by MonoS View Post
How does it compare against punedtree's debicubic/debilinear and firesledge's invks?
It should work the same way as prunedtree's Debilinear and Debicubic.

I'm not sure how fmtconv's resample with invks=True does it, but it's less accurate than this plugin.
Frechdachs is offline   Reply With Quote
Old 14th May 2017, 19:22   #12  |  Link
MonoS
Registered User
 
Join Date: Aug 2012
Posts: 203
Quote:
Originally Posted by Frechdachs View Post
It should work the same way as prunedtree's Debilinear and Debicubic.

I'm not sure how fmtconv's resample with invks=True does it, but it's less accurate than this plugin.
Thanks for your response
MonoS is offline   Reply With Quote
Old 16th May 2017, 22:05   #13  |  Link
ChaosKing
Registered User
 
Join Date: Dec 2005
Location: Germany
Posts: 1,795
Does it make any sense to Descale in 16bit since the upscale was done in 8bit?

Code:
import descale as ds
clip = mvf.Depth(clip, 16)
clip = ds.Debilinear(clip, 1600,900)
__________________
AVSRepoGUI // VSRepoGUI - Package Manager for AviSynth // VapourSynth
VapourSynth Portable FATPACK || VapourSynth Database
ChaosKing is offline   Reply With Quote
Old 18th May 2017, 13:01   #14  |  Link
jackoneill
unsigned int
 
jackoneill's Avatar
 
Join Date: Oct 2012
Location: 🇪🇺
Posts: 760
Quote:
Originally Posted by ChaosKing View Post
Does it make any sense to Descale in 16bit since the upscale was done in 8bit?

Code:
import descale as ds
clip = mvf.Depth(clip, 16)
clip = ds.Debilinear(clip, 1600,900)
It does not. You now have two bit depth conversions. First from 8 to 16, then from 16 to float. If you call ds.Debilinear directly, you get a single conversion, from 8 to float.
__________________
Buy me a "coffee" and/or hire me to write code!
jackoneill is offline   Reply With Quote
Old 26th August 2019, 02:49   #15  |  Link
lansing
Registered User
 
Join Date: Sep 2006
Posts: 1,657
I came to an anime site where I want to save their high quality screenshots, but the image url that they use are a resizer that split out resized images from the input arguments. For example, this, I can input any dimension in the url and its will just give me the image in that resolution. I couldn't find the original dimension.

I am using the python script getnative to find the original resolution, but I don't know which is the right kernel to use. For the image above for example, I'm getting different result

Code:
$ python getnative.py test8.jpg -k bilinear
Script exceeded memory limit. Consider raising cache size.
Using ffms2 as source filter
501/501
Kernel: bilinear AR: 1.33
Native resolution(s) (best guess): 720p, 900p
Code:
$ python getnative.py test8.jpg -k bicubic
Script exceeded memory limit. Consider raising cache size.
Using ffms2 as source filter
501/501
Kernel: bicubic AR: 1.33 B: 0.33 C: 0.33
Native resolution(s) (best guess): 900p, 992p, 638p
I'm suspecting the original resolution to be 720p or 900p, but I don't know which one is the right one.
lansing is offline   Reply With Quote
Old 26th August 2019, 15:07   #16  |  Link
jackoneill
unsigned int
 
jackoneill's Avatar
 
Join Date: Oct 2012
Location: 🇪🇺
Posts: 760
Bilinear does not look very good, so you can tell by looking at the result.

1. Ask for 720p and save that image for testing.

2. Upscale that image yourself with bilinear and with bicubic to something like 3x larger.

3. Ask for 3x larger and compare what you receive with the images from 2.
__________________
Buy me a "coffee" and/or hire me to write code!
jackoneill is offline   Reply With Quote
Old 26th August 2019, 23:09   #17  |  Link
lansing
Registered User
 
Join Date: Sep 2006
Posts: 1,657
Quote:
Originally Posted by jackoneill View Post
Bilinear does not look very good, so you can tell by looking at the result.

1. Ask for 720p and save that image for testing.

2. Upscale that image yourself with bilinear and with bicubic to something like 3x larger.

3. Ask for 3x larger and compare what you receive with the images from 2.
I upscaled the 720p image 3x to 2880 x 2160 using photoshop. The 3x one from the site is a lot sharper and has more details in comparison.
lansing is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 13:43.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.