简体   繁体   English

张量流中的欧几里德距离变换

[英]Euclidean distance transform in tensorflow

I would like to create a tensorflow function, that replicates the euclidean distance transform of scipy for each 2-dimensional matrix in my 3-dimensional tensor. 我想创建一个张量流函数,它复制我的三维张量中每个二维矩阵的欧氏距离变换

I have a 3-dimensional tensor, where the third axis is representing a one-hot encoded feature. 我有一个三维张量,其中第三轴代表一个热门编码的特征。 I would like to create for each feature dimension a matrix, where the values in each cell equal the distance to the nearest feature. 我想为每个要素维创建一个矩阵,其中每个单元格中的值等于到最近要素的距离。

Example: 例:

input = [[1 0 0]
         [0 1 0]
         [0 0 1],

         [0 1 0]
         [0 0 0]
         [1 0 0]]

output = [[0    1   1.41]
          [1    0   1   ]
          [1.41 1   0   ],

          [1    0   1   ]
          [1    1   1.41]
          [0    1   2   ]]              

My current solution is implemented in python. 我目前的解决方案是在python中实现的。 The method iterates through every cell of a feature dimension, creates a ring around the cell and searches if the ring contains a feature. 该方法遍历要素维度的每个单元格,在单元格周围创建环并搜索环是否包含要素。 Then it calculates the distance for the cell to each feature entry and takes the minimum. 然后,它计算单元格到每个要素条目的距离,并采用最小值。 If the ring does not contain a cell with a feature in it, the search ring gets wider. 如果环不包含具有特征的单元格,则搜索环会变宽。

Code: 码:

import numpy as np
import math

def distance_matrix():
    feature_1 = np.eye(5)
    feature_2 = np.array([[0, 1, 0, 0, 0],
                  [0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0],
                  [1, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0],])
    ground_truth = np.stack((feature_1,feature_2), axis=2)
    x = np.zeros(ground_truth.shape)

    for feature_index in range(ground_truth.shape[2]):
        for i in range(ground_truth.shape[0]):
            for j in range(ground_truth.shape[1]):
                x[i,j,feature_index] = search_ring(i,j, feature_index,0,ground_truth)
    print(x[:,:,0])

def search_ring(i, j,feature_index, ring_size, truth):
    if ring_size == 0 and truth[i,j,feature_index] == 1.:
                    return 0
    else:
        distance = truth.shape[0]
        y_min = max(i - ring_size, 0)
        y_max = min(i + ring_size, truth.shape[0] - 1)
        x_min = max(j - ring_size, 0)
        x_max = min(j + ring_size, truth.shape[1] - 1)

        if truth[y_min:y_max+1, x_min:x_max+1, feature_index].sum() > 0:
            for y in range(y_min, y_max + 1):
                for x in range(x_min, x_max + 1):
                    if y == y_min or y == y_max or x == x_min or x == x_max:
                        if truth[y,x,feature_index] == 1.:
                            dist = norm(i,j,y,x,type='euclidean')
                            distance = min(distance, dist)
            return distance
        else:
            return search_ring(i, j,feature_index, ring_size + 1, truth)

def norm(index_y_a, index_x_a, index_y_b, index_x_b, type='euclidean'):
    if type == 'euclidean':
        return math.sqrt(abs(index_y_a - index_y_b)**2 + abs(index_x_a - index_x_b)**2)
    elif type == 'manhattan':
        return abs(index_y_a - index_y_b) + abs(index_x_a - index_x_b)


def main():
    distance_matrix()
if __name__ == '__main__':
    main()

My problem is replicating this in Tensorflow, since I need it for a custom loss function in Keras. 我的问题是在Tensorflow中复制这个,因为我需要它在Keras中的自定义丢失功能。 How can I access the indices of the items I am iterating through? 如何访问我正在迭代的项目的索引?

I don't see any problem for you to use the distance transform in keras , basically, all you need is tf.py_func , which wraps an existing python function to a tensorflow operator. 我没有看到你在keras使用距离变换的任何问题,基本上,你需要的只是tf.py_func ,它将现有的python函数包装到tensorflow运算符。

However, I think the fundamental issue here is about the backpropagation. 但是,我认为这里的根本问题是反向传播。 Your model will have any problem in the forward pass, but what gradient do you expect to propagate? 您的模型在前向传递中会有任何问题,但您希望传播的是什么渐变? Or you simply don't care its gradient at all. 或者你根本不关心它的渐变。

I've done something similar with py_func to create a signed distance transform, using scipy . 我已经做了类似的事情py_func创建一个符号距离变换,使用scipy Here's what it might look like in your case: 以下是您的情况:

import scipy.ndimage.morphology as morph
arrs = []
for channel_index in range(C):
    arrs.append(tf.py_func(morph.distance_transform_edt, [tensor[..., channel_index]], tf.float32))
edt_tf = tf.stack(arrs, axis=-1)

Note the limitations of py_func : they won't be serialized to GraphDefs , so it silently won't serialize the body of the function in the models you save. 请注意py_func的限制:它们不会被序列化为GraphDefs ,因此它将无法在您保存的模型中序列化函数体。 See the tf.py_func documentation . 请参阅tf.py_func文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM