Esempio n. 1
0
    def _get_psychopy_pos(self, p, units=None):
        """Convert Tobii ADCS coordinates to PsychoPy coordinates.

        Args:
            p: Gaze position (x, y) in Tobii ADCS.
            units: The PsychoPy coordinate system to use.

        Returns:
            Gaze position in PsychoPy coordinate systems. For example: (0,0).
        """
        if units is None:
            units = self.win.units

        if units == "norm":
            return (2 * p[0] - 1, -2 * p[1] + 1)
        elif units == "height":
            return ((p[0] - 0.5) * (self.win.size[0] / self.win.size[1]),
                    -p[1] + 0.5)
        elif units in ["pix", "cm", "deg", "degFlat", "degFlatPos"]:
            p_pix = self._tobii2pix(p)
            if units == "pix":
                return p_pix
            elif units == "cm":
                return tuple(pix2cm(pos, self.win.monitor) for pos in p_pix)
            elif units == "deg":
                tuple(pix2deg(pos, self.win.monitor) for pos in p_pix)
            else:
                return tuple(
                    pix2deg(np.array(p_pix),
                            self.win.monitor,
                            correctFlat=True))
        else:
            raise ValueError("unit ({}) is not supported.".format(units))
Esempio n. 2
0
    def _get_psychopy_pos(self, p):
        """Convert Tobii ADCS coordinates to PsychoPy coordinates.

        Args:
            p: Gaze position (x, y) in Tobii ADCS.

        Returns:
            Gaze position in PsychoPy coordinate systems.
        """

        if self.win.units == 'norm':
            return (2 * p[0] - 1, -2 * p[1] + 1)
        elif self.win.units == 'height':
            return ((p[0] - 0.5) * (self.win.size[0] / self.win.size[1]),
                    -p[1] + 0.5)
        elif self.win.units in ['pix', 'cm', 'deg', 'degFlat', 'degFlatPos']:
            p_pix = ((p[0] - 0.5) * self.win.size[0],
                     (-p[1] + 0.5) * self.win.size[1])
            if self.win.units == 'pix':
                return p_pix
            elif self.win.units == 'cm':
                return (pix2cm(p_pix[0], self.win.monitor),
                        pix2cm(p_pix[1], self.win.monitor))
            elif self.win.units == 'deg':
                return (pix2deg(p_pix[0], self.win.monitor),
                        pix2deg(p_pix[1], self.win.monitor))
            else:
                return (pix2deg(
                    np.array(p_pix), self.win.monitor, correctFlat=True))
        else:
            raise ValueError('unit ({}) is not supported.'.format(
                self.win.units))
Esempio n. 3
0
 def _pix2windowUnits(self, win_handle, pos):
     win = self._iohub_server._psychopy_windows.get(win_handle)
     win_units = win['units']
     monitor = win['monitor']
     pos = np.asarray(pos)
     if win_units == 'pix':
         return pos
     elif win_units == 'norm':
         return pos * 2.0 / win['size']
     elif win_units == 'cm':
         if monitor:
             return pix2cm(pos, monitor['monitor'])
         else:
             # should raise exception?
             print2err(
                 "iohub Mouse error: Window is using units %s but has no Monitor definition."
                 % win_units)
     elif win_units == 'deg':
         if monitor:
             return pix2deg(pos, monitor['monitor'])
         else:
             # should raise exception?
             print2err(
                 "iohub Mouse error: Window is using units %s but has no Monitor definition."
                 % win_units)
     elif win_units == 'height':
         return pos / float(win['size'][1])
Esempio n. 4
0
    def size(self, value):
        """
        :ref:`x,y-pair <attrib-xy>`, :ref:`scalar <attrib-scalar>` or None (resets to default). Supports :ref:`operations <attrib-operations>`.
            Units are inherited from the stimulus.
            Sizes can be negative and can extend beyond the window.

            Example::

                stim.size = 0.8  # Set size to (xsize, ysize) = (0.8, 0.8), quadratic.
                print stim.size  # Outputs array([0.8, 0.8])
                stim.size += (0,5, -0.5)  # make wider and flatter. Is now (1.3, 0.3)

            Tip: if you can see the actual pixel range this corresponds to by
            looking at stim._sizeRendered
        """
        value = val2array(value)  # Check correct user input
        self._requestedSize = value  #to track whether we're just using a default
        # None --> set to default
        if value == None:
            """Set the size to default (e.g. to the size of the loaded image etc)"""
            #calculate new size
            if self._origSize is None:  #not an image from a file
                value = numpy.array([0.5, 0.5])  #this was PsychoPy's original default
            else:
                #we have an image - calculate the size in `units` that matches original pixel size
                if self.units == 'pix': value = numpy.array(self._origSize)
                elif self.units == 'deg': value = pix2deg(numpy.array(self._origSize, float), self.win.monitor)
                elif self.units == 'cm': value = pix2cm(numpy.array(self._origSize, float), self.win.monitor)
                elif self.units == 'norm': value = 2 * numpy.array(self._origSize, float) / self.win.size
                elif self.units == 'height': value = numpy.array(self._origSize, float) / self.win.size[1]
        self.__dict__['size'] = value
        self._calcSizeRendered()
        if hasattr(self, '_calcCyclesPerStim'):
            self._calcCyclesPerStim()
        self._needUpdate = True
Esempio n. 5
0
    def _pixToWindowUnits(self, pos):
        """Conversion from 'pix' units to window units.

        The mouse class stores mouse positions in 'pix' units. This function is
        used by getter and setter methods to convert position values to the
        units specified by the window.

        Parameters
        ----------
        pos : ArrayLike
            Position `(x, y)` in 'pix' coordinates to convert.

        Returns
        -------
        ndarray
            Position `(x, y)` in window units.

        """
        pos = np.asarray(pos, dtype=np.float32)

        if self.win is None:
            return pos

        if self.win.units == 'pix':
            if self.win.useRetina:
                pos /= 2.0
            return pos
        elif self.win.units == 'norm':
            return pos * 2.0 / self.win.size
        elif self.win.units == 'cm':
            return pix2cm(pos, self.win.monitor)
        elif self.win.units == 'deg':
            return pix2deg(pos, self.win.monitor)
        elif self.win.units == 'height':
            return pos / float(self.win.size[1])
Esempio n. 6
0
    def __init__(self, win, balloonID, color, maxPumps, gainpoints, initsize, gainsize, mon):
        self.win = win
        self.balloonID = balloonID
        self.color = color
        self.maxPumps = maxPumps
        self.points = gainsize
        self.initSize = initsize  # units 'deg'
        self.initSizeX = 3.5
        self.initSizeY = 5
        self.gainSize = gainsize  # units 'deg'
        self.mon = mon
        self.pump = visual.ImageStim(win, image="assets/pump.png", pos=[0, 0], size=[10, 10])
        self.explosionSound = sound.Sound(value='assets\explode.wav')
        self.explosionSound.setVolume(1.0)
        self.pumpSound = sound.Sound(value='assets\pump4.wav')
        self.pumpSound.setVolume(1.0)

        self.pump.pos = [0, pix2deg(-690 + (deg2pix(self.pump.size[1], mon) / 2), mon)]
        self.stimuli = visual.ImageStim(win, image="assets/bal_blue.png", pos=[0,pix2deg(-400+(deg2pix(self.initSizeY,mon)/2),mon)],size=[self.initSizeX,self.initSizeY])
