opencv高斯模糊_高斯模糊加速及其实现

opencv高斯模糊_高斯模糊加速及其实现_第1张图片

高斯模糊在图像处理中有着非常重要的作用,例如在构建拉普拉斯金字塔时,高斯模糊是核心操作,但是高斯模糊本身比较耗时。本文讲解一个加速高斯模糊的方法,同时会讲一些相关的操作,最后会给出完整的代码。

1、高斯模糊与均值模糊的时间复杂度

在模糊半径为r时,高斯模糊的时间复杂度为

caf8b18ff069c026c8d802f6c626a72f.png
这是个用ppt写出来的公式

,而均值模糊的时间复杂度为O(N)。这是因为高斯模糊核是一个高斯分布,每个位置的值都不一样,在每个像素位置都要老老实实的算完邻域的乘法,而均值模糊的核是一个常数,每个位置的值是相同的,可以通过各种优化手段优化为线性时间复杂度。具体细节可以参考这篇博客。

2、高斯模糊的加速

高斯模糊可以通过3次均值模糊来近似,这个是有相应的论文支撑的,同时我也在工程中做了验证,参考文献[1]中给出了在给定高斯模糊下的标准差时,如何计算3次均值模糊的模糊半径。这里给出相应的代码:

def boxesForGauss(sigma, times=3):
    wIdeal = math.sqrt((12*sigma*sigma/times)+1)
    wl = math.floor(wIdeal)
    if wl % 2 == 0:
        wl -= 1
    wu = wl + 2
    mIdeal = (12*sigma*sigma - times*wl*wl - 4*times*wl - 3*times)/(-4*wl - 4)
    m = round(mIdeal)
    sizes = []
    for i in range(times):
        sizes.append(wl if i < m else wu)
    return sizes

然后是高斯模糊的近似实现:

def FakeGaussianBlur(image, sigma, radius=None, times=3):
    if radius is not None:
        sigma = 0.3 * ((radius - 1) * 0.5 - 1) + 0.8  # 这个后面有介绍
    sizes = boxesForGauss(sigma-1, times)
    img = image.copy()
    for i in range(times):
        ksz = sizes[i]
        img = cv2.blur(img, (ksz, ksz))
    return img

注意,这里是拟合,所以跟真正的高斯模糊相比肯定是有误差的。你会发现我在函数实现里面对sigma做了一个减1的操作,是因为我在测试中发现减1之后跟标准的高斯模糊误差会小一些。

3、高斯模糊半径和高斯标准差的转换

Opencv自带的高斯模糊函数可以同时输入高斯模糊的半径和高斯模糊标准差,但是在加速高斯模糊方法中,只有标准差一个参数。给定标准差,会得到一个高斯分布,高斯分布的特点是离期望值越远,值会越小,所以每个标准差会对应一个“有效半径”。这里给出有效半径和标准差转换的公式,公式来自opencv:

sigma = 0.3 * ((radius - 1) * 0.5 - 1) + 0.8

4、在mask内的高斯模糊

Opencv很多函数在对图像做处理时,可以同时指定mask,只对mask内的内容操作,比如calcHist,在输入图像时同时输入mask,这个函数会只统计mask内的直方图,非常方便。这里也给出只在mask内进行模糊的方法。

假设mask只有0和1两个取值,1是我们想要模糊的区域。Mask内的图像模糊分为4步:

1)把图像中mask为0的区域置为0;

2)对1)得到的图像做高斯模糊;

3)对mask做高斯模糊;

4)用2)的结果除以3)的结果。

好了,最终的代码如下:

def FakeGaussianBlurWithinMask(image, mask, sigma, radius=None):
    assert(len(mask.shape) == 2)
    mask = np.uint8(mask > 0)
    if len(image.shape) == 3:
        mask = mask[:, :, np.newaxis]

    # step 1
    img = image * mask

    # step 2
    img = FakeGaussianBlur(img, sigma, radius)
    # step 3
    msk = mask[:, :, 0].astype(np.float32)
    msk = FakeGaussianBlur(msk, sigma, radius) + 1e-4

    # step 4
    img = img.astype(np.float32)
    if len(image.shape) == 3:
        msk = msk[:, :, np.newaxis]
    res = img / msk

    # result
    res = res * mask + image * (1 - mask)
    return res.astype(image.dtype)

5、测试结果

在一张1080*1920*3的图片上,标准差为25时,加速后的高斯模糊的平均运行时间是24毫秒,opencv的高斯模糊平均运行时间是749毫秒

看一张在mask内模糊的效果图吧:

opencv高斯模糊_高斯模糊加速及其实现_第2张图片
左侧为mask,右侧为模糊结果

参考

  1. ^高斯模糊加速细节 http://blog.ivank.net/fastest-gaussian-blur.html

你可能感兴趣的:(opencv高斯模糊)