Пример #1
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
Пример #2
0
def presentStimulus(win, stimulus, param, info, do_mask=True):
    import time
    if (param.condition == 1):
        pe = ParameterSet({'N_X' : info[NS_X]/2, 'N_Y' : info[NS_Y]/2, 'figpath':'.', 'matpath':'.'})
    else: pe = ParameterSet({'N_X' : info[NS_X], 'N_Y' : info[NS_Y], 'figpath':'.', 'matpath':'.'})
    im = Image(pe)
    if (stimulus.ndim == 3):
        img1 = stim(stimulus[:, :, 0])
        img2 = stim(im.translate(stimulus[:, :, 0], [param.shift, 0]))
    else:
        img1 = stim(stimulus)
        img2 = stim(im.translate(stimulus, [param.shift, 0]))

    if param.flip == -1:
        img2 = 255 - img2

    if do_mask:
        if (param.condition == 1):
            im = Image(ParameterSet({'N_X' : info[NS_X]/2, 'N_Y' : info[NS_Y]/2, 'figpath':'.', 'matpath':'.'}))
        else: im = Image(ParameterSet({'N_X' : info[NS_X], 'N_Y' : info[NS_Y], 'figpath':'.', 'matpath':'.'}))
        mask = im.mask[:, :, np.newaxis]
        img1 = ((img1 - 127)*mask + 127).astype(int)
        img2 = ((img2 - 127)*mask + 127).astype(int)

    win.background.fill(RGB.Gray)
    win.screen.blit(win.background, (0, 0))
    winblit(img1, win, info)
    winblit(img2, win, info)
Пример #3
0
    def init(self):
        Image.init(self)

        self.n_levels = int(np.log(np.max((self.pe.N_X, self.pe.N_Y)))/np.log(self.pe.base_levels))
        self.sf_0 = .5 * (1 - 1/self.n_levels) / np.logspace(0, self.n_levels-1, self.n_levels, base=self.pe.base_levels, endpoint=False)
        self.theta = np.linspace(-np.pi/2, np.pi/2, self.pe.n_theta+1)[1:]
        self.oc = (self.pe.N_X * self.pe.N_Y * self.pe.n_theta * self.n_levels) #(1 - self.pe.base_levels**-2)**-1)
        if self.pe.use_cache is True:
            self.cache = {'band':{}, 'orientation':{}}
Пример #4
0
    def init(self):
        Image.init(self)

        self.n_levels = int(
            np.log(np.max(
                (self.pe.N_X, self.pe.N_Y))) / np.log(self.pe.base_levels))
        self.sf_0 = 1. / np.logspace(
            1, self.n_levels, self.n_levels, base=self.pe.base_levels)
        self.theta = np.linspace(-np.pi / 2, np.pi / 2,
                                 self.pe.n_theta + 1)[1:]
        self.oc = (self.pe.N_X * self.pe.N_Y * self.pe.n_theta * self.n_levels
                   )  #(1 - self.pe.base_levels**-2)**-1)
Пример #5
0
def creation_stimulus(info, screen, param, name_database='blackwhite'):
    import MotionClouds as mc
    from MotionClouds.display import rectif

#   from libpy import lena

    if (param.condition == 1):
        stimulus = (np.random.rand(info[NS_X]/2, info[NS_Y]/2) > .5)
#        stimulus = (np.random.rand(64, 64) > .5)
    elif (param.condition == 2):
        im = Image(ParameterSet({'N_X' : info[NS_X], 'N_Y' : info[NS_Y], 'figpath':'.', 'matpath':'.', 'datapath':'database/', 'do_mask':False, 'seed':None}))
        stimulus, filename, croparea = im.patch(name_database)
