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 18th March 2020, 19:18   #1  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,277
Working psharpen port?

Hi,
G41Fun.py (no clue what happened to the original github for this) contained a psharpen port:
Code:
def psharpen(clip, strength=25, threshold=75, ssx=1, ssy=1, dw=None, dh=None):
    """
    From https://forum.doom9.org/showthread.php?p=683344 by ilpippo80.
    Sharpeing function similar to LimitedSharpenFaster,
    performs two-point sharpening to avoid overshoot.
    
    Args:
        strength  (float) - Strength of the sharpening, 0 to 100.
        threshold (float) - Controls "how much" to be sharpened, 0 to 100.
        ssx, ssy  (float) - Supersampling factor (reduce aliasing on edges).
        dw, dh     (int)  - Output resolution after sharpening.
    """
    
    if not isinstance(clip, vs.VideoNode):
        raise TypeError("psharpen: This is not a clip!")
    
    if clip.format.sample_type != vs.INTEGER:
        raise TypeError("psharpen: clip must be of integer sample type")

    if clip.format.color_family == vs.COMPAT:
        raise TypeError("psharpen: COMPAT color family is not supported!")
    
    color = clip.format.color_family
    ow = clip.width
    oh = clip.height
    ssx = max(ssx, 1.0)
    ssy = max(ssy, 1.0)
    strength = min(max(strength, 0), 100)
    threshold = min(max(threshold, 0), 100)
    xss = m4(ow * ssx)
    yss = m4(oh * ssy)

    if dw is None:
        dw = ow

    if dh is None:
        dh = oh

    # oversampling
    if ssx > 1 or ssy > 1:
        clip = core.resize.Spline36(clip, xss, yss)
    
    tmp = core.std.ShufflePlanes(clip, [0], vs.GRAY) if color in [vs.YUV, vs.YCOCG] else clip

    # calculating the max and min in every 3*3 square
    maxi = core.std.Maximum(tmp)
    mini = core.std.Minimum(tmp)
    
    # normalizing max and val to values from 0 to (max-min)
    nmax = core.std.Expr([maxi, mini], ['x y -'])
    nval = core.std.Expr([tmp,  mini], ['x y -'])
    
    # initializing expression used to obtain the output luma value
    s = strength / 100
    t = threshold / 100
    st = 1 - (s / (s + t - s * t))
    expr = 'x y / 2 * 1 - abs {} < {} 1 = x y 2 / = 0 y 2 / ? x y / 2 * 1 - abs 1 {} - / ? x y / 2 * 1 - abs 1 {} - * {} + ? x y 2 / > 1 -1 ? * 1 + y * 2 /'
    expr = expr.format(st, s, s, t, t)

    # calculates the new luma value pushing it towards min or max
    nval = core.std.Expr([nval, nmax], [expr])
    
    # normalizing val to values from min to max
    tmp = core.std.Expr([nval, mini], ['x y +'])
    
    # resizing the image to the output resolution
    # applying the new luma value to clip
    if dw != ow or dh != oh:
        if color in [vs.YUV, vs.YCOCG]:
            tmp = core.std.ShufflePlanes([tmp, clip], [0, 1, 2], color)
        return core.resize.Spline36(tmp, dw, dh)
    elif ssx > 1 or ssy > 1:
        if color in [vs.YUV, vs.YCOCG]:
            tmp = core.std.ShufflePlanes([tmp, clip], [0, 1, 2], color)
        return core.resize.Spline36(tmp, dw, dh)
    elif color in [vs.YUV, vs.YCOCG]:
        return core.std.ShufflePlanes([tmp, clip], [0, 1, 2], color)
    else:
        return tmp
which sadly gives me tons or artifacts, even with simply scripts:

