4

私は画像解析プログラムに取り組んでおり、ボトルネックを絞り込んで、2D ガウスを小さなウィンドウ (20x20) ピクセルに何度も合わせようとしました。実行時間の 90% がこのコードに費やされます。

この問題については、scipy クックブックに記載されているコードを使用しています。

   def gaussian(height, center_x, center_y, width_x, width_y):
           """Returns a gaussian function with the given parameters"""
        width_x = float(width_x)
        width_y = float(width_y)
        return lambda x,y: height*exp(
                    -(((center_x-x)/width_x)**2+((center_y-y)/width_y)**2)/2)


def moments(data):
    """Returns (height, x, y, width_x, width_y)
    the gaussian parameters of a 2D distribution by calculating its
    moments """
    total = data.sum()
    X, Y = indices(data.shape)
    x = (X*data).sum()/total
    y = (Y*data).sum()/total
    col = data[:, int(y)]
    width_x = sqrt(abs((arange(col.size)-y)**2*col).sum()/col.sum())
    row = data[int(x), :]
    width_y = sqrt(abs((arange(row.size)-x)**2*row).sum()/row.sum())
    height = data.max()
    return height, x, y, width_x, width_y


def fitgaussian(data):
    """Returns (height, x, y, width_x, width_y)
    the gaussian parameters of a 2D distribution found by a fit"""
    params = moments(data)
    errorfunction = lambda p: ravel(gaussian(*p)(*indices(data.shape)) -
                                 data)
    p, success = optimize.leastsq(errorfunction, params, maxfev=50, ftol=1.49012e-05)
    return p

errorfunction() 関数と gaussian() 関数を組み合わせることで、実行時間を半分に短縮できたので、leastsq() が errorfunction() を呼び出すたびに、2 つではなく 1 つの関数呼び出しが発生します。

これにより、leastsq() アルゴリズムが errorfunction() を呼び出すため、残りの実行時間のほとんどが関数呼び出しのオーバーヘッドに費やされていると思われます。

この関数呼び出しのオーバーヘッドを減らす方法はありますか? leastsq() は関数を入力として受け取るため、途方に暮れています。

私の説明が紛らわしい場合は、あらかじめお詫び申し上げます。私は訓練を受けた機械エンジニアであり、Python を学んでいます。他に役立つ情報があれば教えてください。

4

1 に答える 1

1

exp は単調なので、ガウスの対数を誤差関数として使用できます。

def log_gaussian(height, center_x, center_y, width_x, width_y):
    """Returns a gaussian function with the given parameters"""
    width_x = float(width_x)
    width_y = float(width_y)
    log_height = log(height)
    return lambda x,y: (log_height - 
             (((center_x-x)/width_x)**2 - ((center_y-y)/width_y)**2)/2)

これにより、反復ごとにデータセット行ごとに exp を 1 回呼び出すのではなく、反復ごとにログを 1 回呼び出すことになります。

于 2013-03-01T18:01:31.837 に答える