コード例 #1
0
def apply_gabor(image) -> np.array:
    lg = LogGabor("parameters.py")
    lg.set_size(image)
    image[:, :, 0] = image[:, :, 0]*lg.mask
    image[:, :, 1] = image[:, :, 1]*lg.mask
    image[:, :, 2] = image[:, :, 2]*lg.mask
    return image
コード例 #2
0
 def theta_E(self, im, X_, Y_, w):
     try:
         assert (self.slip.N_X == im.shape[1])
     except:
         from NeuroTools.parameters import ParameterSet
         from SLIP import Image
         from LogGabor import LogGabor
         self.slip = Image(
             ParameterSet({
                 'N_X': im.shape[1],
                 'N_Y': im.shape[0]
             }))
         self.lg = LogGabor(self.slip)
     im_ = im.sum(axis=-1)
     im_ = im_ * np.exp(-.5 * ((.5 + .5 * self.slip.x - Y_)**2 +
                               (.5 + .5 * self.slip.y - X_)**2) / w**2)
     E = np.zeros((self.N_theta, ))
     for i_theta, theta in enumerate(self.thetas):
         params = {
             'sf_0': self.sf_0,
             'B_sf': self.B_sf,
             'theta': theta,
             'B_theta': np.pi / self.N_theta
         }
         FT_lg = self.lg.loggabor(0, 0, **params)
         E[i_theta] = np.sum(
             np.absolute(
                 self.slip.FTfilter(np.rot90(im_, -1), FT_lg,
                                    full=True))**2)
     return E
コード例 #3
0
 def theta_E(self, im, X_, Y_, w):
     try:
         assert(self.slip.N_X==im.shape[1])
     except:
         from NeuroTools.parameters import ParameterSet
         from SLIP import Image
         from LogGabor import LogGabor
         self.slip = Image(ParameterSet({'N_X':im.shape[1], 'N_Y':im.shape[0]}))
         self.lg = LogGabor(self.slip)
     im_ = im.sum(axis=-1)
     im_ = im_ * np.exp(-.5*((.5 + .5*self.slip.x-Y_)**2+(.5 + .5*self.slip.y-X_)**2)/w**2)
     E = np.zeros((self.N_theta,))
     for i_theta, theta in enumerate(self.thetas):
         params= {'sf_0':self.sf_0, 'B_sf':self.B_sf, 'theta':theta, 'B_theta': np.pi/self.N_theta}
         FT_lg = self.lg.loggabor(0, 0, **params)
         E[i_theta] = np.sum(np.absolute(self.slip.FTfilter(np.rot90(im_, -1), FT_lg, full=True))**2)
     return E
コード例 #4
0
def get_shape_of_filtered_image(image_file_path):
    image = imread(image_file_path)
    lg = LogGabor('default_param.py')
    lg.set_size(image)
    i_level = 0
    theta = 0
    params = {
        'sf_0': 1. / (2**i_level),
        'B_sf': lg.pe.B_sf,
        'theta': theta,
        'B_theta': lg.pe.B_theta
    }
    FT_lg = lg.loggabor(0, 0, **params)
    filtered_img_mat = lg.FTfilter(image, FT_lg, full=True)
    return filtered_img_mat.shape
コード例 #5
0
def get_gabor_features(image_file_path, num_levels, num_orientations):
    image = imread(image_file_path)
    opts = {
        'vmin': 0.,
        'vmax': 1.,
        'interpolation': 'nearest',
        'origin': 'upper'
    }
    # image = skimage.io.imread
    lg = LogGabor('default_param.py')
    lg.set_size(image)
    # num_features = num_levels*num_orientations*2
    # feature_vec = np.zeros((num_features,1))
    # phi = (np.sqrt(5) +1.)/2. # golden number
    # fig = plt.figure(figsize=(fig_width, fig_width/phi))
    # xmin, ymin, size = 0, 0, 1.
    i = 0
    for i_level in range(num_levels):
        # for theta in np.linspace(0, np.pi, num_orientations, endpoint=False):
        for theta in np.linspace(0, np.pi, num_orientations, endpoint=False):
            params = {
                'sf_0': 1. / (2**i_level),
                'B_sf': lg.pe.B_sf,
                'theta': theta,
                'B_theta': lg.pe.B_theta
            }
            # loggabor takes as args: u, v, sf_0, B_sf, theta, B_theta)
            FT_lg = lg.loggabor(0, 0, **params)
            filtered_img_mat = lg.FTfilter(image, FT_lg, full=True)
            # print "SHAPE OF FILTERED IMAGE IS (%s, %s)" % filtered_img_mat.shape
            im_abs_feature = np.absolute(filtered_img_mat).flatten()
            # im_abs_feature = np.sum(np.absolute(filtered_img_mat))
            # im_sqr_feature = np.sum(np.square(np.real(filtered_img_mat)))
            # im_sqr_feature = np.sum(np.square(filtered_img_mat))
            if i == 0:
                feature_vec = im_abs_feature
            else:
                feature_vec = np.hstack((feature_vec, im_abs_feature))
            i += 1
    print
    return feature_vec
コード例 #6
0
    0,
    '/home/qiang/QiangLi/Python_Utils_Functional/FirstVersion-BioMulti-L-NL-Model-ongoing/SLIP/SLIP'
)
from SLIP import Image

#LogGabor can be install in the first time but when you second time install it,
#It will cause error. Here for how to fix it.
#!pip3 install --upgrade pip setuptools wheel
#!sudo apt-get install libpq-dev
sys.path.insert(
    0,
    '/home/qiang/QiangLi/Python_Utils_Functional/FirstVersion-BioMulti-L-NL-Model-ongoing/LogGabor/LogGabor'
)
from LogGabor import LogGabor
parameterfile = '/home/qiang/QiangLi/Python_Utils_Functional/FirstVersion-BioMulti-L-NL-Model-ongoing/LogGabor/default_param.py'
lg = LogGabor(parameterfile)
print('It works on 23 April2020')

#DWT wavelet filters
sys.path.insert(
    0,
    '/home/qiang/QiangLi/Python_Utils_Functional/FirstVersion-BioMulti-L-NL-Model-ongoing/'
)

from nt_toolbox.general import *
from nt_toolbox.signal import *
from nt_toolbox.compute_wavelet_filter import *
print('It works on 27 April2020')

