【问题标题】:Python add noise to image breaks PNGPython为图像中断PNG添加噪声
【发布时间】:2020-03-28 11:18:36
【问题描述】:

我正在尝试在 Python 3 中创建一个用于 Web 应用程序的图像系统。这个想法是从磁盘加载图像并为其添加一些随机噪声。当我尝试这个时,我得到一个看起来完全随机的图像,与原始图像不同:

import cv2
import numpy as np
from skimage.util import random_noise
from random import randint
from pathlib import Path
from PIL import Image
import io


image_files = [
    {
        'name': 'test1',
        'file': 'test1.png'
    },
    {
        'name': 'test2',
        'file': 'test2.png'
    }
]


def gen_image():
    rand_image = randint(0, len(image_files)-1)
    image_file = image_files[rand_image]['file']
    image_name = image_files[rand_image]['name']
    image_path = str(Path().absolute())+'/img/'+image_file
    img = cv2.imread(image_path)
    noise_img = random_noise(img, mode='s&p', amount=0.1)
    img = Image.fromarray(noise_img, 'RGB')

    fp = io.BytesIO()
    img.save(fp, format="PNG")
    content = fp.getvalue()
    return content


gen_image()

我也尝试过使用 pypng:

import png

# Added the following to gen_image()
content = png.from_array(noise_img, mode='L;1')
content.save('image.png')

如何从磁盘加载 png(具有 alpha 透明度),为其添加一些噪点,然后将其返回,以便它可以通过 Web 服务器代码(flask、aiohttp 等)显示。

正如 makayla 的回答中所指出的,这使它变得更好:noise_img = (noise_img*255).astype(np.uint8) 但颜色仍然错误并且没有透明度。

这是更新后的函数:

def gen_image():
    rand_image = randint(0, len(image_files)-1)
    image_file = image_files[rand_image]['file']
    image_name = image_files[rand_image]['name']
    image_path = str(Path().absolute())+'/img/'+image_file
    img = cv2.imread(image_path)

    cv2.imshow('dst_rt', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

    # Problem exists somewhere below this line.
    img = random_noise(img, mode='s&p', amount=0.1)
    img = (img*255).astype(np.uint8)
    img =  Image.fromarray(img, 'RGB')

    fp = io.BytesIO()
    img.save(fp, format="png")
    content = fp.getvalue()

    return content

这将弹出一个预噪声图像并返回噪声图像。返回的图像中存在 RGB(和 alpha)问题。

我认为问题在于它必须是RGBA,但是当我更改为ValueError: buffer is not large enough时,我得到了ValueError: buffer is not large enough

【问题讨论】:

  • 我没有看到任何试图在原始图像中添加噪点的东西。
  • noise_img = random_noise(img, mode='s&p', amount=0.1)
  • 更新了问题的功能和评论。
  • 需要 RGBA 但形状不对

标签: python python-3.x image-processing signal-processing


【解决方案1】:

鉴于所有新信息,我正在更新我的答案,并提供一些调试问题的提示。

我找到了一个site here,它创建了示例透明图像。我创建了一个透明层为 0.5 的 64x64 青色(R=0,G=255,B=255)图像。我用它来测试你的代码。

我在图片中看到了两种比较方式:im1 = cv2.imread(fileName)im2 = cv2.imread(fileName,cv2.IMREAD_UNCHANGED)np.shape(im1) 返回 (64,64,3)np.shape(im2) 返回 (64,64,4)。这就是为什么需要该标志的原因——opencv 中的默认 imread 设置会将透明图像作为普通 RGB 图像读取。

然而,opencv 以 BGR 而不是 RGB 读取,并且由于您无法使用 opencv 保存,因此您需要将其转换为正确的顺序,否则图像将具有反转颜色。例如,我的青色图像,当用反转颜色查看时,如下所示:

您可以使用 openCV 的 color conversion function 更改此设置,例如 im = cv2.cvtColor(im, cv2.COLOR_BGRA2RGBA)Here 是所有颜色转换代码的列表)。再次,如果需要,请仔细检查图像的大小,因为您将其转换为 RGBA,它仍然应该有四个通道。

您现在可以在图像中添加噪点。 您知道,这也会给您的 Alpha 通道添加噪点,随机使某些像素更透明,而另一些像素则不那么透明。 skimage 的random_noise function 将您的图像转换为浮动并返回它作为浮动。这意味着图像值,通常是从 0 到 255 的整数,将转换为从 0 到 1 的十进制值。您的行 img = Image.fromarray(noise_img, 'RGB') 不知道如何处理浮点noise_img。这就是为什么当你保存它时,以及当我试图显示它时,图像都是一团糟。

所以我拍摄了我的青色图像,添加了噪点,然后将浮点数转换回 8 位。

noise_img = random_noise(im, mode='s&p', amount=0.1)
noise_img = (noise_img*255).astype(np.uint8)
img = Image.fromarray(noise_img, 'RGBA')

现在使用img.show() 看起来像这样(屏幕截图):

我使用 PIL 库而不是 openCV 来保存我的图像,因此它尽可能接近您的代码。

fp = 'saved_im.png'
img.save(fp, format="png")

我将图像加载到 powerpoint 中,以仔细检查使用此方法保存图像时它是否保留了透明度。这是在PowerPoint中覆盖在红色圆圈上的保存图像的屏幕截图:

【讨论】:

  • 谢谢。这使它变得更好,但仍然存在一些问题。如果我将噪声amount 设置为0.0,这很容易看出。请查看更新后的问题。
  • 我认为问题在于它必须是RGBA,但是当我改成那个时,我得到ValueError: buffer is not large enough
  • 我不完全确定你最后几行想要做什么,尤其是io.BytesIO(),但看起来你只是想保存你的图像。我建议只使用openCV's function imwrite。如果您阅读本文,您会发现它特别支持保存带有 alpha 通道的 png 文件。
  • 我还刚刚使用 RGBA 图像测试了您的代码。我不认为您的 imread 电话正在读取 RGBA 图像。请尝试致电 img = cv2.imread(captcha_path, cv2.IMREAD_UNCHANGED)。我还可以看到您的输出图像中的颜色是相反的。这是因为 openCV 使用的是 BGR 格式而不是 RGB。如果您使用 openCV(将在 BGR 中)读取图像,然后尝试使用另一个函数保存它,该函数很可能以 RGB 格式写入,您的颜色将被反转。再次说明为什么我推荐使用 openCV imwrite,因为您已经在使用 openCV 的 imread。
  • 顺便说一句,测试您是否正在使用 Alpha 通道读取图像的一种简单方法是检查图像的形状。 print(np.shape(img)) 。如果您的图像是(行、列、3),则您有 3 个通道,(R、G 和 B)意味着没有透明度。如果您的图像是(行、列、4),则您有 4 个通道(R、G、B 和 A),因此您可能已正确读取它。
猜你喜欢
  • 2018-08-06
  • 2020-06-14
  • 2023-02-09
  • 2014-09-05
  • 2017-07-31
  • 1970-01-01
  • 2021-04-09
  • 2013-10-17
  • 2019-09-12
相关资源
最近更新 更多