6

0から1の範囲の値を持つ画像があります。私がやりたいのは単純な平均化です。
しかし、より具体的には、画像の境界にあるセルについて、画像の範囲内にある近隣/カーネルのその部分のピクセルの平均を計算したいと思います。実際、これは、合計を除算するピクセル数である「平均式」の分母を適応させるために要約されます。

以下に示すようにscipy.ndimage.generic_filter、でこれを行うことができましたが、これは時間効率にはほど遠いです。

def fnc(buffer, count):
    n = float(sum(buffer < 2.0))
    sum = sum(buffer) - ((count - b) * 2.0)
    return (sum / n)

avg = scipy.ndimage.generic_filter(image, fnc, footprint = kernel, \
                                   mode = 'constant', cval = 2.0,   \
                                   extra_keywords = {'count': countkernel})

詳細

  • kernel=正方形の配列(1で表される円)
  • それ以降、ゼロではなく2でパディングすると、パディングされた領域のゼロと実際のラスターのゼロを適切に分離できませんでした。
  • countkernel=の1の数kernel
  • n= image2の値で識別されるパディングされた領域のセルを除外することにより、その中にあるセルの数
  • sum元の近隣の合計から(パディングされたセルの数* 2.0)を引くことによって修正します

更新

1)NaNでパディングすると、計算が約30%増加します。

    def fnc(buffer):
        return (numpy.nansum(buffer) / numpy.sum([~numpy.isnan(buffer)]))

    avg = scipy.ndimage.generic_filter(image, fnc, footprint = kernel, \
                                       mode = 'constant', cval = float(numpy.nan)

2)Yves Daoustによって提案されたソリューション(受け入れられた回答)を適用すると、処理時間が最小限に抑えられます。

    def fnc(buffer):
        return numpy.sum(buffer)

    sumbigimage = scipy.ndimage.generic_filter(image, fnc, \
                                               footprint = kernel, \
                                               mode = 'constant', \
                                               cval = 0.0)
    summask     = scipy.ndimage.generic_filter(mask, fnc, \
                                               footprint = kernel, \
                                               mode = 'constant', \
                                               cval = 0.0)
    avg = sumbigimage / summask

3)Yvesのヒントに基づいて、実際にはマスクを適用している追加のバイナリイメージを使用するために、マスクされた配列の原理に出くわしました。そのため、マスクされた配列は画像とマスク配列を「ブレンド」するため、1つの配列のみを処理する必要があります。
マスク配列の詳細:前回の更新で行ったように、内側の部分(元の画像の範囲)を1で埋め、外側の部分(境界線)を0で埋める代わりに、その逆を行う必要があります。マスクされた配列の1は「無効」を意味し、0は「有効」を意味します。
このコードは、アップデート2)で提供されたコードよりもさらに50%高速です。

    maskedimg = numpy.ma.masked_array(imgarray, mask = maskarray)

    def fnc(buffer):
        return numpy.mean(buffer)

    avg = scipy.ndimage.generic_filter(maskedimg, fnc, footprint = kernel, \
                                       mode = 'constant', cval = 0.0)

->ここで自分を正さなければなりません!
いくつかの計算を実行した後scipy.ndimage.<filters>、フィルター操作中にマスクが考慮されないという意味でmasked_arraysを処理できないように見えたため、検証中に誤解されたに違いありません。ここここ
のように、他の何人かの人々もこれについて言及。


画像の力...

  • 灰色:処理される画像の範囲
  • 白:パッド入りの領域(私の場合は2.0で埋められています)
  • 赤い色合い:カーネルの範囲
    • 濃い赤:効果的な隣人
    • 明るい赤:無視される近隣の一部

ここに画像の説明を入力してください


計算のパフォーマンスを向上させるために、このかなり実用的なコードをどのように変更できますか?

よろしくお願いします!

4

2 に答える 2

1

私はscipyに習熟していないため、これが役立つかどうかはわかりません。灰色の領域に1、白い領域に0の補助画像を使用します(ソース画像でも0)。次に、単純な合計で両方の画像にフィルターを適用します。

scipyが、合計のための組み込み関数を備えた特殊なバージョンのフィルターを提供する場合、スピードアップの希望があります。

これが完了すると、両方の画像をピクセルごとに分割する必要があります。

于 2012-05-24T09:02:51.460 に答える
0

これがどれほど効率的かはわかりませんが、nan境界線とマスクの両方を処理する'sを使用したより単純な定式化を使用しています。

マスクケースなし:

avg = scipy.ndimage.generic_filter(image, np.nanmean, mode='constant', cval=np.nan, footprint=kernel)

マスクケース:

masked_image = np.where(mask, image, np.nan)
avg = scipy.ndimage.generic_filter(masked_image, np.nanmean, mode='constant', cval=np.nan, footprint=kernel)

すべてnumpynan機能を使用できます。

于 2015-06-15T19:06:25.470 に答える