【问题标题】:Producing an array from an ellipse从椭圆生成数组
【发布时间】:2014-09-22 22:13:13
【问题描述】:

我有一个方程,它以一般形式 x^2/a^2 + y^2/b^2 = 1 创建一个椭圆。我希望生成一个数组,其中椭圆内的所有点都设置为 1,并且外面的所有点都是零。然后将这个数组与另一个数组进行卷积。

到目前为止,我已经尝试创建一个空数组,其大小我希望遍历所有 x,y 位置,计算 x^2/a^2 + y^2/b^2 = 1。如果一般形式是小于 1 将 1 输入数组,否则继续下一个 x,y 位置。

这是我的代码:

    arr = numpy.array(im) 
    sh = numpy.shape(arr)
    ar = numpy.empty(sh)

    for x in range (sh[0]):
        xx = x*x
        for y in range (sh[1]):
            yy = y*y
            ellips = xx/(a*a)+yy/(b*b)
            if ellips < 1:
                ar[xx,yy] = '1'
            else:
                break

但是,这并没有产生我所期望的结果,因为我的椭圆总是以 (0,0) 为中心,因此我希望它们位于数组的中心,但它们出现在左上角。

有没有人知道我哪里出错了?或者也许是生产我的阵列的更好方法?

---编辑---

尝试过 EOL 的回答后,我收到了一个椭圆数组,但它与它应该建模的椭圆不匹配。这是一张图片来说明我的意思:http://i.imgur.com/M4vh4il.jpg?1 椭圆数组没有椭圆的旋转。 生成椭圆和椭圆数组的代码如下:

    def Ellipssee(z,stigx,stigy):
        points=100 #Number of points to construct the ellipse
        x0,y0 = 0,0 #Beam is always centred
        z0 = 4 # z0 a constant of the device
        al = 2 # alpha a constant of the device
        de = sqrt((stigx**2 + stigy**2))
        ang = arctan2(stigy, stigx) # result in radians
        a = (z+de-z0)*al
        b = (z-de-z0)*al 
        cos_a,sin_a=cos(ang),sin(ang)
        the=linspace(0,2*pi,points)
        X=a*cos(the)*cos_a-sin_a*b*sin(the)+x0
        Y=a*cos(the)*sin_a+cos_a*b*sin(the)+y0

        img = Image.open("bug.png").convert("L") # load image for array size
        arr = np.array(img) 
        sh = np.shape(arr)

        nx = sh[0]   # number of pixels in x-dir
        ny = sh[1]   # number of pixels in y-dir

        x0 = 0;  # x center, half width                                       
        y0 = 0;  # y center, half height                                      
        x = np.linspace(-60, 60, nx)  # x values of interest
        y = np.linspace(-30, 30, ny)  # y values of interest
        ellipseArr = ((x-x0)/a)**2 + ((y[:,None]-y0)/b)**2 <= 1

我一直在使用值 Ellipse(1,6,8) 调用该方法。

为什么在创建数组时会丢失旋转?

