百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

用Python做科学计算(工具篇)——scipy 使用指南

toyiye 2024-06-21 12:30 13 浏览 0 评论


scipy包含各种专用于科学计算中常见问题的工具箱。其不同的子模块对应不同的应用,如插值、积分、优化、图像处理、统计、特殊函数等。

scipy可以与其他标准科学计算库进行比较,例如 GSL(用于 C 和 C++ 的 GNU 科学库)或 Matlab 的工具箱。scipy是 Python 中科学计算的核心包;它旨在有效地在numpy 数组上运行,以便 numpy 和 scipy 共同使用。

作为非专业程序员,科学家往往倾向于重新发明轮子,这会导致错误、非最优、难以共享和不可维护的代码。相比之下,Scipy经过优化和测试,因此应尽可能使用。

目录

  • 文件输入/输出: scipy.io
  • 特殊函数: scipy.special
  • 线性代数运算: scipy.linalg
  • 插值: scipy.interpolate
  • 优化和拟合: scipy.optimize
  • 统计和随机数: scipy.stats
  • 数值积分: scipy.integrate
  • 快速傅里叶变换: scipy.fftpack
  • 信号处理: scipy.signal
  • 图像处理: scipy.ndimage


scipy 非常丰富,这里我们只介绍一些重点部分,帮助我们了解如何将scipy用于科学计算。

scipy 由特定于任务的子模块组成:

scipy.cluster

矢量量化/Kmeans

scipy.constants

物理和数学常数

scipy.fftpack

傅里叶变换

scipy.integrate

积分

scipy.interpolate

插值

scipy.io

数据输入输出

scipy.linalg

线性代数

scipy.ndimage

n维图像包

scipy.odr

Orthogonal distance regression

scipy.optimize

优化

scipy.signal

信号处理

scipy.sparse

稀疏矩阵

scipy.spatial

空间数据结构和算法

scipy.special

任何特殊的数学函数

scipy.stats

统计数据


它们都依赖于numpy,但大多是相互独立的。导入 Numpy 和这些 Scipy 模块的标准方法是:

>>> import numpy as np
>>> from scipy import stats  

主scipy命名空间大部分包含了真正的numpy函数(scipy.cos , np.cos)。这些都是由于历史原因造成的;没有理由在代码中使用import scipy。

1.1.文件输入/输出:scipy.io

Matlab 文件:加载和保存:

>>>

>>> from scipy import io as spio
>>> a = np.ones((3, 3))
>>> spio.savemat('file.mat', {'a': a}) 
>>> data = spio.loadmat('file.mat')
>>> data['a']
array([[1.,  1.,  1.],
       [1.,  1.,  1.],
       [1.,  1.,  1.]])

Python/Matlab 不匹配例如

>>>

>>> a = np.ones(3)
>>> a
array([1.,  1.,  1.])
>>> spio.savemat('file.mat', {'a': a})
>>> spio.loadmat('file.mat')['a']
array([[1.,  1.,  1.]])

图像文件:读取图像:

>>>

>>> import imageio
>>> imageio.imread('fname.png')    
Array(...)
>>> # Matplotlib also has a similar function
>>> import matplotlib.pyplot as plt
>>> plt.imread('fname.png')    
array(...)

此外

  • 加载文本文件:numpy.loadtxt()/numpy.savetxt()
  • 巧妙加载文本/csv文件: numpy.genfromtxt()/numpy.recfromcsv()
  • 快速高效,但特定于 numpy 的二进制格式: numpy.save()/numpy.load()
  • scikit-image 中更高级的图像输入/输出: skimage.io

1.2.特殊函数:scipy.special

特殊函数是超越函数。scipy.special模块的文档写得很好,所以我们不会在这里列出所有的函数。常用的有:

贝塞尔函数,如scipy.special.jn()(nth integer order Bessel function)

椭圆函数(scipy.special.ellipj()对于雅可比椭圆函数,...)