Esempio n. 7
0
def gazeContingent():
    sample = eyeTracker.getNewestSample()  # get the eye position
    # make sure you choose the eye dominance
    if sample != None:
        if dictInfo['dominance'] == str('Right'):
            gazePos = sample.getRightEye().getGaze()
        elif dictInfo['dominance'] == str('Left'):
            gazePos = sample.getLeftEye().getGaze()
    else:
        gazePos = (0, 0)

    #translates eyelink coordinates to psychopy
    gazePosCorFix = [(gazePos[0] - (scnWidth / 2)),
                     -(gazePos[1] - (scnHeight / 2))]

    #converts the pixel coordinates from the eyelink to visual angle
    gazePosX = pix2deg(gazePosCorFix[0], monitors.Monitor('brittlab5'))
    gazePosY = pix2deg(gazePosCorFix[1], monitors.Monitor('brittlab5'))
    return (gazePosX, gazePosY)
Esempio n. 8
0
 def _pix2windowUnits(self, pos):
     if self.win.units == 'pix':
         return pos
     elif self.win.units == 'norm':
         return pos * 2.0 / self.win.size
     elif self.win.units == 'cm':
         return pix2cm(pos, self.win.monitor)
     elif self.win.units == 'deg':
         return pix2deg(pos, self.win.monitor)
     elif self.win.units == 'height':
         return pos / float(self.win.size[1])
Esempio n. 9
0
 def _pix2windowUnits(self, pos):
     if self.win.units == "pix":
         return pos
     elif self.win.units == "norm":
         return pos * 2.0 / self.win.size
     elif self.win.units == "cm":
         return pix2cm(pos, self.win.monitor)
     elif self.win.units == "deg":
         return pix2deg(pos, self.win.monitor)
     elif self.win.units == "height":
         return pos / float(self.win.size[1])
Esempio n. 10
0
 def _pix2windowUnits(self, pos):
     if self.win.units == 'pix':
         return pos
     elif self.win.units == 'norm':
         return pos * 2.0 / self.win.size
     elif self.win.units == 'cm':
         return pix2cm(pos, self.win.monitor)
     elif self.win.units == 'deg':
         return pix2deg(pos, self.win.monitor)
     elif self.win.units == 'height':
         return pos / float(self.win.size[1])
Esempio n. 11
0
    def convert_coords(self, x, y, to='eyelink'):
        """
        Converts from degrees visual angle units to EyeLink Pixel units.

        :param x: X coordinate in visual angle.
        :type x: float or int
        :param y: Y coordinate in viusal angle.
        :type y: float or int
        :param to: Direction of conversion. Options: 'eyelink' or 'psychopy'.
        :return: Two values in order x, y
        """
        if to == 'eyelink':
            # Convert coordinates to Eyelink space
            elx = deg2pix(x, self.win.monitor) + self.scenter[0]
            ely = -(deg2pix(y, self.win.monitor) - self.scenter[1])

        elif to == 'psychopy':
            elx = pix2deg(x - self.scenter[0], self.win.monitor)
            ely = pix2deg(-(y - self.scenter[1]), self.win.monitor)

        return [elx, ely]
Esempio n. 12
0
    def size(self, value):
        """The size (w,h) of the stimulus in the stimulus :ref:`units <units>`

        Value should be :ref:`x,y-pair <attrib-xy>`, :ref:`scalar <attrib-scalar>` (applies to both dimensions)
        or None (resets to default). :ref:`Operations <attrib-operations>` are supported.

        Sizes can be negative (causes a flip) and can extend beyond the window.

        Example::

            stim.size = 0.8  # Set size to (xsize, ysize) = (0.8, 0.8), quadratic.
            print stim.size  # Outputs array([0.8, 0.8])
            stim.size += (0,5, -0.5)  # make wider and flatter. Is now (1.3, 0.3)

        Tip: if you can see the actual pixel range this corresponds to by
        looking at `stim._sizeRendered`
        """
        value = val2array(value)  # Check correct user input
        self._requestedSize = value  #to track whether we're just using a default
        # None --> set to default
        if value == None:
            """Set the size to default (e.g. to the size of the loaded image etc)"""
            #calculate new size
            if self._origSize is None:  #not an image from a file
                value = numpy.array([0.5, 0.5
                                     ])  #this was PsychoPy's original default
            else:
                #we have an image - calculate the size in `units` that matches original pixel size
                if self.units == 'pix':
                    value = numpy.array(self._origSize)
                elif self.units in ['deg', 'degFlatPos', 'degFlat']:
                    #NB when no size has been set (assume to use orig size in pix) this should not
                    #be corrected for flat anyway, so degFlat==degFlatPos
                    value = pix2deg(numpy.array(self._origSize, float),
                                    self.win.monitor)
                elif self.units == 'norm':
                    value = 2 * numpy.array(self._origSize,
                                            float) / self.win.size
                elif self.units == 'height':
                    value = numpy.array(self._origSize,
                                        float) / self.win.size[1]
                elif self.units == 'cm':
                    value = pix2cm(numpy.array(self._origSize, float),
                                   self.win.monitor)
                else:
                    raise AttributeError, "Failed to create default size for ImageStim. Unsupported unit, %s" % (
                        repr(self.units))
        self.__dict__['size'] = value
        self._needVertexUpdate = True
        self._needUpdate = True
        if hasattr(self, '_calcCyclesPerStim'):
            self._calcCyclesPerStim()
Esempio n. 13
0
    def _get_psychopy_pos_from_trackbox(self, p, units=None):
        """Convert Tobii TBCS coordinates to PsychoPy coordinates.

            Called by show_status.

        Args:
            p: Gaze position (x, y) in Tobii TBCS.
            units: The PsychoPy coordinate system to use.

        Returns:
            Gaze position in PsychoPy coordinate systems.
        """

        if units is None:
            units = self.win.units

        if units == 'norm':
            return (-2 * p[0] + 1, -2 * p[1] + 1)
        elif units == 'height':
            return ((-p[0] + 0.5) * (self.win.size[0] / self.win.size[1]),
                    -p[1] + 0.5)
        elif units in ['pix', 'cm', 'deg', 'degFlat', 'degFlatPos']:
            p_pix = ((-2 * p[0] + 1) * self.win.size[0] / 2,
                     (-2 * p[1] + 1) * self.win.size[1] / 2)
            if units == 'pix':
                return p_pix
            elif units == 'cm':
                return (pix2cm(p_pix[0], self.win.monitor),
                        pix2cm(p_pix[1], self.win.monitor))
            elif units == 'deg':
                return (pix2deg(p_pix[0], self.win.monitor),
                        pix2deg(p_pix[1], self.win.monitor))
            else:
                return (pix2deg(
                    np.array(p_pix), self.win.monitor, correctFlat=True))
        else:
            raise ValueError('unit ({}) is not supported.'.format(
                self.win.units))
