2016-08-23 120 views
-1

我有很多750x750圖像。我想從每幅圖像中獲取非重疊5x5塊的幾何平均值,然後對每幅圖像平均使用這些幾何平均值來爲每幅圖像創建一個特徵。我寫了下面的代碼,它似乎工作得很好。但是,我知道這不是很有效率。在300張左右的圖片上運行大約需要60秒。我有大約3000張圖片。所以,雖然它適用於我的目的,但效率並不高。我怎樣才能改進這個代碼?如何讓此代碼更快?

#each sublist of gmeans will contain a list of 22500 geometric means 
#corresponding to the non-overlapping 5x5 patches for a given image. 
gmeans = [[],[],[],[],[],[],[],[],[],[],[],[]] 
#the loop here populates gmeans. 
for folder in range(len(subfolders)): 
    just_thefilename, colorsourceimages, graycroppedfiles = get_all_images(folder) 
    for items in graycroppedfiles: 
     myarray = misc.imread(items) 
     area_of_big_matrix=750*750 
     area_of_small_matrix= 5*5 
     how_many = area_of_big_matrix/area_of_small_matrix 
     n = 0 
     p = 0 
     mylist=[] 
     while len(mylist) < how_many: 
      mylist.append(gmean(myarray[n:n+5,p:p+5],None)) 
      n=n+5 
      if n == 750: 
       p = p+5 
       n = 0 
     gmeans[folder].append(my list) 
#each sublist of mean_of_gmeans will contain just one feature per image, the mean of the geometric means of the 5x5 patches. 
mean_of_gmeans = [[],[],[],[],[],[],[],[],[],[],[],[]] 
for folder in range(len(subfolders)): 
    for items in range(len(gmeans[0])): 
     mean_of_gmeans[folder].append((np.mean(gmeans[folder][items],dtype=np.float64))) 
+1

可能是代碼審查合作伙伴網站的一個很好的候選人。不過,請確保先查看他們的網站規則。 – cel

+0

對於這樣一個簡單的操作,這確實聽起來很慢(我認爲我的一些代碼計算高達4階累積量,更像直方圖均衡更快)。我會做的第一件事:嘗試[scikit-image](http://scikit-image.org/),它給你一個名爲[view_as_block]的函數(http://scikit-image.org/docs/stable/api /skimage.util.html#view-as-blocks)。這是由一些先進的numpy函數[as_strided]實現的(http://www.scipy-lectures.org/advanced/advanced_numpy/#example-fake-dimensions-with-strides)。我無法保證任何事情,但速度可能會更快! – sascha

+0

代碼審查沒有太多的'numpy'流量;而「矢量化」是關於SO的常規問題。 CR對格式也很挑剔。 – hpaulj

回答

2

我可以理解的建議,這個移動到代碼審查現場, 但這個問題提供了使用矢量 numpy的和SciPy的功能電源的一個很好的例子,所以我會給出一個答案。

下面的函數,巧妙地稱爲func,計算所需的值。 關鍵是將圖像重塑爲四維數組。然後它可以被解釋爲二維數組的二維陣列,其中內部陣列是5×5塊。

scipy.stats.gmean可以計算的幾何平均超過一個 尺寸,以便被用於降低四維陣列的幾何平均值的 期望的二維數組。返回值是這些幾何平均值的 (算術)平均值。

import numpy as np 
from scipy.stats import gmean 


def func(img, blocksize=5): 
    # img must be a 2-d array whose dimensions are divisible by blocksize. 
    if (img.shape[0] % blocksize) != 0 or (img.shape[1] % blocksize) != 0: 
     raise ValueError("blocksize does not divide the shape of img.") 

    # Reshape 'img' into a 4-d array 'blocks', so blocks[i, :, j, :] is 
    # the subarray with shape (blocksize, blocksize). 
    blocks_nrows = img.shape[0] // blocksize 
    blocks_ncols = img.shape[1] // blocksize 
    blocks = img.reshape(blocks_nrows, blocksize, blocks_ncols, blocksize) 

    # Compute the geometric mean over axes 1 and 3 of 'blocks'. This results 
    # in the array of geometric means with size (blocks_nrows, blocks_ncols). 
    gmeans = gmean(blocks, axis=(1, 3), dtype=np.float64) 

    # The return value is the average of 'gmeans'. 
    avg = gmeans.mean() 

    return avg 

例如,此處的函數應用於形狀爲(750,750)的數組。

In [358]: np.random.seed(123) 

In [359]: img = np.random.randint(1, 256, size=(750, 750)).astype(np.uint8) 

In [360]: func(img) 
Out[360]: 97.035648309350179 

這是不容易驗證,這是正確的結果,所以這裏是一個小得多的例子:

In [365]: np.random.seed(123) 

In [366]: img = np.random.randint(1, 4, size=(3, 6)) 

In [367]: img 
Out[367]: 
array([[3, 2, 3, 3, 1, 3], 
     [3, 2, 3, 2, 3, 2], 
     [1, 2, 3, 2, 1, 3]]) 

In [368]: func(img, blocksize=3) 
Out[368]: 2.1863131342986666 

這裏是直接計算:

In [369]: 0.5*(gmean(img[:,:3], axis=None) + gmean(img[:, 3:], axis=None)) 
Out[369]: 2.1863131342986666 
+0

哇。我只用3000張圖像計時了我的功能。炎熱的13分鐘!你的功能 - 1。驚人。我完全不理解,我相信你的技能超過我的技能。但是,我的循環和你的函數在小數點後的第二個數字結尾。我不知道這是爲什麼?我在一些小的5x5矩陣上測試了我的循環,並且你的函數也是一樣的,最後我們得到了相同的值。看起來這些更大的矩陣發生了一些事情。 – dcook

+0

在處理這件事時,我發現'gmean'做了一些不符合其文檔字符串的類型轉換。如果您向類型爲'np.uint8'的數組傳遞'gmean'(通常用於圖像),則返回的結果的數據類型爲'np.float16'!我通過把'img = np.asarray(img,dtype = np。float64)'作爲'func()'的第一行,但事實證明你也可以使用它的'dtype'參數來指定'gmean'計算的數據類型。嘗試將'gmean'調用更改爲'gmean(myarray [n:n + 5,p:p + 5],None,dtype = np.float64)''。我更新了我的版本以使用它。 –