2016-07-04 4 views
1

バイナリイメージ(numpy配列)を1ピクセル分拡張するCython関数を書きました。だから私は単純に配列の値がここ1 ている領域を拡大したい私の素朴なアプローチです:パフォーマンス:拡張バイナリイメージ(形態学的拡張)

def expand_1px (numpy.ndarray[numpy.uint8_t, ndim = 2] A): 
    cdef int h = A.shape[0] 
    cdef int w = A.shape[1] 
    cdef numpy.ndarray[numpy.uint8_t, ndim = 2] RES = numpy.zeros([h, w], dtype = numpy.uint8) 
    # These Two lines below were originally missing 
    cdef int y, x 
    cdef unsigned char prev, cur 

    for x in range (0, w): 
     for y in range (1, h): 
      prev = A[y-1,x] 
      cur = A[y,x] 
      if cur > prev: 
       RES[y-1, x] = 1 
      if cur < prev: 
       RES[y,x] = 1 
    for y in range (0, h): 
     for x in range (1, w): 
      prev = A[y,x-1] 
      cur = A[y,x] 
      if cur > prev: 
       RES[y, x-1] = 1 
      if cur < prev: 
       RES[y,x] = 1 
    return numpy.bitwise_or(A,RES) 

これが正常に動作しますが、は無残遅いです。 OpenCV関数dilate()は、私のCythonの変形よりも〜30倍高速で、同じ結果が得られます。

kernel = numpy.ones((3,3), dtype="uint8") 
kernel[0,0] = 0 
kernel[2,2] = 0 
kernel[0,2] = 0 
kernel[2,0] = 0 
... 
IMG = cv2.dilate(IMG,kernel,iterations = 1) 

Q

非常に高速のOpenCVの変異体でもできますか
  • 私はこのようにそれを使うのか?それは実際には何ですか?
  • 私のCython機能がとても速く動作するようにするにはどうすればよいですか?

更新

このような悪いパフォーマンスは 'CDEF' 宣言、私の悪いの欠落によるものでした。関数にこれを追加すると、違いは:

cdef int y, x 
cdef unsigned char prev, cur 

それでもパフォーマンスの差も一種のdissapointingで約30倍です。さらなる改善のためのアドバイス?

+0

* "私のCython関数はとても速く動作するようにするにはどうすればいいですか?" *ローカル変数(.eg 'x'、' y'、 'prev'、' cur' )を適切なC型に変換する。 –

+0

@WarrenWeckesserありがとうございます。 Youreもちろん、私はおそらくnoob間違いをしていることを知っていた。それでもOpenCVの亜種より30倍遅いです。私は質問を更新します。 –

+1

'-a'コマンドラインオプションを使って、cythonコマンドが色分けされたHTMLバージョンのソースを生成するようにしましたか?暗い黄色の線は、純粋なCを生成するのではなく、Pythonの呼び出しをもたらす行です。最高のパフォーマンスを得るには、ループに黄色がないようにcythonコードを微調整する必要があります。 (これらのループは非常にシンプルなので、すべての変数にCの宣言があれば、ループにPython呼び出しが残っていない可能性があります。) –

答えて

1

機能に大きな問題があります。必要なループが増えています。

import cython 

@wraparound(false) 
def expand_1px(numpy.ndarray[numpy.uint8_t, ndim = 2] A): 
    cdef int h = A.shape[0] 
    cdef int w = A.shape[1] 
    cdef numpy.ndarray[numpy.uint8_t, ndim = 2] RES = numpy.zeros([h, w], dtype = numpy.uint8) 
    cdef int y, x 
    cdef unsigned char prev, cur 

    for x in range(1, w): 
     for y in range(1, h): 
      cur = A[y,x] 

      prev = A[y-1,x] 
      if prev < cur: 
       RES[y-1,x] = 1 
      elif cur < prev: 
       RES[y,x] = 1 

      prev = A[y, x-1] 
      if prev < cur: 
       RES[y,x-1] = 1 
      elif cur < prev: 
       RES[y,x] = 1 

    for x in range(1, w): 
     cur = A[0,x] 
     prev = A[0,x-1] 
     if prev < cur: 
      RES[0,x-1] = 1 
     elif cur < prev: 
      RES[0,x] = 1 

    for y in range(1, h): 
     cur = A[y,0] 
     prev = A[y-1,0] 
     if prev < cur: 
      RES[y-1,0] = 1 
     elif cur < prev: 
      RES[y,0] = 1 

    return numpy.bitwise_or(A,RES) 

もともと、あなたは唯一のwh + w + h反復を行いますこの変更で、2wh反復をやっていました。

+0

これはいいですね。しかし、これは私のものとまったく同じ性能を持っており、より大きな配列でも試みました。反復回数は少なくなりますが、想定される操作量は同じです。したがって、両方のパスを1つのループで収集するだけです。 –