Esempio n. 14
0
    def size(self, value):
        """The size (w,h) of the stimulus in the stimulus :ref:`units <units>`

        Value should be :ref:`x,y-pair <attrib-xy>`, :ref:`scalar <attrib-scalar>` (applies to both dimensions)
        or None (resets to default). :ref:`Operations <attrib-operations>` are supported.

        Sizes can be negative (causing a mirror-image reversal) and can extend beyond the window.

        Example::

            stim.size = 0.8  # Set size to (xsize, ysize) = (0.8, 0.8), quadratic.
            print stim.size  # Outputs array([0.8, 0.8])
            stim.size += (0.5, -0.5)  # make wider and flatter. Is now (1.3, 0.3)

        Tip: if you can see the actual pixel range this corresponds to by
        looking at `stim._sizeRendered`
        """
        value = val2array(value)  # Check correct user input
        self._requestedSize = value  #to track whether we're just using a default
        # None --> set to default
        if value == None:
            """Set the size to default (e.g. to the size of the loaded image etc)"""
            #calculate new size
            if self._origSize is None:  #not an image from a file
                value = numpy.array([0.5, 0.5])  #this was PsychoPy's original default
            else:
                #we have an image - calculate the size in `units` that matches original pixel size
                if self.units == 'pix':
                    value = numpy.array(self._origSize)
                elif self.units in ['deg', 'degFlatPos', 'degFlat']:
                    #NB when no size has been set (assume to use orig size in pix) this should not
                    #be corrected for flat anyway, so degFlat==degFlatPos
                    value = pix2deg(numpy.array(self._origSize, float), self.win.monitor)
                elif self.units == 'norm':
                    value = 2 * numpy.array(self._origSize, float) / self.win.size
                elif self.units == 'height':
                    value = numpy.array(self._origSize, float) / self.win.size[1]
                elif self.units == 'cm':
                    value = pix2cm(numpy.array(self._origSize, float), self.win.monitor)
                else:
                    raise AttributeError, "Failed to create default size for ImageStim. Unsupported unit, %s" %(repr(self.units))
        self.__dict__['size'] = value
        self._needVertexUpdate=True
        self._needUpdate = True
        if hasattr(self, '_calcCyclesPerStim'):
            self._calcCyclesPerStim()
Esempio n. 15
0
def demo_med(window, monitor, flexion, index):  #0=control, 1=experimental
    speed = pix2deg(
        18, monitor)  # this line is for modifying the speed of the balls
    rotation = 35  #degrees
    rot_idx = index
    radius = 2.3
    # flexion = 1 means the ball will rotate when changing direction
    flexion_point = [[0, -pix2deg(.5 * window.size[1], monitor) + .5 * radius],
                     [
                         -pix2deg(.5 * window.size[0], monitor) + .5 * radius,
                         -pix2deg(.5 * window.size[1], monitor) + .5 * radius
                     ]][flexion]
    path_change = [
        -pix2deg(.5 * window.size[0], monitor) + .5 * radius,
        -pix2deg(.5 * window.size[1], monitor) + .5 * radius
    ]
    fixation = visual.Circle(
        window,
        pos=(-pix2deg(.5 * window.size[0], monitor) + .5 * radius,
             pix2deg(.5 * window.size[1], monitor) - .5 * radius),
        lineColor='black',
        fillColor='black',
        radius=.1)
    gabor_coords = make_centers(6, 2.3)
    gabors = [
        visual.ImageStim(
            win=window,
            image='gab.png',
            size=1,
            ori=randint(0, 179),
            pos=(c[0] - pix2deg(.5 * window.size[0], monitor) + .5 * radius,
                 c[1] + pix2deg(.5 * window.size[1], monitor) - .5 * radius),
            units='deg') for c in gabor_coords
    ]
    [gabor.draw() for gabor in gabors]
    fixation.draw()
    window.flip()
    rotated = False
    path_end = False
    path_changed = False
    v = [0, -1]
    while not path_end:
        if fixation.pos[1] <= path_change[1] and not path_changed:
            v = [1, 0]
            path_changed = True
        if ((fixation.pos[0] >= flexion_point[0] and not flexion) or
            (fixation.pos[1] <= flexion_point[1] and flexion)) and not rotated:
            gabors[rot_idx].ori += choice([-1, 1]) * rotation
            rotated = True
        fixation.pos = (fixation.pos[0] + v[0] * speed,
                        fixation.pos[1] + v[1] * speed)
        [
            gabor.setPos(
                (gabor.pos[0] + v[0] * speed, gabor.pos[1] + v[1] * speed))
            for gabor in gabors
        ]
        [gabor.draw() for gabor in gabors]
        fixation.draw()
        window.flip()
        window.getMovieFrame()
        path_end = fixation.pos[0] >= pix2deg(.5 * window.size[0],
                                              monitor) - .5 * radius
    window.saveMovieFrames('medium' + str(index) + '.mp4', fps=60)
Esempio n. 16
0
 def pix2degcoord(self, x, y, display_index=None):
     if display_index == self.getIndex():
         ppx, ppy = display2psychopyPix(x, y)
         #                    print2err('pix2degcoord: ',(x,y),( ppx,ppy),( pix2deg(ppx,self._psychopy_monitor),pix2deg(ppy,self._psychopy_monitor)))
         return pix2deg(ppx, self._psychopy_monitor), pix2deg(ppy, self._psychopy_monitor)
     return x, y
repeats = 2

on_time = 2
off_time = 2

ori_time = on_time + off_time
rep_time = ori_time * len(orientations)

print('Total stimulus time: {}s'.format(rep_time * repeats))
# Getting window information
my_mon = monitors.Monitor('leftMonitor')
mywin = visual.Window([800, 600],
                      fullscr=False,
                      monitor=my_mon,
                      units="degFlat")
screen_sz = (mt.pix2deg(800, monitor=my_mon), mt.pix2deg(600, monitor=my_mon))
frame_rate = mywin.getActualFrameRate()

# Converting to frames
on_frames = int(on_time * frame_rate)
off_frames = int(off_time * frame_rate)

# create some stimuli
grating = visual.GratingStim(win=mywin,
                             tex='sin',
                             size=[2 * x for x in screen_sz],
                             sf=spatial_frequency)  # full field