Code:
# Imports
import os
import sys
import vapoursynth as vs
core = vs.get_core()
# Import scripts folder
scriptPath = 'I:/Hybrid/64bit/vsscripts'
sys.path.append(os.path.abspath(scriptPath))
# Loading Plugins
core.std.LoadPlugin(path="I:/Hybrid/64bit/vsfilters/SourceFilter/FFMS2/ffms2.dll")
# Import scripts
import G41Fun
# Loading source using FFMS2
clip = core.ffms2.Source(source="F:/TESTCL~1/files/test.avi",cachefile="E:/Temp/avi_078c37f69bb356e7b5fa040c71584c40_853323747.ffindex",format=vs.YUV420P8,alpha=False)
# making sure input color matrix is set as 470bg
clip = core.resize.Point(clip, matrix_in_s="470bg",range_s="limited")
# making sure frame rate is set to 25
clip = core.std.AssumeFPS(clip, fpsnum=25, fpsden=1)
# Setting color range to TV (limited) range.
clip = core.std.SetFrameProp(clip=clip, prop="_ColorRange", intval=1)
# sharpening using PSharpen
clip = G41Fun.psharpen(clip=clip, ss_x=2.00, ss_y=2.00)
# Output
clip.set_output()
Anyone know of a working version of this filter?

Cu Selur
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 18th March 2020, 20:18   #2  |  Link
ChaosKing
Registered User
 
Join Date: Dec 2005
Location: Germany
Posts: 1,795
Alternative https://gist.github.com/4re/2545a281e3f17ba6ef82
__________________
AVSRepoGUI // VSRepoGUI - Package Manager for AviSynth // VapourSynth
VapourSynth Portable FATPACK || VapourSynth Database
ChaosKing is offline   Reply With Quote
Old 18th March 2020, 20:36   #3  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,277
Thanks, but sadly, I get the same artifacts with that version.

Cu Selur
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 18th March 2020, 21:16   #4  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,277
When adding:
Code:
# adjusting color space from YUV420P8 to YUV444P16 for Retinex
clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P16, range_s="limited")
# color adjustment using Retinex
clip = core.retinex.MSRCP(input=clip)
before the
psharpen call
the output seems fine.
Just using:
Code:
clip = core.resize.Bicubic(clip=clip, format=vs.YUV444P16, range_s="limited")
on the other hand doesn't. So whatever is causing the problem retinex.MSRCP somehow fixes the issue, but sadly I have no clue how to use the filter without using retinex.MSRCP before it :/

Cu Selur
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 18th March 2020, 21:59   #5  |  Link
ChaosKing
Registered User
 
Join Date: Dec 2005
Location: Germany
Posts: 1,795
I have the same problem. I'm pretty sure that psharpen was not broken last year.

EDIT: just tried my old portable fat pack from 2019-10-09, no artifacts! VS version is R47.
https://github.com/theChaosCoder/vap...eleases/tag/r2
__________________
AVSRepoGUI // VSRepoGUI - Package Manager for AviSynth // VapourSynth
VapourSynth Portable FATPACK || VapourSynth Database

Last edited by ChaosKing; 18th March 2020 at 22:05.
ChaosKing is offline   Reply With Quote
Old 19th March 2020, 11:51   #6  |  Link
gugglu
Registered User
 
Join Date: Jul 2012
Location: Nottingham
Posts: 44
hi Selur, have you tried adjusting 'strength' value's , i was surprised when jumping from strength=99 to strength=100 suddenly got rid of the artifact .

sharp = G41.psharpen(clip=input, strength=100, ssx=2.00, ssy=2.00)

psharpen port used for testing > https://github.com/amayra/G41Fun/blob/master/G41Fun.py

hope this helps
gugglu is offline   Reply With Quote
Old 19th March 2020, 12:03   #7  |  Link
ChaosKing
Registered User
 
Join Date: Dec 2005
Location: Germany
Posts: 1,795
Btw I opened a ticket for that https://github.com/vapoursynth/vapoursynth/issues/538
__________________
AVSRepoGUI // VSRepoGUI - Package Manager for AviSynth // VapourSynth
VapourSynth Portable FATPACK || VapourSynth Database
ChaosKing is offline   Reply With Quote
Old 19th March 2020, 12:12   #8  |  Link
Myrsloik
Professional Code Monkey
 
