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

Как показано в следующем фрагменте кода, функция tensorflow tf.nn.dilation2D не вести себя как обычный оператор расширения.

import tensorflow as tf
tf.InteractiveSession()
A = [[0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 1, 0, 0],
     [0, 0, 0, 1, 1, 1, 0],
     [0, 0, 0, 0, 1, 0, 0],
     [0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0]]
kernel = tf.ones((3,3,1))
input4D = tf.cast(tf.expand_dims(tf.expand_dims(A, -1), 0), tf.float32)
output4D = tf.nn.dilation2d(input4D, filter=kernel, strides=(1,1,1,1), rates=(1,1,1,1), padding="SAME")
print(tf.cast(output4D[0,:,:,0], tf.int32).eval())

Возвращает следующий тензор:

array([[1, 1, 1, 2, 2, 2, 1],
       [1, 1, 2, 2, 2, 2, 2],
       [1, 1, 2, 2, 2, 2, 2],
       [1, 1, 2, 2, 2, 2, 2],
       [1, 1, 1, 2, 2, 2, 1],
       [1, 1, 1, 1, 1, 1, 1]], dtype=int32)

Я не понимаю ни почему он так себя ведет, ни как мне следует использовать tf.nn.dilation2d для получения ожидаемого результата:

array([[0, 0, 0, 1, 1, 1, 0],
       [0, 0, 1, 1, 1, 1, 1],
       [0, 0, 1, 1, 1, 1, 1],
       [0, 0, 1, 1, 1, 1, 1],
       [0, 0, 0, 1, 1, 1, 0],
       [0, 0, 0, 0, 0, 0, 0]], dtype=int32)

Может ли кто-нибудь просветить краткую документацию по тензорному потоку и объяснить, что делает функция tf.nn.dilation2D?


comment
@CrisLuengo, я попытался воспроизвести поведение, выполнив первое поле кода в этом сообщении. Я получаю AttributeError: модуль «tensorflow» не имеет атрибута «InteractiveSession». Когда я удаляю tf.InteractiveSession, я получаю TypeError: dilation2d_v2() получил неожиданный ключевой аргумент «фильтр». Не могли бы вы опубликовать версию этого кода, которая работает для tensorflow v2.4.1?   -  person Mark Lavin    schedule 15.02.2021
comment
@Марк, это не мой код. Я никогда не использовал tensorflow для обработки изображений.   -  person Cris Luengo    schedule 15.02.2021
comment
Спасибо, Крис. @Jav, есть комментарии?   -  person Mark Lavin    schedule 15.02.2021
comment
Этот вопрос был задан 2 года назад, поэтому для tf1.14. Прочтите документацию по tf2, если хотите преобразовать код tf1 в tf2.   -  person Jav    schedule 15.02.2021
comment
Неуместно обновлять вопрос до tensorflow2, поскольку с тех пор поведение могло измениться.   -  person Jav    schedule 15.02.2021


Ответы (2)


Как упоминалось на странице документации по ссылке,

Вычисляет расширение оттенков серого для 4-мерных входных данных и 3-мерных тензоров фильтров.

а также

В частности, морфологическое двумерное расширение в градациях серого представляет собой корреляцию максимальной суммы [...]

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

Сравните это с корреляцией, заменив умножение сложением, а интеграл (или сумму) с максимумом:

свертка: g(t) = ∫ f(????) h(????-t) д????

расширение: g(t) = max???? { f(????) + h(????-t) }

Или в дискретном мире:

свертка: g[n] = ∑k f[k ] ч[к-н]

расширение: g[n] = maxk { f[ k] + h[k-n] }


Расширение с бинарным элементом структурирования (ядро, которое в вопросе называется «обычное расширение») использует элемент структурирования (ядро), который содержит только 1 и 0. Они обозначают «включено» и «исключено». То есть единицы определяют домен структурирующего элемента.

Чтобы воссоздать такое же поведение с расширением значений серого, установите «включенные» пиксели на 0, а «исключенные» пиксели на минус бесконечность.

Например, квадратный структурирующий элемент 3x3, используемый в вопросе, должен представлять собой матрицу 3x3 нулей.

person Cris Luengo    schedule 17.03.2019
comment
Спасибо, не могли бы вы отредактировать, чтобы ответить на вопрос, как его следует использовать [...]? Я думаю, что тогда это зависит от ядра, но я не хотел бы испортить ваш ответ ;-) - person Jav; 18.03.2019
comment
@Jav: я забыл эту часть вопроса. Добавлен. - person Cris Luengo; 18.03.2019
comment
@CrisLuengo, в дополнение к Чтобы воссоздать то же поведение с расширением серого, установите «включенные» пиксели на 0, а «исключенные» пиксели на минус бесконечность. Разве вам также не нужно максимизировать результат с помощью 0, чтобы предотвратить результат, содержащий -бесконечность? - person Mark Lavin; 14.02.2021
comment
@MarkLavin Если в ядре есть хотя бы одно значение, отличное от -бесконечности, операция всегда будет возвращать конечное значение. Конечно, предполагая, что входное изображение содержит только конечные значения. Если бы ядро ​​было all-infinity, операция не имела бы смысла. - person Cris Luengo; 14.02.2021
comment
max(res,0) было бы полезно, чтобы избежать отрицательных значений, а не неконечных значений. - person Cris Luengo; 14.02.2021

можно сделать так:

def dilation2d(self, img4D):
    '''
    '''
    with tf.variable_scope('dilation2d'):
        kernel = tf.ones((3, 3, img4D.get_shape()[3])) 
        output4D = tf.nn.dilation2d(img4D, filter=kernel, strides=(1,1,1,1), rates=(1,1,1,1), padding="SAME")
        output4D = output4D - tf.ones_like(output4D)

        return output4D
person CHEN    schedule 31.05.2019
comment
Грустно, что мой ответ не был понят. Если вы делаете kernel = tf.zeros(...) (вместо ones), то вам не нужно вычитать 1 после расширения. - person Cris Luengo; 10.01.2020