【问题标题】:How to create uint16 gaussian noise image?如何创建 uint16 高斯噪声图像?
【发布时间】:2019-07-03 02:03:20
【问题描述】:

我想创建一个 uint16 具有已定义均值和标准差的高斯噪声图像。

我已经尝试过使用 numpy 的 random.normal,但它返回一个 float64 数组:

mu = 10
sigma = 100
shape = (1024,1024)
gauss_img = np.random.normal(mu, sigma, shape)

print(gauss_img.dtype)

>>> dtype('float64')

有没有办法将gauss_img 转换为 uint16 数组同时保留原始均值和标准差?还是有另一种完全创建 uint16 噪声图像的方法?

编辑:正如 cmets 中提到的,np.random.normal 将不可避免地采样负值给定 sd > mean,这是转换为 uint16 的问题。

所以我认为我需要一种不同的方法来直接创建 unsigned 高斯图像。

【问题讨论】:

  • gauss_img = gauss_img.astype(np.int16) 应该可以解决问题。
  • @mkrieger1 @Victor Valente 仅使用 astype 不会保留原始均值和标准差
  • @holastello 我认为这是因为向下转换时会丢失精度。但在这种特定情况下,情况并非如此。每个我的代码的差异小于 0.1。
  • 这里的问题是您正在使用均值和标准差来尝试描述偏态分布,但是您正在从正态分布中采样。两个想法......有时如果你在一个倾斜的分布上进行一个或多个日志转换(np.log1p()),它会变得更“正常”。您可以记录转换原始数据直到看起来正常,然后使用平均值/标准差生成新数据,然后将 np.expm1() 恢复到原始范围。或者,您可以调查 scipi.stats.skewnorm。

标签: python numpy


【解决方案1】:

所以我认为这与您正在寻找的内容很接近。

导入库并欺骗一些有偏差的数据。在这里,由于输入来源不明,我使用np.expm1(np.random.normal()) 创建了倾斜数据。你也可以使用skewnorm().rvs(),但这有点作弊,因为这也是你用来描述它的库。

我将原始样本展平以使绘制直方图更容易。

import numpy as np
from scipy.stats import skewnorm

# generate dummy raw starting data
# smaller shape just for simplicity
shape = (100, 100)
raw_skewed = np.maximum(0.0, np.expm1(np.random.normal(2, 0.75, shape))).astype('uint16')

# flatten to look at histograms and compare distributions
raw_skewed = raw_skewed.reshape((-1))

现在找到表征您的倾斜数据的参数,并使用这些参数创建一个新的分布以从中采样,希望与您的原始数据匹配。

这两行代码真的是你想要的。

# find params
a, loc, scale = skewnorm.fit(raw_skewed)

# mimick orig distribution with skewnorm
new_samples = skewnorm(a, loc, scale).rvs(10000).astype('uint16')

现在绘制每个分布进行比较。

plt.hist(raw_skewed, bins=np.linspace(0, 60, 30), hatch='\\', label='raw skewed')
plt.hist(new_samples, bins=np.linspace(0, 60, 30), alpha=0.65, color='green', label='mimic skewed dist')
plt.legend()

直方图非常接近。如果这看起来足够好,请将您的新数据重塑为所需的形状。

# final result
new_samples.reshape(shape)

现在...这就是我认为它可能不足的地方。看看每个的热图。原始分布的右侧尾部较长(skewnorm() 没有表征的更多异常值)。

这会绘制每个的热图。

# plot heatmaps of each
fig = plt.figure(2, figsize=(18,9))
ax1 = fig.add_subplot(1, 2, 1)
ax2 = fig.add_subplot(1, 2, 2)

im1 = ax1.imshow(raw_skewed.reshape(shape), vmin=0, vmax=120)
ax1.set_title("raw data - mean: {:3.2f}, std dev: {:3.2f}".format(np.mean(raw_skewed), np.std(raw_skewed)), fontsize=20)

im2 = ax2.imshow(new_samples.reshape(shape), vmin=0, vmax=120)
ax2.set_title("mimicked data - mean: {:3.2f}, std dev: {:3.2f}".format(np.mean(new_samples), np.std(new_samples)), fontsize=20)

plt.tight_layout()

# add colorbar
fig.subplots_adjust(right=0.85)
cbar_ax = fig.add_axes([0.88, 0.1, 0.08, 0.8])  # [left, bottom, width, height]
fig.colorbar(im1, cax=cbar_ax)

看看...您可以看到偶尔出现的黄色斑点,表示原始分布中的值非常高,但没有进入输出。这也显示在输入数据的更高标准差中(参见每个热图中的标题,但同样,在原始问题的 cmets 中......均值和标准差并不能真正表征分布,因为它们不正常...... . 但它们是作为相对比较的)。

但是...这正是我为开始创建的非常具体的倾斜样本所存在的问题。希望这里有足够的内容可以进行调整和调整,直到它适合您的需求和您的特定数据集。祝你好运!

【讨论】:

  • 这太棒了。太感谢了。我在这里用更具体的术语问了这个问题:stackoverflow.com/questions/54600220/…。如果您在此处放置或链接此答案,我也会在此处接受(我认为它更适合该问题)
【解决方案2】:

使用该均值和 sigma,您必然会采样一些负值。所以我猜这个选项可能是你在采样后找到最负的值,并将其绝对值添加到所有样本中。之后按照 cmets 中的建议转换为 uint。但是,您当然会以这种方式失去意思。

【讨论】:

    【解决方案3】:

    如果您有一系列 uint16 数字可供采样,那么您应该查看this post

    这样您就可以使用scipy.stats.truncnorm 生成无符号整数的高斯。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-07
      • 1970-01-01
      • 2016-01-24
      • 2021-07-15
      • 2017-06-10
      • 2015-10-28
      • 1970-01-01
      • 2012-03-27
      相关资源
      最近更新 更多