Python - 给定2D高斯函数的值,找到x和y值

3
我是一名有用的助手,可以为您翻译文本。

我有一个二维高斯函数f(x,y)。我知道函数峰值g₀出现的值x₀y₀。但是我想找到xₑyₑ的值,使得f(xₑ,yₑ)= g₀ / e¹。我知道这个问题有多个解,但只需要至少一个。

目前为止,我有:

def f(x, y, g0,x0,y0,sigma_x,sigma_y,offset):
    return offset + g0* np.exp(-(((x-x0)**(2)/(2*sigma_x**(2))) + ((y-y0)**(2)/(2*sigma_y**(2)))))

所有作为参数传递的变量都是已知的,因为它们是从曲线拟合中提取出来的。

我知道在x方向上求导并将f() = 0,以及在y方向上做同样的操作,可以得到一个可解的线性系统(x,y),但这样手动实现似乎有些过度,一定有一些库或工具可以完成我想要实现的功能吧?


不确定理解问题。您知道所有参数(sigmas和g₀),只需搜索一个示例x,y,使得f(x,y)= g₀ / e?还是相反,您正在寻找一种避免“curve_fit”的方法? - chrslg
还有,这个偏移量是什么?你一开始没有提到它。但是它使得峰值在x₀,y₀ = g₀+offset处,而不仅仅是g₀。如果是这样的话,f(x,y)应该是(offset+g₀)/e还是offset+g₀/e - chrslg
1个回答

2
有无限种可能性(或特殊情况下的值为1或0)。可以使用直接方法在常数时间内计算出解决方案。不需要近似或迭代方法来找到给定函数的根。这只是纯数学。
高斯核具有有趣的对称性。其中之一是当峰值被平移到(0,0)时的旋转不变性。另一个是2D高斯表面的1D截面是高斯曲线。
暂时忽略offset:它实际上并没有改变问题(它只是Z轴平移),并且为分辨率添加了额外的无用项。
几何解法是一个椭圆,因此解决方案(xe,ye)遵循共轭表达式:(xe-x0)² / a² + (ye-y0)² / b² = 1。如果sigma_x=sigma_y,那么解决方案更简单:这是一个带有表达式(xe-x0)² + (ye-y0)² = r的圆。请注意,abr取决于所搜索的值和内核参数(例如sigma_x)。更改sigma_xsigma_y就像拉伸空间一样,因此解决方案也类似地改变。更改x0y0就像平移空间一样,因此解决方案也是如此。
实际上,我们可以解决更简单的情况,其中x0=0y0=0sigma_x=1sigma_y=1。然后,我们可以应用一个翻译,然后使用转换矩阵进行线性变换。基本的4x4矩阵可以做到这一点。解决更简单的情况要容易得多,因为需要考虑的参数较少。实际上,g0offset也可以部分丢弃f,因为它在表达式的两侧,并且只需解决线性方程offset + g0 * h(xe,ye) = g0 / e,因此h(x,y) = 1 / e - offset / g0,其中h(xe, ye) = exp(-(xe² + ye²)/2)。假设我们暂时忘记了翻译和线性变换,那么问题可以很容易地解决:

h(xe, ye) = 1 / e - offset / g0
exp(-(xe² + ye²)/2) = 1 / e - offset / g0
-(xe² + ye²)/2 = ln(1 / e - offset / g0)
xe² + ye² = -2 * ln(1 / e - offset / g0)

我们得到了圆的表达式,其中半径r-2*ln(1 / e - offset / g0)!请注意,表达式中的ln基本上是自然对数。

现在我们可以尝试找出4x4矩阵系数,或者直接尝试解决完整表达式,这最终并不那么困难。

offset + g0 * exp(-((x-x0)²/(2*sigma_x²) + (y-y0)²/(2*sigma_y²))) = g0 / e
exp(-((x-x0)²/(2*sigma_x²) + (y-y0)²/(2*sigma_y²))) = 1 / e - offset / g0
-((x-x0)²/(2*sigma_x²) + (y-y0)²/(2*sigma_y²)) = ln(1 / e - offset / g0)
((x-x0)²/sigma_x² + (y-y0)²/sigma_y²)/2 = -ln(1 / e - offset / g0)
(x-x0)²/sigma_x² + (y-y0)²/sigma_y² = -2 * ln(1 / e - offset / g0)

我们得到了椭圆的表达式,其中r = -2 * ln(1 / e - offset / g0)是一个常数,a = sigma_xb = sigma_y是上述表达式中的未知参数。它可以使用a = sigma_x/sqrt(r)b = sigma_y/sqrt(r)进行归一化,以便右侧完全符合上述表达式,但这只是一些数学细节。

您可以轻松找到椭圆的一个点,因为您知道椭圆的中心(x0, y0),并且至少有一点在线y=y0与上述椭圆表达式的交点处。让我们找到它:

(x-x0)²/sigma_x² + (y0-y0)²/sigma_y² = -2 * ln(1 / e - offset / g0)
(x-x0)²/sigma_x² = -2 * ln(1 / e - offset / g0)
(x-x0)² = -2 * ln(1 / e - offset / g0) * sigma_x²
x = sqrt(-2 * ln(1 / e - offset / g0) * sigma_x²) + x0

请注意,有两个解 (-sqrt(...) + x0),但只需要其中一个。我希望在计算中没有犯任何错误(至少细节足以轻松找到)并且解决方案在您的情况下不是复数。此解决方案的好处是它非常快速地计算

最终解决方案是:
(xe, ye) = (sqrt(-2*ln(1/e-offset/g0)*sigma_x²)+x0, y0)


非常感谢您的详细回复。推导似乎是正确的。不过我在疑惑,最终的解决方案是一个复数。我的(xe,ye)应该是实数。我该怎么获得它们? - hexaquark
我认为,如果平方根中的值为负数,或者对数中的值也是负数,那么你可以得到复数。除非在这种特殊情况下没有解决方案,或者最终分析表达式存在错误,否则这不应该是可能的。假设表达式是有效的,如果 f(x,y) 不能给出 g0 /e,那么这是可能的。例如,如果 offset/g0 >1/e(导致对负值进行了对数运算),那么就有可能。如果您有实际参数的示例,导致出现此问题,我可以检查一下。 - Jérôme Richard

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