Skip to content

风格化之水彩画

有不同的方法去实现这个效果:

方法一:保边滤波

这个原理其实就是保边滤波,不断去滤,其中可以用金字塔加速,即只对金字塔下采样后的图片进行滤波。这个推荐用 edgePreservingFilter,这是一个频率上的保边滤波,速度相当快,非常适合这种操作。

方法二:pyrMeanShiftFiltering

也可以用 pyrMeanShiftFiltering,本质上是 Meanshift + Pyramid,即这里的滤波是 MeanShift 来完成。也可以用 bilateralFilter 多次滤波。

具体原理在我的学习 OpenCV 笔记中有记录:https://github.com/masterAllen/LearnOpenCV/blob/main/details/pyrMeanShiftFilter.md

方法三:oilPainting

也可以用 xphoto 模块的 oilPainting,这个好像就是最正统的油画做法。具体原理从网上看到的是:对于每个像素,如果计算 2×size+1 窗口大小的直方图,将最常出现的值赋给该像素点,这样的结果看起来就很像油画了。

方法四:Kuwahara Filter

也有叫做 Kuwahara Filter 的滤波,它的思路是:把当前像素为中心的块分为四个子块,各自计算方差和均值,然后把方差最小的子块的均值赋给当前中心像素。

1733651087519

代码

# 频域上的保边滤波 edgePreserving;速度相当快,其中 RECURS 速度好于 NORMCONV
out1 = cv2.edgePreservingFilter(src, flags=cv2.RECURS_FILTER, sigma_s=100, sigma_r=0.5)
out2 = cv2.edgePreservingFilter(src, flags=cv2.NORMCONV_FILTER, sigma_s=100, sigma_r=0.5)

# Meanshift + Pyramid
out3 = cv2.pyrMeanShiftFiltering(src, 21, 51)
out4 = cv2.pyrMeanShiftFiltering(src, 11, 31)

# 多次在空域上保边滤波,很慢(可以用金字塔来加速)
out5 = np.copy(src)
# for _ in range(1):
#     out5 = cv2.pyrDown(out5)
for _ in range(7):
    out5 = cv2.bilateralFilter(out5, d=7, sigmaSpace=75, sigmaColor=70)
# for _ in range(1):
#     out5 = cv2.pyrUp(out5)

# OilPainting
for i in [5, 7]:
    for j in [1, 5, 10]:
        out = cv2.xphoto.oilPainting(src, size=i, dynRatio=j)
        result.append((f'oilPainint(size={i}, dynRation={j})', out))

1733651231492

Comments