#         stimulus = lena()
        stimulus = np.rot90(np.fliplr(stimulus))
        stimulus = rectif(stimulus, contrast=1.)
    else:
        fx, fy, ft = mc.get_grids(info[NS_X], info[NS_Y], 1)
        if (param.condition == 3):
            t, b, B_sf, sf_0 = 0, np.pi/32, 0.1, 0.15
        if (param.condition == 4):
            t, b, B_sf, sf_0= 0, np.pi/8, 0.1, 0.15
        if (param.condition == 5):
            t, b, B_sf, sf_0= 0, np.pi/2, 0.1, 0.15
        if (param.condition == 6):
            t, b, B_sf, sf_0= 0, np.pi/32, 0.1, 0.03
        if (param.condition == 7):
            t, b, B_sf, sf_0= 0, np.pi/32, 0.1, 0.075
        if (param.condition == 8):
            t, b, B_sf, sf_0= 0, np.pi/32, 0.25, 0.15
        if (param.condition == 9):
            t, b, B_sf, sf_0= 0, np.pi/32, 0.5, 0.15
        fx, fy, ft = mc.get_grids(info[NS_X], info[NS_Y], 1)
        cloud = mc.random_cloud(mc.envelope_gabor(fx, fy, ft, sf_0=sf_0, B_sf=B_sf, theta=t, B_theta=b, B_V=1000.))
        cloud = rectif(cloud, contrast=1.)
        stimulus = cloud[:, :, 0]

    return (stimulus)
Пример #6
0
    def __init__(self,
                 height=256,
                 width=256,
                 patch_size=(12, 12),
                 database = 'database/',
                 n_components=14**2,
                 learning_algorithm='omp',
                 alpha=None,
                 transform_n_nonzero_coefs=20,
                 n_iter=5000,
                 eta=.01,
                 eta_homeo=.01,
                 alpha_homeo=.01,
                 max_patches=1000,
                 batch_size=100,
                 n_image=200,
                 DEBUG_DOWNSCALE=1, # set to 10 to perform a rapid experiment
                 verbose=0,
                 ):
        self.height = height
        self.width = width
        self.database = database
        self.patch_size = patch_size
        self.n_components = n_components
        self.n_iter = int(n_iter/DEBUG_DOWNSCALE)
        self.max_patches = int(max_patches/DEBUG_DOWNSCALE)
        self.n_image = int(n_image/DEBUG_DOWNSCALE)
        self.batch_size = batch_size
        self.learning_algorithm = learning_algorithm
        self.alpha=alpha

        self.transform_n_nonzero_coefs = transform_n_nonzero_coefs
        self.eta = eta
        self.eta_homeo = eta_homeo
        self.alpha_homeo = alpha_homeo

        self.verbose = verbose
        # Load natural images and extract patches
        self.slip = Image({'N_X':height, 'N_Y':width, 
                                        'white_n_learning' : 0,
                                        'seed': None,
                                        'white_N' : .07,
                                        'white_N_0' : .0, # olshausen = 0.
                                        'white_f_0' : .4, # olshausen = 0.2
                                        'white_alpha' : 1.4,
                                        'white_steepness' : 4.,
                                        'datapath': self.database,
                                        'do_mask':True,
                                        'N_image': n_image})
Пример #7
0
    def __init__(self,
                 height=256,
                 width=256,
                 patch_size=(10, 10),
                 n_components=11**2,
                 learning_algorithm='omp',
                 transform_n_nonzero_coefs=20,
                 n_iter=50000,
                 eta=1./25,
                 eta_homeo=0.001,
                 alpha_homeo=0.02,
                 max_patches=10000,
                 batch_size=100,
                 n_image=200,
                 DEBUG_DOWNSCALE=1, # set to 10 to perform a rapid experiment<D-d>
                 verbose=20,
                 ):
        self.height = height
        self.width = width
        self.patch_size = patch_size
        self.n_components = n_components
        self.n_iter = int(n_iter/DEBUG_DOWNSCALE)
        self.max_patches = int(max_patches/DEBUG_DOWNSCALE)
        self.n_image = int(n_image/DEBUG_DOWNSCALE)
        self.batch_size = batch_size
        self.learning_algorithm = learning_algorithm

        self.transform_n_nonzero_coefs = transform_n_nonzero_coefs
        self.eta = eta
        self.eta_homeo = eta_homeo
        self.alpha_homeo = alpha_homeo

        self.verbose = verbose
        # Load natural images and extract patches
        self.slip = Image(ParameterSet({'N_X':height, 'N_Y':width, 
                                        'white_n_learning' : 0,
                                        'seed': None,
                                        'white_N' : .07,
                                        'white_N_0' : .0, # olshausen = 0.
                                        'white_f_0' : .4, # olshausen = 0.2
                                        'white_alpha' : 1.4,
                                        'white_steepness' : 4.,
                                        'datapath': '/Users/lolo/pool/science/PerrinetBednar15/database/',
                                        'do_mask':True,
                                        'N_image': n_image}))
Пример #8
0
 def __init__(self, pe):
     Image.__init__(self, pe)
     self.init_logging(name='LogGabor')
