簡體   English   中英

使用python在圖像上使用最大似然算法進行分割

[英]Segmentation using maximum likelihood algorithm on images using python

我想使用在python中實現的最大似然算法執行圖像分割。 類的均值向量和協方差矩陣是已知的,並且可以在圖像上進行迭代(很大... 5100X7020),我們可以為每個像素計算成為給定類的一部分的概率。

只需用Python編寫

import numpy as np
from numpy.linalg import inv
from numpy.linalg import det
...

probImage1 = []
probImage1Vector = []

norm = 1.0 / (np.power((2*np.pi), i/2) * np.sqrt(np.linalg.det(covMatrixClass1)))
covMatrixInverz = np.linalg.inv(covMatrixClass1)
for x in xrange(x_img):
    for y in xrange(y_img):
        X = realImage[x,y]
        pixelValueDifference = X - meanVectorClass1
        mult1 = np.multiply(-0.5,np.transpose(pixelValueDifference))
        mult2 = np.dot(covMatrixInverz,pixelValueDifference)
        multMult = np.dot(mult1,mult2)
        expo = np.exp(multMult)     
        probImage1Vector.append(np.multiply(norm,expo))
    probImage1.append(probImage1Vector)
    probImage1Vector = []

這個代碼在大圖像上執行時速度很慢的問題...矢量減法和乘法之類的計算會消耗大量時間,即使它們只是1X3矢量。

您能否提示如何加快此代碼的速度? 我真的很感激。 抱歉,如果我不清楚,我仍然是python的初學者。

仔細看看:

mult1 = np.multiply(-0.5,np.transpose(pixelValueDifference))
mult2 = np.dot(covMatrixInverz,pixelValueDifference)
multMult = np.dot(mult1,mult2)

我們看到該操作基本上是:

A.T (d) C (d) A         # where `(d)` is the dot-product

這三個步驟可以很容易地表示為np.einsum一個字符串符號,就像這樣-

np.einsum('k,lk,l->',pA,covMatrixInverz,-0.5*pA)

在兩個迭代器i(=x)j(=y)執行此操作,我們將得到一個完全矢量化的表達式-

np.einsum('ijk,lk,ijl->ij',pA,covMatrixInverz,-0.5*pA))

或者,我們可以使用np.tensordot減少的第一部分-

mult2_vectorized = np.tensordot(pA, covMatrixInverz, axes=([2],[1]))
output = np.einsum('ijk,ijk->ij',-0.5*pA, mult2_vectorized)

標桿

將所有方法列為功能-

# Original code posted by OP to return array
def org_app(meanVectorClass1, realImage, covMatrixInverz, norm):
    probImage1 = []
    probImage1Vector = []
    x_img, y_img = realImage.shape[:2]
    for x in xrange(x_img):
        for y in xrange(y_img):
            X = realImage[x,y]
            pixelValueDifference = X - meanVectorClass1
            mult1 = np.multiply(-0.5,np.transpose(pixelValueDifference))
            mult2 = np.dot(covMatrixInverz,pixelValueDifference)
            multMult = np.dot(mult1,mult2)
            expo = np.exp(multMult)     
            probImage1Vector.append(np.multiply(norm,expo))
            probImage1.append(probImage1Vector)
            probImage1Vector = []
    return np.asarray(probImage1).reshape(x_img,y_img)

def vectorized(meanVectorClass1, realImage, covMatrixInverz, norm):
    pA = realImage - meanVectorClass1
    mult2_vectorized = np.tensordot(pA, covMatrixInverz, axes=([2],[1]))
    return np.exp(np.einsum('ijk,ijk->ij',-0.5*pA, mult2_vectorized))*norm

def vectorized2(meanVectorClass1, realImage, covMatrixInverz, norm):
    pA = realImage - meanVectorClass1
    return np.exp(np.einsum('ijk,lk,ijl->ij',pA,covMatrixInverz,-0.5*pA))*norm

時間-

In [19]: # Setup inputs
    ...: meanVectorClass1 = np.array([23.96000000, 58.159999, 61.5399])
    ...: 
    ...: covMatrixClass1 = np.array([[ 514.20040404,  461.68323232,  364.35515152],
    ...:        [ 461.68323232,  519.63070707,  446.48848485],
    ...:        [ 364.35515152,  446.48848485,  476.37212121]])
    ...: covMatrixInverz = np.linalg.inv(covMatrixClass1)
    ...: 
    ...: norm = 0.234 # Random float number
    ...: realImage = np.random.rand(1000,2000,3)
    ...: 

In [20]: out1 = org_app(meanVectorClass1, realImage, covMatrixInverz, norm )
    ...: out2 = vectorized(meanVectorClass1, realImage, covMatrixInverz, norm )
    ...: out3 = vectorized2(meanVectorClass1, realImage, covMatrixInverz, norm )
    ...: print np.allclose(out1, out2)
    ...: print np.allclose(out1, out3)
    ...: 
True
True

In [21]: %timeit org_app(meanVectorClass1, realImage, covMatrixInverz, norm )
1 loops, best of 3: 27.8 s per loop

In [22]: %timeit vectorized(meanVectorClass1, realImage, covMatrixInverz, norm )
1 loops, best of 3: 182 ms per loop

In [23]: %timeit vectorized2(meanVectorClass1, realImage, covMatrixInverz, norm )
1 loops, best of 3: 275 ms per loop

看起來完全矢量化的einsum + tensordot混合解決方案做得很好!

為了進一步提高性能,還可以考慮使用numexpr模塊來加速大型數組上的exponential計算。

第一步,我將擺脫不必要的函數調用,例如轉置,點和乘法。 這些都是您應該內聯進行的簡單計算。 當您真正看到自己在做什么時,與其將其隱藏在函數內部,不如將其理解為性能問題。

這里的根本問題是,這似乎至少是四次復雜度運算。 您可能想簡單地將所有循環中要執行的操作數相乘。 是5億,20億,3500億? 多少?

要控制性能,您需要了解您正在執行多少指令。 現代計算機每秒可以執行約10億條指令,但是如果涉及內存移動,則速度可能會大大降低。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM