只是一时兴起写一篇教程,本篇教程内容与本组压制时所采取的处理方式无绝对关系。
关于标题中的「低画质DVD源」:
因为各种关系国内一般拿不到里番DVD原盘,而只有使用hikiko123所压制的DVDRip。
而该源的画质比DVD要差非常多。
由于编写压制脚本非常复杂,本篇文章内容难以详尽,内容可能比较复杂、跳跃。
VapourSynth安装
一般使用该打包好的便携版:https://github.com/AmusementClub/tools/releases
安装微软的 Visual Studio Code
然后在拓展商店中安装Python、Pylance、Black Formatter(可选):
打开 设置 => 配置文件 => 显示配置文件内容 ,在settings.json中间添加:
{
.......
"files.associations": {
"*.vpy": "python"
},
"python.languageServer": "Pylance",
.......
}
keybindings.json中写入:
[
{
"key": "f5",
"command": "workbench.action.tasks.runTask",
"args": "vspreview"
},
]
tasks.json中写入:
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "vspreview",
"type": "shell",
"command": "${command:python.interpreterPath}",
"args": [
"-m",
"vspreview",
"\"'${file}'\"",
]
},
]
}
此时打开任意vpy文件后在vscode右下角选择解释器为便携版中python路径即可。
按下F5即可打开脚本预览。
基础处理
由于hikiko123的DVDRip存在诸多问题,一般需要进行一些处理后再超分。
import vapoursynth as vs
import mvsfunc as mvf
core = vs.core
core.max_cache_size = 4000
# OKE:INPUTFILE
src = "[230303][ばにぃうぉ~か~]OVA母乳ちゃんは射したい。#1セル版(No Watermark).mp4" # 输入
# OKE:DEBUG
debug = True
if debug != True:
debug = False
# 使用精度高的LWLibavSource读取视频
# fpsnum和fpsden相除是帧率,一定要载入准确帧率(23.976即为24000/1001)
res = core.lsmas.LWLibavSource(
src,
fpsnum=24000,
fpsden=1001,
)
# 提升精度至16bit进行后续处理
res = core.fmtc.bitdepth(res, bits=16)
# 由422提升至444
res = mvf.ToYUV(res, css="444", full=False)
# 输出视频
res.set_output(0)
其中,# OKE:INPUTFILE是标记输入文件的,OKEGui会自动替换;# OKE:DEBUG则是标记调试环境的。
按下F5就能打开vspreview进行预览:
选项功能都是比较好理解的,左下角进度条下的Output 0是当前输出节点,由于只有一个输出所以序号为0(可按数字切换输出节点)。
DVDRip是720*480,正常播放时播放器会识别像素宽高比但vspreview中不会,所以画面看上去窄了不少。
因为写set_output()有点麻烦并且有时需要快捷地调试输出效果,所以我个人会写一个专门处理输出的函数:
# 输出节点序号
output_num = 0
def c(clip: vs.VideoNode, label=None, preview=False):
global output_num
output_num += 1
# 如果label带"_diff"字样则对clip的值进行扩大,可以更清楚对比差距
if label != None and "_diff" in label:
exp = "x {value} - 10 * {value} +".format(
value=(1 << (clip.format.bits_per_sample - 1)) - 1
)
clip = clip.std.Expr([exp])
# 将label的字添加在右上角
if label != None:
clip = core.text.Text(
clip, text=label, alignment=7, scale=clip.height > 720 and 3 or 2
)
if preview:
mvf.Preview(clip, depth=8).set_output(output_num)
else:
clip.set_output(output_num)
# 输出视频
c(res, "res")
# 如果不是debug环境则输出最终结果
if not debug:
res.set_output()
这样可以在调试的时候输出res并加上角标,而在压制的时候直接输出res。
VapourSynth使用python,但就算不熟悉python也无妨,借助https://vsdb.top/上的各种滤镜很简单就能进行处理。
一些滤镜可能没有收录在vsdb上,如果需要可以谷歌或者在github上搜索。
预先处理
由于一些原因,部分片源的边界有几个像素宽的区域可能有问题,例如对于つるぺた守護騎士 エルフィナ堕ちる ~前編~:
四个边界都是有问题的——但直接这样看几乎看不出来。
Ctrl+滚轮放大到最大倍率观察左上角:
没错,有一个像素宽的区域明显很灰。
left = 1
top = 1
right = 1
bottom = 1
res = core.edgefixer.Continuity(res, left=left, top=top, right=right, bottom=bottom)
c(res, "fixedge")
一般可以考虑直接Crop剪切掉边界,或者修复这部分数据。
使用edgefixer后的效果:
然后进行抗锯齿:
import vsaa
from functools import partial
def sdaa(clip: vs.VideoNode, aatype: int = 1, sraa=None):
# 抗锯齿只对亮度平面进行处理
Y = core.std.ShufflePlanes(clip, planes=0, colorfamily=vs.GRAY)
if aatype == 1:
args = dict(field=1, dh=True, nsize=3, nns=2, qual=2)
try:
daa = partial(core.nnedi3cl.NNEDI3CL, **args)
except:
try:
daa = partial(core.znedi3.nnedi3, **args)
except:
daa = partial(core.nnedi3.nnedi3, **args)
elif aatype == 2:
args = dict(field=1, mthresh=10, lthresh=20, vthresh=20, maxd=24, nt=50)
try:
daa = partial(core.eedi2cuda.EEDI2, **args)
except:
daa = partial(core.eedi2.EEDI2, **args)
elif aatype == 3:
args = dict(field=1, dh=True, alpha=0.5, beta=0.2, gamma=20.0, nrad=3, mdis=30)
try:
daa = partial(core.eedi3m.EEDI3CL, **args)
except:
daa = partial(core.eedi3.eedi3, **args)
if aatype == 4:
aaed = vsaa.upscaled_sraa(Y, **sraa)
else:
aaed = (
daa(daa(Y).fmtc.resample(clip.width, clip.height, 0, -0.5).std.Transpose())
.fmtc.resample(clip.height, clip.width, 0, -0.5)
.std.Transpose()
)
# 对抗锯齿结果进行修复避免部分像素出错
out = core.rgvs.Repair(aaed, Y, mode=2)
out = core.std.ShufflePlanes([out, clip], [0, 1, 2], colorfamily=vs.YUV)
return out
aatype = 4 # 1:nnedi3, fast weak; 2:eedi2, balanced; 3:eedi3, slow strong; 4:sraa
sraa = dict(
rfactor=2,
ssfunc=vsaa.Nnedi3(),
aafunc=vsaa.Eedi3(),
)
res = sdaa(res, aatype=aatype, sraa=sraa)
c(res, "aa")
效果差不多是:
再是进行dehalo,一般直接使用finedehalo即可:
import havsfunc as haf
res = haf.FineDehalo(res, rx=2.0, darkstr=0, brightstr=1.0)
c(res, "dehalo")
效果为:
降噪和去色带:
Y = mvf.BM3D(core.std.ShufflePlanes(res, 0, vs.GRAY), radius1=1, sigma=2)
UV = core.knlm.KNLMeansCL(res, h=0.4, d=2, a=1, s=3, wmode=2, device_type="GPU")
res = core.std.ShufflePlanes([Y, UV], planes=[0, 1, 2], colorfamily=vs.YUV)
c(res, "denoise")
range1 = 12
y1 = 72
c1 = 48
range2 = 24
y2 = 56
c2 = 32
thr = 0.55
elast = 2.5
deband = core.neo_f3kdb.Deband(res, range1, y1, c1, c1, 0, 0, output_depth=16)
deband = core.neo_f3kdb.Deband(deband, range2, y2, c2, c2, 0, 0, output_depth=16)
res = mvf.LimitFilter(deband, res, thr=thr, thrc=thr * 0.8, elast=elast)
c(res, "deband")
经过上述所有处理后的细节效果:
这些只是简单的处理。
如果要得到更好的效果可以慢慢调试、选用效果更好(但可能降低处理速度)的滤镜。
中间一些环节可以优化,例如在处理完线条之后进行补偿性锐化(上面这个结果的锐度有些低了)。
超分
为了方便与WEB源对比,演示只超分到720p。
说明一下我个人对几个常用模型的看法:
Waifu2x,我个人最喜欢的模型,准确度够高、破坏力低,较为保守,降噪不要开2、3等级。
CUGAN,如果使用我个人推荐用legacy不要用pro,有alpha参数调节强度但推荐不要大于0.7,破坏力较强。
因为CUGAN会修特别多东西,所以用CUGAN的话大概率前面进行的处理没什么效果(全被CUGAN重新修了)。
降噪能关就关,CUGAN推测太多了关掉降噪都留不住什么噪点。
Real-ESRGAN,很多压制者都是用的这个,破坏力极强。
留不住噪点,锐度极其极其高——就算将锐度过低的DVDRip超分到720p跟WEB-DL对比,ESRGAN的线条都能细上一圈。
有一定强度的去雾效果,画面本身有一定模糊的地方会被锐化得跟常规区域锐度相近。
这些观点有明显的个人偏好,如果喜欢使用某个模型那用即可。
import vsmlrt
# scale为放大倍率,目标分辨率除以480然后向上取整即可
# noise为降噪等级
waifuarg = dict(
noise=-1,
scale=2,
model=vsmlrt.Waifu2xModel.cunet,
preprocess=False,
)
rgb = mvf.ToRGB(
res,
depth=32,
sample=vs.FLOAT,
full=False,
)
check = True
# 轮流尝试TRT、CUDA、NCNN
for i in [vsmlrt.Backend.TRT(), vsmlrt.Backend.ORT_CUDA(), vsmlrt.Backend.NCNN_VK()]:
try:
upscaled = vsmlrt.Waifu2x(rgb, **waifuarg, backend=i)
if debug:
print(i)
check = False
break
except:
continue
if check:
raise
upscaled = mvf.ToYUV(
upscaled,
full=False,
css="444",
depth=16,
sample=vs.INTEGER,
matrix=mvf.GetMatrix(res),
)
# 用常规插值降回目标分辨率
res = core.fmtc.resample(upscaled, 1280, 720)
c(res, "upscaled")
将直接使用Waifu2x进行放大、经过上述处理之后Waifu2x放大、WEB-DL进行对比:
直接进行放大时,因为DVDRip本身处理问题造成线条非常脏,这些问题也保留到了超分结果中(并且可能更难处理了)。
其中,如果halo过重可能模型会当做线条进行锐化,让结果的halo更加难看。
不过Waifu2x对比其它模型还是偏保守了,线条的锐度不够高,对比WEB-DL就显得比较糊(一方面这个WEB-DL是高画质源,本身差距太大了)。
线条锐度多少还能用锐化救一救,但是背景树叶区域算是没救了,纹理过于复杂、DVD低分辨率本身信息量不足,不是模型所能够解决的。
如果直接用Real-ESRGAN进行放大:
锐度远超WEB-DL,不少线条被涂掉并且画面模糊效果损失殆尽。
要使用Real-ESRGAN的话应该需要用各种手段限制副作用,我个人不怎么用就不清楚了。
在超分之后可以考虑使用addgrain加噪。
输出前降回420和10bit:
res = mvf.ToYUV(res, full=False, css="420")
res = core.fmtc.bitdepth(res, bits=10)
最后压制可用命令行,简单快捷的话可以使用OKEGui。
结束语
hikiko123的DVDRip真的是太烂了,怎么来都只能死马当活马医。
文中的各种处理与我们平时常用的有不少出入(出于效率考虑),毕竟直接用WEB源进行处理根本就不需要这么折磨了。
以及本篇内容只是一时兴起随便写的,极其不详尽。
还没有评论