Пример #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 __init__(self, pe):
     Image.__init__(self, pe)
     self.init_logging(name='LogGabor')
Пример #11
0
class SHL(object):
    """
    Base class to define SHL experiments:
        - intializing
        - running learning
        - visualization
        - quantitative analysis

    """
    def __init__(self,
                 height=256,
                 width=256,
                 patch_size=(10, 10),
                 n_components=11**2,
                 learning_algorithm='omp',
                 transform_n_nonzero_coefs=20,
                 n_iter=50000,
                 eta=1./25,
                 eta_homeo=0.001,
                 alpha_homeo=0.02,
                 max_patches=10000,
                 batch_size=100,
                 n_image=200,
                 DEBUG_DOWNSCALE=1, # set to 10 to perform a rapid experiment<D-d>
                 verbose=20,
                 ):
        self.height = height
        self.width = width
        self.patch_size = patch_size
        self.n_components = n_components
        self.n_iter = int(n_iter/DEBUG_DOWNSCALE)
        self.max_patches = int(max_patches/DEBUG_DOWNSCALE)
        self.n_image = int(n_image/DEBUG_DOWNSCALE)
        self.batch_size = batch_size
        self.learning_algorithm = learning_algorithm

        self.transform_n_nonzero_coefs = transform_n_nonzero_coefs
        self.eta = eta
        self.eta_homeo = eta_homeo
        self.alpha_homeo = alpha_homeo

        self.verbose = verbose
        # Load natural images and extract patches
        self.slip = Image(ParameterSet({'N_X':height, 'N_Y':width, 
                                        'white_n_learning' : 0,
                                        'seed': None,
                                        'white_N' : .07,
                                        'white_N_0' : .0, # olshausen = 0.
                                        'white_f_0' : .4, # olshausen = 0.2
                                        'white_alpha' : 1.4,
                                        'white_steepness' : 4.,
                                        'datapath': '/Users/lolo/pool/science/PerrinetBednar15/database/',
                                        'do_mask':True,
                                        'N_image': n_image}))


    def get_data(self, name_database='serre07_distractors', seed=None):
        if self.verbose:
            # setup toolbar
            sys.stdout.write('Extracting data...')
            sys.stdout.flush()
            sys.stdout.write("\b" * (toolbar_width+1)) # return to start of line, after '['
            t0 = time.time()
        imagelist = self.slip.make_imagelist(name_database=name_database)#, seed=seed)
        for filename, croparea in imagelist:
            # whitening
            image, filename_, croparea_ = self.slip.patch(name_database, filename=filename, croparea=croparea, center=False)#, , seed=seed)
            image = self.slip.whitening(image)
            # Extract all reference patches
            data_ = extract_patches_2d(image, self.patch_size, max_patches=int(self.max_patches))#, seed=seed)
            data_ = data_.reshape(data_.shape[0], -1)
            data_ -= np.mean(data_, axis=0)
            data_ /= np.std(data_, axis=0)
            try:
                data = np.vstack((data, data_))
            except:
                data = data_.copy()
            if self.verbose:
                # update the bar
                sys.stdout.write(filename + ", ")
                sys.stdout.flush()
        if self.verbose:
            dt = time.time() - t0
            sys.stdout.write("\n")
            sys.stdout.write("Data is of shape : "+ str(data.shape))
            sys.stdout.write('done in %.2fs.' % dt)
            sys.stdout.flush()
        return data


    def learn_dico(self, name_database='serre07_distractors', **kwargs):
        data = self.get_data(name_database)
        # Learn the dictionary from reference patches
        if self.verbose: print('Learning the dictionary...', end=' ')
        t0 = time.time()
        dico = SparseHebbianLearning(eta=self.eta,
                                     n_components=self.n_components, n_iter=self.n_iter,
                                     gain_rate=self.eta_homeo, alpha_homeo=self.alpha_homeo,
                                     transform_n_nonzero_coefs=self.transform_n_nonzero_coefs,
                                     batch_size=self.batch_size, verbose=self.verbose,
                                     transform_algorithm=self.learning_algorithm,
                                                                          **kwargs)
        if self.verbose: print('Training on %d patches' % len(data), end='... ')
        dico.fit(data)
        if self.verbose:
            dt = time.time() - t0
            print('done in %.2fs.' % dt)
        return dico

    def show_dico(self, dico):
        subplotpars = matplotlib.figure.SubplotParams(left=0., right=1., bottom=0., top=1., wspace=0.05, hspace=0.05,)
        fig = plt.figure(figsize=(10, 10), subplotpars=subplotpars)
        for i, comp in enumerate(dico.components_):
            ax = fig.add_subplot(np.sqrt(self.n_components), np.sqrt(self.n_components), i + 1)
            cmax = np.max(np.abs(comp))
            ax.imshow(comp.reshape(self.patch_size), cmap=plt.cm.gray_r, vmin=-cmax, vmax=+cmax,
                    interpolation='nearest')
            ax.set_xticks(())
            ax.set_yticks(())