warnings.filterwarnings('ignore')
#%matplotlib inline
コード例 #7
0
def vectorization(N_theta=N_theta,
                  N_azimuth=N_azimuth,
                  N_eccentricity=N_eccentricity,
                  N_phase=N_phase,
                  N_X=N_X,
                  N_Y=N_Y,
                  rho=rho,
                  ecc_max=.8,
                  B_sf=.4,
                  B_theta=np.pi / N_theta / 2,
                  figure_type='',
                  save=False):
    retina = np.zeros((N_theta, N_azimuth, N_eccentricity, N_phase, N_X * N_Y))
    parameterfile = 'https://raw.githubusercontent.com/bicv/LogGabor/master/default_param.py'
    lg = LogGabor(parameterfile)
    lg.set_size((N_X, N_Y))
    # params = {'sf_0': .1, 'B_sf': lg.pe.B_sf,
    #           'theta': np.pi * 5 / 7., 'B_theta': lg.pe.B_theta}
    # phase = np.pi/4
    # edge = lg.normalize(lg.invert(lg.loggabor(
    #     N_X/3, 3*N_Y/4, **params)*np.exp(-1j*phase)))

    for i_theta in range(N_theta):
        for i_azimuth in range(N_azimuth):
            for i_eccentricity in range(N_eccentricity):
                ecc = ecc_max * (1 / rho)**(N_eccentricity - i_eccentricity)
                r = np.sqrt(N_X**2 + N_Y**2) / 2 * ecc  # radius
                sf_0 = 0.5 * 0.03 / ecc
                x = N_X/2 + r * \
                    np.cos((i_azimuth+(i_eccentricity % 2)*.5)*np.pi*2 / N_azimuth)
                y = N_Y/2 + r * \
                    np.sin((i_azimuth+(i_eccentricity % 2)*.5)*np.pi*2 / N_azimuth)
                for i_phase in range(N_phase):
                    params = {
                        'sf_0': sf_0,
                        'B_sf': B_sf,
                        'theta': i_theta * np.pi / N_theta,
                        'B_theta': B_theta
                    }
                    phase = i_phase * np.pi / 2
                    # print(r, x, y, phase, params)

                    retina[i_theta, i_azimuth, i_eccentricity,
                           i_phase, :] = lg.normalize(
                               lg.invert(
                                   lg.loggabor(x, y, **params) *
                                   np.exp(-1j * phase))).ravel()
    if figure_type == 'retina':
        FIG_WIDTH = 10
        fig, ax = plt.subplots(figsize=(FIG_WIDTH, FIG_WIDTH))
        for i_theta in range(N_theta):
            for i_azimuth in range(N_azimuth):
                for i_eccentricity in range(N_eccentricity):
                    env = np.sqrt(retina[i_theta, i_azimuth, i_eccentricity,
                                         0, :]**2 +
                                  retina[i_theta, i_azimuth, i_eccentricity,
                                         1, :]**2).reshape((N_X, N_Y))
                    ax.contourf(env,
                                levels=[env.max() / 1.2,
                                        env.max() / 1.00001],
                                lw=1,
                                colors=[plt.cm.viridis(i_theta / (N_theta))],
                                alpha=.1)
        fig.suptitle('Tiling of visual space using the retinal filters')
        ax.set_xlabel(r'$Y$')
        ax.set_ylabel(r'$X$')
        ax.axis('equal')
        if save: plt.savefig('retina_filter.pdf')
        plt.tight_layout()
        return fig, ax
    elif figure_type == 'colliculus':
        FIG_WIDTH = 10
        fig, ax = plt.subplots(figsize=(FIG_WIDTH, FIG_WIDTH))
        for i_azimuth in range(N_azimuth):
            for i_eccentricity in range(N_eccentricity):
                env = np.sqrt(colliculus[i_azimuth,
                                         i_eccentricity, :]**2.5).reshape(
                                             (N_X, N_Y))
                #ax.contour(colliculus[i_azimuth, i_eccentricity, :].reshape((N_X, N_Y)), levels=[env.max()/2], lw=1, colors=[plt.cm.viridis(i_theta/(N_theta))])
                ax.contourf(
                    env,
                    levels=[env.max() / 1.2,
                            env.max() / 1.00001],
                    lw=1,
                    colors=[plt.cm.viridis(i_eccentricity / (N_eccentricity))],
                    alpha=.1)
        fig.suptitle('Tiling of visual space using energy')
        ax.set_xlabel(r'$Y$')
        ax.set_ylabel(r'$X$')
        ax.axis('equal')
        plt.tight_layout()
        if save: plt.savefig('colliculus_filter.pdf')
        return fig, ax
    else:
        return retina
コード例 #8
0
ファイル: test.py プロジェクト: buptbubble/qoe
import numpy as np
import cv2
from matplotlib import pyplot as plt
from LogGabor import LogGabor


lg = LogGabor("default_param.py")



exit(0)
lg.set_size(image)
fig_width = 512
phi = (np.sqrt(5) +1.)/2. # golden number
fig = plt.figure(figsize=(fig_width, fig_width/phi))
xmin, ymin, size = 0, 0, 1.
for i_level in range(8):
    a = fig.add_axes((xmin/phi, ymin, size/phi, size), axisbg='w')
    a.axis(c='b', lw=0)
    plt.setp(a, xticks=[])
    plt.setp(a, yticks=[])
    im_RGB = np.zeros((lg.N_X, lg.N_Y, 3))
    for theta in np.linspace(0, np.pi, 8, endpoint=False):
        params = {'sf_0':1./(2**i_level), 'B_sf':lg.pe.B_sf, 'theta':theta, 'B_theta':lg.pe.B_theta}
        # loggabor takes as args: u, v, sf_0, B_sf, theta, B_theta)
        FT_lg = lg.loggabor(0, 0, **params)
        im_abs = np.absolute(lg.FTfilter(image, FT_lg, full=True))
        RGB = np.array([.5*np.sin(2*theta + 2*i*np.pi/3)+.5 for i in range(3)])
        im_RGB += im_abs[:,:, np.newaxis] * RGB[np.newaxis, np.newaxis, :]

    im_RGB /= im_RGB.max()