# draw the stimuli and update the window
session_timer = core.Clock()
start = session_timer.getTime()
Esempio n. 18
0
def prf_stim(dicParam):
    """
    Present stimuli for population receptive field mapping.

    If in logging mode, this script creates a stimulus log of the stimuli used
    for the pRF mapping that can be used for the pRF finding analysis of the
    pyprf library. The stimuli are saved as png files, where each png
    represents the status of visual stimulation for one TR (the png files
    contain modified screenshots of the visual stimulus, and can be directly be
    loaded into the py_pRF_mapping pipepline.
    """
    # *****************************************************************************
    # *** Experimental parameters (from dictionary)

    # Path of design matrix (npz):
    strPthNpz = dicParam['Path of design matrix (npz)']

    # Output path & file name of log file:
    strPthLog = dicParam['Output path (log files)']

    # Target duration [s]:
    varTrgtDur = float(dicParam['Target duration [s]'])

    # Logging mode (logging mode is for creating files for analysis, not to be
    # used during an experiment).
    lgcLogMde = dicParam['Logging mode']

    # On windows, the return value may be a string, not a bool. We need to
    # correct for this.
    if not (isinstance(lgcLogMde, bool)):
        if lgcLogMde == 'True':
            lgcLogMde = True
        else:
            lgcLogMde = False

    # Directory where to save stimulus log (frames) for analysis if in logging
    # mode.
    strPthFrm = dicParam['Output path stimulus log (frames)']

    # Frequency of stimulus bar in Hz:
    varGrtFrq = float(dicParam['Temporal frequency [Hz]'])

    # Sptial frequency of stimulus (cycles along width of bar stimulus):
    varBarSf = float(dicParam['Spatial frequency [cyc per bar]'])

    # Distance between observer and monitor [cm]:
    varMonDist = float(dicParam['Distance between observer and monitor [cm]'])

    # Width of monitor [cm]:
    varMonWdth = float(dicParam['Width of monitor [cm]'])

    # Width of monitor [pixels]:
    varPixX = int(dicParam['Width of monitor [pixels]'])

    # Height of monitor [pixels]:
    varPixY = int(dicParam['Height of monitor [pixels]'])

    # Background colour:
    varBckgrd = float(dicParam['Background colour [-1 to 1]'])

    # Show fixation grid?
    lgcGrd = dicParam['Show fixation grid?']

    # On windows, the return value may be a string, not a bool. We need to
    # correct for this.
    if not (isinstance(lgcGrd, bool)):
        if lgcGrd == 'True':
            lgcGrd = True
        else:
            lgcGrd = False

    # *************************************************************************
    # *** Retrieve design matrix

    # Load stimulus parameters from npz file.
    objNpz = np.load(strPthNpz)

    # Get design matrix (for bar positions and orientation):
    aryDsg = objNpz['aryDsg']

    # Number of volumes:
    varNumVol = aryDsg.shape[0]

    # Vector with times of target events:
    vecTrgt = objNpz['vecTrgt']

    # Number of target events:
    varNumTrgt = vecTrgt.shape[0]

    # Full screen mode? If no, bar stimuli are restricted to a central square.
    # If yes, bars appear on the entire screen. This parameter is set when
    # creating the design matrix.
    lgcFull = bool(objNpz['lgcFull'])

    # Number of bar positions on x-axis:
    varNumPosX = int(objNpz['varNumPosX'])

    # Number of bar positions on y-axis:
    varNumPosY = int(objNpz['varNumPosY'])

    # If in full screen mode, we need to make sure that the bar position along
    # the shorted axis (x-axis) is adjusted, so that the bar is always within
    # the screen area (and not half cut off).
    if lgcFull:
        # Ratio of bar positions (from design matrix), e.g. 18/11:
        varRatioPos = float(varNumPosX) / float(varNumPosY)
        # Ratio of screen widht/height in pixels (e.g. 1920/1200):
        varRatioPix = float(varPixX) / float(varPixY)
        # Scaling factor for bar positions along x-axis:
        varSclPosX = varRatioPos / varRatioPix

    # Adjustments for logging mode:
    if lgcLogMde:

        # Conditional imports:
        from PIL import Image
        from scipy.stats import mode

        # If in logging mode, only present stimuli very briefly. Note: If
        # 'varTr' is set too low in logging mode, frames are dropped and the
        # stimuli do not get logged properly.
        varTr = 0.2

        # In log mode, don't show grid.
        lgcGrd = False

    # Otherwise, use actual volume TR:
    else:
        # Volume TR:
        varTr = float(objNpz['varTr'])

    # *************************************************************************
    # *** Logging

    # Set clock:
    objClck = core.Clock()

    # Set clock for logging:
    logging.setDefaultClock(objClck)

    # Create a log file and set logging verbosity:
    fleLog = logging.LogFile(strPthLog, level=logging.DATA)

    # Log stimulus parameters:
    fleLog.write('Log file path: ' + strPthLog + '\n')
    fleLog.write('Design matrix: ' + strPthNpz + '\n')
    fleLog.write('Full screen: ' + str(lgcFull) + '\n')
    fleLog.write('Volume TR [s] (from design matrix): ' + str(varTr) + '\n')
    fleLog.write('Frequency of stimulus bar in Hz: ' + str(varGrtFrq) + '\n')
    fleLog.write('Sptial frequency of stimulus (cycles along width of ' +
                 'bar stimulus): ' + str(varBarSf) + '\n')
    fleLog.write('Distance between observer and monitor [cm]: ' +
                 str(varMonDist) + '\n')
    fleLog.write('Width of monitor [cm]: ' + str(varMonWdth) + '\n')
    fleLog.write('Width of monitor [pixels]: ' + str(varPixX) + '\n')
    fleLog.write('Height of monitor [pixels]: ' + str(varPixY) + '\n')
    fleLog.write('Background colour [-1 to 1]: ' + str(varBckgrd) + '\n')
    fleLog.write('Target duration [s]: ' + str(varTrgtDur) + '\n')
    fleLog.write('Logging mode: ' + str(lgcLogMde) + '\n')

    # Set console logging verbosity:
    logging.console.setLevel(logging.WARNING)

    # *************************************************************************
    # *** Prepare behavioural response logging

    # Switch target (show target or not?):
    varSwtTrgt = 0

    # Control the logging of participant responses:
    varSwtRspLog = 0

    # The key that the participant has to press after a target event:
    strTrgtKey = '1'

    # Counter for correct/incorrect responses:
    varCntHit = 0  # Counter for hits
    varCntMis = 0  # Counter for misses

    # Time (in seconds) that participants have to respond to a target event in
    # order for the event to be logged as a hit:
    varHitTme = 2.0

    # *************************************************************************
    # *** Setup

    # Create monitor object:
    objMon = monitors.Monitor('Screen_7T_NOVA_32_Channel_Coil',
                              width=varMonWdth,
                              distance=varMonDist)

    # Set size of monitor:
    objMon.setSizePix([varPixX, varPixY])

    # Set screen:
    objWin = visual.Window(
        size=(varPixX, varPixY),
        screen=0,
        winType='pyglet',  # winType : None, 'pyglet', 'pygame'
        allowGUI=False,
        allowStencil=True,
        fullscr=True,
        monitor=objMon,
        color=varBckgrd,
        colorSpace='rgb',
        units='deg',
        blendMode='avg')

    # *************************************************************************
    # *** Spatial stimulus properties

    # The area that will be covered by the bar stimulus depends on whether
    # presenting in full screen mode or not. If in full screen mode, the
    # entire width of the screen will be covered. If not, a central square
    # with a side length equal to the screen height will be covered.
    if lgcFull:
        varPixCov = varPixX
    else:
        varPixCov = varPixY

    # Convert size in pixels to size in degrees (given the monitor settings):
    # varDegCover = pix2deg(varPixCov, objMon)

    # Numberic codes used for bar positions:
    vecPosCode = np.unique(aryDsg[:, 1])

    # Number of bar positions:
    varNumPos = vecPosCode.shape[0]

    # The thickness of the bar stimulus depends on the size of the screen to
    # be covered, and on the number of positions at which to present the bar.
    # Bar thickness in pixels:
    varThckPix = float(varPixCov) / float(varNumPos)

    # Bar thickness in degree:
    varThckDgr = np.around(pix2deg(varThckPix, objMon), decimals=5)

    # Write stimulus parameters to log file.
    fleLog.write('* * * Stimulus properties in degrees of visual angle ' +
                 '* * * \n')
    fleLog.write('Width of bar stimulus [deg]: ' + str(varThckDgr) + '\n')

    # Spatial frequency of bar stimulus is defined (in user input) as cycles
    # along width of the bar  stimulus. We need to convert this to cycles per
    # pixel (for the stimulus creation) and to cycles per degree (for
    # reference, written to log file).

    # Spatial frequency in cycles per pixel:
    varBarSfPix = float(varBarSf) / varThckPix
    tplBarSfPix = (varBarSfPix, varBarSfPix)

    # Spatial frequency in cycles per degree of visual angle (for reference
    # only):
    varBarSfDeg = np.around((float(varBarSf) / varThckDgr), decimals=5)

    # Write stimulus parameters to log file.
    fleLog.write('Spatial frequency of bar stimulus [cyc/deg]: ' +
                 str(varBarSfDeg) + '\n')
    fleLog.write('* * * \n')

    # Bar stimulus size (length & thickness), in pixels.
    tplBarSzePix = (varPixX, int(varThckPix))

    # Offset of the bar stimuli. The bar stimuli should cover the screen area,
    # without extending beyond the screen. Because their position refers to
    # the centre of the bar, we need to limit the extend of positions at the
    # edge of the screen by an offset, Offset in pixels:
    varOffsetPix = varThckPix * 0.5

    # Maximum bar position in pixels, with respect to origin at centre of
    # screen:
    varPosMaxPix = (float(varPixCov) * 0.5) - float(varOffsetPix)

    # Array of possible bar positions (displacement relative to origin at
    # centre of the screen) in pixels:
    vecPosPix = np.linspace(-varPosMaxPix,
                            varPosMaxPix,
                            varNumPos,
                            endpoint=True)

    # Replace numeric position codes with pixel position values:
    for idxPos, varPos in enumerate(vecPosCode):

        # Replace current position code, if this is not a rest block:
        vecLgc = np.multiply((aryDsg[:, 1] == varPos), (aryDsg[:, 0] != 0.0))

        # Place pixel position value in design matrix:
        aryDsg[vecLgc, 1] = vecPosPix[idxPos]

    # Psychopy orientation convention: "Orientation convention is like a clock:
    # 0 is vertical, and positive values rotate clockwise." Actually, 0 is the
    # positive x-axis. Orientations are coded as follows: horizontal = 0.0,
    # vertical = 90.0, lower left to upper right = 45.0, upper left to lower
    # right = 135.0. We need to convert psychopy orientation & direction
    # convention into x and y coordinates.
    lstPos = [None] * varNumVol
    for idxVol in range(varNumVol):

        # Get angle and radius of current volume:
        varRad = float(aryDsg[idxVol, 1])
        varAngle = float(aryDsg[idxVol, 2])

        # Horizontal:
        if varAngle == 0.0:
            varTmpX = 0.0

            # If in full screen mode, make sure that the bar is not partially
            # outside of the screen area.
            if lgcFull:
                # Scale y-position.
                varTmpY = varRad * varSclPosX
            else:
                # Not in full screen mode, don't scale.
                varTmpY = varRad

        # Vertical:
        elif varAngle == 90.0:
            varTmpX = varRad
            varTmpY = 0.0

        # Lower left to upper right:
        elif varAngle == 45.0:
            if varRad < 0.0:
                varTmpX = -np.sqrt(np.add(np.square(varRad),
                                          np.square(varRad)))
            elif 0.0 < varRad:
                varTmpX = np.sqrt(np.add(np.square(varRad), np.square(varRad)))
            else:
                varTmpX = 0.0
            varTmpY = 0.0

        # Upper left to lower right:
        elif varAngle == 135.0:
            if varRad < 0.0:
                varTmpX = -np.sqrt(np.add(np.square(varRad),
                                          np.square(varRad)))
            elif 0.0 < varRad:
                varTmpX = np.sqrt(np.add(np.square(varRad), np.square(varRad)))
            else:
                varTmpX = 0.0
            varTmpY = 0.0

        # Position is coded as a tuple:
        lstPos[idxVol] = (varTmpX, varTmpY)

    # *************************************************************************
    # *** Stimuli

    # Bar stimulus:
    objBar = visual.GratingStim(objWin,
                                contrast=1.0,
                                pos=(0.0, 0.0),
                                tex='sqrXsqr',
                                color=[1.0, 1.0, 1.0],
                                colorSpace='rgb',
                                opacity=1.0,
                                size=tplBarSzePix,
                                sf=tplBarSfPix,
                                ori=0.0,
                                autoLog=False,
                                interpolate=False,
                                units='pix')

    # Colour of fixation dot:
    lstClrFix = [-0.69, 0.83, 0.63]
    # lstClrFix = [0.04, 0.95, -1.0]

    # Colour of fixation dot when it becomes a target:
    lstClrTrgt = [0.95, 0.04, -1.0]

    # Fixation dot:
    objFix = visual.Circle(objWin,
                           units='deg',
                           pos=(0.0, 0.0),
                           radius=0.05,
                           edges=24,
                           fillColor=lstClrFix,
                           fillColorSpace='rgb',
                           lineColor=lstClrFix,
                           lineColorSpace='rgb',
                           lineWidth=0.0,
                           interpolate=False,
                           autoLog=False)

    # Fication dot surround:
    objFixSrd = visual.Circle(objWin,
                              units='deg',
                              pos=(0.0, 0.0),
                              radius=0.09,
                              edges=24,
                              fillColor=lstClrTrgt,
                              fillColorSpace='rgb',
                              lineColor=lstClrTrgt,
                              lineColorSpace='rgb',
                              lineWidth=0.0,
                              interpolate=False,
                              autoLog=False)

    if lgcGrd:

        # Number of grid circles:
        varNumCrcl = 3

        # Radi at which to present grid circles:
        vecGrdCrclRad = np.linspace((0.25 * float(varPixY)),
                                    (0.75 * float(varPixY)),
                                    num=varNumCrcl)

        # In practice 'radius' seems to refer to refer to the diameter of the
        # circle.

        # Fixation grid circles:
        lstGrdCrcl = [None] * varNumCrcl
        for idxCrcl, varRad in enumerate(vecGrdCrclRad):
            lstGrdCrcl[idxCrcl] = visual.Circle(win=objWin,
                                                pos=(0.0, 0.0),
                                                radius=varRad,
                                                edges=128,
                                                lineWidth=1.0,
                                                lineColor=[-0.8, -0.8, -0.8],
                                                lineColorSpace='rgb',
                                                fillColor=None,
                                                fillColorSpace='rgb',
                                                opacity=1.0,
                                                autoLog=False,
                                                interpolate=True,
                                                units='pix')

        # Fixation grid line:
        lstGrdLne = [None] * 4
        for idxLne, varOri in enumerate([0.0, 45.0, 90.0, 135.0]):
            lstGrdLne[idxLne] = visual.Line(win=objWin,
                                            ori=varOri,
                                            start=(int(-varPixY), 0),
                                            end=(int(varPixY), 0),
                                            pos=(0.0, 0.0),
                                            lineWidth=1.0,
                                            lineColor=[-0.8, -0.8, -0.8],
                                            lineColorSpace='rgb',
                                            fillColor=None,
                                            fillColorSpace='rgb',
                                            opacity=1.0,
                                            autoLog=False,
                                            interpolate=True,
                                            units='pix')

    # *************************************************************************
    # *** Aperture

    # The area that will be covered by the bar stimulus depends on whether
    # presenting in full screen mode or not. If in full screen mode, the entire
    # width of the screen will be covered. If not, a central square with a side
    # length equal to the screen height will be covered.

    if not (lgcFull):

        # Aperture side length in degree. For some reason, the aperture does
        # not seem to accept pixel units.
        varDegCov = pix2deg(float(varPixCov), objMon)

        # Aperture for covering left and right side of screen if not presenting
        # in full screen mode.
        objAprtr = visual.Aperture(objWin,
                                   size=varDegCov,
                                   pos=(0, 0),
                                   shape='square',
                                   inverted=False,
                                   units='deg')

        objAprtr.enabled = True

    # *************************************************************************
    # *** Logging mode preparations

    if lgcLogMde:

        print('Logging mode')

        # Calculate area to crop in x-dimension, at left and right (zero is
        # full extend of screeen width is used):
        if lgcFull:
            varCrpX = 0
        else:
            varCrpX = int(np.around((float(varPixX) - float(varPixY)) * 0.5))

        print(('Stimulus log will be cropped by ' + str(varCrpX) +
               ' in x-direction (screen width).'))

        # Temporary array for screenshots, at full screen size and containing
        # RGB values (needed to obtain buffer content from psychopy):
        aryBuff = np.zeros((varPixY, varPixX, 3), dtype=np.int8)

        # It is not necessary to sample every pixel; only every second pixel is
        # sampled. Number of pixel to be sampled along x and y direction:
        varHalfPixX = int(np.around(varPixX * 0.5))
        varHalfPixY = int(np.around(varPixY * 0.5))

        # Prepare array for screenshots. One value per pixel per volume; since
        # the stimuli are greyscale we discard 2nd and 3rd RGB dimension. Also,
        # there is no need to represent the entire screen, just the part of the
        # screen that is actually stimulated (if not in full screen mode, this
        # is a square at the centre of the screen, flanked by unstimulated
        # areas on the left and right side).
        if lgcFull:
            aryFrames = np.zeros((varHalfPixY, varHalfPixX, varNumVol),
                                 dtype=np.uint8)
        else:
            aryFrames = np.zeros((varHalfPixY, varHalfPixY, varNumVol),
                                 dtype=np.uint8)

        # Counter for screenshots:
        idxFrame = 0

    # *************************************************************************
    # *** Timing & switches

    # Target counter:
    varCntTrgt = 0

    # Time of the first target event:
    varTmeTrgt = vecTrgt[varCntTrgt]

    # Switch for grating polarity flicker:
    varSwtGrt = 0

    # The input parameter 'varGrtFrq' gives the grating flicker frequency in
    # Hz. We need to convert to second:
    varGrtDur = 1.0 / float(varGrtFrq)

    # *************************************************************************
    # *** Presentation

    # Hide the mouse cursor:
    event.Mouse(visible=False)

    if not (lgcLogMde):

        if lgcGrd:

            # Draw fixation grid circles:
            for objGrdCrcl in lstGrdCrcl:
                objGrdCrcl.draw(win=objWin)

            # Draw fixation grid lines:
            for objGrdLne in lstGrdLne:
                objGrdLne.draw(win=objWin)

        # Draw fixation dot & surround:
        objFixSrd.draw(win=objWin)
        objFix.draw(win=objWin)

        objWin.flip()

        # Wait for scanner trigger pulse & set clock after receiving trigger
        # pulse (scanner trigger pulse is received as button press ('5')):
        strTrgr = ['0']
        while strTrgr[0][0] != '5':
            # Check for keypress:
            lstTmp = event.getKeys(keyList=['5'], timeStamped=False)
            # Whether the list has the correct length (if nothing has happened,
            # lstTmp # will have length zero):
            if len(lstTmp) == 1:
                strTrgr = lstTmp[0][0]

    # Trigger pulse received, reset clock:
    objClck.reset(newT=0.0)

    # Main timer which represents the starting point of the experiment:
    varTme01 = objClck.getTime()

    # Time that is updated continuously to track time:
    varTme02 = objClck.getTime()

    # Timer used to control the logging of stimulus events:
    varTme03 = objClck.getTime()

    # Timer for grating stimulus polarity flicker:
    varTme04 = objClck.getTime()
    varTme05 = objClck.getTime()

    # Start of the experiment:
    for idxVol in range(varNumVol):

        # Show a grating during this volume?
        lgcOn = (aryDsg[idxVol, 0] == 1.0)

        # Set grating properties for current volume:
        if lgcOn:

            # Get stimulus properties from design matrix:
            varTmpPos = lstPos[idxVol]
            varTmpOri = aryDsg[idxVol, 2]
            varTmpCon = aryDsg[idxVol, 3]

            # Set bar properties:
            objBar.setPos(varTmpPos)
            objBar.setOri(varTmpOri)
            objBar.setColor((varTmpCon, varTmpCon, varTmpCon))

        # Still on the same volume?
        while varTme02 < (varTme01 + (float(idxVol + 1) * varTr)):

            # *****************************************************************
            # *** Draw stimuli

            # Draw fixation grid?
            if lgcGrd:

                # Draw fixation grid circles:
                for objGrdCrcl in lstGrdCrcl:
                    objGrdCrcl.draw(win=objWin)

                # Draw fixation grid lines:
                for objGrdLne in lstGrdLne:
                    objGrdLne.draw(win=objWin)

            # If a grating is shown, which orientation, position, and contrast?
            if lgcOn:

                # Draw grating.
                objBar.draw(win=objWin)

            # Don't draw fixation point in logging mode:
            if not (lgcLogMde):

                # Draw fixation dot & surround:
                objFixSrd.draw(win=objWin)
                objFix.draw(win=objWin)

            # Flip drawn objects to screen:
            objWin.flip()

            # Update current time:
            varTme02 = objClck.getTime()

            # Update current time:
            varTme05 = objClck.getTime()

            # *****************************************************************
            # *** Target control

            # Time for target?
            if ((varTmeTrgt <= varTme02) and (varTme02 <=
                                              (varTmeTrgt + varTrgtDur))):

                # Was the target off on the previous frame?
                if varSwtTrgt == 0:

                    # Switch the target on by changing the fixation dot colour.
                    objFix.fillColor = lstClrTrgt

                    # Log target event:
                    strTmp = ('TARGET scheduled for: ' + str(varTmeTrgt))
                    logging.data(strTmp)

                    # Once after target onset we set varSwtRspLog to one so
                    # that the participant's respond can be logged:
                    varSwtRspLog = 1

                    # Likewise, just after target onset we set the timer for
                    # response logging to the current time so that the response
                    # will only be counted as a hit in a specified time
                    # interval after target onset:
                    varTme03 = objClck.getTime()

                    # Switch the target switch.
                    varSwtTrgt = 1

            else:

                # No time for target.

                # Was the target just on?
                if varSwtTrgt == 1:

                    # Switch the target off (by changing fixation dot colour
                    # back to normal).
                    objFix.fillColor = lstClrFix

                    # Switch the target switch.
                    varSwtTrgt = 0

                    # Only increase the target  counter if the last target has
                    # not been reached yet:
                    if (varCntTrgt + 1) < varNumTrgt:

                        # Increase the target counter:
                        varCntTrgt = varCntTrgt + 1

                        # Time of next target event:
                        varTmeTrgt = vecTrgt[varCntTrgt]

            # Has the participant's response not been reported yet, and is it
            # still within the time window?
            if (varSwtRspLog == 1) and (varTme02 <= (varTme03 + varHitTme)):

                # Check for and log participant's response:
                lstRsps = event.getKeys(keyList=[strTrgtKey],
                                        timeStamped=False)

                # Check whether the list has the correct length:
                if len(lstRsps) == 1:

                    # Does the list contain the response key?
                    if lstRsps[0] == strTrgtKey:

                        # Log hit:
                        logging.data('Hit')

                        # Count hit:
                        varCntHit += 1

                        # After logging the hit, we have to switch off the
                        # response logging, so that the same hit is not logged
                        # over and over again:
                        varSwtRspLog = 0

            elif (varSwtRspLog == 1) and (varTme02 > (varTme03 + varHitTme)):

                # Log miss:
                logging.data('Miss')

                # Count miss:
                varCntMis += 1

                # If the subject does not respond to the target within time, we
                # log this as a miss and set varSwtRspLog to zero (so that the
                # response won't be logged as a hit anymore afterwards):
                varSwtRspLog = 0

            # *****************************************************************
            # *** Grating control

            # If a grating is shown, which orientation, position, and contrast?
            if lgcOn:

                # Change grating polarity:
                if (varTme04 + varGrtDur) <= varTme05:

                    if varSwtGrt == 0:
                        varSwtGrt = 1
                        objBar.contrast = 1.0

                    else:
                        varSwtGrt = 0
                        objBar.contrast = -1.0

                    # Remember time at which grating polarity was switched:
                    varTme04 = objClck.getTime()

            # Update current time:
            # varTme02 = objClck.getTime()

            # Update current time:
            # varTme05 = objClck.getTime()

        if lgcLogMde:

            # Temporary array for single frame (3 values per pixel - RGB):
            aryBuff[:, :, :] = objWin.getMovieFrame(buffer='front')

            # Clear frames (otherwise stack of frames will pile up in memory):
            objWin.movieFrames = []

            # We only save one value per pixel per volume (because the stimuli
            # are greyscale we discard 2nd and 3rd RGB dimension):
            aryRgb = aryBuff[:, :, 0]

            # Sample the relevant part of the screen (all the screen if in
            # full screen mode, central square otherwise).0
            aryRgb = aryRgb[:, varCrpX:(varPixX - varCrpX)]

            # Only sample every second pixel:
            aryRgb = aryRgb[::2, ::2]

            # On first frame, get pixel value of background intensity:
            if idxVol == 0:
                varBck = mode(aryRgb, axis=None)[0]

            # The stimulus log is supposed to contain information about where
            # the stimulus was presented on each volume, and at which contrast.
            # The pattern inside the stimulus (chequerboard) is not of
            # interest. Therefore, we create a logical array (True = stimulus
            # was present on this pixel).
            aryRgb = np.not_equal(aryRgb, varBck).astype(np.int8)

            # Contrast value on current volume:
            varTmpMax = int(np.around(255.0 * aryDsg[idxVol, 3]))

            # Rescale to range 0 to 255:
            aryRgb = np.multiply(aryRgb, varTmpMax).astype(np.uint8)

            # Hard copy:
            aryFrames[:, :, idxFrame] = np.copy(aryRgb)

            idxFrame = idxFrame + 1

        # Check whether exit keys have been pressed:
        if func_exit() == 1:
            break

    # *************************************************************************
    # *** Feedback

    logging.data('------End of the experiment.------')

    # Performance feedback only if there were any targets:
    if 0.0 < float(varCntHit + varCntMis):

        # Ratio of hits:
        varHitRatio = float(varCntHit) / float(varCntHit + varCntMis)

        # Present participant with feedback on her target detection
        # performance:
        if 0.99 < varHitRatio:
            # Perfect performance:
            strFeedback = ('You have detected ' + str(varCntHit) +
                           ' targets out of ' + str(varCntHit + varCntMis) +
                           '\n' + 'Keep up the good work :)')
        elif 0.9 < varHitRatio:
            # OKish performance:
            strFeedback = ('You have detected ' + str(varCntHit) +
                           ' targets out of ' + str(varCntHit + varCntMis) +
                           '\n' + 'There is still room for improvement ;)')
        else:
            # Low performance:
            strFeedback = ('You have detected ' + str(varCntHit) +
                           ' targets out of ' + str(varCntHit + varCntMis) +
                           '\n' + 'Please try to focus more :(')

        # Create text object:
        objTxtTmr = visual.TextStim(objWin,
                                    text=strFeedback,
                                    font="Courier New",
                                    pos=(0.0, 0.0),
                                    color=(1.0, 1.0, 1.0),
                                    colorSpace='rgb',
                                    opacity=1.0,
                                    contrast=1.0,
                                    ori=0.0,
                                    height=0.5,
                                    antialias=True,
                                    alignHoriz='center',
                                    alignVert='center',
                                    flipHoriz=False,
                                    flipVert=False,
                                    autoLog=False)

        if not (lgcLogMde):

            # Show feedback text:
            varTme04 = objClck.getTime()
            while varTme02 < (varTme04 + 3.0):
                objTxtTmr.draw()
                objWin.flip()
                varTme02 = objClck.getTime()

        # Log total number of hits and misses:
        logging.data(('Number of hits: ' + str(varCntHit)))
        logging.data(('Number of misses: ' + str(varCntMis)))
        logging.data(('Percentage of hits: ' +
                      str(np.around((varHitRatio * 100.0), decimals=1))))

    # *************************************************************************
    # *** End of the experiment

    # Make the mouse cursor visible again:
    event.Mouse(visible=True)

    # Close window:
    objWin.close()

    # *************************************************************************
    # *** Logging mode

    # Save screenshots (logging mode):
    if lgcLogMde:

        print('Saving screenshots')

        # Check whether target directory for frames (screenshots) for frames
        # exists, if not create it:
        lgcDir = os.path.isdir(strPthFrm)

        # If directory does not exist, create it:
        if not (lgcDir):
            # Create direcotry for segments:
            os.mkdir(strPthFrm)

        # Save stimulus frame array to npy file:
        np.savez_compressed((strPthFrm + os.path.sep + 'stimulus_log'),
                            aryFrames=aryFrames)

        # Loop through volumes and save PNGs:
        for idxVol in range(varNumVol):

            # print(('---Frame '
            #       + str(idxVol)
            #       + ' out of '
            #       + str(int(varNumVol))))

            # Create image:
            objImg = Image.fromarray(aryFrames[:, :, idxVol], mode='L')

            # File name (with leading zeros, e.g. '*_004' or '*_042'). For
            # consistency with earlier versions, the numbering of frames (PNG
            # files  corresponding to fMRI volumes) starts at '1' (not at '0').
            strTmpPth = (strPthFrm + os.path.sep + 'frame_' +
                         str(idxVol + 1).zfill(3) + '.png')

            # Save image to disk:
            objImg.save(strTmpPth)

    # *************************************************************************
    # *** Close everyting

    core.quit()
    monitors.quit()
    logging.quit()
    event.quit()