Myrsloik's Avatar
 
Join Date: Jun 2003
Location: Kinnarps Chair
Posts: 2,554
Basically the summary is: Inf and NaN behavior is undefined. Don't rely on it.
__________________
VapourSynth - proving that scripting languages and video processing isn't dead yet
Myrsloik is offline   Reply With Quote
Old 19th March 2020, 12:15   #9  |  Link
gugglu
Registered User
 
Join Date: Jul 2012
Location: Nottingham
Posts: 44
Quote:
Originally Posted by ChaosKing View Post
thanks, hopefully this issue will be fixed soon or later.
gugglu is offline   Reply With Quote
Old 19th March 2020, 16:53   #10  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,277
Thanks for all of you looking into it. (Man really happy this is not because of my system going crazy,...)

Cu Selur
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 31st October 2020, 11:52   #11  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,277
Since the issue has been marked as *fixed*
As solution it was said:
Quote:
The fix for this issue is to modify the expression so that it does not divide by zero. One approach would be to replace all instances of "x y /" with "y 0 = TRAP x y / ?". Another approach would be to add a small value to y, i.e. "x y 0 = y EPSILON + y ? /", or simply "x y EPSILON + /" if all possible values are positive.
trying to do the first adjustment I changed:
Code:
expr = 'x y / 2 * 1 - abs {} < {} 1 = x y 2 / = 0 y 2 / ? x y / 2 * 1 - abs 1 {} - / ? x y / 2 * 1 - abs 1 {} - * {} + ? x y 2 / > 1 -1 ? * 1 + y * 2 /'
to
Code:
expr = 'y 0 = TRAP x y / ? 2 * 1 - abs {} < {} 1 = x y 2 / = 0 y 2 / ? y 0 = TRAP x y / ? 2 * 1 - abs 1 {} - / ? y 0 = TRAP x y / ? 2 * 1 - abs 1 {} - * {} + ? x y 2 / > 1 -1 ? * 1 + y * 2 /'
but that gives me:
Quote:
Python exception: Expr: failed to convert 'TRAP' to float
-> could someone please share a working fix for this?
Thanks!

Cu Selur
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 31st October 2020, 12:30   #12  |  Link
Myrsloik
Professional Code Monkey
 
Myrsloik's Avatar
 
Join Date: Jun 2003
Location: Kinnarps Chair
Posts: 2,554
Your expression looks like you failed to replace the TRAP string with the actual variable value. Hence the error message.
__________________
VapourSynth - proving that scripting languages and video processing isn't dead yet
Myrsloik is offline   Reply With Quote
Old 1st November 2020, 18:29   #13  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,277
okay, so if you know how to modify it properly could you share how to do it?
__________________
Hybrid here in the forum, homepage
Selur is offline   Reply With Quote
Old 1st November 2020, 19:11   #14  |  Link
_Al_
Registered User
 
Join Date: May 2011
Posts: 321
that psharpen.py is perhaps fixed here: https://gist.github.com/4re/2545a281...sharpen-py-L64
so you might copy/paste it into G41Fun.py if using that
it uses that small epsilon value that adds it to y to avoid zero division
to modify your code that chooses TRAP value, it might need to be modified in this pattern:
Code:
TRAP=0 #or more likely max size value for a given bitdepth, or just x , really don't know now
expr =f'y 0 = {TRAP} x y / ? ......' #it uses TRAP value if y=0 or x/y  but not sure what the correct TRAP value must be
not sure what is faster, using conditions and default (TRAP), using condition and add some small value, or just add small value to y all the time (that posted fixed expression in psharpen.py) so it is never zero

Last edited by _Al_; 1st November 2020 at 19:42.
_Al_ is offline   Reply With Quote
Old 1st November 2020, 20:43   #15  |  Link
Selur
Registered User
 
Selur's Avatar
 
Join Date: Oct 2001
Location: Germany
Posts: 7,277
Thanks!
__________________
Hybrid here in the forum, homepage
Selur 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 19:40.


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