在 VapourSynth 中使用 OpenCV Python - WolframRhodium/muvsfunc GitHub Wiki
在 VapourSynth 中使用 OpenCV-Python
本教程讲述 OpenCV-Python 在 VapourSynth 中的安装与使用。
通过 pip 安装
安装部分针对 Windows 平台,不过其他平台上的安装方法应该是类似的。
-
安装 pip (如果你正常安装了 Python,它应该也被安装了) 并确保它能正确工作 (例如, 在 shell 中输入
pip -V
以检查 pip 的版本)。 -
编译 NumPy 和 OpenCV-Python, 或者从 NumPy 和 OpenCV-Python 下载预编译的包。
-
在 shell 中输入
pip install *.whl
安装两个库。 -
在 Python 终端中输入
import numpy as np
print(np.__version__)
import cv2
print(cv2.__version__)
检查安装情况。
在 VapourSynth 中使用 OpenCV-Python
因为 OpenCV-Python 中的函数只作用于 NumPy 的数组,所以它们不能直接通过 clip = cv2.GaussianBlur(clip)
的形式来直接调用。
我已经写了支持脚本 muvsfunc_numpy.py 以简化调用过程。
为了让 OpenCV-Python 中的函数能在 VapourSynth 下使用,你只需要定义一个输入一个或多个 NumPy 数组、并输出一个 NumPy 数组的函数(流水线),正如下面的例子所展示的那样。
值得一提的是,不同的 OpenCV-Python 的函数对于输入的格式有不同的限制。使用前你最好在 OpenCV 官方文档 中确认这些限制。
在以下样例中,我假定已通过以下代码导入库
import numpy as np
import cv2
import muvsfunc_numpy as mufnp
在灰度图上的高斯模糊
纯 VapourSynth 版:
sigma = 1.0
output = core.tcanny.TCanny(gray, sigma=sigma, mode=-1)
OpenCV-Python 版:
sigma = 1.0
ksize = (round(sigma*3)*2+1, round(sigma*3)*2+1)
gaussian_core = lambda img: cv2.GaussianBlur(img, ksize=ksize, sigmaX=sigma)
output = mufnp.numpy_process(gray, gaussian_core)
我喜欢在函数名的后面加上 _core
来表示它的输入输出是 NumPy 中的数据。
Domain Transform 增强 RGB 图像
使用据我所知,在 VapourSynth 上还没有 DT 这个函数的实现。 因此,有着大量函数的 OpenCV-Python 极大地增加了滤镜的选择。
OpenCV-Python 版:
# enhance_core = lambda img: cv2.detailEnhance(img)
enhace_core = cv2.detailEnhance # 使用别名
output = mufnp.numpy_process(rgb, gaussian_core, input_per_plane=False, output_per_plane=False)
# 因为我们同时处理三个平面,所以 ***_per_plane=False 是必要的
Canny 边缘检测算子
同属于 OpenCV-Python 的滤镜可以被放在单独的一个函数中。这提供了使用复杂流水线的方法,同时也可能提升性能。
纯 VapourSynth 版:
sigma = 1.0
output = core.tcanny.TCanny(gray, sigma=sigma, mode=0)
OpenCV-Python 版:
# 现在我们显式定义一个函数,而不是使用匿名函数来定义
def canny_core(img):
blur = cv2.GaussianBlur(img, ksize=(7, 7), sigmaX=1)
edge = cv2.Canny(blur, threshold1=1.0, threshold2=8.0)
return edge
output = mufnp.numpy_process(gray, canny_core)
(两者的输出不同。我不知道也不关心为什么会这样。)
Resize
纯 VapourSynth 版:
output = core.resize.Bicubic(gray, 1280, 720)
对于 OpenCV-Python 中的 resize 等改变输出的格式的操作,需要对 mufnp.numpy_process
的输入进行特殊处理,就像下面所展示的那样,因为 VapourSynth 的 std.ModifyFrame 要求输入输出的格式必须相同。
OpenCV-Python v1版:
def resize_core1(blank, img):
return cv2.resize(img, dsize=(blank.shape[1], blank.shape[0]), interpolation=cv2.INTER_CUBIC)
blank_clip = core.std.BlankClip(gray, width=1280, height=720)
output = mufnp.numpy_process([blank_clip, gray], resize_core1)
OpenCV-Python v2版:
def resize_core2(img, w, h):
return cv2.resize(img, dsize=(w, h), interpolation=cv2.INTER_CUBIC)
blank_clip = core.std.BlankClip(gray, width=1280, height=720)
output = mufnp.numpy_process([blank_clip, gray], resize_core2, w=1280, h=720, omit_first_clip=True)
(再一次,两者的输出不同。)
铅笔画化
OpenCV-Python 版(灰度输出):
pencil_core1 = lambda img: cv2.pencilSketch(img)[0]
blank_clip = core.std.BlankClip(rgb, format=vs.GRAY8)
output = mufnp.numpy_process([blank_clip, rgb], pencil_core1, input_per_plane=False, omit_first_clip=True)
OpenCV-Python 版(彩色输出)
pencil_core2 = lambda img: cv2.pencilSketch(img)[1]
output = mufnp.numpy_process(rgb, pencil_core2, input_per_plane=False, output_per_plane=False)
引导滤波
OpenCV-Python 版(使用灰度图引导 RGB 上的处理):
gf_core = lambda img, guide: cv2.ximgproc.guidedFilter(guide, img, radius=4, eps=100)
output = mufnp.numpy_process([rgb, gray], gf_core, input_per_plane=False, output_per_plane=False)
OpenCV-Python 版(使用 RGB 引导 RGB 上的处理):
gf_core = lambda img, guide: cv2.ximgproc.guidedFilter(guide, img, radius=4, eps=100)
output = mufnp.numpy_process([rgb, rgb], gf_core, input_per_plane=False, output_per_plane=False)
图像修复
OpenCV-Python 版:
def inpaint_core(img, mask, radius=1, flags=cv2.INPAINT_NS):
return cv2.inpaint(img, mask, inpaintRadius=radius, flags=flags)
inpainting = mufnp.numpy_process([gray, mask], inpaint_core, radius=1, flags=cv2.INPAINT_NS)
inpainting = core.std.MaskedMerge(gray, inpainting, mask)
限制
- 现在时域的函数不能正常工作。具体来说,我不知道怎么在 std.ModifyFrame 这个支持函数中使用它们。