Esempio n. 19
0
 def updateBalloonPos(self):
     return [0, pix2deg(-400 + (deg2pix(self.stimuli.size[1], self.mon) / 2), self.mon)]
Esempio n. 20
0
 def get_position(self):
     x, y = self.tracker.get_gaze()
     elx = pix2deg(x - self.tracker.scenter[0], self.tracker.win.monitor)
     ely = pix2deg(-(y - self.tracker.scenter[1]), self.tracker.win.monitor)
     return elx, ely
Esempio n. 21
0
    def __init__(self, win, mon):
        self.lastScoreText = u'Ostatnia wygrana: '
        self.totalScoreText = u'Całkowita wygrana: '
        self.lastScore = visual.TextStim(win, text=self.lastScoreText, units='deg', pos=(20,-12), color=u'black')
        self.totalScore = visual.TextStim(win, text=self.totalScoreText, units='deg', pos=(20.3,-13.5), color=u'black')

        self.keyPump = visual.ImageStim(win, image="assets/key_up.png", pos=[-12,-12],size=[pix2deg(128,mon),pix2deg(128,mon)])
        self.keyCollect = visual.ImageStim(win, image="assets/key_enter.png", pos=[-20,-12],size=[pix2deg(128,mon),pix2deg(128,mon)])
        self.keyPumpLabel = visual.TextStim(win, text=u'DMUCHNIJ', units='deg', pos=(-12,-15), color='#404040')
        self.keyCollectLabel = visual.TextStim(win, text=u'ZAKOŃCZ', units='deg', pos=(-20,-15), color='#404040')