コード例 #9
0
class EdgeGrid():
    def __init__(
        self,
        N_lame=8 * 72,
        N_lame_X=None,
        figsize=13,
        line_width=4.,
        grid_type='hex',
        structure=False,
        struct_angles=[-15., -65., -102.],
        verb=False,
        mode='both',
        filename=None,
        period=None,
        #**kw_args
    ):
        self.t0 = self.time(True)
        self.t = self.time()
        self.dt = self.t - self.t0
        self.verb = verb
        self.display = (mode == 'display') or (mode == 'both')
        self.stream = (mode == 'stream') or (mode == 'display')
        #if mode=='display': self.stream = True
        self.filename = filename
        self.serial = (
            mode == 'serial'
        )  # converting a stream to the serial port to control the arduino
        if self.serial: self.verb = True
        #         self.desired_fps = 750.
        self.desired_fps = 30.
        self.structure = structure
        self.screenshot = True  # saves a screenshot after the rendering

        self.port = "5556"
        # moteur:
        self.serial_port, self.baud_rate = '/dev/ttyUSB0', 115200
        # 1.8 deg par pas (=200 pas par tour) x 32 divisions de pas
        # demultiplication : pignon1= 14 dents, pignon2 = 60 dents
        self.n_pas = 200. * 32. * 60 / 14
        # TODO : Vitesse Max moteur = 1 tour en 3,88
        self.n_pas_max = 148  # 150

        # taille installation
        self.total_width = 8  # en mètres
        self.lames_width = 5  # en mètres
        self.lames_height = 3  # en mètres
        self.background_depth = 100  # taille du 104 en profondeur
        self.f = .1
        self.struct_N = 6
        self.struct_position = [0., 3.5]
        self.struct_longueur = 3.
        self.struct_angles = struct_angles
        self.figsize = figsize
        self.line_width = line_width
        self.grid_type = grid_type
        self.grid(N_lame=N_lame, N_lame_X=N_lame_X)
        # self.lames[2, :] = np.pi*np.random.rand(self.N_lame)

        self.N_particles_per_lame = 2**3
        self.N_particles = self.struct_N * self.N_particles_per_lame
        if structure: self.sample_structure()

        # enregistrement / playback
        self.period = period
        self.load()

        self.vext = '.mp4'
        self.figpath = '../files/figures/elasticite/'
        self.fps = 25

    def load(self):
        if not self.filename is None:
            if os.path.isfile(self.filename):
                # le fichier existe, on charge
                self.z = np.load(self.filename)
                self.period = self.z[:, 0].max()

    def time(self, init=False):
        if init: return time.time()
        else: return time.time() - self.t0

    def grid(self, N_lame, N_lame_X):
        """
        The coordinates of the screen are centered on the (0, 0) point and axis are the classical convention:

         y
         ^
         |
         +---> x

         angles are from the horizontal, then in trigonometric order (anticlockwise)

         """

        self.DEBUG = True
        self.DEBUG = False

        self.N_lame = N_lame
        #if N_lame_X is None:

        if self.grid_type == 'hex':
            self.N_lame_X = np.int(np.sqrt(self.N_lame))  #*np.sqrt(3) / 2)
            self.lames = np.zeros((4, self.N_lame))
            self.lames[0, :] = np.mod(np.arange(self.N_lame), self.N_lame_X)
            self.lames[0, :] += np.mod(
                np.floor(np.arange(self.N_lame) / self.N_lame_X), 2) / 2
            self.lames[1, :] = np.floor(np.arange(self.N_lame) / self.N_lame_X)
            self.lames[1, :] *= np.sqrt(3) / 2
            self.lames[0, :] /= self.N_lame_X
            self.lames[1, :] /= self.N_lame_X
            self.lames[0, :] += .5 / self.N_lame_X - .5
            self.lames[
                1, :] += 1.5 / self.N_lame_X  # TODO : prove analytically
            self.lames[0, :] *= self.total_width
            self.lames[1, :] *= self.total_width
            self.lames[1, :] -= self.total_width / 2
            self.lame_length = .99 / self.N_lame_X * self.total_width * np.ones(
                self.N_lame)
            self.lame_width = .03 / self.N_lame_X * self.total_width * np.ones(
                self.N_lame)
        elif self.grid_type == 'line':
            self.N_lame_X = self.N_lame
            self.lames = np.zeros((4, self.N_lame))
            self.lames[0, :] = np.linspace(-self.lames_width / 2,
                                           self.lames_width / 2,
                                           self.N_lame,
                                           endpoint=True)
            #self.lames[1, :] = self.total_width/2
            self.lame_length = .12 * np.ones(self.N_lame)  # en mètres
            self.lame_width = .042 * np.ones(self.N_lame)  # en mètres

        if self.structure: self.add_structure()

        self.lames_minmax = np.array([
            self.lames[0, :].min(), self.lames[0, :].max(),
            self.lames[1, :].min(), self.lames[1, :].max()
        ])

    def do_structure(self):
        structure_ = np.zeros((3, self.struct_N))
        chain = np.zeros((2, 4))
        chain[:, 0] = np.array(self.struct_position).T
        for i, angle in enumerate(self.struct_angles):
            chain[0, i + 1] = chain[0, i] + self.struct_longueur * np.cos(
                angle * np.pi / 180.)
            chain[1, i + 1] = chain[1, i] + self.struct_longueur * np.sin(
                angle * np.pi / 180.)
            structure_[2, 3 + i] = +angle * np.pi / 180.
            structure_[2, i] = np.pi - angle * np.pi / 180
        structure_[0, 3:] = .5 * (chain[0, 1:] + chain[0, :-1])
        structure_[0, :3] = -.5 * (chain[0, 1:] + chain[0, :-1])
        structure_[1, 3:] = .5 * (chain[1, 1:] + chain[1, :-1])
        structure_[1, :3] = .5 * (chain[1, 1:] + chain[1, :-1])
        return structure_

    def add_structure(self):
        self.N_lame += self.struct_N
        self.lames = np.hstack((self.lames, np.zeros((4, self.struct_N))))
        self.lames[:3, -self.struct_N:] = self.do_structure()
        self.lame_length = np.hstack(
            (self.lame_length,
             self.struct_longueur * np.ones(self.struct_N)))  # en mètres
        self.lame_width = np.hstack(
            (self.lame_width, .042 * np.ones(self.struct_N)))  # en mètres

    def sample_structure(self, N_mirror=0, alpha=.8):
        struct = self.lames[:3, -self.struct_N:]
        self.particles = np.ones((3, self.N_particles))
        N_particles_ = self.N_particles / self.struct_N
        for i, vec in enumerate(struct.T.tolist()):
            x0, x1 = vec[0] - .5 * self.struct_longueur * np.cos(
                vec[2]), vec[0] + .5 * self.struct_longueur * np.cos(vec[2])
            y0, y1 = vec[1] - .5 * self.struct_longueur * np.sin(
                vec[2]), vec[1] + .5 * self.struct_longueur * np.sin(vec[2])
            self.particles[0,
                           int(i *
                               N_particles_):int((i + 1) *
                                                 N_particles_)] = np.linspace(
                                                     x0, x1, N_particles_)
            self.particles[1,
                           int(i *
                               N_particles_):int((i + 1) *
                                                 N_particles_)] = np.linspace(
                                                     y0, y1, N_particles_)

        # duplicate according to mirrors
        for i in range(N_mirror):
            particles = self.particles.copy(
            )  # the current structure to mirror
            particles_mirror = particles.copy(
            )  # the new set of particles with their mirror image
            for segment in self.structure_as_segments():
                particles_mirror = np.hstack((particles_mirror,
                                              mirror(particles, segment,
                                                     alpha**(i + 1))))
            # print(alpha**(i+1), particles_mirror[-1, -1])
            self.particles = particles_mirror

    def structure_as_segments(self):
        struct = self.lames[:3, -self.struct_N:]
        segments = []
        for i, vec in enumerate(struct.T.tolist()):
            x0, x1 = vec[0] - .5 * self.struct_longueur * np.cos(
                vec[2]), vec[0] + .5 * self.struct_longueur * np.cos(vec[2])
            y0, y1 = vec[1] - .5 * self.struct_longueur * np.sin(
                vec[2]), vec[1] + .5 * self.struct_longueur * np.sin(vec[2])
            segments.append(np.array([[x0, y0], [x1, y1]]).T)
        return segments

    def theta_E(self, im, X_, Y_, w):
        try:
            assert (self.slip.N_X == im.shape[1])
        except:
            from NeuroTools.parameters import ParameterSet
            from SLIP import Image
            from LogGabor import LogGabor
            self.slip = Image(
                ParameterSet({
                    'N_X': im.shape[1],
                    'N_Y': im.shape[0]
                }))
            self.lg = LogGabor(self.slip)
        im_ = im.sum(axis=-1)
        im_ = im_ * np.exp(-.5 * ((.5 + .5 * self.slip.x - Y_)**2 +
                                  (.5 + .5 * self.slip.y - X_)**2) / w**2)
        E = np.zeros((self.N_theta, ))
        for i_theta, theta in enumerate(self.thetas):
            params = {
                'sf_0': self.sf_0,
                'B_sf': self.B_sf,
                'theta': theta,
                'B_theta': np.pi / self.N_theta
            }
            FT_lg = self.lg.loggabor(0, 0, **params)
            E[i_theta] = np.sum(
                np.absolute(
                    self.slip.FTfilter(np.rot90(im_, -1), FT_lg,
                                       full=True))**2)
        return E

    def theta_max(self, im, X_, Y_, w):
        E = self.theta_E(im, X_, Y_, w)
        return self.thetas[np.argmax(E)] - np.pi / 2

    def theta_sobel(self, im, N_blur):
        im_ = im.copy()
        sobel = np.array([[
            1,
            2,
            1,
        ], [
            0,
            0,
            0,
        ], [
            -1,
            -2,
            -1,
        ]])
        if im_.ndim == 3: im_ = im_.sum(axis=-1)
        from scipy.signal import convolve2d
        im_X = convolve2d(im_, sobel, 'same')
        im_Y = convolve2d(im_, sobel.T, 'same')

        N_X, N_Y = im_.shape
        x, y = np.mgrid[0:1:1j * N_X, 0:1:1j * N_Y]
        mask = np.exp(-.5 * ((x - .5)**2 + (y - .5)**2) / w**2)
        im_X = convolve2d(im_X, mask, 'same')
        im_Y = convolve2d(im_Y, mask, 'same')
        blur = np.array([[1, 2, 1], [2, 8, 2], [1, 2, 1]])
        for i in range(N_blur):
            im_X = convolve2d(im_X, blur, 'same')
            im_Y = convolve2d(im_Y, blur, 'same')

        angle = np.arctan2(im_Y, im_X)

        bord = .1
        angles = np.empty(self.N_lame)
        N_X, N_Y = im_.shape
        for i in range(self.N_lame):
            angles[i] = angle[int(
                (bord + self.lames[0, i] * (1 - 2 * bord)) * N_X),
                              int((bord + self.lames[1, i] * (1 - 2 * bord)) *
                                  N_Y)]
        return angles - np.pi / 2

    def pos_rel(self, do_torus=False):
        def torus(x, w=1.):
            """
            center x in the range [-w/2., w/2.]

            To see what this does, try out:
            >> x = np.linspace(-4,4,100)
            >> pylab.plot(x, torus(x, 2.))

            """
            return np.mod(x + w / 2., w) - w / 2.

        dx = self.lames[0, :, np.newaxis] - self.lames[0, np.newaxis, :]
        dy = self.lames[1, :, np.newaxis] - self.lames[1, np.newaxis, :]
        if do_torus:
            return torus(dx), torus(dy)
        else:
            return dx, dy

    def distance(self, do_torus=False):
        dx, dy = self.pos_rel(do_torus=do_torus)
        return np.sqrt(dx**2 + dy**2)

    def angle_relatif(self):
        return self.lames[2, :, np.newaxis] - self.lames[2, np.newaxis, :]

    def angle_cocir(self, do_torus=False):
        dx, dy = self.pos_rel(do_torus=do_torus)
        theta = self.angle_relatif()
        return np.arctan2(dy, dx) - np.pi / 2 - theta

    def champ(self):
        if self.structure: N_lame = self.N_lame - self.struct_N
        else: N_lame = self.N_lame
        force = np.zeros_like(self.lames[2, :N_lame])
        noise = lambda t: 0.2 * np.exp((np.cos(2 * np.pi *
                                               (t - 0.) / 6.) - 1.) / 1.5**2)
        damp = lambda t: 0.01  #* np.exp(np.cos(t / 6.) / 3.**2)
        colin_t = lambda t: -.1 * np.exp((np.cos(2 * np.pi *
                                                 (t - 2.) / 6.) - 1.) / .3**2)
        cocir_t = lambda t: -4. * np.exp((np.cos(2 * np.pi *
                                                 (t - 4.) / 6.) - 1.) / .5**2)
        cocir_d = lambda d: np.exp(-d / .05)
        colin_d = lambda d: np.exp(-d / .2)

        force += colin_t(
            self.t) * np.sum(np.sin(2 * (self.angle_relatif()[:N_lame])) *
                             colin_d(self.distance()[:N_lame]),
                             axis=1)
        force += cocir_t(
            self.t) * np.sum(np.sin(2 * (self.angle_cocir()[:N_lame])) *
                             cocir_d(self.distance()[:N_lame]),
                             axis=1)
        force += noise(self.t) * np.pi * np.random.randn(N_lame)
        force -= damp(self.t) * self.lames[3, :N_lame] / self.dt
        return 42. * force

    def update(self):
        if self.structure: N_lame = self.N_lame - self.struct_N
        else: N_lame = self.N_lame
        self.lames[2, :N_lame] += self.lames[3, :N_lame] * self.dt / 2
        self.lames[3, :N_lame] += self.champ() * self.dt
        self.lames[2, :N_lame] += self.lames[3, :N_lame] * self.dt / 2
        # angles are defined as non oriented between -pi/2 and pi/2
        self.lames[2, :N_lame] = np.mod(self.lames[2, :N_lame] + np.pi / 2,
                                        np.pi) - np.pi / 2

    def receive(self):
        if not self.filename is None:
            if os.path.isfile(self.filename):
                if self.structure: N_lame = self.N_lame - self.struct_N
                else: N_lame = self.N_lame
                self.t = self.time()
                i_t = np.argmin(self.z[:, 0] < np.mod(self.t, self.period))
                if self.verb:
                    print("playback at t=", np.mod(self.t, self.period), i_t)
                self.lames[2, :N_lame] = self.z[i_t, 1:]
                return

        if self.stream:
            if self.verb: print("Sending request")
            self.socket.send(b"Hello")
            if self.verb: print("Received reply ", message)
            self.lames[2, :] = recv_array(self.socket)
            if self.verb: print("Received reply ", Theta.shape)
        else:
            self.dt = self.time() - self.t
            self.update()
            self.t = self.time()