Gamma function: scipy.special.gamma(),还要注意 scipy.special.gammaln()这将使 Gamma 的对数具有更高的数值精度。

Erf,高斯曲线下的面积: scipy.special.erf()

1.3.线性代数运算:scipy.linalg

scipy.linalg模块提供标准的线性代数运算。

from scipy import linalg
>>> arr = np.array([[1, 2],
...                 [3, 4]])
>>> linalg.det(arr)
-2.0
>>> arr = np.array([[3, 2],
...                 [6, 4]])
>>> linalg.det(arr) 
0.0
>>> linalg.det(np.ones((3, 4)))
Traceback (most recent call last):
...
ValueError: expected square matrix
  • scipy.linalg.inv()函数计算方阵的逆:
>>> arr = np.array([[1, 2],
...                 [3, 4]])
>>> iarr = linalg.inv(arr)
>>> iarr
array([[-2. ,  1. ],
       [ 1.5, -0.5]])
>>> np.allclose(np.dot(arr, iarr), np.eye(2))
True


  • 可以使用更高级的操作,例如奇异值分解 (SVD):

arr = np.array([[3, 2], ... [6, 4]])

>>> linalg.inv(arr) Traceback (most recent call last): ... ...

LinAlgError: singular matrix


  • 得到的数组谱为:

>>> spec array([14.88982544, 0.45294236, 0.29654967])

  • 原始矩阵可以通过svdwith的输出的矩阵乘法重新组合

np.dot

>>> sarr = np.diag(spec)

>>> svd_mat = uarr.dot(sarr).dot(vharr) >>> np.allclose(svd_mat, arr) True

  • SVD 常用于统计和信号处理。许多其他标准分解(QR、LU、Cholesky、Schur)以及线性系统的求解器都包含在scipy.linalg.

1.4.插值:scipy.interpolate

scipy.interpolate对于从实验数据拟合函数非常有用,因此可以对不存在测度的点进行评估。该模块基于FITPACK Fortran。

通过想象接近正弦函数的实验数据:

>>>

>>> measured_time = np.linspace(0, 1, 10)
>>> noise = (np.random.random(10)*2 - 1) * 1e-1
>>> measures = np.sin(2 * np.pi * measured_time) + noise

scipy.interpolate.interp1d 可以创建一个线性插值函数:

>>>

>>> from scipy.interpolate import interp1d
>>> linear_interp = interp1d(measured_time, measures)

然后可以在感兴趣的点估算结果:

>>>

>>> interpolation_time = np.linspace(0, 1, 50)
>>> linear_results = linear_interp(interpolation_time)

三次插值也可以通过提供kind可选关键字参数来选择:

>>>

>>> cubic_interp = interp1d(measured_time, measures, kind='cubic')
>>> cubic_results = cubic_interp(interpolation_time)

scipy.interpolate.interp2d类似于 scipy.interpolate.interp1d,但适用于二维数组。请注意,对于interp系列,插值点必须保持在给定数据点的范围内。

1.5 优化和拟合:scipy.optimize

优化是找到最小化或相等的数值解的问题。

scipy.optimize模块提供函数最小化(标量或多维)、曲线拟合和求根的算法。

>>>

>>> from scipy import optimize

1.5.1。曲线拟合

假设我们有一个正弦波数据,带有一些噪声:

>>>

>>> x_data = np.linspace(-5, 5, num=50)
>>> y_data = 2.9 * np.sin(1.5 * x_data) + np.random.normal(size=50)

如果我们知道数据位于正弦波上,而不知道振幅或周期,我们可以通过最小二乘曲线拟合找到它们。首先,我们必须定义要拟合的测试函数,这里有一个振幅和周期未知的正弦:

>>>

>>> def test_func(x, a, b):
...     return a * np.sin(b * x)

然后我们使用scipy.optimize.curve_fit()来寻找 a 和b:

>>>

>>> params, params_covariance = optimize.curve_fit(test_func, x_data, y_data, p0=[2, 2])
>>> print(params)
[3.05931973  1.45754553]


