2016-07-04 3 views
1

Я написал функцию Cython, которая расширяет двоичное изображение (массив numpy) на 1 пиксель. Поэтому я хочу, чтобы просто расширить область, где значение массива является: 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() равна ~ 30 раз быстрее, чем мой вариант Cython, и дает тот же результат. Я использую это так:

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 работать так быстро?

Update:

Такое плохое выступление было из-за отсутствия 'CDEF' деклараций, мой плохой. Добавление этой функции делает разницу:

cdef int y, x 
cdef unsigned char prev, cur 

Тем не менее, разница в производительности составляет около 30 раз, что также вид dissapointing. Любые советы для дальнейшего совершенствования?

+0

* «Как я могу заставить свою функцию Cython работать так быстро?» * Вы можете начать с объявления большего количества (возможно, всех) ваших локальных переменных (.eg 'x',' y', 'prev',' cur') с соответствующим типом С; см. http://docs.cython.org/src/quickstart/cythonize.html –

+0

@WarrenWeckesser Спасибо. Вы, конечно, конечно, я знал, что, вероятно, совершу ошибку в noob. Тем не менее это ~ 30 раз медленнее, чем вариант OpenCV, я обновлю вопрос. –

+1

Вы использовали параметр командной строки '-a', чтобы команда cython генерировала раскрашенную HTML-версию источника? Темно-желтые линии - это линии, которые приводят к вызовам Python вместо генерации чистого C. Для достижения максимальной производительности вы хотите настроить код 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) 

Первоначально вы делали 2wh итераций, с этим изменением вы будете только делать wh + w + h итераций.

+0

Это приятно.Но это имеет то же значение, что и у меня, а также с большими массивами. Меньше итераций, но такое же количество операций, я полагаю, поэтому вы просто собираете оба прохода в одном цикле. –

Смежные вопросы