仅沿一个轴平滑2D阵列

时间:2015-08-22 11:17:35

标签: python numpy scipy convolution smoothing

我想知道是否有人可以帮助我将the smoothing example in the SciPy cookbook扩展到2D问题。

此脚本非常适合平滑1D功能,它们还为两个轴上的2D平滑提供代码(即模糊图像)。

但是,我想将此功能应用于2D数据集,但仅沿一个轴(x方向)。我可以循环执行此操作,方法是检查y中的每个切片,应用1D卷积,然后重建阵列。但这似乎是糟糕的编码技术。

因此,我想知道如何在2D中完成它?我想我需要制作一个2D内核,权重只沿一个方向变化,但我不知道如何做到这一点,或者使用哪个卷积函数(numpy.convolvescipy.signal.convolve,{ {1}}等。)

2 个答案:

答案 0 :(得分:4)

简介

似乎你应该能够ny=1执行2D图像的一维卷积,但这表明cookbook函数实际上使用了长度为2 * n + 1的内核。这让我觉得您可以使用ny=0,但这会在内核的定义中创建0/0。所以,那里也没有运气。 :(基于此,我认为食谱不适合您的目的,所以我提供了另一种方法来做您所要求的。

要仅通过1维卷积来执行2D数组的平滑处理,您只需要创建一个沿着其中一个维度具有形状1的2D数组(内核),

import numpy as np

kern = np.ones((11, 1))  # This will smooth along columns

并将其标准化,使其总和为一,

kern /= kern.sum()

然后用信号对其进行卷积,

import scipy.signal as signal

X, Y = np.mgrid[-70:70, -70:70]
Z = np.cos((X**2+Y**2)/200.) + np.random.normal(size=X.shape)

Z_smooth = signal.convolve(Z, kern)

这应该给你这样的东西, man page for SCons

更好的内核

上面我使用了'boxcar'内核(常数值),许多人认为这种内核有些粗糙。人们通常更喜欢使用更清晰或更平滑的过滤器(例如,在烹饪书中使用'hanning'或'gaussian')。

kern_hanning = signal.hanning(11)[:, None]
kern_hanning /= kern_hanning.sum()
kern_gauss7 = signal.gaussian(11, 7)[:, None]
kern_gauss7 /= kern_gauss7.sum()
kern_gauss3 = signal.gaussian(11, 3)[:, None]
kern_gauss3 /= kern_gauss3.sum()

这些不同的窗口看起来像这样,

Boxcar window.

应用这些过滤器后,您将获得类似的内容,

Kernels Hanning Kernel. Gauss3 Kernel

请注意,'Gauss7'内核与boxcar几乎相同,因此它在输出中产生非常相似的结果。另一方面,hanning窗口更精细,因此它可以生成更清晰的数据过滤器(更不用说在环上涂抹)。

答案 1 :(得分:3)

也许最简单的选择是在scipy.ndimage.filters中使用其中一个过滤器:

using System.Linq;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.OData;
using Microsoft.WindowsAzure.Mobile.Service;
using TempService.DataObjects;
using TempService.Models;
using System.Web.Http.OData.Query;
using System.Collections.Generic;

namespace TempService.Controllers
{
public class TodoItemController : TableController<TodoItem>
{

    protected override void Initialize(HttpControllerContext controllerContext)
    {
        base.Initialize(controllerContext);

        // Create a new Azure Storage domain manager using the stored 
        // connection string and the name of the table exposed by the controller.
        string connectionStringName = "StorageConnectionString";
        var tableName = controllerContext.ControllerDescriptor.ControllerName.ToLowerInvariant();
        DomainManager = new StorageDomainManager<TodoItem>(connectionStringName,
            tableName, Request, Services);
    }

    public Task<IEnumerable<TodoItem>> GetAllTodoItems(ODataQueryOptions options)
    {
        // Call QueryAsync, passing the supplied query options.
        return DomainManager.QueryAsync(options);
    }

    // GET tables/TodoItem/1777
    public SingleResult<TodoItem> GetTodoItem(string id)
    {
        return Lookup(id);
    }

    // PATCH tables/TodoItem/1456
    public Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch)
    {
        return UpdateAsync(id, patch);
    }

    // POST tables/TodoItem
    public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
    {
        TodoItem current = await InsertAsync(item);
        return CreatedAtRoute("Tables", new { id = current.Id }, current);
    }

    // DELETE tables/TodoItem/1234
    public Task DeleteTodoItem(string id)
    {
        return DeleteAsync(id);
    }
}

你也可以像这样使用过滤器的非1D版本:from scipy import ndimage from scipy.misc import lena img = lena() # a uniform (boxcar) filter with a width of 50 boxcar = ndimage.uniform_filter1d(img, 50, 1) # a Gaussian filter with a standard deviation of 10 gauss = ndimage.gaussian_filter1d(img, 10, 1) (即为你不想平滑的轴设置过滤器宽度为0)。

要使任意内核平滑,您可以使用scipy.ndimage.convolve1d

ndimage.gaussian_filter(img, (0, 10))

这是各种输出的样子:

import numpy as np

kern = np.hanning(50)   # a Hanning window with width 50
kern /= kern.sum()      # normalize the kernel weights to sum to 1

hanning = ndimage.convolve1d(img, kern, 1)

enter image description here