#         fig.suptitle('Dictionary learned from image patches\n' +
#                     'Using ' + learning_algorithm.replace('_', ' '),
#                     fontsize=12)
        #fig.tight_layout(rect=[0, 0, .9, 1])
        return fig

    def code(self, data, dico, intercept, coding_algorithm='omp', **kwargs):
        if self.verbose:
            print('Coding data...', end=' ')
            t0 = time.time()
        dico.set_params(transform_algorithm=coding_algorithm, **kwargs)
        code = dico.transform(data)
        V = dico.components_

        patches = np.dot(code, V)
        if coding_algorithm == 'threshold':
            patches -= patches.min()
            patches /= patches.max()

        patches += intercept
        patches = patches.reshape(len(data), *self.patch_size)
        if coding_algorithm == 'threshold':
            patches -= patches.min()
            patches /= patches.max()
        if self.verbose:
            dt = time.time() - t0
            print('done in %.2fs.' % dt)
        return patches
Пример #12
0
def get_data(height=256,
             width=256,
             n_image=200,
             patch_size=(12, 12),
             datapath='database/',
             name_database='serre07_distractors',
             max_patches=1024,
             seed=None,
             patch_norm=True,
             verbose=0,
             data_cache='/tmp/data_cache',
             matname=None):
    """
    Extract data:

    Extract from a given database composed of image of size (height, width) a
    series a random patches.

    """
    if matname is None:
        # Load natural images and extract patches
        from SLIP import Image
        slip = Image({
            'N_X': height,
            'N_Y': width,
            'white_n_learning': 0,
            'seed': seed,
            'white_N': .07,
            'white_N_0': .0,  # olshausen = 0.
            'white_f_0': .4,  # olshausen = 0.2
            'white_alpha': 1.4,
            'white_steepness': 4.,
            'datapath': datapath,
            'do_mask': True,
            'N_image': n_image
        })

        if verbose:
            import sys
            # setup toolbar
            sys.stdout.write('Extracting data...')
            sys.stdout.flush()
            sys.stdout.write(
                "\b" *
                (toolbar_width + 1))  # return to start of line, after '['
            t0 = time.time()
        import os
        imagelist = slip.make_imagelist(
            name_database=name_database)  #, seed=seed)
        for filename, croparea in imagelist:
            # whitening
            image, filename_, croparea_ = slip.patch(
                name_database,
                filename=filename,
                croparea=croparea,
                center=False)  #, seed=seed)
            image = slip.whitening(image)
            # Extract all reference patches and ravel them
            data_ = slip.extract_patches_2d(
                image, patch_size, N_patches=int(max_patches))  #, seed=seed)
            data_ = data_.reshape(data_.shape[0], -1)
            data_ -= np.mean(data_, axis=0)
            if patch_norm:
                data_ /= np.std(data_, axis=0)
            # collect everything as a matrix
            try:
                data = np.vstack((data, data_))
            except Exception:
                data = data_.copy()
            if verbose:
                # update the bar
                sys.stdout.write(filename + ", ")
                sys.stdout.flush()
        if verbose:
            dt = time.time() - t0
            sys.stdout.write("\n")
            sys.stdout.write("Data is of shape : " + str(data.shape))
            sys.stdout.write(' - done in %.2fs.' % dt)
            sys.stdout.flush()
    else:
        import os
        fmatname = os.path.join(data_cache, matname)
        if not (os.path.isfile(fmatname + '_data.npy')):
            if not (os.path.isfile(fmatname + '_data' + '_lock')):
                touch(fmatname + '_data' + '_lock')
                try:
                    if verbose:
                        print('No cache found {}: Extracting data...'.format(
                            fmatname + '_data'),
                              end=' ')
                    print(datapath)
                    data = get_data(height=height,
                                    width=width,
                                    n_image=n_image,
                                    patch_size=patch_size,
                                    datapath=datapath,
                                    name_database=name_database,
                                    max_patches=max_patches,
                                    seed=seed,
                                    patch_norm=patch_norm,
                                    verbose=verbose,
                                    matname=None)
                    np.save(fmatname + '_data.npy', data)
                finally:
                    try:
                        os.remove(fmatname + '_data' + '_lock')
                    except:
                        print('Coud not remove ', fmatname + '_data')
            else:
                print('the data extraction is locked', fmatname + '_data')
                return 'lock'
        else:
            if verbose:
                print("loading the data called : {0}".format(fmatname +
                                                             '_data'))
            # Une seule fois mp ici
            data = np.load(fmatname + '_data.npy')
    return data
