使用 python 模糊图像部分的最优雅的方法是什么?

问题描述 投票:0回答:2

我发现以下答案使用 PIL 在本地模糊图像: 使用 PIL、python 过滤部分图像。提议的答案裁剪图像的一部分,对其进行模糊处理并将其复制回原始图像。这会在模糊部分和原始图像之间创建锐利边缘(请参见下面的示例)。

image

我想避免这种影响。

python scipy filtering python-imaging-library
2个回答
5
投票

要避免此问题,可以使用以下过程:

  • 给定图像和掩码(值在 0 到 1 之间)
  • 模糊完整的输入图像和蒙版
  • 使用模糊蒙版对原始图像进行加权
  • 使用反转模糊蒙版对模糊图像进行加权
  • 添加加权图像

下面是一些使用 scipy 的示例代码:

import numpy as np
import matplotlib.pyplot as plt
from scipy import misc
import scipy.ndimage


def gaussian_blur(sharp_image, sigma):
    # Filter channels individually to avoid gray scale images
    blurred_image_r = scipy.ndimage.filters.gaussian_filter(sharp_image[:, :, 0], sigma=sigma)
    blurred_image_g = scipy.ndimage.filters.gaussian_filter(sharp_image[:, :, 1], sigma=sigma)
    blurred_image_b = scipy.ndimage.filters.gaussian_filter(sharp_image[:, :, 2], sigma=sigma)
    blurred_image = np.dstack((blurred_image_r, blurred_image_g, blurred_image_b))
    return blurred_image


def uniform_blur(sharp_image, uniform_filter_size):
    # The multidimensional filter is required to avoid gray scale images
    multidim_filter_size = (uniform_filter_size, uniform_filter_size, 1)
    blurred_image = scipy.ndimage.filters.uniform_filter(sharp_image, size=multidim_filter_size)
    return blurred_image


def blur_image_locally(sharp_image, mask, use_gaussian_blur, gaussian_sigma, uniform_filter_size):

    one_values_f32 = np.full(sharp_image.shape, fill_value=1.0, dtype=np.float32)
    sharp_image_f32 = sharp_image.astype(dtype=np.float32)
    sharp_mask_f32 = mask.astype(dtype=np.float32)

    if use_gaussian_blur:
        blurred_image_f32 = gaussian_blur(sharp_image_f32, sigma=gaussian_sigma)
        blurred_mask_f32 = gaussian_blur(sharp_mask_f32, sigma=gaussian_sigma)

    else:
        blurred_image_f32 = uniform_blur(sharp_image_f32, uniform_filter_size)
        blurred_mask_f32 = uniform_blur(sharp_mask_f32, uniform_filter_size)

    blurred_mask_inverted_f32 = one_values_f32 - blurred_mask_f32
    weighted_sharp_image = np.multiply(sharp_image_f32, blurred_mask_f32)
    weighted_blurred_image = np.multiply(blurred_image_f32, blurred_mask_inverted_f32)
    locally_blurred_image_f32 = weighted_sharp_image + weighted_blurred_image

    locally_blurred_image = locally_blurred_image_f32.astype(dtype=np.uint8)

    return locally_blurred_image


if __name__ == '__main__':

    sharp_image = misc.face()
    height, width, channels = sharp_image.shape
    sharp_mask = np.full((height, width, channels), fill_value=1)
    sharp_mask[int(height / 4): int(3 * height / 4), int(width / 4): int(3 * width / 4), :] = 0

    result = blur_image_locally(
        sharp_image,
        sharp_mask,
        use_gaussian_blur=True,
        gaussian_sigma=31,
        uniform_filter_size=201)
    plt.imshow(result)
    plt.show()

结果: enter image description here


0
投票

我也在寻找解决这个问题的优雅方法。 ChatGPT 只提供了部分帮助,我需要想出一种自己的方法,主要受 https://note.nkmk.me/en/python-pillow-composite/.

的影响

总而言之:

from PIL import Image, ImageFilter, ImageDraw

def apply_blur_with_gradient(image_path, output_path, blur_area, blur_radius, gradient_width):
    # Load the original image
    image = Image.open(image_path)

    # Create the blurred area
    blurred_image = image.filter(ImageFilter.GaussianBlur(blur_radius))

    # Create the gradient mask
    mask = Image.new("L", image.size, 255)
    draw = ImageDraw.Draw(mask)
    draw.rectangle(blur_area, fill=0)
    mask = mask.filter(ImageFilter.GaussianBlur(gradient_width))

    # Composite the images using Image.composite
    output = Image.composite(image, blurred_image, mask)

    # Alternatively, you can use the paste method
    # output = blurred_image.copy()
    # output.paste(image, mask)

    # Save the output image
    output.save(output_path)

# Usage
image_path = 'path/to/your/image.jpg'
output_path = 'output_image.jpg'
blur_area = (100, 150, 300, 400)  # x1, y1, x2, y2
blur_radius = 10  # Gaussian blur radius
gradient_width = 20  # Gradient width for smooth transition

apply_blur_with_gradient(image_path, output_path, blur_area, blur_radius, gradient_width)

print("Task completed! Check 'output_image.jpg'.")

这最终也应该满足“优雅”的要求,至少我试图让它尽可能简单,并且用尽可能少的代码行。

© www.soinside.com 2019 - 2024. All rights reserved.