Эффективное вычисление адаптированного к границам среднего значения окрестности

У меня есть изображение со значениями в диапазоне от 0 до 1. Что мне нравится делать, так это простое усреднение.
Но, более конкретно, для ячейки на границе изображения я хотел бы вычислить среднее значение пикселей для той части окрестности/ядра, которая находится в пределах изображения. На самом деле это сводится к адаптации знаменателя «средней формулы», количества пикселей, на которое вы делите сумму.

Мне удалось сделать это, как показано ниже, с scipy.ndimage.generic_filter, но это далеко не эффективно по времени.

def fnc(buffer, count):
    n = float(sum(buffer < 2.0))
    sum = sum(buffer) - ((count - b) * 2.0)
    return (sum / n)

avg = scipy.ndimage.generic_filter(image, fnc, footprint = kernel, \
                                   mode = 'constant', cval = 2.0,   \
                                   extra_keywords = {'count': countkernel})

Details

  • kernel= квадратный массив (круг, представленный единицами)
  • Заполнение двойками, а не нулями, так как с тех пор я не мог правильно разделить нули заполненной области и нули фактического растра
  • countkernel= количество единиц в ядре
  • n= количество ячеек, лежащих в пределах imageза счет исключения ячеек заполненной области, идентифицированных значениями 2
  • Исправьте сумму, вычитая (количество заполненных ячеек * 2.0) из исходной общей суммы окрестности

Обновление(я)

1) Добавление NaN увеличивает вычисление примерно на 30%:

    def fnc(buffer):
        return (numpy.nansum(buffer) / numpy.sum([~numpy.isnan(buffer)]))

    avg = scipy.ndimage.generic_filter(image, fnc, footprint = kernel, \
                                       mode = 'constant', cval = float(numpy.nan)

2) Применение решения, предложенного Ивом Даустом( принятый ответ), определенно сокращает время обработки до минимума:

    def fnc(buffer):
        return numpy.sum(buffer)

    sumbigimage = scipy.ndimage.generic_filter(image, fnc, \
                                               footprint = kernel, \
                                               mode = 'constant', \
                                               cval = 0.0)
    summask     = scipy.ndimage.generic_filter(mask, fnc, \
                                               footprint = kernel, \
                                               mode = 'constant', \
                                               cval = 0.0)
    avg = sumbigimage / summask

3) Основываясь на совете Иваиспользовать дополнительное бинарное изображение, которое фактически является применением маски, я наткнулся на принцип маскированные массивы. Таким образом, необходимо обрабатывать только один массив, потому что маскированный массив «сочетает» массивы изображений и масок вместе.
Небольшая деталь о массиве масок: вместо заполнения внутренней части (протяженности исходного изображения) единицами и заполнения внешней части (границы) нулями, как это было сделано в предыдущем обновлении, вы должны сделать наоборот. 1 в замаскированном массиве означает «недействительный», 0 означает «действительный».
Этот код даже на 50% быстрее, чем код, представленный в обновлении 2):

    maskedimg = numpy.ma.masked_array(imgarray, mask = maskarray)

    def fnc(buffer):
        return numpy.mean(buffer)

    avg = scipy.ndimage.generic_filter(maskedimg, fnc, footprint = kernel, \
                                       mode = 'constant', cval = 0.0)

--> Здесь я должен исправиться!
Должно быть, я ошибся при валидации, так как после некоторых прогонов вычислений оказалось, что scipy.ndimage.не может обрабатывать masked_arrays в том смысле, что при работе фильтра маска не учитывается .
Некоторые другие люди также упомянули об этом, например здесьи здесь.


Сила изображения...

  • серый: размер обрабатываемого изображения
  • белый: заполненная область (в моем случае заполнена 2.0's)
  • оттенки красного: степень ядра
    • темно-красный: эффективная окрестность
    • светло-красный: часть окрестности игнорируется

enter image description here


Как можно изменить этот довольно прагматичный фрагмент кода, чтобы повысить производительность вычислений?

Заранее большое спасибо!

6
задан kadéem 26 May 2012 в 13:29
поделиться