Эффективное размытие изображения с использованием маски в python - PullRequest
1 голос
/ 27 сентября 2019

Мне нужно размыть определенные области изображения.Я получаю изображение и маску, изображающую области изображения, которые должны быть размыты.Это работает, но немного медленнее, чем ожидалось, учитывая, что мне нужно размыть десятки изображений.

Вот код, который я использую:

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)

Ответы [ 2 ]

2 голосов
/ 27 сентября 2019

Вам нужно использовать другой алгоритм размытия.Давайте определим два параметра: n - количество пикселей в изображении и r размер окна фильтра размытия по Гауссу.

Вы используете очень большое ядро ​​- 221x221 пикселей, поэтому r равнодо 221. Это требует 221 ^ 2 = 48841 операций на пиксель с использованием стандартного подхода свертки.Это приведет к вычислительной сложности O (r^2*n).Однако вы можете использовать Центральную предельную теорему и аппроксимировать ядро, используемое при размытии, с помощью серии блочных фильтров отдельно в двух направлениях.Вы можете добиться еще более быстрого времени обработки, если используете тот факт, что соседство двух последовательных пикселей отличается только одним пикселем.Наконец, вы можете получить вычислительную сложность, которая не зависит от размера окна: O (n).Смотрите эту ссылку , которая объясняет весь процесс.Он написан на Javascript, но математика проста и хорошо объяснена, поэтому вы определенно можете реализовать ее с помощью Python.

0 голосов
/ 28 сентября 2019

Вот метод с использованием Numpy Slicing

  • Преобразование маски в оттенки серого и поиск контуров по маске
  • Перебор контуров и извлечение ROI
  • Размытие каждого ROI изаменить в исходном изображении

Ввод и маска изображения

image image

Захват ROI с использованием Numpy нарезки (слева), ROI размытия (справа)

image image

Заменить размытую область интереса обратно на исходное изображение

image

Этот метод должен быть быстрее, так как вы 'снова воспользоваться нарезкой 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()
...