从2D图像中提取1D椭圆

时间:2015-02-28 16:39:10

标签: python

我尝试模拟2D Sérsic配置文件,然后在其上测试提取例程。然而,当我通过提取沿着假定与图像对齐的椭圆的所有点进行测试时,我得到一个周期函数。它是一条直线,因为沿着椭圆的所有点应该具有相等的强度,尽管由于粗略坐标估计(get_I())中的舍入误差会有少量的偏差。

from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import NearestNDInterpolator

def rotate(x, y, angle):
    x1 = x*np.cos(angle) + y*np.sin(angle)
    y1 = y*np.cos(angle) - x*np.sin(angle)
    return x1, y1

def sersic_1d(R, mu0, h, n, zp=0):
    exponent = (R / h) **  (1 / n)
    I0 = np.exp((zp - mu0) / 2.5)
    return I0 * np.exp(-1.* exponent)

def sersic_2d(x, y, e, i, mu0, h, n, zp=0):
    xp, yp = rotate(x, y, i)
    alpha = np.arctan2(yp, xp * (1-e))
    a = xp / np.cos(alpha)
    b = a * (1 - e)
    # R2 = (a*a) + ((1 - (e*e)) * yp*yp)
    return sersic_1d(a, mu0, h, n, zp)


def ellipse(x0, y0, a, e, i, theta):
    b = a * (1 - e)
    x = a * np.cos(theta)
    y = b * np.sin(theta)
    x, y = rotate(x, y, i)
    return x + x0, y + y0   

def get_I(x, y, Z):
    return Z[np.round(x).astype(int), np.round(y).astype(int)]

if __name__ == '__main__':
    n = np.linspace(-100,100,1000)
    nx, ny = np.meshgrid(n, n)
    Z = sersic_2d(nx, ny, 0.5, 0., 0, 50, 1, 25)

    theta = np.linspace(0, 2*np.pi, 1000.)
    a = 100.
    e = 0.5
    i = np.pi / 4.
    x, y = ellipse(0, 0, a, e, i, theta)
    I = get_I(x, y, Z)
    plt.plot(I)
    # plt.imshow(Z)
    plt.show()

然而,我实际得到的是一个大规模的周期函数。 wrong extraction我已经检查了对齐方式,并且它是正确的,浮动 - > int舍入错误不能解释这种转变吗?

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

有两件事让我觉得奇怪,其中一件肯定不是你想要的,另一件我不确定,因为天文学不是我的专业领域。

第一个是你的函数get_I

def get_I(x, y, Z):
    return Z[np.round(x).astype(int), np.round(y).astype(int)]

当您调用该函数时,x y会勾勒出一个椭圆,其中心位于原点(0,0)。这意味着xy在某些时候都会变为负数。您在该函数中执行的索引将从数组的最后元素中获取值,因为Z[0,0]实际上是图像的左上角(您已绘制,但已注释),而Z[-1, -1]是右下角。您想要的是获取椭圆轮廓上的Z值,但两者必须具有相同的中心。要做到这一点,首先要确保使用不均匀的样本量n(最终定义shape的{​​{1}}),其次,你将添加索引偏移量

Z

另请注意,我更改了def get_I(x, y, Z): offset = Z.shape[0]//2 return Z[np.round(y).astype(int) + offset, np.round(x).astype(int) + offset] ... n = np.linspace(-100,100,1001) # changed from 1000 to 1001 to ensure a point of origin is present and that the image exhibits point symmetry yx的顺序:那是因为您首先沿着行(我们通常采用y坐标)进行索引,并且仅然后沿着列(在大多数约定中映射到x坐标)。

让我觉得不寻常的第二个项目是你的椭圆的轴相对于水平轴的角度为get_I,而你的pi/4(它映射到sersic的2D数组{1}})根本没有倾斜。


改变这一切,我最终得到了这段代码:

Z

和这张图片:

ellipse extracted from Sersic profile

对于我来说,强度变化看起来像量化噪声,但峰值除外,这是由from __future__ import division import numpy as np import matplotlib.pyplot as plt def rotate(x, y, angle): x1 = x*np.cos(angle) + y*np.sin(angle) y1 = y*np.cos(angle) - x*np.sin(angle) return x1, y1 def sersic_1d(R, mu0, h, n, zp=0): exponent = (R / h) ** (1 / n) I0 = np.exp((zp - mu0) / 2.5) return I0 * np.exp(-1.* exponent) def sersic_2d(x, y, e, ang, mu0, h, n, zp=0): xp, yp = rotate(x, y, ang) alpha = np.arctan2(yp, xp * (1-e)) a = xp / np.cos(alpha) b = a * (1 - e) return sersic_1d(a, mu0, h, n, zp) def ellipse(x0, y0, a, e, i, theta): b = a * (1 - e) # half of a x = a * np.cos(theta) y = b * np.sin(theta) x, y = rotate(x, y, i) # rotated by 45deg return x + x0, y + y0 def get_I(x, y, Z): offset = Z.shape[0]//2 return Z[np.round(y).astype(int) + offset, np.round(x).astype(int) + offset] #return Z[np.round(y).astype(int), np.round(x).astype(int)] if __name__ == '__main__': n = np.linspace(-100,100,1001) # changed nx, ny = np.meshgrid(n, n) ang = 0;#np.pi / 4. Z = sersic_2d(nx, ny, 0.5, ang=0, mu0=0, h=50, n=1, zp=25) f, ax = plt.subplots(1,2) dn = n[1]-n[0] ax[0].imshow(Z, cmap='gray', aspect='equal', extent=[-100-dn/2, 100+dn/2, -100-dn/2, 100+dn/2]) theta = np.linspace(0, 2*np.pi, 1000.) a = 20. # decreased long axis of ellipse to see the intensity-map closer to the "center of the galaxy" e = 0.5 x, y = ellipse(0,0, a, e, ang, theta) I = get_I(x, y, Z) ax[0].plot(x,y) # easier to see where you want the intensities ax[1].plot(I) plt.show() 中的渐近线引起的。