#         if not self.filename is None:
#             if not os.path.isfile(self.filename):
#                 # recording
#                 if self.verb: print("recording at t=", self.t)
#                 self.z = np.vstack((self.z, np.hstack((np.array(self.t), self.lames[2, :] ))))
        return

    def render(self,
               fps=10,
               W=1000,
               H=618,
               location=[0, 1.75, -5],
               head_size=.4,
               light_intensity=1.2,
               reflection=1.,
               look_at=[0, 1.5, 0],
               fov=75,
               antialiasing=0.001,
               duration=5,
               fname='/tmp/temp.mp4'):
        def scene(t):
            """
            Returns the scene at time 't' (in seconds)
            """

            head_location = np.array(location) - np.array([0, 0, head_size])
            import vapory
            light = vapory.LightSource([15, 15, 1], 'color',
                                       [light_intensity] * 3)
            background = vapory.Box(
                [0, 0, 0], [1, 1, 1],
                vapory.Texture(
                    vapory.Pigment(
                        vapory.ImageMap('png',
                                        '"../files/VISUEL_104.png"', 'once')),
                    vapory.Finish('ambient', 1.2)), 'scale',
                [self.background_depth, self.background_depth, 0], 'translate',
                [
                    -self.background_depth / 2, -.45 * self.background_depth,
                    -self.background_depth / 2
                ])
            me = vapory.Sphere(
                head_location, head_size,
                vapory.Texture(vapory.Pigment('color', [1, 0, 1])))
            self.t = t
            self.update()
            objects = [background, me, light]

            for i_lame in range(self.N_lame):
                #print(i_lame, self.lame_length[i_lame], self.lame_width[i_lame])
                objects.append(
                    vapory.Box(
                        [
                            -self.lame_length[i_lame] / 2, 0,
                            -self.lame_width[i_lame] / 2
                        ],
                        [
                            self.lame_length[i_lame] / 2, self.lames_height,
                            self.lame_width[i_lame] / 2
                        ],
                        vapory.Pigment('color', [1, 1, 1]),
                        vapory.Finish('phong', 0.8, 'reflection', reflection),
                        'rotate',
                        (0, -self.lames[2, i_lame] * 180 / np.pi, 0),  #HACK?
                        'translate',
                        (self.lames[0, i_lame], 0, self.lames[1, i_lame])))

            objects.append(light)
            return vapory.Scene(vapory.Camera('angle', fov, "location",
                                              location, "look_at", look_at),
                                objects=objects,
                                included=["glass.inc"])

        import moviepy.editor as mpy
        if not os.path.isfile(fname):
            self.dt = 1. / fps

            def make_frame(t):
                return scene(t).render(width=W,
                                       height=H,
                                       antialiasing=antialiasing)

            clip = mpy.VideoClip(make_frame, duration=duration)
            clip.write_videofile(fname, fps=fps)
        return mpy.ipython_display(fname, fps=fps, loop=1, autoplay=1)

    def plot_structure(self,
                       W=1000,
                       H=618,
                       fig=None,
                       ax=None,
                       border=0.0,
                       opts=dict(vmin=-1,
                                 vmax=1.,
                                 linewidths=0,
                                 cmap=None,
                                 alpha=.1,
                                 s=5.),
                       scale='auto'):  #
        opts.update(cmap=plt.cm.hsv)
        if fig is None:
            fig = plt.figure(figsize=(self.figsize, self.figsize * H / W))
        if ax is None:
            ax = fig.add_axes((border, border, 1. - 2 * border,
                               1. - 2 * border))  #, axisbg='w')
        scat = ax.scatter(self.particles[0, ::-1],
                          self.particles[1, ::-1],
                          c=self.particles[2, ::-1],
                          **opts)
        if type(scale) is float:
            ax.set_xlim([-scale, scale])
            ax.set_ylim([-scale * H / W, scale * H / W])
        elif not scale is 'auto':
            ax.set_xlim([-self.total_width, self.total_width])
            ax.set_ylim([-self.total_width * H / W, self.total_width * H / W])
        else:
            ax.set_xlim([
                min(self.particles[0, :].min(),
                    self.particles[1, :].min() / H * W),
                max(self.particles[0, :].max(),
                    self.particles[1, :].max() / H * W)
            ])
            ax.set_ylim([
                min(self.particles[1, :].min(),
                    self.particles[0, :].min() * H / W),
                max(self.particles[1, :].max(),
                    self.particles[0, :].max() * H / W)
            ])
        ax.axis('off')
        return fig, ax

    def animate(self,
                fps=10,
                W=1000,
                H=618,
                duration=20,
                scale='auto',
                fname=None):
        if fname is None:
            import tempfile
            fname = tempfile.mktemp() + '.mp4'
        import matplotlib.pyplot as plt
        self.dt = 1. / fps
        inches_per_pt = 1.0 / 72.27
        from moviepy.video.io.bindings import mplfig_to_npimage
        import moviepy.editor as mpy

        def make_frame_mpl(t):
            self.t = t
            self.update()
            fig = plt.figure(figsize=(W * inches_per_pt, H * inches_per_pt))
            fig, ax = self.plot_structure(fig=fig, ax=None, scale=scale)
            #ax.clear()
            ax.axis('off')
            #fig, ax = self.plot_structure(fig=fig, ax=ax)
            return mplfig_to_npimage(fig)  # RGB image of the figure

        animation = mpy.VideoClip(make_frame_mpl, duration=duration)
        plt.close('all')
        animation.write_videofile(fname, fps=fps)
        return mpy.ipython_display(fname, fps=fps, loop=1, autoplay=1, width=W)

    def show_edges(self, fig=None, a=None):
        self.N_theta = 12
        self.thetas = np.linspace(0, np.pi, self.N_theta)
        self.sf_0 = .3
        self.B_sf = .3
        """
        Shows the quiver plot of a set of edges, optionally associated to an image.

        """
        import pylab
        import matplotlib.cm as cm
        if fig == None:
            fig = pylab.figure(figsize=(self.figsize, self.figsize))
        if a == None:
            border = 0.0
            a = fig.add_axes(
                (border, border, 1. - 2 * border, 1. - 2 * border), axisbg='w')
        else:
            self.update_lines()
        marge = self.lame_length * 3.
        a.axis(self.lames_minmax + np.array([-marge, +marge, -marge, +marge]))
        a.add_collection(self.lines)
        a.axis(c='b', lw=0)
        pylab.setp(a, xticks=[])
        pylab.setp(a, yticks=[])
        pylab.draw()
        return fig, a

    #def set_lines(self):
    #from matplotlib.collections import LineCollection
    #import matplotlib.patches as patches
    # draw the segments
    #segments, colors, linewidths = list(), list(), list()
