Python:生成“曲线拟合分数”

时间:2015-06-02 07:12:01

标签: python numpy scipy

我正在研究一个项目,我试图在kymograph中模拟对象的移动。为此,我将曲线拟合到图像中的每行像素,并附加顶点的位置以近似模拟图像中对象的位置。下面是一个示例图片。

Image to be analyzed

正如您所看到的,在时间序列的早期(图像顶部),对象的位置很好地聚焦,并且可以使用高斯曲线轻松建模。然而,接近时间序列的末尾(在图像的底部),峰值更加分散。我怀疑图像底部的数据将通过建模泊松分布的曲线(下图,右图)更紧密地拟合,而图像顶部/中间的数据将通过高斯更紧密地拟合或多项式曲线(下图,左图)。

good and bad examples

对于每行像素,是否有任何方法可以为同一数据拟合多条曲线,然后根据最小二乘拟合对每一条曲线进行评分?通过这种方式,我可以(希望)在模型中途切换模型,以适应我想要跟踪的对象的变化行为。我目前的代码如下:

from PIL import Image

def populateData(picture) :
    """Open an image and populate a list of lists with the grayscale value"""
    im = Image.open(picture)           
    size = im.size                    
    width = size[0]                   
    height = size[1]                   
    allPixels = list(im.getdata())      
    pixelList = [allPixels[width*i :    
                       width * (i+1)] for i in range(height)] 
    return(pixelList)

rawData = populateData("testTop.tif")   

import numpy as np
from scipy.optimize import curve_fit

def findVertex(listOfRows) :

    xList = []
    for row in listOfRows :
        x = np.arange(len(row))
        ffunc = lambda x, a, x0, s: a*np.exp(-0.5*(x-x0)**2/s**2) 
        p, _ = curve_fit(ffunc, x, row, p0=[100,5,2])
        x0 = p[1] 
        xList.append(x0)
    xArray = np.array(xList)    
    return(xArray)

xValues = findVertex(rawData)

def buildRows(listOfRows) :
    yArray = np.arange(len(listOfRows))
    return(yArray)

yValues = buildRows(rawData)

from matplotlib import pyplot as plt
from scipy import ndimage

image = ndimage.imread("testTop.tif",flatten=True)
fig = plt.figure()
axes = fig.add_subplot(111)
axes.imshow(image)
axes.plot(xValues, yValues, 'k-')

axes.set_title('testLine')
axes.grid()
axes.set_xlabel('x')
axes.set_ylabel('time')
plt.show()

program output

编辑: 这是我用作输入的文件(testTop.tif) input image

3 个答案:

答案 0 :(得分:0)

您需要在拟合和数据之间找出某种形式的goodness of fit。取当前拟合(高斯)与数据之间的平方差之和除以方差。

sumerrsq = 0.
for i in range(yValues.shape[0]):
    sumerrsq += np.power(yValues[i] - xValues[i],2)

goodfit = np.sqrt(sumerrsq/var)

我认为你可以使用曲线拟合的第二个输出(协方差)来得到方差,

p, pcov = curve_fit(ffunc, x, row, p0=[100,5,2])
var = np.diag(pcov)

然后您可以检查goodfit的值,如果还不够,请切换到其他分布。在使用不同的分布时,您可能需要使用不同的误差估计(这假设误差是正态分布的)。

注意,没有数据(并且不确定哪个数组是哪个)我无法测试任何此代码...

答案 1 :(得分:0)

根据curve_fit docs

  

要使用perr = np.sqrt(np.diag(pcov))计算参数的一个标准差错误。

因此,如果这是您要比较的值,那么您可以从curve_fit(您当前分配给_的那个)获取第二个返回值,使用它来计算{{ 1}}如上所述,并比较多条曲线之间的误差。

答案 2 :(得分:0)

我建议您使用2D拟合模型。 1d高斯分布是基础,但均值和方差取决于位置和时间。然后,您可以根据2D图像数据拟合模型。

如果你想继续使用你的方法,看起来它只是你需要调整的均值和方差的起始值,以便更好地适应大量时间的线。

对于您的问题,您可以为所需的任何分数函数建模,因此您可以执行以下操作:

def score(x,y):
    if x < 10:
         return x**2 - y
    else:
         return x - y

因此,为了使用不同范围内的两个不同模型,请遵循此示例。