1.5.2。求标量函数的最小值

让我们定义以下函数:

>>>

>>> def f(x):
...     return x**2 + 10*np.sin(x)
>>> x = np.arange(-10, 10, 0.1)
>>> plt.plot(x, f(x)) 
>>> plt.show() 

这个函数的全局最小值大约为 -1.3 ,局部最小值大约为3.8。

搜索最小值可以用 scipy.optimize.minimize() 来做,给定起点 x0,找到最小值的位置:


scipy.optimize.minimize()是一个复合对象,包含所有关于收敛的信息

>>>

>>> result = optimize.minimize(f, x0=0)
>>> result 
      fun: -7.9458233756...
 hess_inv: array([[0.0858...]])
      jac: array([-1.19209...e-06])
  message: 'Optimization terminated successfully.'
     nfev: 18
      nit: 5
     njev: 6
   status: 0
  success: True
        x: array([-1.30644...])
>>> result.x # The coordinate of the minimum  
array([-1.30644...])

方法:由于该函数是一个平滑函数,因此基于梯度下降的方法是不错的选择。一般lBFGS算法是一个不错的选择:

>>>

>>> optimize.minimize(f, x0=0, method="L-BFGS-B")  
      fun: array([-7.94582338])
 hess_inv: <1x1 LbfgsInvHessProduct with dtype=float64>
      jac: array([-1.42108547e-06])
  message: ...'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
     nfev: 12
      nit: 5
   status: 0
  success: True
        x: array([-1.30644013])

上面只需要12个函数就可以为最小值找到一个合适的值。


全局最小值:这种方法的一个可能问题是,如果函数具有局部最小值,算法可能会根据初始点 x0 找到这些局部最小值而不是全局最小值:

>>>

>>> res = optimize.minimize(f, x0=3, method="L-BFGS-B")
>>> res.x
array([3.83746709])

如果我们不知道全局最小值的邻域来选择初始点,我们需要求助于更复杂的全局优化。为了找到全局最小值,我们使用scipy.optimize.basinhopping() ,它将局部优化器与起点采样相结合:

>>>

>>> optimize.basinhopping(f, 0)  
                  nfev: 1725
 minimization_failures: 0
                   fun: -7.9458233756152845
                     x: array([-1.30644001])
               message: ['requested number of basinhopping iterations completed successfully']
                  njev: 575
                   nit: 100


约束:我们可以使用“bounds”参数将变量约束到区间 :(0, 10)

边界列表

由于minimize()通常适用于x个多维,“bounds”参数是每个维度上的一个边界列表。

>>>

>>> res = optimize.minimize(f, x0=1,
...                         bounds=((0, 10), ))
>>> res.x    
array([0.])


发生了什么?为什么我们会找到 0,这不是函数的最小值。

最小化多个变量的函数

要最小化多个变量,诀窍是将它们转换为多维变量(向量)的函数。


scipy.optimize.minimize_scalar() 是一种具有专用方法的函数,可以最小化只有一个变量的函数。

1.5.3。寻找标量函数的根

要找到 f(x) = 0 的根,

我们可以使用scipy.optimize.root()

>>>

>>> root = optimize.root(f, x0=1)  # our initial guess is 1
>>> root    # The full result
    fjac: array([[-1.]])
     fun: array([0.])
 message: 'The solution converged.'
    nfev: 10
     qtf: array([1.33310463e-32])
       r: array([-10.])
  status: 1
 success: True
       x: array([0.])
>>> root.x  # Only the root found
array([0.])

请注意,仅找到一个根。图像显示在 -2.5 附近有第二个根。我们通过调整我们的初始猜测来找到它的确切值:

>>>

>>> root2 = optimize.root(f, x0=-2.5)
>>> root2.x
array([-2.47948183])

scipy. optimization .root()也提供了各种算法,通过“method”参数进行设置。

现在我们已经找到了最小值和根并对其进行了曲线拟合,我们将所有这些结果放在一个图中。

