【问题标题】:Efficient blurring of image using a mask in python在 python 中使用蒙版对图像进行有效模糊
【发布时间】:2019-09-27 11:10:36
【问题描述】:

我需要模糊图像的特定区域。我得到了图像和一个蒙版,描绘了图像中需要模糊的区域。它可以工作,但比预期的要慢一些,因为我需要模糊几十张图像。

这是我使用的代码:

def soft_blur_with_mask(image: np.ndarray, mask: np.ndarray) -> np.ndarray:
    assert len(mask.shape) == 2, mask.shape
    # Create a blurred copy of the original image. This can take up to 1-2 seconds today, because the image is big (~5-10 Megapixels)
    blurred_image = cv2.GaussianBlur(image, (221, 221), sigmaX=20, sigmaY=20)
    image_height, image_width = image.shape[:2]
    mask = cv2.resize(mask.astype(np.uint8), (image_width, image_height), interpolation=cv2.INTER_NEAREST)
    # Blurring the mask itself to get a softer mask with no firm edges
    mask = cv2.GaussianBlur(mask.astype(np.float32), (11, 11), 10, 10)[:, :, None]
    mask = mask/255.0

    # Take the blurred image where the mask it positive, and the original image where the image is original
    return (mask * blurred_image + (1.0 - mask) * image).clip(0, 255.0).astype(np.uint8)

【问题讨论】:

  • 你能给我们一些号码吗?它有多慢,你期望它有多快。由于图像的值空间最后是 uint8,因此在 uint8 类型上执行 cv2.GaussianBlur 而不是可能很慢的 float32 将是一个优势。 OpenCV 函数正在使用优化的代码(例如 SSE),它在小数据类型(uint8)上比在大数据类型上更快。检查编译 OpenCV 时是否启用了 SSE。 (我相信默认情况下应该是)

标签: python numpy opencv image-processing blur


【解决方案1】:

您需要使用不同的算法进行模糊处理。让我们定义两个参数:n - 图像中的像素数和r 高斯模糊滤镜的窗口大小。

您使用了一个非常大的内核 - 221x221 像素,因此 r 等于 221。这需要使用标准卷积方法每个像素进行 221^2 = 48841 次操作。这将导致 O(r^2*n) 的计算复杂度。但是,您可以使用中心极限定理,并在两个方向上分别使用一系列盒式过滤器来近似模糊中使用的内核。如果使用两个连续像素的邻域仅在一个像素上不同的事实,则可以实现更快的处理时间。最后,您可以获得与窗口大小无关的计算复杂度:O(n)。请参阅此 link 解释整个过程。它是用 Javascript 编写的,但数学很简单且解释清楚,因此您绝对可以使用 Python 来实现它。

【讨论】:

    【解决方案2】:

    这是一个使用 Numpy 切片的方法

    • 将蒙版转换为灰度并在蒙版上查找轮廓
    • 遍历轮廓并提取 ROI
    • 模糊每个 ROI 并在原始图像中替换

    输入和掩码图像

    使用 Numpy 切片获取 ROI(左),模糊 ROI(右)

    将模糊的 ROI 替换回原始图像

    这种方法应该更快,因为您正在利用 Numpy 切片

    import cv2
    import numpy as np
    
    def soft_blur_with_mask(image: np.ndarray, mask: np.ndarray) -> np.ndarray:
        mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
        cnts = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        cnts = cnts[0] if len(cnts) == 2 else cnts[1]
        for c in cnts:
            x,y,w,h = cv2.boundingRect(c)
            ROI = image[y:y+h, x:x+w]
            image[y:y+h, x:x+w] = cv2.GaussianBlur(ROI, (41,41), 0)
        return image
    
    if __name__ == '__main__':
        image = cv2.imread('1.png')
        mask = cv2.imread('mask.png')
    
        result = soft_blur_with_mask(image, mask)
    
        cv2.imshow('result', result)
        cv2.waitKey()
    

    【讨论】:

      猜你喜欢
      • 2020-05-05
      • 1970-01-01
      • 2019-12-24
      • 2022-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多