Python中的下采样数组
Posted
技术标签:
【中文标题】Python中的下采样数组【英文标题】:Downsample array in Python 【发布时间】:2013-09-11 00:57:59 【问题描述】:我有基本的二维 numpy 数组,我想将它们“下采样”到更粗略的分辨率。是否有一个简单的 numpy 或 scipy 模块可以轻松做到这一点?我还应该注意,这个数组是通过 Basemap 模块在地理上显示的。
示例:
【问题讨论】:
【参考方案1】:scikit-image
在这里实现了downsampling
的工作版本,虽然他们回避称它为downsampling
,因为它不是 DSP 方面的下采样,如果我理解正确的话:
http://scikit-image.org/docs/dev/api/skimage.measure.html#skimage.measure.block_reduce
但它工作得很好,它是我在 Python 中找到的唯一一个可以处理图像中的np.nan
的downsampler
。我很快就用这个对巨大的图像进行了下采样。
【讨论】:
【参考方案2】:在下采样时,插值是错误的做法。始终使用聚合方法。
我使用块手段来做到这一点,使用“因素”来降低分辨率。
import numpy as np
from scipy import ndimage
def block_mean(ar, fact):
assert isinstance(fact, int), type(fact)
sx, sy = ar.shape
X, Y = np.ogrid[0:sx, 0:sy]
regions = sy/fact * (X/fact) + Y/fact
res = ndimage.mean(ar, labels=regions, index=np.arange(regions.max() + 1))
res.shape = (sx/fact, sy/fact)
return res
例如,使用因子为 5(5x5 块)的 (100, 200) 形状数组会产生 (20, 40) 数组结果:
ar = np.random.rand(20000).reshape((100, 200))
block_mean(ar, 5).shape # (20, 40)
【讨论】:
谢谢,迈克。我认为您的解决方案更多的是我正在寻找的。应用您的代码时,由于数组大小不匹配而出现错误:File "diffplot.py", line 38, in block_mean res.shape = (sx/fact, sy/fact) ValueError: total size of new array must be unchanged
上述问题是由于需要将因子等分成原始数组形状。但是,此功能仍然提供不正确的结果。有趣的。似乎不像我正在寻找的那样“重新采样”。相反,它使用 diff 数组并在底图窗口中多次绘制它。我想我需要某种聚合或溶解技术。感谢您迄今为止的意见。
嗨,迈克,您介意解释一下为什么插值是一种不好的下采样方法吗?如果插值不好,是否有一种很好的方法来处理图像尺寸不能被所需块大小整除的情况?
这是同一件事的另一种实现,我相信:github.com/keflavich/image_registration/blob/master/…。我不确定速度比较如何,但我敢打赌 scipy.ndimage 会快一点。
不起作用:ValueError:新数组的总大小必须不变【参考方案3】:
imresize 和 ndimage.interpolation.zoom 看起来像他们做你想做的事
我之前没有尝试过 imresize,但这里是我使用 ndimage.interpolation.zoom 的方式
a = np.array(64).reshape(8,8)
a = ndimage.interpolation.zoom(a,.5) #decimate resolution
a 是一个 4x4 矩阵,其中包含插值
【讨论】:
这里是一个代码 sn-p:findiff = scipy.misc.imresize(diff, 30., interp='bilinear', mode=None) frefcobj = m.pcolormesh(x,y,findiff,shading='flat',vmin=-15,vmax=15,cmap=cmap,zorder=1) colbar = m.colorbar(frefcobj,"bottom",size="4%",pad="5%",extend='both',ticks=intervals)
diff 是一个 699x699 数组。似乎没有完成任务。
我之前没有尝试过imresize,但是我使用缩放添加了一个sn-p。这不是你要找的吗?我目前无法测试 imresize,因为我有一个旧版本的 scipy,它似乎没有包含它
有趣。似乎不像我正在寻找的那样“重新采样”。相反,它使用 diff 数组并在底图窗口中多次绘制它。我想我需要某种聚合或溶解技术。感谢您迄今为止的意见。
下采样是指您想要的样本比开始时少,对吧?或者你的意思是你想模糊你的矩阵?
我想让新数组更“粗糙”,从而减少样本。【参考方案4】:
因为 OP 只想要更粗的分辨率,我想我会分享我的方法,将每个维度的像素数减少一半。我取 2x2 块的平均值。这可以多次应用以减少 2 倍。
from scipy.ndimage import convolve
array_downsampled = convolve(array,
np.array([[0.25,0.25],[0.25,0.25]]))[:array.shape[0]:2,:array.shape[1]:2]
【讨论】:
【参考方案5】:最简单的方法:
您可以使用array[0::2]
表示法,它只考虑每隔一个索引。
例如
array= np.array([[i+j for i in range(0,10)] for j in range(0,10)])
down_sampled=array[0::2,0::2]
print("array \n", array)
print("array2 \n",down_sampled)
有输出:
array
[[ 0 1 2 3 4 5 6 7 8 9]
[ 1 2 3 4 5 6 7 8 9 10]
[ 2 3 4 5 6 7 8 9 10 11]
[ 3 4 5 6 7 8 9 10 11 12]
[ 4 5 6 7 8 9 10 11 12 13]
[ 5 6 7 8 9 10 11 12 13 14]
[ 6 7 8 9 10 11 12 13 14 15]
[ 7 8 9 10 11 12 13 14 15 16]
[ 8 9 10 11 12 13 14 15 16 17]
[ 9 10 11 12 13 14 15 16 17 18]]
array2
[[ 0 2 4 6 8]
[ 2 4 6 8 10]
[ 4 6 8 10 12]
[ 6 8 10 12 14]
[ 8 10 12 14 16]]
【讨论】:
【参考方案6】:xarray 的“coarsen”方法可以对 xarray.Dataset 或 xarray.DataArray 进行下采样
http://xarray.pydata.org/en/stable/generated/xarray.DataArray.coarsen.html http://xarray.pydata.org/en/stable/computation.html#coarsen-large-arrays例如:
import xarray as xr
import numpy as np
import matplotlib.pyplot as plt
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15,5))
# Create a 10x10 array of random numbers
a = xr.DataArray(np.random.rand(10,10)*100, dims=['x', 'y'])
# "Downscale" the array, mean of blocks of size (2x2)
b = a.coarsen(x=2, y=2).mean()
# "Downscale" the array, mean of blocks of size (5x5)
c = a.coarsen(x=5, y=5).mean()
# Plot and cosmetics
a.plot(ax=ax1)
ax1.set_title("Full Data")
b.plot(ax=ax2)
ax2.set_title("mean of (2x2) boxes")
c.plot(ax=ax3)
ax3.set_title("mean of (5x5) boxes")
【讨论】:
【参考方案7】:这可能不是您想要的,但为了完整起见,我想我会提到它。
您可以尝试安装 scikits.samplerate
(docs),它是 libsamplerate 的 Python 包装器。它提供了很好的、高质量的重采样算法——但据我所知,它只适用于一维。您可能可以先沿一个轴然后沿另一个轴重新采样您的 2D 信号,但我认为这可能会抵消高质量重新采样的好处。
【讨论】:
是的,这不适用于这种情况,但感谢您的意见。我需要一些可以在空间上聚合的东西。【参考方案8】:这将获取任何分辨率的图像,并通过获取图像数组的第 4 个索引仅返回其大小的四分之一。
import cv2
import numpy as np
def quarter_res_drop(im):
resized_image = im[0::4, 0::4]
cv2.imwrite('resize_result_image.png', resized_image)
return resized_image
im = cv2.imread('Your_test_image.png', 1)
quarter_res_drop(im)
【讨论】:
以上是关于Python中的下采样数组的主要内容,如果未能解决你的问题,请参考以下文章