#
#X, Y, Theta = self.lames[0, :], self.lames[1, :].real, self.lames[2, :]
#for x, y, theta in zip(X, Y, Theta):
#u_, v_ = np.cos(theta)*self.lame_length, np.sin(theta)*self.lame_length
#segments.append([(x - u_, y - v_), (x + u_, y + v_)])
#colors.append((0, 0, 0, 1))# black
#linewidths.append(self.line_width)
#return LineCollection(segments, linewidths=linewidths, colors=colors, linestyles='solid')

    def update_lines(self):
        from matplotlib.collections import LineCollection
        import matplotlib.patches as patches
        X, Y, Theta = self.lames[0, :], self.lames[1, :], self.lames[2, :]
        segments = list()

        for i, (x, y, theta) in enumerate(zip(X, Y, Theta)):
            u_, v_ = np.cos(theta) * self.lame_length, np.sin(
                theta) * self.lame_length
            segments.append([(x - u_, y - v_), (x + u_, y + v_)])
        self.lines.set_segments(segments)

    def fname(self, name):
        return os.path.join(self.figpath, name + self.vext)

    def make_anim(self, name, make_lames, duration=3., redo=False):
        if redo or not os.path.isfile(self.fname(name)):

            import matplotlib.pyplot as plt
            from moviepy.video.io.bindings import mplfig_to_npimage
            import moviepy.editor as mpy

            fig_mpl, ax = plt.subplots(1,
                                       figsize=(self.figsize, self.figsize),
                                       facecolor='white')

            def make_frame_mpl(t):
                # on ne peut changer que l'orientation des lames:
                self.t = t
                self.lames[2, :] = make_lames(self)
                self.update_lines()
                fig_mpl, ax = self.show_edges()  #fig_mpl, ax)
                self.t_old = t
                return mplfig_to_npimage(fig_mpl)  # RGB image of the figure

            animation = mpy.VideoClip(make_frame_mpl, duration=duration)
            animation.write_videofile(self.fname(name), fps=self.fps)
コード例 #10
0
def generate_spectrum_from_RDC(filename,
                               numFrames=500,
                               numADCSamples=128,
                               numTxAntennas=3,
                               numRxAntennas=4,
                               numLoopsPerFrame=128,
                               numAngleBins=64,
                               chirpPeriod=0.06,
                               logGabor=False,
                               accumulate=True,
                               save_full=False):
    numChirpsPerFrame = numTxAntennas * numLoopsPerFrame

    # =============================================================================
    #     numADCSamples = number of range bins
    #     numLoopsPerFrame = number of doppler bins
    # =============================================================================

    range_resolution, bandwidth = dsp.range_resolution(numADCSamples)
    doppler_resolution = dsp.doppler_resolution(bandwidth)

    if filename[-4:] != '.bin':
        filename += '.bin'

    adc_data = np.fromfile(filename, dtype=np.int16)
    adc_data = adc_data.reshape(numFrames, -1)
    adc_data = np.apply_along_axis(DCA1000.organize,
                                   1,
                                   adc_data,
                                   num_chirps=numChirpsPerFrame,
                                   num_rx=numRxAntennas,
                                   num_samples=numADCSamples)
    print("Data Loaded!")

    dataCube = adc_data
    micro_doppler_data = np.zeros((numFrames, numLoopsPerFrame, numADCSamples),
                                  dtype=np.float64)
    theta_data = np.zeros((numFrames, numLoopsPerFrame,
                           numTxAntennas * numRxAntennas, numADCSamples),
                          dtype=np.complex)

    for i, frame in enumerate(dataCube):
        # (2) Range Processing
        from mmwave.dsp.utils import Window

        radar_cube = dsp.range_processing(frame,
                                          window_type_1d=Window.BLACKMAN)
        assert radar_cube.shape == (
            numChirpsPerFrame, numRxAntennas,
            numADCSamples), "[ERROR] Radar cube is not the correct shape!"

        # (3) Doppler Processing
        det_matrix, theta_data[i] = dsp.doppler_processing(
            radar_cube,
            num_tx_antennas=3,
            clutter_removal_enabled=True,
            window_type_2d=Window.HAMMING)

        # --- Shifts & Store
        det_matrix_vis = np.fft.fftshift(det_matrix, axes=1)
        micro_doppler_data[i, :, :] = det_matrix_vis
        # Data should now be ready. Needs to be in micro_doppler_data, a 3D-numpy array with shape [numDoppler, numRanges, numFrames]

        # LOG GABOR
        if logGabor:
            if accumulate:
                image = micro_doppler_data.sum(axis=1).T
            else:
                image = micro_doppler_data.T

            from LogGabor import LogGabor
            import holoviews as hv

            lg = LogGabor("default_param.py")
            lg.set_size(image)
            lg.pe.datapath = 'database/'

            image = lg.normalize(image, center=True)

            # display input image
            # hv.Image(image)

            # display log gabor'd image
            image = lg.whitening(image) * lg.mask
            hv.Image(image)

            uDoppler = image
        elif accumulate:
            uDoppler = micro_doppler_data.sum(axis=1).T
        else:
            uDoppler = micro_doppler_data.T

    if save_full:
        return range_resolution, doppler_resolution, uDoppler, theta_data
    else:
        return range_resolution, doppler_resolution, uDoppler
コード例 #11
0
ファイル: lg_test.py プロジェクト: Julymycin/codes
from LogGabor import LogGabor
import cv2

parameterfile = './lg_para.py'
lg = LogGabor(parameterfile)