orientations = [0, 45, 90]
repeats = 2

on_time = 5
off_time = 0

ori_time = on_time + off_time
rep_time = ori_time * len(orientations)
# Getting window information

mon = monitors.Monitor('leftMonitor')
mywin = visual.Window([800, 600],
                      fullscr=False,
                      monitor="leftMonitor",
                      units="deg")
screen_sz = (monitorunittools.pix2deg(800, monitor=mon),
             monitorunittools.pix2deg(600, monitor=mon))

frame_rate = mywin.getActualFrameRate()
# Converting to frames
on_frames = int(on_time * frame_rate)
off_frames = int(off_time * frame_rate)
#create a window

mytex = np.array([[1, -1, 1], [-1, 1, -1], [1, -1, 1]])
#create some stimuli
grating = visual.GratingStim(win=mywin, tex='sqrXsqr', size=screen_sz,
                             sf=1)  # full field

#draw the stimuli and update the window
session_timer = core.Clock()
Esempio n. 23
0
								 dataFileName=filename)

# Setup the Window
monitorName = 'LG Flatron L1718S'
monitorName = 'SyncMaster 797MB'
monitorName = 'ASUS ML 239'
#monitorName = 'HP Compaq LA2205wg'
monitorName = 'Dell Vostro 5470'
monitorName = 'testMonitor'
frameRate = 60
mon = monitors.Monitor(monitorName)

