NMM碗柜:http://nmm.me/z4
我的所有avsi脚本所需滤镜(Requirements)打包下载(文件夹分享):http://pan.baidu.com/s/1Bt2fY
简要说明
函数名nnedi3_resize16()
以upscale(resize)以及chroma resample为目的的脚本。
从v3.0开始仅支持AviSynth 2.6及以上版本。
原理
upscale时对edge部分使用nnedi3进行插补,然后用16bit resizer修正shift并可以进行浮点精度的crop、pad以及更精细的大小调整,对flat区域使用16bit resizer。
downscale时则是对整个画面使用16bit resizer,不再使用nnedi3。
能有效改善flat区域用8bit resizer时因精度不足而产生的banding,并且对于flat区域使用的B-Spline的质量也比nnedi3中的Bicubic高一些。
有个参数ratiothr用于是否使用nnedi3的判断控制,默认值1.125——当某个方向上的缩放系数大于1.125时在这个方向上使用2倍的nnedi3(一次nnedi3插补),小于等于1.125时直接使用16bit resizer,当某个方向上缩放系数大于2.25时在这个方向上使用4倍的nnedi3(两次nnedi3插补),当某个方向上缩放系数大于4.5时在这个方向上使用8倍的nnedi3(三次nnedi3插补)……
v1.1增加两个函数nnedi3_444resize16和nnedi3_420to444,前者用于对YV24的源进行resize,后者用于将YV12的源转换为YV24/RGB24/RGB32/RGB48Y/RGB48YV12。
这两个函数均基于nnedi3_resize16实现。
v2.0整个函数全部重写,核心部分从原先使用的nnedi3_rpow2更换为nnedi3(dh=true)——也就是nnedi3_rpow2内部的实现方式,这样可以实现更自由与高效的调整与变换——resize、chroma resample可以一步完成,横向和纵向的缩放也能够自动根据缩放比例分别调整使用nnedi3(dh=true)的次数。
同时重点在于专门针对luma与chroma在interpolation以及colorspace转换后产生的shift进行修正——为了计算这些五花八门的组合产生的shift值至少花了6个小时……所以chroma subsampling必须死。
v2.4优化了旋转部分的代码并加入了对FTurn的支持,当载入FTurn时使用速度更快的FTurn,没有载入时则仍然使用AVS内置的Turn。同时加入了mixed参数,默认情况下为true,设为false可以取消对于flat区域单独resize的处理,在常见使用情况下速度有2-8倍的提升,对于质量要求不是非常高的人可以通过设置这个参数有效提升运行速度。
v2.5增加了对Dither_resize16部分使用gamma-aware resize的支持,新增参数curve与gcor,与Dither_y_gamma_to_linear和Dither_y_linear_to_gamma中的相应参数意义相同。curve默认为"linear"也就是不考虑gamma,设为"709"、"2020"、"srgb"、"240"则为对应的gamma-aware处理,gcor通常情况下不需要设置。
gamma的概念及它给图像处理带来的相关问题
不过实际使用中不推荐在upscale时使用nnedi3_resize16的gamma-aware处理,一方面是因为upscale时起主要作用的nnedi3部分并不是gamma-aware的(nnedi3只能输入输出8bit,使用linear colorspace精度不够),另一方面是根据实际测试,对于一般的resizer使用gamma-aware upscale时会产生更多的ringing和aliasing,副作用大于正面作用。
另外要注意的一点就是由于gamma compression往往是在RGB下完成的,如果要进行gamma-aware的处理最好也是在RGB下,所以可以将输入源转成RGB48Y后输入给nnedi3_resize16进行gamma-aware downscale,之后再根据需要转回YUV444/YUV420
CODEBOX_PLUS_CODE: [全选]
[CODEBOX_PLUS_EXPAND/CODEBOX_PLUS_COLLAPSE]
XXXSource("xxx.xxx")
# 1920x1080 8bit YUV 4:2:0 - input
output_width = 1280
output_height = 720
input_tvrange = True
output_tvrange = True
input_matrix = "709"
output_matrix = "709"
input_transfer = "709"
output_colorspace = "YV24"
# You can achieve matrix & TV/PC range conversion here
nnedi3_resize16(lsb_in=False, tv_range=input_tvrange, matrix=input_matrix, output="RGB48Y")
# 1920x1080 stacked-16bit RGB conveyed on Y of YV12
nnedi3_resize16(output_width, output_height, lsb_in=True, lsb=True, tv_range=False, curve=input_transfer, Y=3, U=1, V=1)
# 1280x720 stacked-16bit RGB conveyed on Y of YV12
# Here for RGB48Y input, nnedi3_resize16 processes it the same as YV12, so we set "U=1, V=1" and don't set "output" here.
Dither_convert_rgb_to_yuv(SelectEvery(3, 0), SelectEvery(3, 1), SelectEvery(3, 2), lsb=True, tv_range=output_tvrange, output=output_colorspace)
# 1280x720 stacked-16bit YUV 4:4:4
Down10(TVrange=output_tvrange, stack=False)
# 1280x720 interleaved-10bit YUV 4:4:4 - output
# 1920x1080 8bit YUV 4:2:0 - input
output_width = 1280
output_height = 720
input_tvrange = True
output_tvrange = True
input_matrix = "709"
output_matrix = "709"
input_transfer = "709"
output_colorspace = "YV24"
# You can achieve matrix & TV/PC range conversion here
nnedi3_resize16(lsb_in=False, tv_range=input_tvrange, matrix=input_matrix, output="RGB48Y")
# 1920x1080 stacked-16bit RGB conveyed on Y of YV12
nnedi3_resize16(output_width, output_height, lsb_in=True, lsb=True, tv_range=False, curve=input_transfer, Y=3, U=1, V=1)
# 1280x720 stacked-16bit RGB conveyed on Y of YV12
# Here for RGB48Y input, nnedi3_resize16 processes it the same as YV12, so we set "U=1, V=1" and don't set "output" here.
Dither_convert_rgb_to_yuv(SelectEvery(3, 0), SelectEvery(3, 1), SelectEvery(3, 2), lsb=True, tv_range=output_tvrange, output=output_colorspace)
# 1280x720 stacked-16bit YUV 4:4:4
Down10(TVrange=output_tvrange, stack=False)
# 1280x720 interleaved-10bit YUV 4:4:4 - output
参数中tv_range不仅对于YUV——RGB转换、gamma-aware处理起作用,同时对于8bit——16bit转换也有作用,当tv_range=False时会调用SmoothCurve16进行正确的bit depth转换,所以Requirements包括了SmoothAdjust。
核心处理部分
前6个参数的意义和一般的resizer相同,分别为target_width, target_height, src_left, src_top, src_width, src_height。
其他的具体参数的说明见脚本内部的注释。
merge相关
thr: 值有效范围为(0, 10.0],具体作用和Dither_limit_dif16的thr相同。默认为1.0。
elast:值有效范围为[1, 10.0],具体作用和Dither_limit_dif16的elast相同。默认为1.5。
v3.0开始放弃了原先使用的mask merge方式来结合nnedi3和Dither_resize16的结果,而改用Dither_limit_dif16根据像素的差值来结合两者的结果。
具体处理原理:
当nnedi3处理得到的像素值与Dither_resize16处理得到的像素值相差小于等于thr(8bit scale)时取Dither_resize16的结果,相差大于thr*elast时取nnedi3的结果,相差在thr和thr*elast之间时为两个结果的混合。
YUV平面的设置
Y/U/V三个参数控制是否处理各个平面,3为处理,2为不处理,1为完全不管输出的结果。默认Y=3、U=3、V=3,也就是处理全部平面。
输入输出的设置
lsb_in默认false,决定输入的clip是否为16bit stack格式。
lsb默认false,决定输出的clip是否为16bit stack格式。内部处理精度始终为16bit,此参数仅影响输出精度。
dither默认6,设置16bit降至8bit时使用的dither方式,等于DitherPost中的mode参数。
show默认false,设为true时输出edge mask,可以用于预览并调整mask相关的参数。
example
对8bit 1920x1080的输入视频做resize到3840x2160并输出16bit,然后降为10bit输出给x264。
CODEBOX_PLUS_CODE: [全选]
[CODEBOX_PLUS_EXPAND/CODEBOX_PLUS_COLLAPSE]
XXXSource("xxx.xxx")
# 1920x1080 8bit YUV 4:2:0 - input
nnedi3_resize16(3840, 2160, lsb_in=False, lsb=True)
# 3840x2160 stacked-16bit YUV 4:2:0
Down10(stack=False)
# 3840x2160 interleaved-10bit YUV 4:2:0 - output
# 1920x1080 8bit YUV 4:2:0 - input
nnedi3_resize16(3840, 2160, lsb_in=False, lsb=True)
# 3840x2160 stacked-16bit YUV 4:2:0
Down10(stack=False)
# 3840x2160 interleaved-10bit YUV 4:2:0 - output
CODEBOX_PLUS_CODE: [全选]
[CODEBOX_PLUS_EXPAND/CODEBOX_PLUS_COLLAPSE]
XXXSource("xxx.xxx")
# 1920x1080 8bit YUV 4:2:0 - input
nnedi3_resize16(3840, 2160, lsb_in=False, lsb=True, mixed=False)
# 3840x2160 stacked-16bit YUV 4:2:0
Down10(stack=False)
# 3840x2160 interleaved-10bit YUV 4:2:0 - output
# 1920x1080 8bit YUV 4:2:0 - input
nnedi3_resize16(3840, 2160, lsb_in=False, lsb=True, mixed=False)
# 3840x2160 stacked-16bit YUV 4:2:0
Down10(stack=False)
# 3840x2160 interleaved-10bit YUV 4:2:0 - output
尽管nnedi3_resize16可以直接输出RGB48YV12,但是由于目前AvsPmod是通过avs脚本中的Dither_convert_yuv_to_rgb来判断输出是否为RGB48YV12,所以这里我们先通过nnedi3_resize16将420输入转为444,再单独使用Dither_convert_yuv_to_rgb转为RGB48YV12——方法、结果和nnedi3_resize16内部转换是一样的,然后就可以通过AvsPmod的截图功能得到16bit PNG了。
CODEBOX_PLUS_CODE: [全选]
[CODEBOX_PLUS_EXPAND/CODEBOX_PLUS_COLLAPSE]
XXXSource("xxx.xxx")
# 8bit YUV 4:2:0 - input
nnedi3_resize16(lsb_in=False, lsb=True, output="YV24")
# stacked-16bit YUV 4:4:4
Dither_convert_yuv_to_rgb(lsb_in=True, output="RGB48YV12")
# RGB48 conveyed on YV12 - output
# 8bit YUV 4:2:0 - input
nnedi3_resize16(lsb_in=False, lsb=True, output="YV24")
# stacked-16bit YUV 4:4:4
Dither_convert_yuv_to_rgb(lsb_in=True, output="RGB48YV12")
# RGB48 conveyed on YV12 - output
CODEBOX_PLUS_CODE: [全选]
[CODEBOX_PLUS_EXPAND/CODEBOX_PLUS_COLLAPSE]
ImageSource("xxx.png")
# 8bit RGB (RGB24/RGB32) - input
Interleave(ShowRed("Y8"), ShowGreen("Y8"), ShowBlue("Y8"))
# 8bit RGB in Y8
U16(TVrange=False)
# stacked-16bit RGB in Y8 (RGB48Y)
nnedi3_resize16(3840, 2160, lsb_in=True, lsb=True, tv_range=False)
# scaling
Down10(8, TVrange=False)
# 8bit RGB in Y8
MergeRGB(SelectEvery(3, 0), SelectEvery(3, 1), SelectEvery(3, 2), "RGB24")
# 8bit RGB (RGB24) - output
# 8bit RGB (RGB24/RGB32) - input
Interleave(ShowRed("Y8"), ShowGreen("Y8"), ShowBlue("Y8"))
# 8bit RGB in Y8
U16(TVrange=False)
# stacked-16bit RGB in Y8 (RGB48Y)
nnedi3_resize16(3840, 2160, lsb_in=True, lsb=True, tv_range=False)
# scaling
Down10(8, TVrange=False)
# 8bit RGB in Y8
MergeRGB(SelectEvery(3, 0), SelectEvery(3, 1), SelectEvery(3, 2), "RGB24")
# 8bit RGB (RGB24) - output
Changelog
v1.0
Release
v1.1
增加两个函数nnedi3_444resize16和nnedi3_420to444,前者用于对YV24的源进行resize,后者用于将YV12的源转换为YV24/RGB24/RGB32/RGB48Y。
v2.0
整个函数全部重写,核心部分从原先使用的nnedi3_rpow2更换为nnedi3(dh=true)——也就是nnedi3_rpow2内部的实现方式,这样可以实现更自由与高效的调整与变换——resize、chroma resample可以一步完成,横向和纵向的缩放也能够自动根据缩放比例分别调整使用nnedi3(dh=true)的次数。
同时重点在于专门针对luma与chroma在interpolation以及colorspace转换后产生的shift进行修正——为了计算这些五花八门的组合产生的shift值至少花了6个小时……所以chroma subsampling必须死。
现在nnedi3_resize16能够直接接受YV12、YV16、YV24的输入,并能够输出YV12、YV16、YV24、RGB32、RGB24、RGB48YV12、RGB48Y。
新增的参数中tv_range不仅对于YUV——RGB转换起作用,同时对于8bit——16bit转换也有作用,当tv_range=false时会调用SmoothCurve16进行正确的bit depth转换,所以Requirements新增了SmoothAdjust。
v2.1
一个关于kernel_u和kernel_d使用选择的bug修复。
参数ratiothr的控制调整,实现更智能化的resize滤镜/nnedi3倍数选择,详见上方说明。
当Y、U、V缩放时既有upscale又有downscale时的处理速度优化,避免无意义的运算。(例如输入YV24输出YV12时进行1.5倍的upscale,这时Y是1.5倍而UV是0.75倍,所以UV可以直接取flat部分的resize结果而不需要和edge部分的resize结果进行merge)
nnedi3的质量/速度相关参数nns的默认值从原版本的4调整到3,可以提升50%的运行速度,画面在我的测试素材中基本看不出区别,当然要是觉得nnedi3_resize16不够慢可以自己手动设置参数nns=4。
v2.2
增加参数sharp,默认为0,当有用到nnedi3进行upscale时设置此参数即可调用Contra-Sharpen mod进行锐化,sharp的数值即为锐化的强度(通常使用100左右)。CSmod使用的其他参数固定,如有需要调整可自行改动脚本。此功能的加入主要是为了方便,在需要锐化时相比另外加锐化滤镜能提升一定的处理效率。
mask相关参数edgethr默认值从14调整至12,edgethrc默认值从edgethr/2调整为edgethr*2/3;增加参数edgeex,默认为true,即对edge mask覆盖范围进行扩展,可根据具体的源配合show=true参数做调整(一般DVD源设为true,我做言叶4K时用的是false,因为源本身精度较高缺陷较少,edge mask无需扩展即能覆盖需要使用nnedi3放大的区域)。
v2.3
考虑到O16mod v1.7.0中对于PC Range的bit depth conversion的改动,nnedi3_resize16中对于PC Range下的bit depth conversion也需要修正SmoothCurve16中使用的表达式,这里就是给CbCr增加了一个neutral point的限定——原先的转换方式对于CbCr的neutral point会有0.5(8bit scale)的shift。
这个改动不影响绝大部分使用情况除非你用了tv_range=false。
v2.4
优化了旋转部分的代码并加入了对FTurn的支持,当载入FTurn时使用速度更快的FTurn,没有载入时则仍然使用AVS内置的Turn。
加入了mixed参数,默认情况下为true,设为false可以取消对于flat区域单独resize的处理,在常见使用情况下速度有2-8倍的提升,对于质量要求不是非常高的人可以通过设置这个参数有效提升运行速度。
修正sharp>0时CSmod直接对stack-16bit clip处理的问题。
其他一些代码优化,尽可能减少不必要的初始化载入的滤镜以及某些特殊情况下的不必要处理。
v2.5
增加了对Dither_resize16部分使用gamma-aware resize的支持,新增参数curve与gcor,与Dither_y_gamma_to_linear和Dither_y_linear_to_gamma中的相应参数意义相同。curve默认为"linear"也就是不考虑gamma,设为"709"、"2020"、"srgb"、"240"则为对应的gamma-aware处理,gcor通常情况下不需要设置。
v2.5.1
修复v2.5里有一对Dither_y_gamma_to_linear和Dither_y_linear_to_gamma中多写了参数Y导致报错的bug。
关于gamma-aware的相关知识,上面有详细说明。
v2.6
由于SmoothAdjust更新了v2.80修改了一些参数的名字,所以v2.6也修改相应参数,不再兼容以前版本的SmoothAdjust,另外SmoothAdjust v2.60以后的avs 2.6.x的版本都是对应AviSynth 2.6 Alpha4的API,所以也请还在使用AviSynth 2.6 Alpha3的人更新到Alpha4,对应Alpha4 API的masktools也在上方提供的Requirements里包含了。
v3.0
修正v2.4引进的一个typo,它导致横向放大系数超过2.25时(横向使用两次及以上nnedi3)出现center shift。
新增Y8色彩空间输入输出的支持。
去除对AviSynth 2.5的支持,现在仅支持AviSynth 2.6。
去除原先upscale+mixed=True时使用的mask merge方式,改为使用Dither_limit_dif16来结合nnedi3和Dither_resize16的upscale结果。在我的E3-1230 V2(4c8t)上CPU占用率从17-25%提高到50-75%,1920x1080 YV12放大至3840x2160 YV12的速度从1.80fps提升到6.80fps。脚本所需滤镜去除RemoveGrain。
其他一些代码逻辑判断上的改进。
v3.1
增加更多注释并提高可读性。
新增参数f_d, f_u, taps, a1, a2, a3, invks_d, invks_u, invkstaps,加上原本就有的参数kernel_d, kernel_u,对应于Dither_resize16中的相应参数,带有_d/_u后缀的分别表示downscale/upscale时使用的值——当横向/纵向缩放系数大于ratiothr时视为upscale,否则视为downscale。
参数elast默认值由1.0改为1.5。
v3.2
由于O16mod对于PC Range下CbCr的改动,相应地改动nnedi3_resize16内部的bit depth转换函数。
修正tv_range=False时参数dither的默认值(从6改为50)。
v3.3
由于O16mod对于PC Range下CbCr的改动,相应地改动Bit Depth转换函数——将CbCr表达式超界的部分通过线性缩放限制在对应Bit Depth的上界,防止CbCr降低Bit Depth且输出为PC Range时导致Overflow。