def bessel_cost_func(vol1_org, vol2_org, thetas, axis, mask=False, smooth = False, mode = 1):
    '''
    vol1: original image
    vol2: volume to be rotated
    thetas: list of degress to try
    cf: cost function
    arg: string for plot titles
    '''
    vol1 = vol1_org.copy()
    vol2 = vol2_org.copy()
    cost_func = np.zeros([len(thetas),])
    if(mask):
        for i in xrange(len(vol1)):
            if(axis == 0):
                vol1[i,:,:] = circle_mask(vol1[i,:,:], smooth, mode)
            elif(axis == 1):
                vol1[:,i,:] = circle_mask(vol1[:,i,:], smooth, mode)
            else:
                vol1[:,:,i] = circle_mask(vol1[:,:,i], smooth, mode)

    for idx, t in enumerate(thetas):
        print t,
        new_vol2 = np.zeros(vol2.shape)
        for i in xrange(len(vol2)):
            if(axis == 0):
                new_vol2[i,:,:] = bessel_rotate(vol2[i,:,:], t, mask, smooth, mode)
            elif(axis == 1):
                new_vol2[:,i,:] = bessel_rotate(vol2[:,i,:], t, mask, smooth, mode)
            else:
                new_vol2[:,:,i] = bessel_rotate(vol2[:,:,i], t, mask, smooth, mode)
        cost_func[idx] = cf_ssd(new_vol2, vol1)
    return cost_func
def imrotate(image_org, theta, interpolation = 'bilinear', mask=False, smooth = False, mode = 1,x=None, y=None):
    image = image_org.copy()
    if(mask):
        image = circle_mask(image,smooth,mode)
    theta = to_radian(theta)
    ox = image.shape[1]/2.-0.5
    oy = image.shape[0]/2.-0.5
    
    if((x == None) and (y == None)): #i.e. x and y not specified
        x = np.linspace(0, image.shape[1]-1, image.shape[1]).astype(int)
        y = np.linspace(0, image.shape[0]-1, image.shape[0]).astype(int)
        xx, yy = np.meshgrid(x,y)
        dest_x, dest_y = rotate_coords(xx, yy, theta, ox, oy)
    else:
        dest_x, dest_y = rotate_coords(x, y, theta, ox, oy)
    
    if(interpolation == 'bicubic'):
        dest = bicubic_interp(image, dest_x, dest_y)
    if(interpolation == 'bilinear'):
        dest = bilinear_interp(image, dest_x, dest_y)
    if(interpolation == 'bessel'):
        dest = bessel_rotate(image, theta) 
    if(interpolation == 'spline'):
        spline = scipy.interpolate.RectBivariateSpline(x, y, image)
        dest = spline.ev(dest_y,dest_x)        
    return dest
def bessel_rotate(image_org, theta, mask = False, smooth = False, mode = 1):
    image = image_org.copy()
    if(mask):
        image = circle_mask(image, smooth, mode)
    Ib = np.zeros(image.shape)
    theta = to_radian(theta)
    s = (image.shape[0]-1)/2.
    x = np.linspace(-s, s, image.shape[1])
    y = np.linspace(-s, s, image.shape[0])
    
    xx, yy = np.meshgrid(x,y)
    
    rM = np.array([[np.cos(theta), -np.sin(theta)],[np.sin(theta), np.cos(theta)]])
    for i in np.arange(-s,s+1):
        for j in np.arange(-s,s+1):
            new_x = np.dot(rM, np.array([i,j]))

            if(np.sum(abs(np.round(new_x,5))>s)):
                Ib[i+s,j+s] = 0
            else:
                R = np.sqrt((xx-new_x[1])**2 + (yy-new_x[0])**2)
                mask_R = (R == 0)
                Bess = np.zeros(R.shape)
                Bess[~mask_R] = scipy.special.j1(np.pi*R[~mask_R])*hann(R[~mask_R],image.shape[0]*mode)/(np.pi*R[~mask_R])
                Bess[mask_R] = 0.5
                Bess = Bess/np.sum(Bess)
                tmp = image*Bess
                Ib[i+s,j+s] = np.sum(tmp) #np.round(np.sum(tmp),10)
    return Ib
