在python中计算图像的特征向量

发布于 2024-12-29 02:29:27 字数 334 浏览 0 评论 0 原文

我正在尝试将二维高斯拟合到图像中。噪声非常低,所以我的尝试是旋转图像,使两个主轴不共变,找出最大值并计算两个维度的标准偏差。选择的武器是蟒蛇。

2d more-or-less 高斯分布

但是我在寻找图像的特征向量时遇到了困难 - numpy.linalg .py 假设离散数据点。我考虑过将此图像视为概率分布,对几千个点进行采样,然后根据该分布计算特征向量,但我确信一定有一种方法可以找到特征向量(即半主向量和半主向量)高斯椭圆的短轴)直接来自该图像。有什么想法吗?

多谢 :)

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 more-or-less gaussian distribution

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?

Thanks a lot :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

瑶笙 2025-01-05 02:29:27

简单说明一下,有几种工具可以使图像适合高斯。我唯一能想到的是 scikits.learn,它不是完全以图像为导向,但我知道还有其他的。

准确地按照您的想法计算协方差矩阵的特征向量在计算上非常昂贵。您必须将图像的每个像素(或较大的随机样本)与 x,y 点相关联。

基本上,你可以这样做:

    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)

你可以利用它是定期采样的图像这一事实并计算它的矩(或“惯性轴”)。对于大图像来说,这会快得多。

举一个简单的例子,(我正在使用我的以前的答案的一部分,以防您发现它有用。 ..)

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()

在此处输入图像描述

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.

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.

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()

enter image description here

莫多说 2025-01-05 02:29:27

稳健地拟合高斯函数可能很棘手。 IEEE 信号处理杂志上有一篇关于这个主题的有趣文章:

郭宏伟,“一种拟合高斯函数的简单算法”IEEE
信号处理杂志,2011 年 9 月,第 134--137 页

我在这里给出一维案例的实现:

http://scipy-central.org/item/28/2/fitting-a-gaussian-to-noisy-data-points

(向下滚动查看拟合结果)

Fitting a Gaussian robustly can be tricky. There was a fun article on this topic in the IEEE Signal Processing Magazine:

Hongwei Guo, "A Simple Algorithm for Fitting a Gaussian Function" IEEE
Signal Processing Magazine, September 2011, pp. 134--137

I give an implementation of the 1D case here:

http://scipy-central.org/item/28/2/fitting-a-gaussian-to-noisy-data-points

(Scroll down to see the resulting fits)

情感失落者 2025-01-05 02:29:27

您尝试过主成分分析(PCA)吗?也许 MDP 包 可以轻松完成这项工作。

Did you try Principal Component Analysis (PCA)? Maybe the MDP package could do the job with minimal effort.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文