def atan2(y_x):
y, x = y_x[0], y_x[1]+K.epsilon()
atan = K.tf.atan(y/x)
angle = K.tf.where(K.tf.greater(x,0.0), atan, K.tf.zeros_like(x))
angle = K.tf.where(K.tf.logical_and(K.tf.less(x,0.0), K.tf.greater_equal(y,0.0)), atan+np.pi, angle)
angle = K.tf.where(K.tf.logical_and(K.tf.less(x,0.0), K.tf.less(y,0.0)), atan-np.pi, angle)
return angle
# traditional orientation estimation
def orientation(image, stride=8, window=17):
with K.tf.name_scope('orientation'):
assert image.get_shape().as_list()[3] == 1, 'Images must be grayscale'
strides = [1, stride, stride, 1]
E = np.ones([window, window, 1, 1])
sobelx = np.reshape(np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=float), [3, 3, 1, 1])
sobely = np.reshape(np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]], dtype=float), [3, 3, 1, 1])
gaussian = np.reshape(gaussian2d((5, 5), 1), [5, 5, 1, 1])
with K.tf.name_scope('sobel_gradient'):
Ix = K.tf.nn.conv2d(image, sobelx, strides=[1,1,1,1], padding='SAME', name='sobel_x')
Iy = K.tf.nn.conv2d(image, sobely, strides=[1,1,1,1], padding='SAME', name='sobel_y')
with K.tf.name_scope('eltwise_1'):
Ix2 = K.tf.multiply(Ix, Ix, name='IxIx')
Iy2 = K.tf.multiply(Iy, Iy, name='IyIy')
Ixy = K.tf.multiply(Ix, Iy, name='IxIy')
with K.tf.name_scope('range_sum'):
Gxx = K.tf.nn.conv2d(Ix2, E, strides=strides, padding='SAME', name='Gxx_sum')
Gyy = K.tf.nn.conv2d(Iy2, E, strides=strides, padding='SAME', name='Gyy_sum')
Gxy = K.tf.nn.conv2d(Ixy, E, strides=strides, padding='SAME', name='Gxy_sum')
with K.tf.name_scope('eltwise_2'):
Gxx_Gyy = K.tf.subtract(Gxx, Gyy, name='Gxx_Gyy')
theta = atan2([2*Gxy, Gxx_Gyy]) + np.pi
# two-dimensional low-pass filter: Gaussian filter here
with K.tf.name_scope('gaussian_filter'):
phi_x = K.tf.nn.conv2d(K.tf.cos(theta), gaussian, strides=[1,1,1,1], padding='SAME', name='gaussian_x')
phi_y = K.tf.nn.conv2d(K.tf.sin(theta), gaussian, strides=[1,1,1,1], padding='SAME', name='gaussian_y')
theta = atan2([phi_y, phi_x])/2
return theta