def configure(self, color=[1, 1, 1, 1], cylinder_radius=0.5, cylinder_height=0.5, n_faces=16, cylinder_locations=[[+5, 0, 0]]): """ Collection of tower objects created with a single shader program """ self.color = color self.cylinder_radius = cylinder_radius self.cylinder_height = cylinder_height self.cylinder_locations = cylinder_locations self.n_faces = n_faces self.stim_object = GlVertices() # This step is slow. Make template once then use .translate() on copies to make cylinders cylinder = GlCylinder(cylinder_height=self.cylinder_height, cylinder_radius=self.cylinder_radius, cylinder_location=[0, 0, 0], color=self.color, n_faces=self.n_faces) for tree_loc in self.cylinder_locations: new_cyl = copy.copy(cylinder).translate(tree_loc) self.stim_object.add(new_cyl)
def configure(self, color=[1, 0, 0, 1], cylinder_radius=0.5, cylinder_height=0.5, cylinder_location=[+5, 0, 0], n_faces=16): """ Cylindrical tower object in arbitrary x, y, z coords :param color: [r,g,b,a] color of cylinder. Applied to entire texture, which is monochrome :param cylinder_radius: meters :param cylinder_height: meters :param cylinder_location: [x, y, z] location of the center of the cylinder, meters :param n_faces: number of quad faces to make the cylinder out of """ self.color = color self.cylinder_radius = cylinder_radius self.cylinder_height = cylinder_height self.cylinder_location = cylinder_location self.n_faces = n_faces self.stim_object = GlCylinder(cylinder_height=self.cylinder_height, cylinder_radius=self.cylinder_radius, cylinder_location=self.cylinder_location, color=self.color, n_faces=self.n_faces)
def configure(self, period=20, mean=0.5, contrast=1.0, offset=0.0, profile='sine', color=[1, 1, 1, 1], cylinder_radius=1, cylinder_height=10, theta=0, phi=0, angle=0.0): """ Grating texture painted on a cylinder :param period: spatial period, degrees :param mean: mean intensity of grating texture :param contrast: Weber contrast of grating texture :param offset: phase offset of grating texture, degrees :param profile: 'sine' or 'square'; spatial profile of grating texture :params color, cylinder_radius, cylinder_height, theta, phi, angle: see parent class *Any of these params except cylinder_radius, cylinder_height and profile can be passed as a trajectory dict to vary as a function of time """ super().configure(color=color, cylinder_radius=cylinder_radius, cylinder_height=cylinder_height, theta=theta, phi=phi, angle=angle) self.period = period self.mean = mean self.contrast = contrast self.offset = offset self.profile = profile self.period = period # Only renders part of the cylinder if the period is not a divisor of 360 n_cycles = np.floor(360 / self.period) self.cylinder_angular_extent = n_cycles * self.period self.stim_object = GlCylinder( cylinder_height=self.cylinder_height, cylinder_radius=self.cylinder_radius, cylinder_angular_extent=self.cylinder_angular_extent, color=[1, 1, 1, 1], texture=True).rotate(np.radians(self.theta), np.radians(self.phi), np.radians(self.angle)) if np.any([type(x) == dict for x in [mean, contrast, offset]]): pass else: self.updateTexture(self.mean, self.contrast, self.offset)
def configure(self, rate=10, period=20, mean=0.5, contrast=1.0, offset=0.0, profile='square', color=[1, 1, 1, 1], alpha_by_face=None, cylinder_radius=1, cylinder_height=10, theta=0, phi=0, angle=0): """ Subclass of CylindricalGrating that rotates the grating along the varying axis of the grating Note that the rotation effect is achieved by translating the texture on a semi-cylinder. This allows for arbitrary spatial periods to be achieved with no discontinuities in the grating :param rate: rotation rate, degrees/sec :other params: see CylindricalGrating, TexturedCylinder """ super().configure(period=period, mean=mean, contrast=contrast, offset=offset, profile=profile, color=color, cylinder_radius=cylinder_radius, cylinder_height=cylinder_height, theta=theta, phi=phi, angle=angle) self.rate = rate self.alpha_by_face = alpha_by_face if self.alpha_by_face is None: self.n_faces = 32 else: self.n_faces = len(self.alpha_by_face) self.updateTexture(mean=mean, contrast=contrast, offset=offset) self.stim_object_template = GlCylinder( cylinder_height=self.cylinder_height, cylinder_radius=self.cylinder_radius, cylinder_angular_extent=self.cylinder_angular_extent, color=self.color, alpha_by_face=self.alpha_by_face, n_faces=self.n_faces, texture=True)
def configure(self, color=[1, 1, 1, 1], cylinder_radius=5, cylinder_height=5, image_path=None): super().configure(color=color, cylinder_radius=cylinder_radius, cylinder_height=cylinder_height, theta=0, phi=0, angle=0.0) if image_path is None: load_image = False elif os.path.isfile(image_path): load_image = True else: load_image = False if load_image: with open(image_path, 'rb') as handle: s = handle.read() arr = array.array('H', s) arr.byteswap() img = np.array(arr, dtype='uint16').reshape(1024, 1536) img = np.uint8(255 * (img / np.max(img))) img = img[:, :1024] else: # use a dummy texture np.random.seed(0) face_colors = np.random.uniform(size=(128, 128)) img = (255 * face_colors).astype(np.uint8) self.texture_interpolation = 'LINEAR' self.texture_image = img self.stim_template = GlCylinder(cylinder_height=self.cylinder_height, cylinder_radius=self.cylinder_radius, cylinder_location=(0, 0, 0), color=self.color, texture=True).rotz(np.radians(180))
def configure(self, patch_width=4, patch_height=4, cylinder_vertical_extent=160, cylinder_angular_extent=360, color=[1, 1, 1, 1], cylinder_radius=1, theta=0, phi=0, angle=0.0): """ Periodic checkerboard pattern painted on the inside of a cylinder :param patch width: Azimuth extent (degrees) of each patch :param patch height: Elevation extent (degrees) of each patch :param cylinder_vertical_extent: Elevation extent of the entire cylinder (degrees) :param cylinder_angular_extent: Azimuth extent of the cylinder texture (degrees) :other params: see TexturedCylinder """ # Only renders part of the cylinder if the period is not a divisor of cylinder_angular_extent self.n_patches_width = int( np.floor(cylinder_angular_extent / patch_width)) self.cylinder_angular_extent = self.n_patches_width * patch_width # assuming fly is at (0,0,0), calculate cylinder height required to achieve (approx.) vert_extent (degrees) # actual vert. extent is based on floor-nearest integer number of patch heights assert cylinder_vertical_extent < 180 self.n_patches_height = int( np.floor(cylinder_vertical_extent / patch_height)) patch_height_m = cylinder_radius * np.tan( np.radians(patch_height)) # in meters cylinder_height = self.n_patches_height * patch_height_m super().configure(color=color, angle=angle, cylinder_radius=cylinder_radius, cylinder_height=cylinder_height) self.patch_width = patch_width self.patch_height = patch_height # Only renders part of the cylinder if the period is not a divisor of 360 self.n_patches_width = int(np.floor(360 / self.patch_width)) self.cylinder_angular_extent = self.n_patches_width * self.patch_width self.patch_height_m = self.cylinder_radius * np.tan( np.radians(self.patch_height)) # in meters self.n_patches_height = int( np.floor(self.cylinder_height / self.patch_height_m)) # create the texture face_colors = np.zeros((self.n_patches_height, self.n_patches_width)) face_colors[0::2, 0::2] = 1 face_colors[1::2, 1::2] = 1 # make and apply the texture img = (255 * face_colors).astype(np.uint8) self.texture_interpolation = 'NEAREST' self.texture_image = img self.stim_object = GlCylinder( cylinder_height=self.cylinder_height, cylinder_radius=self.cylinder_radius, cylinder_angular_extent=self.cylinder_angular_extent, color=self.color, texture=True).rotate(np.radians(self.theta), np.radians(self.phi), np.radians(self.angle))
def configure(self, patch_width=10, patch_height=10, cylinder_vertical_extent=160, cylinder_angular_extent=360, distribution_data=None, update_rate=60.0, start_seed=0, color=[1, 1, 1, 1], cylinder_radius=1, theta=0, phi=0, angle=0.0): """ Random square grid pattern painted on the inside of a cylinder :param patch width: Azimuth extent (degrees) of each patch :param patch height: Elevation extent (degrees) of each patch :param cylinder_vertical_extent: Elevation extent of the entire cylinder (degrees) :param cylinder_angular_extent: Azimuth extent of the cylinder texture (degrees) :param distribution_data: dict. containing name and args/kwargs for random distribution (see flystim.distribution) :param update_rate: Hz, update rate of bar intensity :param start_seed: seed with which to start rng at the beginning of the stimulus presentation :other params: see TexturedCylinder """ # Only renders part of the cylinder if the period is not a divisor of cylinder_angular_extent self.n_patches_width = int( np.floor(cylinder_angular_extent / patch_width)) self.cylinder_angular_extent = self.n_patches_width * patch_width # assuming fly is at (0,0,0), calculate cylinder height required to achieve (approx.) vert_extent (degrees) # actual vert. extent is based on floor-nearest integer number of patch heights assert cylinder_vertical_extent < 180 self.n_patches_height = int( np.floor(cylinder_vertical_extent / patch_height)) patch_height_m = cylinder_radius * np.tan( np.radians(patch_height)) # in meters cylinder_height = self.n_patches_height * patch_height_m super().configure(color=color, angle=angle, cylinder_radius=cylinder_radius, cylinder_height=cylinder_height, theta=theta, phi=phi) # get the noise distribution if distribution_data is None: distribution_data = { 'name': 'Uniform', 'args': [0, 1], 'kwargs': {} } self.noise_distribution = getattr( distribution, distribution_data['name'])(*distribution_data.get('args', []), **distribution_data.get('kwargs', {})) self.patch_width = patch_width self.patch_height = patch_height self.start_seed = start_seed self.update_rate = update_rate self.stim_object = GlCylinder( cylinder_height=self.cylinder_height, cylinder_radius=self.cylinder_radius, cylinder_angular_extent=self.cylinder_angular_extent, color=self.color, texture=True).rotate(np.radians(self.theta), np.radians(self.phi), np.radians(self.angle))
def configure(self, period=20, width=5, vert_extent=80, theta_offset=0, background=0.5, distribution_data=None, update_rate=60.0, start_seed=0, color=[1, 1, 1, 1], cylinder_radius=1, theta=0, phi=0, angle=0.0, cylinder_location=(0, 0, 0)): """ Periodic bars of randomized intensity painted on the inside of a cylinder :param period: spatial period (degrees) of bar locations :param width: width (degrees) of each bar :param vert_extent: vertical extent (degrees) of bars :param theta_offset: offset of periodic bar pattern (degrees) :param background: intensity (mono) of texture background, where no bars appear :param distribution_data: dict. containing name and args/kwargs for random distribution (see flystim.distribution) :param update_rate: Hz, update rate of bar intensity :param start_seed: seed with which to start rng at the beginning of the stimulus presentation :other params: see TexturedCylinder """ # assuming fly is at (0,0,0), calculate cylinder height required to achieve vert_extent (degrees) # tan(vert_extent/2) = (cylinder_height/2) / cylinder_radius assert vert_extent < 180 cylinder_height = 2 * cylinder_radius * np.tan( np.radians(vert_extent / 2)) super().configure(color=color, cylinder_radius=cylinder_radius, cylinder_height=cylinder_height, theta=theta, phi=phi, angle=angle) # get the noise distribution if distribution_data is None: distribution_data = { 'name': 'Uniform', 'args': [0, 1], 'kwargs': {} } self.noise_distribution = getattr( distribution, distribution_data['name'])(*distribution_data.get('args', []), **distribution_data.get('kwargs', {})) self.period = period self.width = width self.vert_extent = vert_extent self.theta_offset = theta_offset self.background = background self.update_rate = update_rate self.start_seed = start_seed self.cylinder_location = cylinder_location # Only renders part of the cylinder if the period is not a divisor of 360 self.n_bars = int(np.floor(360 / self.period)) self.cylinder_angular_extent = self.n_bars * self.period # degrees self.stim_object_template = GlCylinder( cylinder_height=self.cylinder_height, cylinder_radius=self.cylinder_radius, cylinder_angular_extent=self.cylinder_angular_extent, color=self.color, cylinder_location=self.cylinder_location, texture=True)