image = cv2.imread("example1.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
lg.set_size(gray)
コード例 #12
0
def generate_gabors_coordinates(theta, params, N_X, N_Y, centers_coordinates,
                                B_theta=15, sf_0=.05, B_sf=.5,
                                distrib_size=8, grid_res=3,
                                on_thresh=.1, off_thresh=-.1,
                                verbose=True):
    '''
    Given some gabor parameters, a set of coordinates for centering gabors, returns a set of 
    coordinates for filters belonging into the gabors


    Params :
        theta : gabor theta angle
        params : the default parameters dictionnary for the gabor generation
        N_X, N_Y : Gabor size, usually the same as the video

        centers_coordinates : a 2D array giving the centers of each gabor

        B_theta, sf_0, B_sf : Parameters for the LogGabor shape
                            B_theta is the opening of the gabor, 
                            sf_0 is the spatial frequency 
                            b_sf is the bandwidth frequency

        distrib_size : the size of each group of filters, in image coordinates
        grid_res : resolution of the group of filters, passed in a np.mgrid

        on_thresh, off_thresh : threshold at which a filter is selected to 
                                be on/off, by scanning the Gabor phi-space

        verbose : display the filter size as a sanity check  
    '''

    xs = centers_coordinates[0]
    ys = centers_coordinates[1]
    nbr_gabors = len(xs)

    N_X = int(N_X)
    N_Y = int(N_Y)
    N_phase = 2

    lg = LogGabor(params)
    lg.set_size((N_X, N_Y))

    B_theta = B_theta / 180 * np.pi
    params = {'sf_0': sf_0, 'B_sf': B_sf, 'B_theta': B_theta}
    params.update(theta=theta)

    phi = np.zeros((1, N_phase, N_X, N_Y))

    filters_per_gab = []
    for gab in range(nbr_gabors):
        x = xs[gab]
        y = ys[gab]

        for i_phase in range(N_phase):
            phase = i_phase * np.pi/2
            kernel = lg.invert(lg.loggabor(
                x, y, **params)*np.exp(-1j*phase))
            phi[0, i_phase, :] = lg.normalize(kernel)

        fx_min = x - distrib_size
        fx_max = x + distrib_size
        fy_min = y - distrib_size
        fy_max = y + distrib_size
        filters_coordinates = np.mgrid[fx_min:fx_max:grid_res,
                                       fy_min:fy_max:grid_res].reshape(2, -1).T
        if verbose and gab == 0:
            print('Thread started !\nFilter grid shape',
                  filters_coordinates.shape, '\n')

        filters_in_gabor = gabor_connectivity(filters=filters_coordinates,
                                              phi=phi, theta=0, threshold=on_thresh)
        off_filters_in_gabor = gabor_connectivity(filters=filters_coordinates,
                                                  phi=phi, theta=0, threshold=off_thresh, on=False)

        filters_per_gab.append((filters_in_gabor, off_filters_in_gabor))

    return filters_per_gab
コード例 #13
0
    # LOG GABOR
    
    if logGabor:
        if accumulate:
            image = micro_doppler_data.sum(axis=1).T
        else:
            image = micro_doppler_data[:,120,:].T

        from LogGabor import LogGabor
        import holoviews as hv
        import os
        fig_width = 12
        figsize=(fig_width, .618*fig_width)

        lg = LogGabor("default_param.py")
        lg.set_size(image)
        lg.pe.datapath = 'database/'

        image = lg.normalize(image, center=True)

        # display input image
        # hv.Image(image)

        # display log gabor'd image
        image = lg.whitening(image)*lg.mask
        hv.Image(image)

        uDoppler = image
    elif accumulate:
        uDoppler = micro_doppler_data.sum(axis=1).T
コード例 #14
0
def get_gabor_features_texture_classification(image_file_path, num_levels,
                                              num_orientations):
    # image = imread(image_file_path)
    # image = skimage.io.imread(image_file_path)
    print 'length of image'
    print len(image_file_path.shape)
    if (len(image_file_path.shape) == 3):
        image = image_file_path[:, :, 0]
    else:
        image = image_file_path[:, :]
    opts = {
        'vmin': 0.,
        'vmax': 1.,
        'interpolation': 'nearest',
        'origin': 'upper'
    }
    print image.shape

    # image = image_file_path
    # image = image[30:70,30:70]
    sum_sqr_num_feat = num_levels * num_orientations

    sum_sqr_feat_vec = np.zeros((1, sum_sqr_num_feat))
    print 'shape of sum sqr vec is:'
    print sum_sqr_feat_vec.shape
    lg = LogGabor('default_param.py')
    lg.set_size(image)
    # num_features = num_levels*num_orientations*2
    # feature_vec = np.zeros((num_features,1))
    # phi = (np.sqrt(5) +1.)/2. # golden number
    # fig = plt.figure(figsize=(fig_width, fig_width/phi))
    # xmin, ymin, size = 0, 0, 1.
    i = 0
    first_response = None
    for i_level in range(num_levels):
        # for theta in np.linspace(0, np.pi, num_orientations, endpoint=False):
        for theta in np.linspace(0, np.pi, num_orientations, endpoint=False):
            params = {
                'sf_0': 1. / (2**i_level),
                'B_sf': lg.pe.B_sf,
                'theta': theta,
                'B_theta': lg.pe.B_theta
            }
            # loggabor takes as args: u, v, sf_0, B_sf, theta, B_theta)
            FT_lg = lg.loggabor(0, 0, **params)
            filtered_img_mat = lg.FTfilter(image, FT_lg, full=True)
            # print "SHAPE OF FILTERED IMAGE IS (%s, %s)" % filtered_img_mat.shape
            im_abs_feature = np.absolute(filtered_img_mat).flatten()
            # im_abs_feature = np.sum(np.absolute(filtered_img_mat))
            # im_sqr_feature = np.sum(np.square(np.real(filtered_img_mat)))
            # im_sqr_feature = np.sum(np.square(filtered_img_mat))
            if i == 0:
                first_response = im_abs_feature.reshape(
                    1, im_abs_feature.shape[0])
            # print type(im_abs_feature)
            # print im_abs_feature.shape
            # print im_abs_feature
            # print LA.norm(im_abs_feature.reshape(1, im_abs_feature.shape[0]))
            sum_sqr_feat_vec[0, i] = LA.norm(
                im_abs_feature.reshape(1, im_abs_feature.shape[0]))

            # print 'L2 norm squared is:'
            # print sum_sqr_feat_vec[0,i]

            # if i == 0:
            #     feature_vec = im_abs_feature
            # else:
            #     feature_vec = np.hstack((feature_vec, im_abs_feature))
            i += 1
    print
    return sum_sqr_feat_vec
コード例 #15
0
class EdgeGrid():
    def __init__(self,
                 N_lame = 8*72,
                 N_lame_X = None,
                 figsize = 13,
                 line_width = 4.,
                 grid_type = 'hex',
                 structure = True, struct_angles = [-15., -65., -102.],
                 verb = False,
                 mode = 'both',
                 filename = None,
                 period = None,
                 #**kw_args
                 ):
        self.t0 = self.time(True)
        self.t = self.time()
        self.dt = self.t - self.t0
        self.verb = verb
        self.display = (mode=='display') or (mode=='both')
        self.stream =  (mode=='stream') or (mode=='display')
        #if mode=='display': self.stream = True
        self.filename = filename
        self.serial =  (mode=='serial') # converting a stream to the serial port to control the arduino
        if self.serial: self.verb=True
#         self.desired_fps = 750.
        self.desired_fps = 30.
        self.structure = structure
        self.screenshot = True # saves a screenshot after the rendering

        self.port = "5556"
        # moteur:
        self.serial_port, self.baud_rate = '/dev/ttyUSB0', 115200
        # 1.8 deg par pas (=200 pas par tour) x 32 divisions de pas
        # demultiplication : pignon1= 14 dents, pignon2 = 60 dents
        self.n_pas = 200. * 32. * 60 / 14
        # TODO : Vitesse Max moteur = 1 tour en 3,88
        self.n_pas_max = 148 # 150

        # taille installation
        self.total_width = 8 # en mètres
        self.lames_width = 5 # en mètres
        self.lames_height = 3 # en mètres
        self.background_depth = 100 # taille du 104 en profondeur
        self.f = .1
        self.struct_N = 6
        self.struct_position = [0., 3.5]
        self.struct_longueur = 3.
        self.struct_angles = struct_angles
        self.figsize = figsize
        self.line_width = line_width
        self.grid_type = grid_type
        self.grid(N_lame=N_lame, N_lame_X=N_lame_X)
        # self.lames[2, :] = np.pi*np.random.rand(self.N_lame)

        self.N_particles_per_lame = 2**3
        self.N_particles = self.struct_N * self.N_particles_per_lame
        if structure: self.sample_structure()

        # enregistrement / playback
        self.period = period
        self.load()

    def load(self):
        if not self.filename is None:
            if os.path.isfile(self.filename):
            # le fichier existe, on charge
                self.z = np.load(self.filename)
                self.period = self.z[:, 0].max()

    def time(self, init=False):
        if init: return time.time()
        else: return time.time() - self.t0

    def grid(self, N_lame, N_lame_X):
        """
        The coordinates of the screen are centered on the (0, 0) point and axis are the classical convention:

         y
         ^
         |
         +---> x

         angles are from the horizontal, then in trigonometric order (anticlockwise)

         """

        self.DEBUG = False
        self.DEBUG = True

        self.N_lame = N_lame
        #if N_lame_X is None:

        if self.grid_type=='hex':
            self.N_lame_X = np.int(np.sqrt(self.N_lame))#*np.sqrt(3) / 2)
            self.lames = np.zeros((4, self.N_lame))
            self.lames[0, :] = np.mod(np.arange(self.N_lame), self.N_lame_X)
            self.lames[0, :] += np.mod(np.floor(np.arange(self.N_lame)/self.N_lame_X), 2)/2
            self.lames[1, :] = np.floor(np.arange(self.N_lame)/self.N_lame_X)
            self.lames[1, :] *= np.sqrt(3) / 2
            self.lames[0, :] /= self.N_lame_X
            self.lames[1, :] /= self.N_lame_X
            self.lames[0, :] += .5/self.N_lame_X - .5
            self.lames[1, :] += 1.5/self.N_lame_X # TODO : prove analytically
            self.lames[0, :] *= self.total_width
            self.lames[1, :] *= self.total_width
            self.lame_length = .99/self.N_lame_X*self.total_width*np.ones(self.N_lame)
            self.lame_width = .03/self.N_lame_X*self.total_width*np.ones(self.N_lame)
        elif self.grid_type=='line':
            self.N_lame_X = self.N_lame
            self.lames = np.zeros((4, self.N_lame))
            self.lames[0, :] = np.linspace(-self.lames_width/2, self.lames_width/2, self.N_lame, endpoint=True)
            #self.lames[1, :] = self.total_width/2
            self.lame_length = .12*np.ones(self.N_lame) # en mètres
            self.lame_width = .042*np.ones(self.N_lame) # en mètres

        if self.structure: self.add_structure()

        self.lames_minmax = np.array([self.lames[0, :].min(), self.lames[0, :].max(), self.lames[1, :].min(), self.lames[1, :].max()])

    def do_structure(self):
        structure_ = np.zeros((3, self.struct_N))
        chain = np.zeros((2, 4))
        chain[:, 0] = np.array(self.struct_position).T
        for i, angle in enumerate(self.struct_angles):
            chain[0, i+1] = chain[0, i] + self.struct_longueur*np.cos(angle*np.pi/180.) 
            chain[1, i+1] = chain[1, i] + self.struct_longueur*np.sin(angle*np.pi/180.) 
            structure_[2, 3+i] = +angle*np.pi/180. 
            structure_[2, i] = np.pi-angle*np.pi/180
        structure_[0, 3:] = .5*(chain[0, 1:]+chain[0, :-1])
        structure_[0, :3] = -.5*(chain[0, 1:]+chain[0, :-1])
        structure_[1, 3:] = .5*(chain[1, 1:]+chain[1, :-1])
        structure_[1, :3] = .5*(chain[1, 1:]+chain[1, :-1])
        return structure_

    def add_structure(self):
        self.N_lame += self.struct_N
        self.lames = np.hstack((self.lames, np.zeros((4, self.struct_N))))
        self.lames[:3, -self.struct_N:] = self.do_structure()
        self.lame_length = np.hstack((self.lame_length, self.struct_longueur*np.ones(self.struct_N))) # en mètres
        self.lame_width = np.hstack((self.lame_width, .042*np.ones(self.struct_N))) # en mètres
        
        
    def sample_structure(self, N_mirror=0, alpha = .8):
        struct = self.lames[:3, -self.struct_N:]
        self.particles = np.ones((3, self.N_particles))
        N_particles_ = self.N_particles/self.struct_N
        for i, vec in enumerate(struct.T.tolist()):
            x0, x1 = vec[0] - .5*self.struct_longueur*np.cos(vec[2]), vec[0] + .5*self.struct_longueur*np.cos(vec[2])
            y0, y1 = vec[1] - .5*self.struct_longueur*np.sin(vec[2]), vec[1] + .5*self.struct_longueur*np.sin(vec[2])
            self.particles[0, i*N_particles_:(i+1)*N_particles_] = np.linspace(x0, x1, N_particles_)
            self.particles[1, i*N_particles_:(i+1)*N_particles_] = np.linspace(y0, y1, N_particles_)
        
        # duplicate according to mirrors
        for i in range(N_mirror):
            particles = self.particles.copy() # the current structure to mirror
            particles_mirror = particles.copy() # the new set of particles with their mirror image
            for segment in self.structure_as_segments():
                particles_mirror = np.hstack((particles_mirror, mirror(particles, segment, alpha**(i+1))))
            # print(alpha**(i+1), particles_mirror[-1, -1])
            self.particles = particles_mirror

    def structure_as_segments(self):
        struct = self.lames[:3, -self.struct_N:]
        segments = []
        for i, vec in enumerate(struct.T.tolist()):
            x0, x1 = vec[0] - .5*self.struct_longueur*np.cos(vec[2]), vec[0] + .5*self.struct_longueur*np.cos(vec[2])
            y0, y1 = vec[1] - .5*self.struct_longueur*np.sin(vec[2]), vec[1] + .5*self.struct_longueur*np.sin(vec[2])
            segments.append(np.array([[x0, y0], [x1, y1]]).T)
        return segments
            
    def theta_E(self, im, X_, Y_, w):
        try:
            assert(self.slip.N_X==im.shape[1])
        except:
            from NeuroTools.parameters import ParameterSet
            from SLIP import Image
            from LogGabor import LogGabor
            self.slip = Image(ParameterSet({'N_X':im.shape[1], 'N_Y':im.shape[0]}))
            self.lg = LogGabor(self.slip)
        im_ = im.sum(axis=-1)
        im_ = im_ * np.exp(-.5*((.5 + .5*self.slip.x-Y_)**2+(.5 + .5*self.slip.y-X_)**2)/w**2)
        E = np.zeros((self.N_theta,))
        for i_theta, theta in enumerate(self.thetas):
            params= {'sf_0':self.sf_0, 'B_sf':self.B_sf, 'theta':theta, 'B_theta': np.pi/self.N_theta}
            FT_lg = self.lg.loggabor(0, 0, **params)
            E[i_theta] = np.sum(np.absolute(self.slip.FTfilter(np.rot90(im_, -1), FT_lg, full=True))**2)
        return E

    def theta_max(self, im, X_, Y_, w):
        E = self.theta_E(im, X_, Y_, w)
        return self.thetas[np.argmax(E)] - np.pi/2


    def theta_sobel(self, im, N_blur):
        im_ = im.copy()
        sobel = np.array([[1,   2,  1,],
                          [0,   0,  0,],
                          [-1, -2, -1,]])
        if im_.ndim==3: im_ = im_.sum(axis=-1)
        from scipy.signal import convolve2d
        im_X = convolve2d(im_, sobel, 'same')
        im_Y = convolve2d(im_, sobel.T, 'same')

        N_X, N_Y = im_.shape
        x, y = np.mgrid[0:1:1j*N_X, 0:1:1j*N_Y]
        mask = np.exp(-.5*((x-.5)**2+(y-.5)**2)/w**2)
        im_X = convolve2d(im_X, mask, 'same')
        im_Y = convolve2d(im_Y, mask, 'same')
        blur = np.array([[1, 2, 1],
                         [2, 8, 2],
                         [1, 2, 1]])
        for i in range(N_blur):
            im_X = convolve2d(im_X, blur, 'same')
            im_Y = convolve2d(im_Y, blur, 'same')

        angle = np.arctan2(im_Y, im_X)

        bord = .1
        angles = np.empty(self.N_lame)
        N_X, N_Y = im_.shape
        for i in range(self.N_lame):
            angles[i] = angle[int((bord+self.lames[0, i]*(1-2*bord))*N_X),
                              int((bord+self.lames[1, i]*(1-2*bord))*N_Y)]
        return angles - np.pi/2

    def pos_rel(self, do_torus=False):
        def torus(x, w=1.):
            """
            center x in the range [-w/2., w/2.]

            To see what this does, try out:
            >> x = np.linspace(-4,4,100)
            >> pylab.plot(x, torus(x, 2.))

            """
            return np.mod(x + w/2., w) - w/2.
        dx = self.lames[0, :, np.newaxis]-self.lames[0, np.newaxis, :]
        dy = self.lames[1, :, np.newaxis]-self.lames[1, np.newaxis, :]
        if do_torus:
            return torus(dx), torus(dy)
        else:
            return dx, dy

    def distance(self, do_torus=False):
        dx, dy = self.pos_rel(do_torus=do_torus) 
        return np.sqrt(dx **2 + dy **2)

    def angle_relatif(self):
        return self.lames[2, :, np.newaxis]-self.lames[2, np.newaxis, :]

    def angle_cocir(self, do_torus=False):
        dx, dy = self.pos_rel(do_torus=do_torus)
        theta = self.angle_relatif()
        return np.arctan2(dy, dx) - np.pi/2 - theta

    def champ(self):
        if self.structure: N_lame = self.N_lame-self.struct_N
        else: N_lame = self.N_lame
        force = np.zeros_like(self.lames[2, :N_lame])
        noise = lambda t: 0.2 * np.exp((np.cos(2*np.pi*(t-0.) / 6.)-1.)/ 1.5**2)
        damp = lambda t: 0.01 #* np.exp(np.cos(t / 6.) / 3.**2)
        colin_t = lambda t: -.1*np.exp((np.cos(2*np.pi*(t-2.) / 6.)-1.)/ .3**2)
        cocir_t = lambda t: -4.*np.exp((np.cos(2*np.pi*(t-4.) / 6.)-1.)/ .5**2)
        cocir_d = lambda d: np.exp(-d/.05)
        colin_d = lambda d: np.exp(-d/.2)

        force += colin_t(self.t) * np.sum(np.sin(2*(self.angle_relatif()[:N_lame]))*colin_d(self.distance()[:N_lame]), axis=1)
        force += cocir_t(self.t) * np.sum(np.sin(2*(self.angle_cocir()[:N_lame]))*cocir_d(self.distance()[:N_lame]), axis=1)
        force += noise(self.t)*np.pi*np.random.randn(N_lame)
        force -= damp(self.t) * self.lames[3, :N_lame]/self.dt
        return 42.*force

    def update(self):
        if self.structure: N_lame = self.N_lame-self.struct_N
        else: N_lame = self.N_lame
        self.lames[2, :N_lame] += self.lames[3, :N_lame]*self.dt/2
        self.lames[3, :N_lame] += self.champ() * self.dt
        self.lames[2, :N_lame] += self.lames[3, :N_lame]*self.dt/2
        # angles are defined as non oriented between -pi/2 and pi/2 
        self.lames[2, :N_lame] = np.mod(self.lames[2, :N_lame] + np.pi/2, np.pi) - np.pi/2  

    def receive(self):
        if not self.filename is None:
            if os.path.isfile(self.filename):
                if self.structure: N_lame = self.N_lame-self.struct_N
                else: N_lame = self.N_lame
                self.t = self.time()
                i_t = np.argmin(self.z[:, 0] < np.mod(self.t, self.period))
                if self.verb: print("playback at t=", np.mod(self.t, self.period), i_t)
                self.lames[2, :N_lame] =  self.z[i_t, 1:]
                return

        if self.stream:
            if self.verb: print("Sending request")
            self.socket.send (b"Hello")
            if self.verb: print( "Received reply ", message)
            self.lames[2, :] = recv_array(self.socket)
            if self.verb: print("Received reply ", Theta.shape)
        else:
            self.dt = self.time() - self.t
            self.update()
            self.t = self.time()

#         if not self.filename is None:
#             if not os.path.isfile(self.filename):
#                 # recording
#                 if self.verb: print("recording at t=", self.t)
#                 self.z = np.vstack((self.z, np.hstack((np.array(self.t), self.lames[2, :] ))))
        return

    def render(self, fps=10, W=1000, H=618, location=[0, 1.75, -5], head_size=.4, light_intensity=1.2, reflection=1., 
               look_at=[0, 1.5, 0], fov=75, antialiasing=0.001, duration=5, fname='/tmp/temp.webm'):

        def scene(t):
            """ 
            Returns the scene at time 't' (in seconds) 
            """

            head_location = np.array(location) - np.array([0, 0, head_size])
            import vapory
            light = vapory.LightSource([15, 15, 1], 'color', [light_intensity]*3)
            background = vapory.Box([0, 0, 0], [1, 1, 1], 
                     vapory.Texture(vapory.Pigment(vapory.ImageMap('png', '"../files/VISUEL_104.png"', 'once')),
                             vapory.Finish('ambient', 1.2) ),
                     'scale', [self.background_depth, self.background_depth, 0],
                     'translate', [-self.background_depth/2, -.45*self.background_depth, -self.background_depth/2])
            me = vapory.Sphere( head_location, head_size, vapory.Texture( vapory.Pigment( 'color', [1, 0, 1] )))
            self.t = t
            self.update()
            objects = [background, me, light]

            for i_lame in range(self.N_lame):
                #print(i_lame, self.lame_length[i_lame], self.lame_width[i_lame])
                objects.append(vapory.Box([-self.lame_length[i_lame]/2, 0, -self.lame_width[i_lame]/2], 
                                          [self.lame_length[i_lame]/2, self.lames_height,  self.lame_width[i_lame]/2], 
                                           vapory.Pigment('color', [1, 1, 1]),
                                           vapory.Finish('phong', 0.8, 'reflection', reflection),
                                           'rotate', (0, -self.lames[2, i_lame]*180/np.pi, 0), #HACK?
                                           'translate', (self.lames[0, i_lame], 0, self.lames[1, i_lame])
                                          )
                              )

            objects.append(light)
            return vapory.Scene( vapory.Camera('angle', fov, "location", location, "look_at", look_at),
                           objects = objects,
                           included=["glass.inc"] )
        import moviepy.editor as mpy
        if not os.path.isfile(fname):
            self.dt = 1./fps
            def make_frame(t):
                return scene(t).render(width=W, height=H, antialiasing=antialiasing)

            clip = mpy.VideoClip(make_frame, duration=duration)
            clip.write_videofile(fname, fps=fps)
        return mpy.ipython_display(fname, fps=fps, loop=1, autoplay=1)

    def plot_structure(self, W=1000, H=618, fig=None, ax=None, border = 0.0, 
            opts = dict(vmin=-1, vmax=1., linewidths=0, cmap=None, alpha=.1, s=5.), 
            scale='auto'): #
        opts.update(cmap=plt.cm.hsv)
        if fig is None: fig = plt.figure(figsize=(self.figsize, self.figsize*H/W))
        if ax is None: ax = fig.add_axes((border, border, 1.-2*border, 1.-2*border), axisbg='w')
        scat  = ax.scatter(self.particles[0,::-1], self.particles[1,::-1], c=self.particles[2,::-1], **opts)
        if type(scale) is float:
            ax.set_xlim([-scale, scale])
            ax.set_ylim([-scale*H/W, scale*H/W])
        elif not scale is 'auto':
            ax.set_xlim([-self.total_width, self.total_width])
            ax.set_ylim([-self.total_width*H/W, self.total_width*H/W])
        else:
            ax.set_xlim([min(self.particles[0, :].min(), self.particles[1, :].min()/H*W), 
                         max(self.particles[0, :].max(), self.particles[1, :].max()/H*W)])
            ax.set_ylim([min(self.particles[1, :].min(), self.particles[0, :].min()*H/W), 
                         max(self.particles[1, :].max(), self.particles[0, :].max()*H/W)])
        ax.axis('off') 
        return fig, ax
    
    def animate(self, fps=10, W=1000, H=618, duration=20, scale='auto', fname=None):
        if fname is None:
            import tempfile
            fname = tempfile.mktemp() + '.webm'
        import matplotlib.pyplot as plt
        self.dt = 1./fps
        inches_per_pt = 1.0/72.27
        from moviepy.video.io.bindings import mplfig_to_npimage
        import moviepy.editor as mpy
        def make_frame_mpl(t):
            self.t = t
            self.update()
            fig = plt.figure(figsize=(W*inches_per_pt, H*inches_per_pt))
            fig, ax = self.plot_structure(fig=fig, ax=None, scale=scale)
            #ax.clear()
            ax.axis('off')
            #fig, ax = self.plot_structure(fig=fig, ax=ax)
            return mplfig_to_npimage(fig) # RGB image of the figure

        animation = mpy.VideoClip(make_frame_mpl, duration=duration)
        plt.close('all')
        animation.write_videofile(fname, fps=fps)
        return mpy.ipython_display(fname, fps=fps, loop=1, autoplay=1, width=W)