使用 TensorFlow 对图像中的点进行插值采样
Interpolated sampling of points in an image with TensorFlow
给定的是灰度图像 I 作为 2D 张量(维度 W,H)和坐标张量 C(暗淡。None,2).我想将 C 的行解释为 I 中的坐标,在这些坐标处使用一些示例 I一种插值(双线性可能适合我的用例),并将结果值存储在新的 Tensor P(维度 None,即 1 维,如许多条目,因为 C 有行)。
使用 TensorFlow 可以(有效地)做到这一点吗?我所能找到的只是调整图像大小(如果你愿意,可以进行等距重采样)的函数。但是我找不到任何开箱即用的东西来在坐标列表中进行采样。
即我本以为会找到类似 tf.interpolate() 函数的东西:
I = tf.placeholder("float", shape=[128, 128])
C = tf.placeholder("float", shape=[None, 2])
P = tf.interpolate(I, C, axis=[0, 1], method="linear")
理想情况下,我会寻找一种解决方案,允许我使用 C[=32= 沿 M 维插入 N 维张量 I ] 形状为 (None, M) 并产生 N-M+1 维输出,如上面代码中的 "axis" 参数所示。
(顺便说一句,我的应用程序中的 "image" 不是图片,它是来自物理模型(用作占位符时)或替代学习模型(用作变量时)的采样数据。现在这个物理模型有 2 个自由度,因此在 "image" 中插值目前就足够了,但我可能会在未来研究更高维度的模型。)
如果现有的 TensorFlow 功能无法实现类似的功能:当我想实现类似 tf.interpolate() 运算符的功能时,我应该从哪里开始? (文档and/or简单示例代码)
没有 built-in 操作可以执行这种插值,但您应该能够使用现有 TensorFlow 操作的组合来完成。对于双线性情况,我建议采用以下策略:
根据索引的张量 C
,计算对应于四个角点的整数张量。例如(假设原点在左上角的名称):
top_left = tf.cast(tf.floor(C), tf.int32)
top_right = tf.cast(
tf.concat(1, [tf.floor(C[:, 0:1]), tf.ceil(C[:, 1:2])]), tf.int32)
bottom_left = tf.cast(
tf.concat(1, [tf.ceil(C[:, 0:1]), tf.floor(C[:, 1:2])]), tf.int32)
bottom_right = tf.cast(tf.ceil(C), tf.int32)
从代表特定角点的每个张量中,从这些点的 I
中提取值向量。例如,对于以下函数,它针对二维情况执行此操作:
def get_values_at_coordinates(input, coordinates):
input_as_vector = tf.reshape(input, [-1])
coordinates_as_indices = (coordinates[:, 0] * tf.shape(input)[1]) + coordinates[:, 1]
return tf.gather(input_as_vector, coordinates_as_indices)
values_at_top_left = get_values_at_coordinates(I, top_left)
values_at_top_right = get_values_at_coordinates(I, top_right)
values_at_bottom_left = get_values_at_coordinates(I, bottom_left)
values_at_bottom_right = get_values_at_coordinates(I, bottom_right)
先计算水平方向的插值:
# Varies between 0.0 and 1.0.
horizontal_offset = C[:, 0] - tf.cast(top_left[:, 0], tf.float32)
horizontal_interpolated_top = (
((1.0 - horizontal_offset) * values_at_top_left)
+ (horizontal_offset * values_at_top_right))
horizontal_interpolated_bottom = (
((1.0 - horizontal_offset) * values_at_bottom_left)
+ (horizontal_offset * values_at_bottom_right))
现在计算垂直方向的插值:
vertical_offset = C[:, 1] - tf.cast(top_left[:, 1], tf.float32)
interpolated_result = (
((1.0 - vertical_offset) * horizontal_interpolated_top)
+ (vertical_offset * horizontal_interpolated_bottom))
鉴于 TF 尚不具备 Numpy 切片通用性 (github issue #206),而且 gather
仅适用于第一维,事实证明这对于最近的邻居来说很棘手。但是这里有一种方法可以通过使用 gather->transpose->gather->extract diagonal
来解决它
def identity_matrix(n):
"""Returns nxn identity matrix."""
# note, if n is a constant node, this assert node won't be executed,
# this error will be caught during shape analysis
assert_op = tf.Assert(tf.greater(n, 0), ["Matrix size must be positive"])
with tf.control_dependencies([assert_op]):
ones = tf.fill(n, 1)
diag = tf.diag(ones)
return diag
def extract_diagonal(tensor):
"""Extract diagonal of a square matrix."""
shape = tf.shape(tensor)
n = shape[0]
assert_op = tf.Assert(tf.equal(shape[0], shape[1]), ["Can't get diagonal of "
"a non-square matrix"])
with tf.control_dependencies([assert_op]):
return tf.reduce_sum(tf.mul(tensor, identity_matrix(n)), [0])
# create sample matrix
size=4
I0=np.zeros((size,size), dtype=np.int32)
for i in range(size):
for j in range(size):
I0[i, j] = 10*i+j
I = tf.placeholder(dtype=np.int32, shape=(size,size))
C = tf.placeholder(np.int32, shape=[None, 2])
C0 = np.array([[0, 1], [1, 2], [2, 3]])
row_indices = C[:, 0]
col_indices = C[:, 1]
# since gather only supports dim0, have to transpose
I1 = tf.gather(I, row_indices)
I2 = tf.gather(tf.transpose(I1), col_indices)
I3 = extract_diagonal(tf.transpose(I2))
sess = create_session()
print sess.run([I3], feed_dict={I:I0, C:C0})
所以从这样的矩阵开始:
array([[ 0, 1, 2, 3],
[10, 11, 12, 13],
[20, 21, 22, 23],
[30, 31, 32, 33]], dtype=int32)
此代码提取主线上方的对角线
[array([ 1, 12, 23], dtype=int32)]
[] 运算符变成了 Squeeze
和 Slice
发生了一些神奇的事情
给定的是灰度图像 I 作为 2D 张量(维度 W,H)和坐标张量 C(暗淡。None,2).我想将 C 的行解释为 I 中的坐标,在这些坐标处使用一些示例 I一种插值(双线性可能适合我的用例),并将结果值存储在新的 Tensor P(维度 None,即 1 维,如许多条目,因为 C 有行)。
使用 TensorFlow 可以(有效地)做到这一点吗?我所能找到的只是调整图像大小(如果你愿意,可以进行等距重采样)的函数。但是我找不到任何开箱即用的东西来在坐标列表中进行采样。
即我本以为会找到类似 tf.interpolate() 函数的东西:
I = tf.placeholder("float", shape=[128, 128])
C = tf.placeholder("float", shape=[None, 2])
P = tf.interpolate(I, C, axis=[0, 1], method="linear")
理想情况下,我会寻找一种解决方案,允许我使用 C[=32= 沿 M 维插入 N 维张量 I ] 形状为 (None, M) 并产生 N-M+1 维输出,如上面代码中的 "axis" 参数所示。
(顺便说一句,我的应用程序中的 "image" 不是图片,它是来自物理模型(用作占位符时)或替代学习模型(用作变量时)的采样数据。现在这个物理模型有 2 个自由度,因此在 "image" 中插值目前就足够了,但我可能会在未来研究更高维度的模型。)
如果现有的 TensorFlow 功能无法实现类似的功能:当我想实现类似 tf.interpolate() 运算符的功能时,我应该从哪里开始? (文档and/or简单示例代码)
没有 built-in 操作可以执行这种插值,但您应该能够使用现有 TensorFlow 操作的组合来完成。对于双线性情况,我建议采用以下策略:
根据索引的张量
C
,计算对应于四个角点的整数张量。例如(假设原点在左上角的名称):top_left = tf.cast(tf.floor(C), tf.int32) top_right = tf.cast( tf.concat(1, [tf.floor(C[:, 0:1]), tf.ceil(C[:, 1:2])]), tf.int32) bottom_left = tf.cast( tf.concat(1, [tf.ceil(C[:, 0:1]), tf.floor(C[:, 1:2])]), tf.int32) bottom_right = tf.cast(tf.ceil(C), tf.int32)
从代表特定角点的每个张量中,从这些点的
I
中提取值向量。例如,对于以下函数,它针对二维情况执行此操作:def get_values_at_coordinates(input, coordinates): input_as_vector = tf.reshape(input, [-1]) coordinates_as_indices = (coordinates[:, 0] * tf.shape(input)[1]) + coordinates[:, 1] return tf.gather(input_as_vector, coordinates_as_indices) values_at_top_left = get_values_at_coordinates(I, top_left) values_at_top_right = get_values_at_coordinates(I, top_right) values_at_bottom_left = get_values_at_coordinates(I, bottom_left) values_at_bottom_right = get_values_at_coordinates(I, bottom_right)
先计算水平方向的插值:
# Varies between 0.0 and 1.0. horizontal_offset = C[:, 0] - tf.cast(top_left[:, 0], tf.float32) horizontal_interpolated_top = ( ((1.0 - horizontal_offset) * values_at_top_left) + (horizontal_offset * values_at_top_right)) horizontal_interpolated_bottom = ( ((1.0 - horizontal_offset) * values_at_bottom_left) + (horizontal_offset * values_at_bottom_right))
现在计算垂直方向的插值:
vertical_offset = C[:, 1] - tf.cast(top_left[:, 1], tf.float32) interpolated_result = ( ((1.0 - vertical_offset) * horizontal_interpolated_top) + (vertical_offset * horizontal_interpolated_bottom))
鉴于 TF 尚不具备 Numpy 切片通用性 (github issue #206),而且 gather
仅适用于第一维,事实证明这对于最近的邻居来说很棘手。但是这里有一种方法可以通过使用 gather->transpose->gather->extract diagonal
def identity_matrix(n):
"""Returns nxn identity matrix."""
# note, if n is a constant node, this assert node won't be executed,
# this error will be caught during shape analysis
assert_op = tf.Assert(tf.greater(n, 0), ["Matrix size must be positive"])
with tf.control_dependencies([assert_op]):
ones = tf.fill(n, 1)
diag = tf.diag(ones)
return diag
def extract_diagonal(tensor):
"""Extract diagonal of a square matrix."""
shape = tf.shape(tensor)
n = shape[0]
assert_op = tf.Assert(tf.equal(shape[0], shape[1]), ["Can't get diagonal of "
"a non-square matrix"])
with tf.control_dependencies([assert_op]):
return tf.reduce_sum(tf.mul(tensor, identity_matrix(n)), [0])
# create sample matrix
size=4
I0=np.zeros((size,size), dtype=np.int32)
for i in range(size):
for j in range(size):
I0[i, j] = 10*i+j
I = tf.placeholder(dtype=np.int32, shape=(size,size))
C = tf.placeholder(np.int32, shape=[None, 2])
C0 = np.array([[0, 1], [1, 2], [2, 3]])
row_indices = C[:, 0]
col_indices = C[:, 1]
# since gather only supports dim0, have to transpose
I1 = tf.gather(I, row_indices)
I2 = tf.gather(tf.transpose(I1), col_indices)
I3 = extract_diagonal(tf.transpose(I2))
sess = create_session()
print sess.run([I3], feed_dict={I:I0, C:C0})
所以从这样的矩阵开始:
array([[ 0, 1, 2, 3],
[10, 11, 12, 13],
[20, 21, 22, 23],
[30, 31, 32, 33]], dtype=int32)
此代码提取主线上方的对角线
[array([ 1, 12, 23], dtype=int32)]
[] 运算符变成了 Squeeze
和 Slice