1.6 统计和随机数:scipy.stats

该模块scipy.stats包含随机过程的统计工具和概率描述。各种随机过程的随机数生成器可以在 numpy.random 中找到。

1.6.1 分布:直方图和概率密度函数

对给定随机过程的观察,它们的直方图是随机过程 PDF(概率密度函数)的估计量:

>>>

>>> samples = np.random.normal(size=1000)
>>> bins = np.arange(-4, 5)
>>> bins
array([-4, -3, -2, -1,  0,  1,  2,  3,  4])
>>> histogram = np.histogram(samples, bins=bins, density=True)[0]
>>> bins = 0.5*(bins[1:] + bins[:-1])
>>> bins
array([-3.5, -2.5, -1.5, -0.5,  0.5,  1.5,  2.5,  3.5])
>>> from scipy import stats
>>> pdf = stats.norm.pdf(bins)  # norm is a distribution object

>>> plt.plot(bins, histogram) 
[<matplotlib.lines.Line2D object at ...>]
>>> plt.plot(bins, pdf) 
[<matplotlib.lines.Line2D object at ...>]

分布对象

scipy.stats.norm是一个分布对象:每个分布都表示为一个对象。norm 是正态分布,包含有 PDF、CDF 等等。

如果我们知道随机过程属于给定的随机过程族,例如正态过程,我们可以对观测值进行最大似然拟合以估计基础分布的参数。在这里,我们将正态过程拟合到观察到的数据:

>>>

loc, std = stats.norm.fit(samples)
print(loc,std)
-0.004822316383745015 1.0050446891199836

1.6.2 平均值、中位数和百分位数

均值

>>> np.mean(samples)     
-0.004822316383745015

中位数

>>> np.median(samples)     
 0.03361659877914626

与平均值不同,中位数对分布的尾部不敏感。


中位数也是百分位数 50,因为 50% 的观察值低于它:

>>>

>>> stats.scoreatpercentile(samples, 50)     
 0.03361659877914626

同样,我们可以计算百分位数 90:

>>> stats.scoreatpercentile(samples, 90)     
1.2565894469998924

百分位数是累积分布函数的估计量:。

1.6.3 统计检验

统计检验是一个决策指标。例如,如果我们有两组观察值,我们假设它们是从高斯过程生成的,我们可以使用 T 检验来确定两组观察值的均值是否显着不同:

>>>

a = np.random.normal(0, 1, size=100)
b = np.random.normal(1, 1, size=10)
stats.ttest_ind(a, b)
Out[14]: Ttest_indResult(statistic=-3.6062755503726986, pvalue=0.0004718656448315962)

输出结果由以下部分组成:

  • T统计值: 它是一个数字,其符号与两个随机过程的差值成正比,其大小与这个差值的显著性有关。
  • p值:两个过程相同的概率。如果它接近于1,那么这两个过程几乎肯定是相同的。它越接近于零,过程就越有可能有不同的方法。


1.7 数值积分:scipy.integrate

1.7.1 函数积分

最通用的是scipy.integrate.quad(). 计算

>>>

>>> from scipy.integrate import quad
>>> res, err = quad(np.sin, 0, np.pi/2)
>>> np.allclose(res, 1)   # Res是结果,应该接近1
True
>>> np.allclose(err, 1 - res)  # Err是误差
True

其它: scipy.integrate.fixed_quad(), scipy.integrate.quadrature(), scipy.integrate.romberg()...

1.7.2 积分微分方程

scipy.integrate还具有用于常微分方程 (ODE) 的例程。特别是scipy.integrate.odeint()求解以下形式的 ODE:

dy/dt = rhs(y1, y2, .., t0,...)

作为介绍,让我们计算在t=0-4之间的常微分方程 dy/dt = -2y,其初始条件y(t=0) = 1。首先需要定义计算位置导数的函数:

>>>

>>> def calc_derivative(ypos, time):
...     return -2 * ypos

