2015-03-08 5 views
8

मैं एक परियोजना पर काम कर रहा हूं जिसमें एक छवि का अंतर प्राप्त करने की आवश्यकता है। वर्तमान में मैं 2 दृष्टिकोण ले रहा हूँ (दोनों काम लेकिन बहुत धीमी गति से कर रहे हैं):एक छवि पायथन कुशलता से भिन्नता की गणना

  1. व्यक्तिगत रूप से प्रत्येक पिक्सेल के लिए विचरण की गणना:

यह numpy का उपयोग कर कोड है, varianceMatrix उत्पादन

है
varianceMatrix = np.zeros(im.shape,np.uint8) 
w = 1    # the radius of pixels neighbors 
ny = len(im) 
nx = len(im[0]) 


for i in range(w,nx-w): 
    for j in range(w,ny-w): 

     sampleframe = im[j-w:j+w, i-w:i+w] 
     variance = np.var(sampleframe) 
     varianceMatrix[j][i] = int(variance) 

return varianceMatrix 
  1. एक मौजूदा scipy समारोह का उपयोग करना:

यह scipy समारोह है:

from scipy import ndimage 

varianceMatrix = ndimage.generic_filter(im, np.var, size = 3) 

scipy समारोह तेजी से होता है, लेकिन इतना नहीं। मैं भिन्नता की गणना करने के लिए एक बेहतर विकल्प की तलाश में हूं।

कोई विचार ???

उत्तर

0

यदि ndimage.generic_filter का उपयोग करने की विधि पर्याप्त तेज़ नहीं है, तो आप Cython में भिन्न गणना के लिए अपना स्वयं का अनुकूलित कार्यान्वयन लिख सकते हैं।

1

आप गणना को तेज करने के लिए एक प्रसिद्ध sliding window stride trick का उपयोग कर सकते हैं। यह डेटा की प्रतिलिपि किए बिना सरणी के अंत में दो "वर्चुअल आयाम" जोड़ता है, और फिर उन पर भिन्नता की गणना करता है।

ध्यान दें कि आपके कोड में, im[j-w:j+w, ..] सूचकांक j-w,j-w+1,...,j+w-1 पर चला जाता है, अंतिम वाला एकमात्र अनन्य है, जिसका आप मतलब नहीं हो सकते हैं। इसके अलावा, भिन्नताएं uint8 रेंज से बड़ी हैं, इसलिए आप पूर्णांक रैपरराउंड के साथ समाप्त होते हैं।

import numpy as np 
import time 
np.random.seed(1234) 

img = (np.random.rand(200, 200)*256).astype(np.uint8) 

def sliding_window(a, window, axis=-1): 
    shape = list(a.shape) + [window] 
    shape[axis] -= window - 1 
    if shape[axis] < 0: 
     raise ValueError("Array too small") 
    strides = a.strides + (a.strides[axis],) 
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides) 

def sliding_img_var(img, window): 
    if window <= 0: 
     raise ValueError("invalid window size") 
    buf = sliding_window(img, 2*window, 0) 
    buf = sliding_window(buf, 2*window, 1) 

    out = np.zeros(img.shape, dtype=np.float32) 
    np.var(buf[:-1,:-1], axis=(-1,-2), out=out[window:-window,window:-window]) 
    return out 

def looping_img_var(im, w): 
    nx, ny = img.shape 
    varianceMatrix = np.zeros(im.shape, np.float32) 
    for i in range(w,nx-w): 
     for j in range(w,ny-w): 
      sampleframe = im[j-w:j+w, i-w:i+w] 
      variance = np.var(sampleframe) 
      varianceMatrix[j][i] = variance 
    return varianceMatrix 

np.set_printoptions(linewidth=1000, edgeitems=5) 
start = time.time() 
print(sliding_img_var(img, 1)) 
time_sliding = time.time() - start 
start = time.time() 
print(looping_img_var(img, 1)) 
time_looping = time.time() - start 
print("duration: sliding: {0} s, looping: {1} s".format(time_sliding, time_looping)) 
+0

यहां मेरी मशीन पर आउटपुट की आखिरी पंक्ति, गति दिखा रहा है: 'अवधि: स्लाइडिंग: 0.00510311126709 एस, लूपिंग: 0.955919027328 एस'। –

4

यहाँ OpenCV का उपयोग कर एक तेजी से समाधान:।

import cv2 

def winVar(img, wlen): 
    wmean, wsqrmean = (cv2.boxFilter(x, -1, (wlen, wlen), 
    borderType=cv2.BORDER_REFLECT) for x in (img, img*img)) 
    return wsqrmean - wmean*wmean 

मेरी मशीन पर और निम्नलिखित उदाहरण के लिए, winVar() 2915 बार ndimage.generic_filter() तुलना में तेजी से और 10.8 गुना तेजी से sliding_img_var() से (PV देखना है के जवाब):

In [66]: img = np.random.randint(0, 256, (500,500)).astype(np.float) 

In [67]: %timeit winVar(img, 3) 
100 loops, best of 3: 1.76 ms per loop 

In [68]: %timeit ndimage.generic_filter(img, np.var, size=3) 
1 loops, best of 3: 5.13 s per loop 

In [69]: %timeit sliding_img_var(img, 1) 
100 loops, best of 3: 19 ms per loop 

परिणाम से मेल खाता है ndimage.generic_filter() की:

In [70]: np.allclose(winVar(img, 3), ndimage.generic_filter(img, np.var, size=3)) 
Out[70]: True 
+1

'ndimage.uniform_filter()' 'cv2.boxFilter()' के बजाय उपयोग किया जा सकता है, [इस उत्तर] (http://stackoverflow.com/a/33497963/1628638) को इसी तरह के प्रश्न पर देखें। उदाहरण के लिए मैंने यहां उपयोग किया, ओपनसीवी संस्करण 4.1 गुना तेज था। –

+1

इसके बजाए मानक विचलन की गणना करने के लिए (यानी, 'winVar()' को 'winStd()' में बदलें), बस 'वापसी np.sqrt (wsqrmean - wmean * wmean)' में बदलें। –

संबंधित मुद्दे