在numpy数组中遮罩一个圆形扇区

13

我有一个将numpy数组切片成圆形的代码。我希望只恢复圆形中包含在某个角度范围内的值,并屏蔽数组。例如:用圆形上0到45度之间的(x,y)位置屏蔽原始数组。

有没有一种Pythonic的方法来实现这个功能?

以下是我的(简化后的)原始代码:

import numpy as np
matrix = np.zeros((500,500))
x = 240
y = 280
radius = 10
mask=np.ogrid[x-radius:x+radius+1,y-radius:y+radius+1]
matrix[mask]

提前感谢您。

编辑:我忽略了半径可以变化的事实。


2
你的代码将在数组中遮盖一个正方形而不是圆形 - 你确定你想要的是圆形吗? - ali_m
是的,我看到了我的错误并正在尝试解决它! - Guadancil11
也许这是https://dev59.com/C2oy5IYBdhLWcg3wScPb的重复。 - Saullo G. P. Castro
在这种情况下,它是一个圆锥扇形,而不仅仅是一个圆。 - ali_m
@ali_m 谢谢你...我不确定它是否是重复的! - Saullo G. P. Castro
2个回答

31

我会通过将笛卡尔坐标转换为极坐标,并构建圆形和想要的角度范围的布尔掩码来实现此目的:

import numpy as np

def sector_mask(shape,centre,radius,angle_range):
    """
    Return a boolean mask for a circular sector. The start/stop angles in  
    `angle_range` should be given in clockwise order.
    """

    x,y = np.ogrid[:shape[0],:shape[1]]
    cx,cy = centre
    tmin,tmax = np.deg2rad(angle_range)

    # ensure stop angle > start angle
    if tmax < tmin:
            tmax += 2*np.pi

    # convert cartesian --> polar coordinates
    r2 = (x-cx)*(x-cx) + (y-cy)*(y-cy)
    theta = np.arctan2(x-cx,y-cy) - tmin

    # wrap angles between 0 and 2*pi
    theta %= (2*np.pi)

    # circular mask
    circmask = r2 <= radius*radius

    # angular mask
    anglemask = theta <= (tmax-tmin)

    return circmask*anglemask
例如:
from matplotlib import pyplot as pp
from scipy.misc import lena

matrix = lena()
mask = sector_mask(matrix.shape,(200,100),300,(0,50))
matrix[~mask] = 0
pp.imshow(matrix)
pp.show()

这里输入图像描述


1
@ali_m +1。希望你不介意,我把图片加到答案里,这样我们就可以清楚地看到发生了什么。 - Hooked
2
必须将theta = np.arctan2(x-cx,y-cy)转换为所有正角度,使用theta = np.where(theta<0,2*pi+theta,theta),否则对于大于180度的角度,上面的代码将无法正确工作。 - Developer
@开发者,你发现得很好,我已经编辑了我的函数来解决这个问题。 - ali_m

1

对于正方形矩阵中心圆的处理方法相同:

def circleMask(mat, r=0):
    if mat.shape[0] != mat.shape[1]:
        raise TypeError('Matrix has to be square')
    if not isinstance(r, int):
        raise TypeError('Radius has to be of type int')

    s = mat.shape[0]
    d = num.abs(num.arange(-s/2 + s%2, s/2 + s%2))
    dm = num.sqrt(d[:, num.newaxis]**2 + d[num.newaxis, :]**2)

    return num.logical_and(dm >= r-.5, dm < r+.5)

循环这个隐式函数的成本很高!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接