• Facebook
  • Twitter
  • Reddit
  • StumbleUpon
  • Digg
  • email

#################################################################
# SE(n) acting on Rn via group morphology
#################################################################
 
import scipy as sp;
import math;
import scipy.signal as signal;
import r_mor   as rn;
from indicator import *;
 
 
#################################################################
# Pointwise Group/Homogeneous space operators (untested)
#################################################################
 
 
#Group element product
def productp(g, h):
	c = math.cos(g[0]);
	s = math.sqrt(1. - c*c);
	return (g[0] + h[0], g[1] + c*h[1] - s*h[2], g[2] + s*h[1] + c*h[2]);
 
#Group element inverse
def inversep(g):
	c = math.cos(g[0]);
	s = math.sqrt(1. - c*c);
	return (-g[0], c*g[1] + s*g[2], -s*g[1] + c*g[2]);
 
#Applies the action g = (theta,x,y) to an element in R2
def actionp(g, p):
	c = math.cos(g[0]);
	s = math.sqrt(1. - c*c);
	return (g[1] + c*p[0] - s*p[1], g[2] + s*p[0] + c*p[1]);
 
#Projects an element g in SE(2) down to a point in R2
def projectp(g):
	return action(g, (0,0));
 
#Maps a point p in R2 to an element in SE(2)
def taup(p):
	return (0, p[0], p[1]);
 
#Gamma map
def gammap(g):
	return g[0];
 
 
#################################################################
# Index conversion (untested)
#################################################################
 
#Converts an indexed element (i,j,k) to an element of SE(2), given by (theta, x,y) according to the specified grid resolution dims
def index2group(index, dims):
	return (tr[2] * 2. * sp.pi / float(dims[2]), dims[0]/2 - index[0] , index[1]/2 - tr[1]);
 
#Converts a group element to an index
def group2index(g, dims):
	i,j = int(g[1] - dims[0]/2), int(g[2] - dims[1]/2);
	k = int(.5 * g[0] * dims[0] / sp.pi);
	if(k < 0):
		k += (int(k/dims[0]) + 1) * dims[0];
	return (i,j,k%dims[0]);
 
 
#################################################################
# Group-function primitives (untested)
#################################################################
 
#Computes the support of a function in SE(2)
def supp(f):
	return vol(f);
 
#Applies a rotation to the function f
def rotate(theta, f):
	return scipy.misc.imrotate(f, theta * 180. / pi);
 
#Group product on functions over the group (left action)
def product_l(g, f):
	res = sp.zeros((f.shape[0]+abs(g[1]), f.shape[1] + abs(g[2]), f.shape[3]));
	for r in range(f.shape[2]):
		theta = float(r) * pi / float(f.shape[2]);
		res[:,:,r] = r2.shift((g[1], g[2]), rotate(g[0], f));
	return res;
 
#Group product on functions over the group (right action)
def product_r(f, g):
	res = sp.zeros(f.shape);
	assert(False);
 
#Computes inversion of functions on the group
def inversion(f):
	res = sp.zeros(f.shape);
	for r in range(f.shape[2]):
		res[:,:,r] = f[:,:,(f.shape[2] - r)%f.shape[2]];
	return res;
 
#Applies the action g = (theta,x,y) to an indicator map f in R2
def action(g, f):
	return r2.shift((g[1], g[2]), rotate(g[0], f));
 
#Lifts the function f on R2 to a full function on SE(2) sampled at resolution R
def lift(f, R):
	res = sp.zeros((f.shape[0], f.shape[1], R));
	for r in range(R):
		theta = float(r) * 2. * pi / float(R);
		res[:,:,r] = rotate(theta, f);
	return res;
 
#Projects a function on SE(2) down to the homogeneous space about the given origin
def project(f):
	res = sp.zeros((f.shape[0], f.shape[1]));
	for x in range(f.shape[0]):
		for y in range(f.shape[1]):
			res[x,y] = sum(f[x,y,:].flatten());
	return res;
 
#The map tau from the paper
def tau(s, R):
	res = sp.zeros((s.shape[0], s.shape[1], R));
	res[:,:,0] = s;
	return s;
 
#The map gamma from the paper
def gamma(f):
	res = sp.zeros((f.shape[2]));
	for r in range(f.shape[2]):
		res[r] = sum(f[:,:,r].flatten());
	return res;
 
 
#################################################################
# Convolution operators
#################################################################
 
#Computes the full SE(2) convolution via the homogeneous method
# Not listed in paper due to space considerations, but derivation is easy
def conv(f, g):
	res = np.zeros((f.shape[0] + g.shape[0] - 1, \
					f.shape[1] + g.shape[1] - 1, \
					f.shape[2]));
	tmp = np.zeros((g.shape[0], g.shape[1]));	
	for r in range(f.shape[2]):
		theta_r = 360. * float(r)/float(f.shape[2]);
		tmp[:,:] = 0.;
		for q in range(f.shape[2]):
			theta_q = 360.*float(q)/float(g.shape[2]);
			tmp += sp.misc.imrotate(g[:,:,q], theta_q - theta_r);
		res[:,:,r] += r2.conv(f[:,:,r], tmp);
	del tmp;
	return res;
 
#Computes the convolution of a function on SE(2) acting on a function in R2
# (From cor 2)
def act_conv(f, s):
	res = np.zeros((s.shape[0]+f.shape[0]-1,s.shape[1]+f.shape[1]-1));
	for r in range(f.shape[2]):
		theta = r / float(f.shape[2]) * 360.;
		res += r2.conv(s, scipy.misc.imrotate(f[:,:,r], -theta));
	return res;
 
#Computes a homogeneous convolution over SE(2) between two functions in R2 at R uniform rotational samples
# (From cor 3)
def hg_conv(s, t, R):
	res = np.zeros((s.shape[0] + t.shape[0] - 1, s.shape[1] + t.shape[1] - 1, R));
	for r in range(R):
		theta = r / float(R) * 360.;
		res[:,:,r] = r2.conv(t, scipy.misc.imrotate(s, -theta));
	return r;
 
 
 
 
#################################################################
# Morphological operators
#################################################################
 
#Minkowski product
def mink_prod(f,g):
	return to_ind(conv(f,g));
 
#Left Minkowski quotient
def mink_quot_l(f,g):
	return to_ind(conv(f,g), supp(f) - 0.001);
 
#Right Minkowski quotient	
def mink_quot_r(f,g):
	return to_ind(conv(f,g), supp(g) - 0.001);
 
#Dilation
def dilation(f,s):
	return to_ind(act_conv(f,s));
 
#Erosion
def erosion(f,s):
	return to_ind(act_conv(f,s), supp(f) - 0.001);
 
#Homogeneous product
def hg_prod(s,t,R):
	return to_ind(hg_conv(s,t,R));
 
#Left Homogeneous quotient
def hg_quot_l(s,t,R):
	return to_ind(hg_conv(s,t,R), r2.supp(s) - 0.001);
 
#Right Homogeneous quotient
def hg_quot_r(s,t,R):
	return to_ind(hg_conv(s,t,R), r2.supp(t) - 0.001);