Пример #13
0
        FT_lg = self.loggabor(u, v, sf_0, B_sf, theta, B_theta)
        fig, a1, a2 = self.im.show_FT(FT_lg * np.exp(-1j * phase))
        return fig, a1, a2


def _test():
    import doctest
    doctest.testmod()


#####################################
#
if __name__ == '__main__':
    _test()

    #### Main
    """
    Some examples of use for the class

    """
    from pylab import imread
    image = imread('database/lena512.png')[:, :, 0]

    from NeuroTools.parameters import ParameterSet
    pe = ParameterSet('default_param.py')
    pe.N_X, pe.N_Y = image.shape

    from SLIP import Image
    im = Image(pe)
    lg = LogGabor(im)
Пример #14
0
class SHL(object):
    """
    Base class to define SHL experiments:
        - intializing
        - running learning
        - visualization
        - quantitative analysis

    """
    def __init__(self,
                 height=256,
                 width=256,
                 patch_size=(12, 12),
                 database = 'database/',
                 n_components=14**2,
                 learning_algorithm='omp',
                 alpha=None,
                 transform_n_nonzero_coefs=20,
                 n_iter=5000,
                 eta=.01,
                 eta_homeo=.01,
                 alpha_homeo=.01,
                 max_patches=1000,
                 batch_size=100,
                 n_image=200,
                 DEBUG_DOWNSCALE=1, # set to 10 to perform a rapid experiment
                 verbose=0,
                 ):
        self.height = height
        self.width = width
        self.database = database
        self.patch_size = patch_size
        self.n_components = n_components
        self.n_iter = int(n_iter/DEBUG_DOWNSCALE)
        self.max_patches = int(max_patches/DEBUG_DOWNSCALE)
        self.n_image = int(n_image/DEBUG_DOWNSCALE)
        self.batch_size = batch_size
        self.learning_algorithm = learning_algorithm
        self.alpha=alpha

        self.transform_n_nonzero_coefs = transform_n_nonzero_coefs
        self.eta = eta
        self.eta_homeo = eta_homeo
        self.alpha_homeo = alpha_homeo

        self.verbose = verbose
        # Load natural images and extract patches
        self.slip = Image({'N_X':height, 'N_Y':width, 
                                        'white_n_learning' : 0,
                                        'seed': None,
                                        'white_N' : .07,
                                        'white_N_0' : .0, # olshausen = 0.
                                        'white_f_0' : .4, # olshausen = 0.2
                                        'white_alpha' : 1.4,
                                        'white_steepness' : 4.,
                                        'datapath': self.database,
                                        'do_mask':True,
                                        'N_image': n_image})

    def get_data(self, name_database='serre07_distractors', seed=None, patch_norm=True):
        if self.verbose:
            # setup toolbar
            sys.stdout.write('Extracting data...')
            sys.stdout.flush()
            sys.stdout.write("\b" * (toolbar_width+1)) # return to start of line, after '['
            t0 = time.time()
        imagelist = self.slip.make_imagelist(name_database=name_database)#, seed=seed)
        for filename, croparea in imagelist:
            # whitening
            image, filename_, croparea_ = self.slip.patch(name_database, filename=filename, croparea=croparea, center=False)#, , seed=seed)
            image = self.slip.whitening(image)
            # Extract all reference patches and ravel them
            data_ = extract_patches_2d(image, self.patch_size, max_patches=int(self.max_patches))#, seed=seed)
            data_ = data_.reshape(data_.shape[0], -1)
            data_ -= np.mean(data_, axis=0)
            if patch_norm:
                data_ /= np.std(data_, axis=0)
            # collect everything as a matrix 
            try:
                data = np.vstack((data, data_))
            except:
                data = data_.copy()
            if self.verbose:
                # update the bar
                sys.stdout.write(filename + ", ")
                sys.stdout.flush()
        if self.verbose:
            dt = time.time() - t0
            sys.stdout.write("\n")
            sys.stdout.write("Data is of shape : "+ str(data.shape))
            sys.stdout.write('done in %.2fs.' % dt)
            sys.stdout.flush()
        return data


    def learn_dico(self, name_database='serre07_distractors', **kwargs):
        data = self.get_data(name_database)
        # Learn the dictionary from reference patches
        if self.verbose: print('Learning the dictionary...', end=' ')
        t0 = time.time()
        dico = SparseHebbianLearning(eta=self.eta,
                                     n_components=self.n_components, n_iter=self.n_iter,
                                     gain_rate=self.eta_homeo, alpha_homeo=self.alpha_homeo,
                                     transform_n_nonzero_coefs=self.transform_n_nonzero_coefs,
                                     batch_size=self.batch_size, verbose=self.verbose, n_jobs=1,
                                     transform_algorithm=self.learning_algorithm, transform_alpha=self.alpha, **kwargs)
        if self.verbose: print('Training on %d patches' % len(data), end='... ')
        dico.fit(data)
        if self.verbose:
            dt = time.time() - t0
            print('done in %.2fs.' % dt)
        return dico

    def show_dico(self, dico, title=None, fname=None):
        subplotpars = matplotlib.figure.SubplotParams(left=0., right=1., bottom=0., top=1., wspace=0.05, hspace=0.05,)
        fig = plt.figure(figsize=(10, 10), subplotpars=subplotpars)
        for i, component in enumerate(dico.components_):
            ax = fig.add_subplot(np.sqrt(self.n_components), np.sqrt(self.n_components), i + 1)
            cmax = np.max(np.abs(component))
            ax.imshow(component.reshape(self.patch_size), cmap=plt.cm.gray_r, vmin=-cmax, vmax=+cmax,
                    interpolation='nearest')
            ax.set_xticks(())
            ax.set_yticks(())
        if title is not None:
            fig.suptitle(title, fontsize=12, backgroundcolor = 'white', color = 'k')
        #fig.tight_layout(rect=[0, 0, .9, 1])
        if not fname is None: fig.savefig(fname, dpi=200)
        return fig, ax

    def code(self, data, dico, intercept=0., coding_algorithm='omp', **kwargs):
        if self.verbose:
            print('Coding data...', end=' ')
            t0 = time.time()
        dico.set_params(transform_algorithm=coding_algorithm, **kwargs)
        code = dico.transform(data)
        V = dico.components_

        patches = np.dot(code, V)
        if coding_algorithm == 'threshold':
            patches -= patches.min()
            patches /= patches.max()

        patches += intercept
