I'm trying to fit a 2D Gaussian to an image. Noise is very low, so my attempt was to rotate the image such that the two principal axes do not co-vary, figure out the maximum and just compute the standard deviation in both dimensions. Weapon of choice is python.
我正在尝试将2D高斯拟合到图像中。噪音非常低,所以我的尝试是旋转图像,使两个主轴不共同变化,找出最大值并计算两个维度的标准偏差。选择的武器是python。
However I got stuck at finding the eigenvectors of the image - numpy.linalg.py
assumes discrete data points. I thought about taking this image to be a probability distribution, sampling a few thousand points and then computing the eigenvectors from that distribution, but I'm sure there must be a way of finding the eigenvectors (ie., semi-major and semi-minor axes of the gaussian ellipse) directly from that image. Any ideas?
然而,我一直在寻找图像的特征向量 - numpy.linalg.py假设离散数据点。我想过将这个图像作为一个概率分布,对几千个点进行采样,然后根据该分布计算特征向量,但我确信必须有一种找到特征向量的方法(即,半主和半 - 直接来自该图像的高斯椭圆的短轴。有任何想法吗?
Thanks a lot :)
非常感谢 :)
3 个解决方案
#1
17
Just a quick note, there are several tools to fit a gaussian to an image. The only thing I can think of off the top of my head is scikits.learn, which isn't completely image-oriented, but I know there are others.
简而言之,有几种工具可以将高斯拟合到图像中。我唯一能想到的就是scikits.learn,它不是完全以图像为导向的,但我知道还有其他的。
To calculate the eigenvectors of the covariance matrix exactly as you had in mind is very computationally expensive. You have to associate each pixel (or a large-ish random sample) of image with an x,y point.
准确计算协方差矩阵的特征向量就像你想象的那样计算成本非常高。您必须将图像的每个像素(或大型随机样本)与x,y点相关联。
Basically, you do something like:
基本上,你做的事情如下:
import numpy as np
# grid is your image data, here...
grid = np.random.random((10,10))
nrows, ncols = grid.shape
i,j = np.mgrid[:nrows, :ncols]
coords = np.vstack((i.reshape(-1), j.reshape(-1), grid.reshape(-1))).T
cov = np.cov(coords)
eigvals, eigvecs = np.linalg.eigh(cov)
You can instead make use of the fact that it's a regularly-sampled image and compute it's moments (or "intertial axes") instead. This will be considerably faster for large images.
您可以使用这样一个事实,即它是一个定期采样的图像,并计算它的瞬间(或“惯性轴”)。对于大图像,这将快得多。
As a quick example, (I'm using a part of one of my previous answers, in case you find it useful...)
作为一个简单的例子,(我正在使用我以前的一个答案的一部分,以防你发现它有用......)
import numpy as np
import matplotlib.pyplot as plt
def main():
data = generate_data()
xbar, ybar, cov = intertial_axis(data)
fig, ax = plt.subplots()
ax.imshow(data)
plot_bars(xbar, ybar, cov, ax)
plt.show()
def generate_data():
data = np.zeros((200, 200), dtype=np.float)
cov = np.array([[200, 100], [100, 200]])
ij = np.random.multivariate_normal((100,100), cov, int(1e5))
for i,j in ij:
data[int(i), int(j)] += 1
return data
def raw_moment(data, iord, jord):
nrows, ncols = data.shape
y, x = np.mgrid[:nrows, :ncols]
data = data * x**iord * y**jord
return data.sum()
def intertial_axis(data):
"""Calculate the x-mean, y-mean, and cov matrix of an image."""
data_sum = data.sum()
m10 = raw_moment(data, 1, 0)
m01 = raw_moment(data, 0, 1)
x_bar = m10 / data_sum
y_bar = m01 / data_sum
u11 = (raw_moment(data, 1, 1) - x_bar * m01) / data_sum
u20 = (raw_moment(data, 2, 0) - x_bar * m10) / data_sum
u02 = (raw_moment(data, 0, 2) - y_bar * m01) / data_sum
cov = np.array([[u20, u11], [u11, u02]])
return x_bar, y_bar, cov
def plot_bars(x_bar, y_bar, cov, ax):
"""Plot bars with a length of 2 stddev along the principal axes."""
def make_lines(eigvals, eigvecs, mean, i):
"""Make lines a length of 2 stddev."""
std = np.sqrt(eigvals[i])
vec = 2 * std * eigvecs[:,i] / np.hypot(*eigvecs[:,i])
x, y = np.vstack((mean-vec, mean, mean+vec)).T
return x, y
mean = np.array([x_bar, y_bar])
eigvals, eigvecs = np.linalg.eigh(cov)
ax.plot(*make_lines(eigvals, eigvecs, mean, 0), marker='o', color='white')
ax.plot(*make_lines(eigvals, eigvecs, mean, -1), marker='o', color='red')
ax.axis('image')
if __name__ == '__main__':
main()
#2
3
Fitting a Gaussian robustly can be tricky. There was a fun article on this topic in the IEEE Signal Processing Magazine:
稳健地拟合高斯可能是棘手的。 IEEE信号处理杂志上有一篇关于这个主题的有趣文章:
Hongwei Guo, "A Simple Algorithm for Fitting a Gaussian Function" IEEE Signal Processing Magazine, September 2011, pp. 134--137
郭宏伟,“拟合高斯函数的简单算法”IEEE信号处理杂志,2011年9月,第134--137页
I give an implementation of the 1D case here:
我在这里给出了1D案例的实现:
http://scipy-central.org/item/28/2/fitting-a-gaussian-to-noisy-data-points
(Scroll down to see the resulting fits)
(向下滚动以查看最终的拟合)
#3
1
Did you try Principal Component Analysis (PCA)? Maybe the MDP package could do the job with minimal effort.
您是否尝试过主成分分析(PCA)?也许MDP包可以用最少的努力完成工作。
#1
17
Just a quick note, there are several tools to fit a gaussian to an image. The only thing I can think of off the top of my head is scikits.learn, which isn't completely image-oriented, but I know there are others.
简而言之,有几种工具可以将高斯拟合到图像中。我唯一能想到的就是scikits.learn,它不是完全以图像为导向的,但我知道还有其他的。
To calculate the eigenvectors of the covariance matrix exactly as you had in mind is very computationally expensive. You have to associate each pixel (or a large-ish random sample) of image with an x,y point.
准确计算协方差矩阵的特征向量就像你想象的那样计算成本非常高。您必须将图像的每个像素(或大型随机样本)与x,y点相关联。
Basically, you do something like:
基本上,你做的事情如下:
import numpy as np
# grid is your image data, here...
grid = np.random.random((10,10))
nrows, ncols = grid.shape
i,j = np.mgrid[:nrows, :ncols]
coords = np.vstack((i.reshape(-1), j.reshape(-1), grid.reshape(-1))).T
cov = np.cov(coords)
eigvals, eigvecs = np.linalg.eigh(cov)
You can instead make use of the fact that it's a regularly-sampled image and compute it's moments (or "intertial axes") instead. This will be considerably faster for large images.
您可以使用这样一个事实,即它是一个定期采样的图像,并计算它的瞬间(或“惯性轴”)。对于大图像,这将快得多。
As a quick example, (I'm using a part of one of my previous answers, in case you find it useful...)
作为一个简单的例子,(我正在使用我以前的一个答案的一部分,以防你发现它有用......)
import numpy as np
import matplotlib.pyplot as plt
def main():
data = generate_data()
xbar, ybar, cov = intertial_axis(data)
fig, ax = plt.subplots()
ax.imshow(data)
plot_bars(xbar, ybar, cov, ax)
plt.show()
def generate_data():
data = np.zeros((200, 200), dtype=np.float)
cov = np.array([[200, 100], [100, 200]])
ij = np.random.multivariate_normal((100,100), cov, int(1e5))
for i,j in ij:
data[int(i), int(j)] += 1
return data
def raw_moment(data, iord, jord):
nrows, ncols = data.shape
y, x = np.mgrid[:nrows, :ncols]
data = data * x**iord * y**jord
return data.sum()
def intertial_axis(data):
"""Calculate the x-mean, y-mean, and cov matrix of an image."""
data_sum = data.sum()
m10 = raw_moment(data, 1, 0)
m01 = raw_moment(data, 0, 1)
x_bar = m10 / data_sum
y_bar = m01 / data_sum
u11 = (raw_moment(data, 1, 1) - x_bar * m01) / data_sum
u20 = (raw_moment(data, 2, 0) - x_bar * m10) / data_sum
u02 = (raw_moment(data, 0, 2) - y_bar * m01) / data_sum
cov = np.array([[u20, u11], [u11, u02]])
return x_bar, y_bar, cov
def plot_bars(x_bar, y_bar, cov, ax):
"""Plot bars with a length of 2 stddev along the principal axes."""
def make_lines(eigvals, eigvecs, mean, i):
"""Make lines a length of 2 stddev."""
std = np.sqrt(eigvals[i])
vec = 2 * std * eigvecs[:,i] / np.hypot(*eigvecs[:,i])
x, y = np.vstack((mean-vec, mean, mean+vec)).T
return x, y
mean = np.array([x_bar, y_bar])
eigvals, eigvecs = np.linalg.eigh(cov)
ax.plot(*make_lines(eigvals, eigvecs, mean, 0), marker='o', color='white')
ax.plot(*make_lines(eigvals, eigvecs, mean, -1), marker='o', color='red')
ax.axis('image')
if __name__ == '__main__':
main()
#2
3
Fitting a Gaussian robustly can be tricky. There was a fun article on this topic in the IEEE Signal Processing Magazine:
稳健地拟合高斯可能是棘手的。 IEEE信号处理杂志上有一篇关于这个主题的有趣文章:
Hongwei Guo, "A Simple Algorithm for Fitting a Gaussian Function" IEEE Signal Processing Magazine, September 2011, pp. 134--137
郭宏伟,“拟合高斯函数的简单算法”IEEE信号处理杂志,2011年9月,第134--137页
I give an implementation of the 1D case here:
我在这里给出了1D案例的实现:
http://scipy-central.org/item/28/2/fitting-a-gaussian-to-noisy-data-points
(Scroll down to see the resulting fits)
(向下滚动以查看最终的拟合)
#3
1
Did you try Principal Component Analysis (PCA)? Maybe the MDP package could do the job with minimal effort.
您是否尝试过主成分分析(PCA)?也许MDP包可以用最少的努力完成工作。