然后,计算y为时间的函数:

>>>

>>> from scipy.integrate import odeint
>>> time_vec = np.linspace(0, 4, 40)
>>> y = odeint(calc_derivative, y0=1, t=time_vec)

让我们用模块去计算一个更复杂的 ODE:阻尼弹簧谐振子。连接到弹簧上的质点的位置服从二阶ODE

k 为 弹簧常数,m 质量和

c 为阻尼系数。我们设置:

>>>

>>> mass = 0.5  # kg
>>> kspring = 4  # N/m
>>> cviscous = 0.4  # N s/m

因此:

>>>

>>> eps = cviscous / (2 * mass * np.sqrt(kspring/mass))
>>> omega = np.sqrt(kspring / mass)

系统是欠阻尼的,因为:

>>> eps < 1
True

对于odeint(),二阶方程需要转换两个一阶方程组

函数计算速度和加速度:

>>>

>>> def calc_deri(yvec, time, eps, omega):
...     return (yvec[1], -2.0 * eps * omega * yvec[1] - omega **2 * yvec[0])

结果如下:

>>>

>>> time_vec = np.linspace(0, 10, 100)
>>> yinit = (1, 0)
>>> yarr = odeint(calc_deri, yinit, time_vec, args=(eps, omega))

odeint()使用LSODA(常微分方程的Livermore求解器,具有刚性和非刚性问题的自动方法切换),请参阅ODEPACK Fortran库了解更多细节。

1.8 快速傅里叶变换:scipy.fftpack

scipy.fftpack模块计算快速傅里叶变换 (FFT) 并提供处理它们的实用程序。主要功能有:

  • scipy.fftpack.fft() 计算 FFT
  • scipy.fftpack.fftfreq() 生成采样频率
  • scipy.fftpack.ifft() 计算从频率空间到信号空间的逆 FFT


例如,一个(噪声)输入信号 ( sig) 及其 FFT:

>>>

>>> from scipy import fftpack
>>> sig_fft = fftpack.fft(sig) 
>>> freqs = fftpack.fftfreq(sig.size, d=time_step) 

信号

快速傅里叶变换

由于信号来自实函数,因此傅里叶变换是对称的。

峰值信号频率可以用 freqs[power.argmax()]

将高于该频率的傅里叶分量设置为零,并用 反 FFT scipy.fftpack.ifft(),得到一个滤波信号。

numpy.fft

Numpy 也有 FFT ( numpy.fft)的实现。但是,应该首选 scipy,因为它使用更有效的底层实现。


1.9 信号处理:scipy.signal


scipy.signal 用于典型的信号处理:一维、规则采样信号。

重采样 scipy.signal.resample(): 使用 FFT将信号采样到n个点。

>>>

>>> t = np.linspace(0, 5, 100)
>>> x = np.sin(t)

>>> from scipy import signal
>>> x_resampled = signal.resample(x, 25)

>>> plt.plot(t, x) 
[<matplotlib.lines.Line2D object at ...>]
>>> plt.plot(t[::4], x_resampled, 'ko') 
[<matplotlib.lines.Line2D object at ...>]


请注意,在窗口的一侧,重新采样的准确性会降低,并且会产生涟漪效应。

这种重采样不同于提供的插值,scipy.interpolate因为它仅适用于定期采样的数据。

消解趋势 scipy.signal.detrend():从信号中去除线性趋势:

>>>

>>> t = np.linspace(0, 5, 100)
>>> x = t + np.random.normal(size=100)

>>> from scipy import signal
>>> x_detrended = signal.detrend(x)

>>> plt.plot(t, x) 
[<matplotlib.lines.Line2D object at ...>]
>>> plt.plot(t, x_detrended) 
[<matplotlib.lines.Line2D object at ...>]

过滤:对于非线性过滤,scipy.signal有过滤(中值过滤scipy.signal.medfilt()Wiener scipy.signal.wiener())。