#         patches = patches.reshape(len(data), *self.patch_size)
        if coding_algorithm == 'threshold':
            patches -= patches.min()
            patches /= patches.max()
        if self.verbose:
            dt = time.time() - t0
            print('done in %.2fs.' % dt)
        return patches

    def plot_variance(self, dico, name_database='serre07_distractors', fname=None):
        data = self.get_data(name_database)
        code = self.code(data, dico)
        Z = np.mean(code**2)
        fig = plt.figure(figsize=(12, 4))
        ax = fig.add_subplot(111)
        ax.bar(np.arange(self.n_components), np.mean(code**2/Z, axis=0))#, yerr=np.std(code**2/Z, axis=0))
        ax.set_title('Variance of coefficients')
        ax.set_ylabel('Variance')
        ax.set_xlabel('#')
        ax.axis('tight')
        if not fname is None: fig.savefig(fname, dpi=200)
        return fig, ax

    def plot_variance_histogram(self, dico, name_database='serre07_distractors', fname=None):
        data = self.get_data(name_database)
        import pandas as pd
        import seaborn as sns
        code = self.code(data, dico)
        fig = plt.figure(figsize=(6, 4))
        ax = fig.add_subplot(111)
        data = pd.DataFrame(np.mean(code**2, axis=0)/np.mean(code**2), columns=['Variance'])
        with sns.axes_style("white"):
            ax = sns.distplot(data['Variance'],  kde_kws={'clip':(0., 5.)})
        ax.set_title('distribution of the mean variance of coefficients')
        ax.set_ylabel('pdf')
        if not fname is None: fig.savefig(fname, dpi=200)
        return fig, ax