【问题讨论】:

  • 如果您希望椭圆位于 (0, 0) 以外的其他位置(即“左上角”),例如 (x0, y0),那么您应该使用 ellips = ((x-x0)/a)**2 + ((y-y0)/b)**2
  • @EOL 感谢您的评论。我不希望我的椭圆在中心 (0,0) 以外的任何地方,因此不需要在一般方程中包含 x0,y0 项。编辑* 阅读了 Gabriel 的回答后,我明白你现在的意思了。感谢您指出这一点:)
  • EOL 是对的 Nate。您必须调整方程,或使用以 (0,0) 为中心的坐标系。详情见我的回答
  • 另外,正如您的原始代码一样,您不想使用break,而是要设置ar[xx,yy] = '0' where break`。 np.empty 创建一个数组而不初始化任何值,因此如果它们不满足不等式,则需要将它们设置为 '0'。
  • @Nate:坐标的问题是数组“开始”在 (0, 0) - 这是它们的角之一。这就是为什么如果您将椭圆居中在 (0, 0) 中,那么您就是将其居中在一个角上——因此需要将椭圆居中于其他位置。

标签: python arrays python-2.7 numpy ellipse


【解决方案1】:

这是使用numpy 的一些技巧的答案。

import numpy as np

a = 3.0
b = 1.0
nx = 256   # number of pixels in x-dir
ny = 256   # number of pixels in y-dir

# set up a coordinate system
x = np.linspace(-5.0, 5.0, nx)
y = np.linspace(-5.0, 5.0, ny)

# Setup arrays which just list the x and y coordinates
xgrid, ygrid = np.meshgrid(x, y)

# Calculate the ellipse values all at once
ellipse = xgrid**2 / a**2 + ygrid**2 / b**2

# Create an array of int32 zeros
grey = np.zeros((nx,ny), dtype=np.int32)

# Put 1's where ellipse is less than 1.0
# Note ellipse <1.0 produces a boolean array that then indexes grey
grey[ellipse < 1.0] = 1

请注意,我使用了坐标xgridygrid,而不是您在OP 中使用的像素数。因为我的坐标系以 0.0,0.0 为中心,所以我的数组中间有一个椭圆。在您的问题中,您使用了角落中具有 0,0 的像素索引,因此您在角落中得到了一个椭圆。您可以移动坐标系(如我所做的那样)或考虑椭圆方程的偏移(如评论所建议的那样)。

【讨论】:

  • 这比我的答案低内存和计算效率:这是一个不太通用的解决方案(当内存或计算时间是一个重要标准时)。事实上,meshgrid() 在不需要的时候会创建完整的二维数组(只有椭圆函数的值需要是二维数组)。此外,计算xgrid**2 比计算x**2 更昂贵,因为它是nx(256!)倍大。最后,没有必要先返回int32 的数组,而grey = ellips &lt; 1 可以(也不需要1.0:NumPy 知道它的数字转换)。
  • 现在,只关注时间(不是内存),我刚刚做了一个测试(nx = ny = 100):meshgrid()+xgrid**2+ygrid**2慢 4 倍x**2 + y[:,None]**2——除了使用多 3 倍的内存。所以,在这种情况下,mesgrid() 机器需要更多的步骤(xgridygrid 的构造)、更多的内存和更多的计算时间(随着点数越来越多,事情变得越来越糟)。
  • 广播规则很棒,但有时清晰度胜过效率。如果您需要生成大型数组或多次执行此操作,请务必选择广播解决方案。它既流畅又快速。但是,使用这种方法,您仍然可以在几分之一秒内为 1080p 显示器 (nx=ny=2048) 生成像素足够多的图像,并且更易于阅读。
  • 我同意不必考虑广播可以让事情更容易理解。我也同意显示器的使用。但是,除了显示结果之外,还有其他用途(例如,必须在循环中计算许多 2D 函数,例如优化某些参数等)。所以,是的,在易读性和速度之间有一个有意义的选择,在这里。我仍然看不出有任何理由不做grey = ellips &lt; 1。不过,我没有投反对票。
【解决方案2】:

NumPy 可以直接执行此操作,无需 Python 循环:

>>> import numpy as np
>>> from matplotlib import pyplot

>>> x0 = 4; a = 5  # x center, half width                                       
>>> y0 = 2; b = 3  # y center, half height                                      
>>> x = np.linspace(-10, 10, 100)  # x values of interest
>>> y = np.linspace(-5, 5, 100)[:,None]  # y values of interest, as a "column" array
>>> ellipse = ((x-x0)/a)**2 + ((y-y0)/b)**2 <= 1  # True for points inside the ellipse

>>> pyplot.imshow(ellipse, extent=(x[0], x[-1], y[0], y[-1]), origin="lower")  # Plot

这项技术的几个关键点是:

  • 正方形(在 x 和 y 中)仅计算一次(而不是单独计算每个点)。这比使用numpy.meshgrid() 更好。

  • 1234563 987654326@ 仍然是行向量)。也不需要像 numpy.meshgrid() 那样需要更大的 2D 中间数组。
  • NumPy 可以执行“在椭圆中吗?”直接测试(即 &lt;= 1 部分),没有 Python 循环。

现在,如果你只能使用整数坐标,xy 可以简单地使用 np.arange() 而不是更“精致”的np.linspace() 获得。

虽然ellipse 是一个布尔数组(椭圆内/外),但在计算中,False 被视为 0,True 被视为 1(例如,ellipse*10 产生一个包含 0 和 10 值的数组),所以你可以在你的 NumPy 计算中使用它。

【讨论】:

  • 我玩过你的代码,但是我的椭圆数组与我的椭圆不匹配。我将编辑我的问题以解释我的意思。另外,感谢您对另一种方法的讨论并解释其缺点。
  • 等式((x-x0)/a)**2 + ((y-y0)/b)**2 绝对不是椭圆的一般形式:它是一个椭圆,其轴是垂直的和水平的。如果你想要一个更通用的椭圆,你只需要使用ellipse = … 中更通用的方程。我稍微修改了代码,以便您可以在ellipse 的表达式中直接使用正确的椭圆方程。不过,您需要弄清楚正确的方程式是什么(要记住的是,在您的问题中 Xx 不代表相同的数量;您想表达 X (和 Y ) 作为 xy 首先的函数。
  • 糟糕!你说得很对。我的一般方程有X=xcos(the)-sin(the)Y=xsin(the)+ycos(the) 以适应角度。我看我的涂鸦不够仔细!感谢您的帮助
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 2021-11-03
  • 1970-01-01
  • 1970-01-01
  • 2018-08-30
相关资源
最近更新 更多