def rot_cost_func(vol1_org, vol2_org, thetas, axis, interpolation='bilinear', mask=False, smooth=False, mode=1, x=None, y=None):
    '''
    vol1: original image
    vol2: volume to be rotated
    thetas: list of degress to try
    arg: string for plot titles
    '''
    vol1 = vol1_org.copy()
    vol2 = vol2_org.copy()
    if(mask):
        for i in xrange(len(vol1)):
            if(axis == 0):
                vol1[i,:,:] = circle_mask(vol1[i,:,:], smooth, mode)
            elif(axis == 1):
                vol1[:,i,:] = circle_mask(vol1[:,i,:], smooth, mode)
            else:
                vol1[:,:,i] = circle_mask(vol1[:,:,i], smooth, mode)

    cost_func = np.zeros([len(thetas),])
    for idx, t in enumerate(thetas):
        new_vol2 = np.ones(vol2.shape)
        for i in xrange(len(vol2)):
            if(axis == 0):
                sub = vol2[i,:,:]
            elif(axis == 1):
                sub = vol2[:,i,:]
            else:
                sub = vol2[:,:,i]
            
            rot = imrotate(sub, t, interpolation, mask, smooth, mode, x, y)

            if(axis == 0):
                new_vol2[i,:,:] = rot
            elif(axis == 1):
                new_vol2[:,i,:] = rot
            else:
                new_vol2[:,:,i] = rot
        cost_func[idx] = cf_ssd(new_vol2,vol1)
    return cost_func
def rot_halton_cost_func(vol1_org, vol2_org, N, thetas, axis, interpolation='bilinear', smooth = True, mode = 1):
    '''
    vol1: original image
    vol2: volume to be rotated
    thetas: list of degress to try
    cf: cost function
    arg: string for plot titles
    '''
    vol1 = vol1_org.copy()
    vol2 = vol2_org.copy()

    cost_func = np.zeros([len(thetas),])
    # generate Halton sample points
    s = (len(vol1)-1)/2.
    sequencer = ghalton.GeneralizedHalton(ghalton.EA_PERMS[:3])
    sequencer.reset()
    points = sequencer.get(N)
    pts = np.array(points)
    xx1 = (len(vol1)-1) * pts[:,0] - s
    yy1 = (len(vol1)-1) * pts[:,1] - s
    mask = np.sqrt(xx1**2+yy1**2) < s*0.7
    x1 = xx1[mask]
    y1 = yy1[mask]
    new_vol1 = np.zeros([len(vol1),len(x1)])
    print len(x1),
    for i in xrange(len(vol1)):
        if(axis == 0):
            sub1 = circle_mask(vol1[i,:,:], smooth = True, mode = 1)
        elif(axis == 1):
            sub1 = circle_mask(vol1[:,i,:], smooth = True, mode = 1)
        else:
            sub1 = circle_mask(vol1[:,:,i], smooth = True, mode = 1)
        rot = imrotate(sub1, 0, interpolation, True, smooth, mode, x1, y1)
        new_vol1[i] = rot
    for idx, t in enumerate(thetas):
        new_vol2 = np.empty([len(vol2),len(x1)])
        for i in xrange(len(vol2)):
            if(axis==0):
                sub2 = circle_mask(vol2[i,:,:], smooth = True, mode = 1)
            elif(axis==1):
                sub2 = circle_mask(vol2[:,i,:], smooth = True, mode = 1)
            else:
                sub2 = circle_mask(vol2[:,:,i], smooth = True, mode = 1)
            rot = imrotate(sub2, t, interpolation, True, smooth, mode, x1, y1)
            new_vol2[i] = rot
        cost_func[idx] = cf_ssd(new_vol2,new_vol1)
    return cost_func
def bessel_halton_cost_func(vol1_org, vol2, N, thetas, axis):
    '''
    vol1: original image
    vol2: volume to be rotated
    thetas: list of degress to try
    cf: cost function
    arg: string for plot titles
    '''
    vol1 = vol1_org.copy()
    # initialize vector to store cost
    cost_func = np.zeros([len(thetas),])
    # generate Halton sample points
    s = (len(vol1)-1)/2.
    sequencer = ghalton.GeneralizedHalton(ghalton.EA_PERMS[:3])
    sequencer.reset()
    points = sequencer.get(N)
    pts = np.array(points)
    x1 = (len(vol1)-1) * pts[:,0] - s
    y1 = (len(vol1)-1) * pts[:,1] - s
    new_vol1 = np.empty([len(vol1),N])
    for i in xrange(len(vol1)):
        if(axis == 0):
            sub1 = circle_mask(vol1[i,:,:])
        elif(axis == 1):
            sub1 = circle_mask(vol1[:,i,:])
        else:
            sub1 = circle_mask(vol1[:,:,i])
        rot = bessel_rotate_halton(sub1, 0, x1, y1)
        new_vol1[i] = rot
    for idx, t in enumerate(thetas):
        print t, 
        new_vol2 = np.empty([len(vol2),N])
        for i in xrange(len(vol2)):
            if(axis==0):
                sub2 = circle_mask(vol2[i,:,:])
            elif(axis==1):
                sub2 = circle_mask(vol2[:,i,:])
            else:
                sub2 = circle_mask(vol2[:,:,i])
            new_vol2[i] = bessel_rotate_halton(sub2, t, x1, y1)
        cost_func[idx] = cf_ssd(new_vol2,new_vol1)
    return cost_func