scipy.signal 还有一整套用于设计线性滤波器(有限和无限响应滤波器)的工具。

频谱分析scipy.signal.spectrogram()计算频谱图——连续时间窗口上的频谱——同时计算 scipy.signal.welch()功率谱密度(PSD)。

1.10 图像处理:scipy.ndimage

scipy.ndimage 提供将 n 维数组作为图像进行操作。

1.10.1。图像的几何变换

改变方向,分辨率,..

>>>

>>> from scipy import misc  # Load an image
>>> face = misc.face(gray=True)

>>> from scipy import ndimage # Shift, roate and zoom it
>>> shifted_face = ndimage.shift(face, (50, 50))
>>> shifted_face2 = ndimage.shift(face, (50, 50), mode='nearest')
>>> rotated_face = ndimage.rotate(face, 30)
>>> cropped_face = face[50:-50, 50:-50]
>>> zoomed_face = ndimage.zoom(face, 2)
>>> zoomed_face.shape
(1536, 2048)

>>>

>>> plt.subplot(151)    
<matplotlib.axes._subplots.AxesSubplot object at 0x...>

>>> plt.imshow(shifted_face, cmap=plt.cm.gray)    
<matplotlib.image.AxesImage object at 0x...>

>>> plt.axis('off')
(-0.5, 1023.5, 767.5, -0.5)

>>> # etc.

1.10.2 图像过滤

生成一张嘈杂的脸:

>>>

>>> from scipy import misc
>>> face = misc.face(gray=True)
>>> face = face[:512, -512:]  # crop out square on right
>>> import numpy as np
>>> noisy_face = np.copy(face).astype(np.float)
>>> noisy_face += face.std() * 0.5 * np.random.standard_normal(face.shape)

在其上应用各种过滤器:

>>>

>>> blurred_face = ndimage.gaussian_filter(noisy_face, sigma=3)
>>> median_face = ndimage.median_filter(noisy_face, size=5)
>>> from scipy import signal
>>> wiener_face = signal.wiener(noisy_face, (5, 5))

在其它过滤器scipy.ndimage.filtersscipy.signal 可应用于图像。


1.10.3 数学形态学

数学形态学源于集合论。它表征和转换几何结构。尤其是二进制(黑白)图像,可以使用该理论进行转换:要转换的集合是相邻非零值像素的集合。该理论还扩展到灰度图像。

数学形态学操作使用结构元素 来修改几何结构。

首先生成一个结构元素:

>>>

>>> el = ndimage.generate_binary_structure(2, 1)
>>> el 
array([[False, True, False],
       [...True, True, True],
       [False, True, False]])
>>> el.astype(np.int)
array([[0, 1, 0],
       [1, 1, 1],
       [0, 1, 0]])
  • Erosion scipy.ndimage.binary_erosion()


a = np.zeros((7, 7), dtype=np.int)
a[1:6, 2:5] = 1

a
Out[4]: 
array([[0, 0, 0, 0, 0, 0, 0],
       [0, 0, 1, 1, 1, 0, 0],
       [0, 0, 1, 1, 1, 0, 0],
       [0, 0, 1, 1, 1, 0, 0],
       [0, 0, 1, 1, 1, 0, 0],
       [0, 0, 1, 1, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 0]])


ndimage.binary_erosion(a).astype(a.dtype)
Out[7]: 
array([[0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 1, 0, 0, 0],
       [0, 0, 0, 1, 0, 0, 0],
       [0, 0, 0, 1, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0]])

ndimage.binary_erosion(a, structure=np.ones((5,5))).astype(a.dtype)
Out[8]: 
array([[0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0]])


  • Dilation scipy.ndimage.binary_dilation()
a = np.zeros((5, 5))

a[2, 2] = 1

a
Out[11]: 
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])

ndimage.binary_dilation(a).astype(a.dtype)
Out[12]: 
array([[0., 0., 0., 0., 0.],
       [0., 0., 1., 0., 0.],
       [0., 1., 1., 1., 0.],
       [0., 0., 1., 0., 0.],
       [0., 0., 0., 0., 0.]])
  • Opening scipy.ndimage.binary_opening()