win = visual.Window(size=[1024, 768], fullscr=True, screen=0, allowGUI=True, allowStencil=True,
					monitor=mon, color=[1, 1, 1], colorSpace=u'rgb', units=u'pix')

screen_dim_deg = [pix2deg(win.size[0], mon), pix2deg(win.size[1], mon)]
#print 'Refresh rate %.3f' % win.getActualFrameRate()

f = codecs.open("instr.txt", "r", encoding='utf-8')

try:
	f = codecs.open("instr.txt", "r", encoding='utf-8')
	try:
		instrContent = [f.read()]
	finally:
		f.close()
except IOError:
	pass

myMouse = event.Mouse(win=win)
instr_text = visual.TextStim(win=win, name='instr_text',
Esempio n. 24
0
def TransformStim(xin, yin):

    #initialize variable, transfer labels
    trans_y = np.zeros(np.shape(xin)[0])

    # Convert x values; as long as input's x-values are in 0-100 space, this
    # line linearly transforms those values to -1:2 space; to choose
    # a different range, simply change the linear scaling, but be sure to
    # change the scaling for the y transformation as well so the ratio of the
    # axes remains the same.
    trans_x = (xin / 100) * 3 - 0.5
    # trans_x = (xin / 100) * 3 - 1

    # Nonlinear conversion of x values: trans_x exponentiated, resulting in a
    # range of .5-4 for CPD. DO NOT CHANGE.
    trans_x = 2**trans_x

    # Y values should also be in 0-100; negative values in particular cause
    # problems.
    if np.any(xin < 0) or np.any(yin < 0):
        print('Negative value for input!')

    # Linear conversion of y values to pi/11:(3*pi/8+pi/11) space. Again,
    # different ranges and bounds can be chosen at this step.
    # y = (yin / 100) * ((3 * np.pi / 8) + (np.pi / 11))
    y = (yin / 100) * ((3 * np.pi / 8) + (np.pi / 9))

    # The remainder of the code performs the nonlinear transformation on the y
    # values, which remain in the same space, but warped. DO NOT CHANGE.
    ind = np.argsort(y)
    sort_y = y[ind]
    z = 4.7 * np.sin(sort_y)**2

    trans_y[0] = np.sqrt(sort_y[0]**2 + z[0]**2)

    for i in range(1, np.shape(sort_y)[0]):
        trans_y[i] = trans_y[i - 1] + np.sqrt(
            np.power(sort_y[i] - sort_y[i - 1], 2) +
            np.power(z[i] - z[i - 1], 2))

    range_trans_y = np.amax(trans_y) - np.amin(trans_y)
    range_sort_y = np.amax(sort_y) - np.amin(sort_y)

    trans_y = trans_y / range_trans_y * range_sort_y
    trans_y = trans_y - np.min(trans_y) + np.min(sort_y)

    # NOTE: Convert radians to degrees
    trans_y = trans_y * 180 / np.pi

    xout = trans_x
    yout = np.zeros(np.shape(xin)[0])
    for i in range(0, len(ind)):
        yout[ind[i]] = trans_y[i]

    # NOTE: Convert Cycles per degree to cycles per cm
    mon = Monitor('testMonitor')
    mon.distance = 20.0  # viewing distance in cm
    xout = xout * (pix2deg(1, mon) / pix2cm(1, mon))

    # xout = (xin / 100) * 5 + 1
    # yout = (yin / 100) * 90

    return ([xout, yout])