a = np.zeros((5, 5), dtype=np.int)

a[1:4, 1:4] = 1

a[4, 4] = 1

a
Out[16]: 
array([[0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0],
       [0, 1, 1, 1, 0],
       [0, 1, 1, 1, 0],
       [0, 0, 0, 0, 1]])

ndimage.binary_opening(a, structure=np.ones((3, 3))).astype(np.int)
Out[17]: 
array([[0, 0, 0, 0, 0],
       [0, 1, 1, 1, 0],
       [0, 1, 1, 1, 0],
       [0, 1, 1, 1, 0],
       [0, 0, 0, 0, 0]])

ndimage.binary_opening(a).astype(np.int)
Out[18]: 
array([[0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0],
       [0, 1, 1, 1, 0],
       [0, 0, 1, 0, 0],
       [0, 0, 0, 0, 0]])
  • Closing: scipy.ndimage.binary_closing()


打开操作会移除小结构,而关闭操作会填充小孔。因此,此类操作可用于“清理”图像。

>>>

>>> a = np.zeros((50, 50))
>>> a[10:-10, 10:-10] = 1
>>> a += 0.25 * np.random.standard_normal(a.shape)
>>> mask = a>=0.5
>>> opened_mask = ndimage.binary_opening(mask)
>>> closed_mask = ndimage.binary_closing(opened_mask)


对于灰度值图像,腐蚀(或膨胀)相当于用以感兴趣像素为中心的结构元素覆盖的像素中的最小(或最大)值替换像素。

>>>

>>> a = np.zeros((7, 7), dtype=np.int)
>>> a[1:6, 1:6] = 3
>>> a[4, 4] = 2; a[2, 3] = 1
>>> a
array([[0, 0, 0, 0, 0, 0, 0],
       [0, 3, 3, 3, 3, 3, 0],
       [0, 3, 3, 1, 3, 3, 0],
       [0, 3, 3, 3, 3, 3, 0],
       [0, 3, 3, 3, 2, 3, 0],
       [0, 3, 3, 3, 3, 3, 0],
       [0, 0, 0, 0, 0, 0, 0]])
>>> ndimage.grey_erosion(a, size=(3, 3))
array([[0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 1, 1, 1, 0, 0],
       [0, 0, 1, 1, 1, 0, 0],
       [0, 0, 3, 2, 2, 0, 0],
       [0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0]])

1.10.4 连接组件和图像测量

我们首先生成一个漂亮的合成二进制图像。

>>>

>>> x, y = np.indices((100, 100))
>>> sig = np.sin(2*np.pi*x/50.) * np.sin(2*np.pi*y/50.) * (1+x*y/50.**2)**2
>>> mask = sig > 1

scipy.ndimage.label() 为每个连接的组件分配不同的标签:

>>>

>>> labels, nb = ndimage.label(mask)
>>> nb
8

现在计算每个连接组件的测量值:

>>>

>>> areas = ndimage.sum(mask, labels, range(1, labels.max()+1))
>>> areas   # The number of pixels in each connected component
array([190.,   45.,  424.,  278.,  459.,  190.,  549.,  424.])
>>> maxima = ndimage.maximum(sig, labels, range(1, labels.max()+1))
>>> maxima  # The maximum signal in each connected component
array([ 1.80238238,   1.13527605,   5.51954079,   2.49611818, 6.71673619,
        1.80238238,  16.76547217,   5.51954079])

提取第 4 个连通分量,并裁剪它周围的数组:

>>>

>>> ndimage.find_objects(labels==4) 
[(slice(30L, 48L, None), slice(30L, 48L, None))]
>>> sl = ndimage.find_objects(labels==4)
>>> from matplotlib import pyplot as plt
>>> plt.imshow(sig[sl[0]])   
<matplotlib.image.AxesImage object at ...>

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码