def dkl2rgb(dkl_Nx3, conversionMatrix=None): #Convert from DKL color space (cone-opponent space from Derrington, #Krauskopf & Lennie) to RGB. #Requires a conversion matrix, which will be generated from generic #Sony Trinitron phosphors if not supplied (note that this will not be #an accurate representation of the color space unless you supply a #conversion matrix # #usage: #rgb(Nx3) = dkl2rgb(dkl_Nx3(el,az,radius), conversionMatrix) dkl_3xN = numpy.transpose(dkl_Nx3)#its easier to use in the other orientation! if numpy.size(dkl_3xN)==3: RG, BY, LUM = sph2cart(dkl_3xN[0],dkl_3xN[1],dkl_3xN[2]) else: RG, BY, LUM = sph2cart(dkl_3xN[0,:],dkl_3xN[1,:],dkl_3xN[2,:]) dkl_cartesian = numpy.asarray([LUM, RG, BY]) if conversionMatrix==None: conversionMatrix = numpy.asarray([ \ #LUMIN %L-M %L+M-S (note that dkl has to be in cartesian coords first!) [1.0000, 1.0000, -0.1462],#R [1.0000, -0.3900, 0.2094],#G [1.0000, 0.0180, -1.0000]])#B log.warning('This monitor has not been color-calibrated. Using default DKL conversion matrix.') rgb = numpy.dot(conversionMatrix, dkl_cartesian) return numpy.transpose(rgb)#return in the shape we received it
def waitForVBL(screen=0, nFrames=1): """Wait for the given screen (typically screen is 0 or 1) to finish drawing before returning/ If no screen is given then screen 0 is used. This is based on detecting the display beam position and may give unpredictable results for an LCD. """ if importCtypesFailed: return False screens = getScreens() if screen > (len(screens) - 1): raise IndexError, "Requested refresh rate of screen %i, but only %i screens were found" % ( screen, len(screens)) else: scrID = getScreens()[screen] framePeriod = 1.0 / getRefreshRate(screen) if screen > 0: #got multiple screens, check if they have same rate mainFramePeriod = 1.0 / getRefreshRate(0) if mainFramePeriod != framePeriod: #CGDisplayBeamPosition is unpredictable in this case - usually synced to the first monitor, but maybe better if 2 gfx cards? log.warning( "You are trying to wait for blanking on a secondary monitor that has a different \ refresh rate to your primary monitor. This is not recommended (likely to reduce your frame rate to the primary monitor)." ) #when we're in a VBL the current beam position is greater than the screen height (for up to ~30 lines) top = getScreenSizePix(screen)[0] if cocoa.CGDisplayBeamPosition(scrID) > top: nFrames += 1 #we're in a VBL already, wait for one more while nFrames > 0: beamPos = cocoa.CGDisplayBeamPosition(scrID) #get current pos #choose how long to wait while framePeriod * ( top - beamPos ) / top > 0.005: #we have at least 5ms to go so can wait for 1ms # print 'plenty', beamPos, framePeriod*(top-beamPos)/top, time.time() # time.sleep(0.0001)#actually it seems that time.sleep() waits too long on os x beamPos = cocoa.CGDisplayBeamPosition(scrID) #get current pos #now near top so poll continuously while beamPos < top: beamPos = cocoa.CGDisplayBeamPosition(scrID) #get current pos #if this was not the last frame, then wait until start of next frame before continuing #so that we don't detect the VBL again. If this was the last frame then get back to script asap if nFrames > 1: while beamPos >= top: beamPos = cocoa.CGDisplayBeamPosition(scrID) nFrames -= 1 #beamPos = cocoa.CGDisplayBeamPosition(1) #while beamPos<=1000: # beamPos = cocoa.CGDisplayBeamPosition(1) # print beamPos #first=last=time.time() #print getRefreshRate(1) #for nFrames in range(20): # waitForVBL(1, nFrames=1) # time.sleep(0.005) # this=time.time() # print this-first, this-last, 1/(this-last) # last=this #rush()
def rgb2dklCart(picture, conversionMatrix=None): """convert an RGB image into Cartesian DKL space""" #Turn the picture into an array so we can do maths picture=scipy.array(picture) #Find the original dimensions of the picture origShape = picture.shape #this is the inversion of the dkl2rgb conversion matrix if conversionMatrix==None: conversionMatrix = np.asarray([\ #LUMIN->%L-M->L+M-S [ 0.25145542, 0.64933633, 0.09920825], [ 0.78737943, -0.55586618, -0.23151325], [ 0.26562825, 0.63933074, -0.90495899]]) log.warning('This monitor has not been color-calibrated. Using default DKL conversion matrix.') else: conversionMatrix = np.linalg.inv(conversionMatrix) #Reshape the picture so that it can multiplied by the conversion matrix red = picture[:,:,0] green = picture[:,:,1] blue = picture[:,:,2] dkl = np.asarray([red.reshape([-1]), green.reshape([-1]), blue.reshape([-1])]) #Multiply the picture by the conversion matrix dkl=np.dot(conversionMatrix, dkl) #Reshape the picture so that it's back to it's original shape dklPicture = np.reshape(np.transpose(dkl), origShape) return dklPicture
def dkl2rgb(dkl_Nx3, conversionMatrix=None): #Convert from DKL color space (cone-opponent space from Derrington, #Krauskopf & Lennie) to RGB. #Requires a conversion matrix, which will be generated from generic #Sony Trinitron phosphors if not supplied (note that this will not be #an accurate representation of the color space unless you supply a #conversion matrix # #usage: #rgb(Nx3) = dkl2rgb(dkl_Nx3(el,az,radius), conversionMatrix) dkl_3xN = numpy.transpose( dkl_Nx3) #its easier to use in the other orientation! if numpy.size(dkl_3xN) == 3: RG, BY, LUM = sph2cart(dkl_3xN[0], dkl_3xN[1], dkl_3xN[2]) else: RG, BY, LUM = sph2cart(dkl_3xN[0, :], dkl_3xN[1, :], dkl_3xN[2, :]) dkl_cartesian = numpy.asarray([LUM, RG, BY]) if conversionMatrix == None: conversionMatrix = numpy.asarray([ \ #LUMIN %L-M %L+M-S (note that dkl has to be in cartesian coords first!) [1.0000, 1.0000, -0.1462],#R [1.0000, -0.3900, 0.2094],#G [1.0000, 0.0180, -1.0000]])#B log.warning( 'This monitor has not been color-calibrated. Using default DKL conversion matrix.' ) rgb = numpy.dot(conversionMatrix, dkl_cartesian) return numpy.transpose(rgb) #return in the shape we received it
def lms2rgb(lms_Nx3, conversionMatrix=None): #Convert from cone space (Long, Medium, Short) to RGB. #Requires a conversion matrix, which will be generated from generic #Sony Trinitron phosphors if not supplied (note that you will not get #an accurate representation of the color space unless you supply a #conversion matrix) # #usage: #rgb(Nx3) = lms2rgb(dkl_Nx3(el,az,radius), conversionMatrix) lms_3xN = numpy.transpose(lms_Nx3)#its easier to use in the other orientation! if conversionMatrix==None: cones_to_rgb = numpy.asarray([ \ #L M S [ 4.97068857, -4.14354132, 0.17285275],#R [-0.90913894, 2.15671326, -0.24757432],#G [-0.03976551, -0.14253782, 1.18230333]#B ]) log.warning('This monitor has not been color-calibrated. Using default LMS conversion matrix.') else: cones_to_rgb=conversionMatrix rgb_to_cones = numpy.linalg.pinv(cones_to_rgb)#get inverse rgb = numpy.dot(cones_to_rgb, lms_3xN) return numpy.transpose(rgb)#return in the shape we received it
def __init__(self, win, contrast=1.0, gamma=[1.0,1.0,1.0], nEntries=256, bitsType='bits++',): self.win = win self.contrast=contrast self.nEntries=nEntries self.bitsType=bitsType self.method = 'fast' if len(gamma)>2: # [Lum,R,G,B] or [R,G,B] self.gamma=gamma[-3:] else: self.gamma = [gamma, gamma, gamma] if init(): setVideoMode(NOGAMMACORRECT|VIDEOENCODEDCOMMS) self.initialised=True log.debug('found and initialised bits++') else: self.initialised=False log.warning("couldn't initialise bits++") #do the processing self._HEADandLUT = numpy.zeros((524,1,3),numpy.uint8) self._HEADandLUT[:12,:,0] = numpy.asarray([ 36, 63, 8, 211, 3, 112, 56, 34,0,0,0,0]).reshape([12,1])#R self._HEADandLUT[:12,:,1] = numpy.asarray([ 106, 136, 19, 25, 115, 68, 41, 159,0,0,0,0]).reshape([12,1])#G self._HEADandLUT[:12,:,2] = numpy.asarray([ 133, 163, 138, 46, 164, 9, 49, 208,0,0,0,0]).reshape([12,1])#B self.LUT=numpy.zeros((256,3),'d') #just a place holder self.setLUT()#this will set self.LUT and update self._LUTandHEAD
def lms2rgb(lms_Nx3, conversionMatrix=None): #Convert from cone space (Long, Medium, Short) to RGB. #Requires a conversion matrix, which will be generated from generic #Sony Trinitron phosphors if not supplied (note that you will not get #an accurate representation of the color space unless you supply a #conversion matrix) # #usage: #rgb(Nx3) = lms2rgb(dkl_Nx3(el,az,radius), conversionMatrix) lms_3xN = numpy.transpose( lms_Nx3) #its easier to use in the other orientation! if conversionMatrix == None: cones_to_rgb = numpy.asarray([ \ #L M S [ 4.97068857, -4.14354132, 0.17285275],#R [-0.90913894, 2.15671326, -0.24757432],#G [-0.03976551, -0.14253782, 1.18230333]#B ]) log.warning( 'This monitor has not been color-calibrated. Using default LMS conversion matrix.' ) else: cones_to_rgb = conversionMatrix rgb_to_cones = numpy.linalg.pinv(cones_to_rgb) #get inverse rgb = numpy.dot(cones_to_rgb, lms_3xN) return numpy.transpose(rgb) #return in the shape we received it
def rush(value=True): """Raise the priority of the current thread/process using - sched_setscheduler NB for rush() to work on (debian-based?) linux requires that the script is run using a copy of python that is allowed to change priority, eg: sudo setcap cap_sys_nice=eip <sys.executable>, and maybe restart PsychoPy. If <sys.executable> is the system python, its important to restore it back to normal to avoid possible side-effects. Alternatively, use a different python executable, and change its cap_sys_nice. For RedHat-based systems, 'sudo chrt ...' at run-time might be needed instead, not sure. see http://rt.et.redhat.com/wiki/images/8/8e/Rtprio.pdf """ if importCtypesFailed: return False if value:#set to RR with max priority schedParams = _SchedParams() schedParams.sched_priority = c.sched_get_priority_max(SCHED_RR) err = c.sched_setscheduler(0,SCHED_RR, ctypes.byref(schedParams)) if err==-1:#returns 0 if OK log.warning("""Failed to raise thread priority with sched_setscheduler. To enable rush(), if you are using a debian-based linux, try this in a terminal window: 'sudo setcap cap_sys_nice=eip %s' [NB: You may need to install 'setcap' first.] If you are using the system's python (eg /usr/bin/python2.x), its highly recommended to change cap_sys_nice back to normal afterwards: 'sudo setcap cap_sys_nice= %s'""" % (sys.executable,sys.executable)) else:#set to RR with normal priority schedParams = _SchedParams() schedParams.sched_priority = c.sched_get_priority_min(SCHED_NORMAL) err = c.sched_setscheduler(0,SCHED_NORMAL, ctypes.byref(schedParams)) if err==-1:#returns 0 if OK log.warning("""Failed to set thread priority back to normal level with sched_setscheduler. Try: 'sudo setcap cap_sys_nice= %s'""" % (sys.executable)) return True
def gammaInvFun(yy, minLum, maxLum, gamma, b=None, eq=1): """Returns inverse gamma function for desired luminance values. x = gammaInvFun(y, minLum, maxLum, gamma) a and b are calculated directly from minLum, maxLum, gamma **Parameters:** - **xx** are the input values (range 0-255 or 0.0-1.0) - **minLum** = the minimum luminance of your monitor - **maxLum** = the maximum luminance of your monitor (for this gun) - **gamma** = the value of gamma (for this gun) - **eq** determines the gamma equation used; eq==1[default]: yy = a + (b*xx)**gamma eq==2: yy = (a + b*xx)**gamma """ #x should be 0:1 #y should be 0:1, then converted to minLum:maxLum #eq1: y = a + (b*xx)**gamma #eq2: y = (a+b*xx)**gamma #eq4: y = a+(b+kxx)**gamma if max(yy)==255: yy=numpy.asarray(yy)/255.0 elif min(yy)<0 or max(yy)>1: log.warning('User supplied values outside the expected range (0:1)') #get into range minLum:maxLum yy = numpy.asarray(yy)*(maxLum - minLum) + minLum if eq==1: a = minLum b = (maxLum-a)**(1/gamma) xx = ((yy-a)**(1/gamma))/b minLUT = ((minLum-a)**(1/gamma))/b maxLUT = ((maxLum-a)**(1/gamma))/b elif eq==2: a = minLum**(1/gamma) b = maxLum**(1/gamma)-a xx = (yy**(1/gamma)-a)/b maxLUT = (maxLum**(1/gamma)-a)/b minLUT = (minLum**(1/gamma)-a)/b elif eq==3:#NB method 3 was an interpolation method that didn't work well pass elif eq==4: #this is not the same as Zhang and Pelli's inverse #see http://www.psychopy.org/general/gamma.html for derivation a = minLum-b**gamma k = (maxLum-a)**(1./gamma) - b xx = ((yy-a)**(1/gamma) - b)/k yy = (((1-xx)*b**gamma + xx*(b+k)**gamma)**(1/gamma)-b)/k maxLUT = ((maxLum-a)**(1/gamma) - b)/k minLUT = ((minLum-a)**(1/gamma) - b)/k #print "we are linearising with the special wichmann style equation" #then return to range (0:1) xx = xx/(maxLUT-minLUT) - minLUT return xx
def gammaInvFun(yy, minLum, maxLum, gamma, b=None, eq=1): """Returns inverse gamma function for desired luminance values. x = gammaInvFun(y, minLum, maxLum, gamma) a and b are calculated directly from minLum, maxLum, gamma **Parameters:** - **xx** are the input values (range 0-255 or 0.0-1.0) - **minLum** = the minimum luminance of your monitor - **maxLum** = the maximum luminance of your monitor (for this gun) - **gamma** = the value of gamma (for this gun) - **eq** determines the gamma equation used; eq==1[default]: yy = a + (b*xx)**gamma eq==2: yy = (a + b*xx)**gamma """ #x should be 0:1 #y should be 0:1, then converted to minLum:maxLum #eq1: y = a + (b*xx)**gamma #eq2: y = (a+b*xx)**gamma #eq4: y = a+(b+kxx)**gamma if max(yy) == 255: yy = numpy.asarray(yy) / 255.0 elif min(yy) < 0 or max(yy) > 1: log.warning('User supplied values outside the expected range (0:1)') #get into range minLum:maxLum yy = numpy.asarray(yy) * (maxLum - minLum) + minLum if eq == 1: a = minLum b = (maxLum - a)**(1 / gamma) xx = ((yy - a)**(1 / gamma)) / b minLUT = ((minLum - a)**(1 / gamma)) / b maxLUT = ((maxLum - a)**(1 / gamma)) / b elif eq == 2: a = minLum**(1 / gamma) b = maxLum**(1 / gamma) - a xx = (yy**(1 / gamma) - a) / b maxLUT = (maxLum**(1 / gamma) - a) / b minLUT = (minLum**(1 / gamma) - a) / b elif eq == 3: #NB method 3 was an interpolation method that didn't work well pass elif eq == 4: #this is not the same as Zhang and Pelli's inverse #see http://www.psychopy.org/general/gamma.html for derivation a = minLum - b**gamma k = (maxLum - a)**(1. / gamma) - b xx = ((yy - a)**(1 / gamma) - b) / k yy = (((1 - xx) * b**gamma + xx * (b + k)**gamma)**(1 / gamma) - b) / k maxLUT = ((maxLum - a)**(1 / gamma) - b) / k minLUT = ((minLum - a)**(1 / gamma) - b) / k #print "we are linearising with the special wichmann style equation" #then return to range (0:1) xx = xx / (maxLUT - minLUT) - minLUT return xx
def waitForVBL(screen=0,nFrames=1): """DEPRECATED: the code for doing this is now smaller and cross-platform so is included in visual.Window.flip() This version is based on detecting the display beam position. It may give unpredictable results for an LCD. """ if importCtypesFailed: return False screens=getScreens() if screen>(len(screens)-1): raise IndexError, "Requested refresh rate of screen %i, but only %i screens were found" %(screen, len(screens)) else: scrID=getScreens()[screen] framePeriod=1.0/getRefreshRate(screen) if screen>0: #got multiple screens, check if they have same rate mainFramePeriod = 1.0/getRefreshRate(0) if mainFramePeriod!=framePeriod: #CGDisplayBeamPosition is unpredictable in this case - usually synced to the first monitor, but maybe better if 2 gfx cards? log.warning("You are trying to wait for blanking on a secondary monitor that has a different \ refresh rate to your primary monitor. This is not recommended (likely to reduce your frame rate to the primary monitor).") #when we're in a VBL the current beam position is greater than the screen height (for up to ~30 lines) top=getScreenSizePix(screen)[0] if cocoa.CGDisplayBeamPosition(scrID)>top: nFrames+=1#we're in a VBL already, wait for one more while nFrames>0: beamPos = cocoa.CGDisplayBeamPosition(scrID)#get current pos #choose how long to wait while framePeriod*(top-beamPos)/top > 0.005:#we have at least 5ms to go so can wait for 1ms # print 'plenty', beamPos, framePeriod*(top-beamPos)/top, time.time() # time.sleep(0.0001)#actually it seems that time.sleep() waits too long on os x beamPos = cocoa.CGDisplayBeamPosition(scrID)#get current pos #now near top so poll continuously while beamPos<top: beamPos = cocoa.CGDisplayBeamPosition(scrID)#get current pos #if this was not the last frame, then wait until start of next frame before continuing #so that we don't detect the VBL again. If this was the last frame then get back to script asap if nFrames>1: while beamPos>=top: beamPos = cocoa.CGDisplayBeamPosition(scrID) nFrames-=1 #beamPos = cocoa.CGDisplayBeamPosition(1) #while beamPos<=1000: # beamPos = cocoa.CGDisplayBeamPosition(1) # print beamPos #first=last=time.time() #print getRefreshRate(1) #for nFrames in range(20): # waitForVBL(1, nFrames=1) # time.sleep(0.005) # this=time.time() # print this-first, this-last, 1/(this-last) # last=this #rush()
def sendUsageStats(proxy=None): """Sends anonymous, very basic usage stats to psychopy server: the version of PsychoPy the system used (platform and version) the date If http_proxy is set in the system environment variables these will be used automatically, but additional proxies can be provided here as the argument proxies. """ v=psychopy.__version__ dateNow = time.strftime("%Y-%m-%d_%H:%M") miscInfo = '' #urllib.install_opener(opener) #check for proxies if proxy in [None,""]: pass#use default opener (no proxies) else: #build the url opener with proxy and cookie handling opener = urllib2.build_opener( urllib2.ProxyHandler({'http':proxy})) urllib2.install_opener(opener) #get platform-specific info if sys.platform=='darwin': OSXver, junk, architecture = platform.mac_ver() systemInfo = "OSX_%s_%s" %(OSXver, architecture) elif sys.platform.startswith('linux'): systemInfo = '%s_%s_%s' % ( 'Linux', ':'.join([x for x in platform.dist() if x != '']), platform.release()) elif sys.platform=='win32': ver=sys.getwindowsversion() if len(ver[4])>0: systemInfo=("win32_v%i.%i.%i_%s" %(ver[0],ver[1],ver[2],ver[4])).replace(' ','') else: systemInfo="win32_v%i.%i.%i" %(ver[0],ver[1],ver[2]) else: systemInfo = platform.system()+platform.release() URL = "http://www.psychopy.org/usage.php?date=%s&sys=%s&version=%s&misc=%s" \ %(dateNow, systemInfo, v, miscInfo) try: req = urllib2.Request(URL) page = urllib2.urlopen(req)#proxies except: log.warning("Couldn't connect to psychopy.org\n"+\ "Check internet settings (and proxy setting in PsychoPy Preferences.")
def sendUsageStats(proxy=None): """Sends anonymous, very basic usage stats to psychopy server: the version of PsychoPy the system used (platform and version) the date If http_proxy is set in the system environment variables these will be used automatically, but additional proxies can be provided here as the argument proxies. """ v=psychopy.__version__ dateNow = time.strftime("%Y-%m-%d_%H:%M") miscInfo = '' #urllib.install_opener(opener) #check for proxies if proxy in [None,""]: pass#use default opener (no proxies) else: #build the url opener with proxy and cookie handling opener = urllib2.build_opener( urllib2.ProxyHandler({'http':proxy})) urllib2.install_opener(opener) #get platform-specific info if sys.platform=='darwin': OSXver, junk, architecture = platform.mac_ver() systemInfo = "OSX_%s_%s" %(OSXver, architecture) elif sys.platform=='linux': systemInfo = '%s_%s_%s' % ( 'Linux', ':'.join([x for x in platform.dist() if x != '']), platform.release()) elif sys.platform=='win32': ver=sys.getwindowsversion() if len(ver[4])>0: systemInfo=("win32_v%i.%i.%i_%s" %(ver[0],ver[1],ver[2],ver[4])).replace(' ','') else: systemInfo="win32_v%i.%i.%i" %(ver[0],ver[1],ver[2]) else: systemInfo = platform.system()+platform.release() URL = "http://www.psychopy.org/usage.php?date=%s&sys=%s&version=%s&misc=%s" \ %(dateNow, systemInfo, v, miscInfo) try: req = urllib2.Request(URL) page = urllib2.urlopen(req)#proxies except: log.warning("Couldn't connect to psychopy.org\n"+\ "Check internet settings (and proxy setting in PsychoPy Preferences.")
def getLumSeriesPR650(lumLevels=8, winSize=(800, 600), monitor=None, gamma=1.0, allGuns=True, useBits=False, autoMode='auto', stimSize=0.3, photometer='COM1'): """DEPRECATED (since v1.60.01): Use :class:`pscyhopy.monitors.getLumSeries()` instead""" log.warning( "DEPRECATED (since v1.60.01): Use monitors.getLumSeries() instead") val = getLumSeries(lumLevels, winSize, monitor, gamma, allGuns, useBits, autoMode, stimSize, photometer) return val
def show(self): """Presents the dialog and waits for the user to press either OK or CANCEL. This function returns nothing. When they do, dlg.OK will be set to True or False (according to which button they pressed. If OK==True then dlg.data will be populated with a list of values coming from each of the input fields created. """ #add buttons for OK and Cancel buttons = wx.BoxSizer(wx.HORIZONTAL) OK = wx.Button(self, wx.ID_OK, " OK ") OK.SetDefault() buttons.Add(OK) CANCEL = wx.Button(self, wx.ID_CANCEL, " Cancel ") buttons.Add(CANCEL) self.sizer.Add(buttons, 1, flag=wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM, border=5) self.SetSizerAndFit(self.sizer) if self.ShowModal() == wx.ID_OK: self.data = [] #get data from input fields for n in range(len(self.inputFields)): thisName = self.inputFieldNames[n] thisVal = self.inputFields[n].GetValue() thisType = self.inputFieldTypes[n] #try to handle different types of input from strings log.debug("%s: %s" % (self.inputFieldNames[n], unicode(thisVal))) if thisType in [tuple, list, float, int]: #probably a tuple or list exec("self.data.append(" + thisVal + ")") #evaluate it elif thisType == numpy.ndarray: exec("self.data.append(numpy.array(" + thisVal + "))") elif thisType in [str, unicode, bool]: self.data.append(thisVal) else: log.warning('unknown type:' + self.inputFieldNames[n]) self.data.append(thisVal) self.OK = True else: self.OK = False self.Destroy()
def _loadAll(self): """Fetches the calibs for this monitor from disk, storing them as self.calibs""" thisFileName = os.path.join(\ monitorFolder, self.name+".calib") #the name of the actual file if not os.path.exists(thisFileName): log.warning("Creating new monitor...") self.calibNames = [] else: thisFile = open(thisFileName,'r') self.calibs = cPickle.load(thisFile) self.calibNames = self.calibs.keys() self.calibNames.sort() thisFile.close()
def getLumSeriesPR650(lumLevels=8, winSize=(800,600), monitor=None, gamma=1.0, allGuns = True, useBits=False, autoMode='auto', stimSize = 0.3, photometer='COM1'): """DEPRECATED (since v1.60.01): Use :class:`pscyhopy.monitors.getLumSeries()` instead""" log.warning("DEPRECATED (since v1.60.01): Use monitors.getLumSeries() instead") val= getLumSeries(lumLevels, winSize,monitor, gamma,allGuns, useBits, autoMode,stimSize,photometer) return val
def gammaInvFun(yy, minLum, maxLum, gamma, eq=1): """Returns inverse gamma function for desired luminance values. x = gammaInvFun(y, minLum, maxLum, gamma) a and b are calculated directly from minLum, maxLum, gamma **Parameters:** - **xx** are the input values (range 0-255 or 0.0-1.0) - **minLum** = the minimum luminance of your monitor - **maxLum** = the maximum luminance of your monitor (for this gun) - **gamma** = the value of gamma (for this gun) - **eq** determines the gamma equation used; eq==1[default]: yy = a + (b*xx)**gamma eq==2: yy = (a + b*xx)**gamma """ #x should be 0:1 #y should be 0:1, then converted to minLum:maxLum #eq1: y = a + (b*xx)**gamma #eq2: y = (a+b*xx)**gamma if max(yy)==255: yy=numpy.asarray(yy)/255.0 elif min(yy)<0 or max(yy)>1: log.warning('User supplied values outside the expected range (0:1)') #get into range minLum:maxLum yy = numpy.asarray(yy)*(maxLum - minLum) + minLum if eq==1: a = minLum b = (maxLum-a)**(1/gamma) xx = ((yy-a)**(1/gamma))/b minLUT = ((minLum-a)**(1/gamma))/b maxLUT = ((maxLum-a)**(1/gamma))/b elif eq==2: a = minLum**(1/gamma) b = maxLum**(1/gamma)-a xx = (yy**(1/gamma)-a)/b maxLUT = (maxLum**(1/gamma)-a)/b minLUT = (minLum**(1/gamma)-a)/b #then return to range (0:1) xx = xx/(maxLUT-minLUT) - minLUT return xx
def onCalibGammaBtn(self, event): if NO_MEASUREMENTS: #recalculate from previous measure lumsPre = self.currentMon.getLumsPre() lumLevels = self.currentMon.getLevelsPre() else: #present a dialogue to get details for calibration calibDlg = GammaDlg(self, self.currentMon) if calibDlg.ShowModal() != wx.ID_OK: calibDlg.Destroy() return 1 nPoints = int(calibDlg.ctrlNPoints.GetStringSelection()) stimSize = float(calibDlg.ctrlStimSize.GetValue()) useBits = calibDlg.ctrlUseBits.GetValue() calibDlg.Destroy() autoMode = calibDlg.methodChoiceBx.GetStringSelection() #run the calibration itself lumLevels = monitors.DACrange(nPoints) lumsPre = monitors.getLumSeries( photometer=self.photom, lumLevels=lumLevels, useBits=useBits, autoMode=autoMode, winSize=self.currentMon.getSizePix(), stimSize=stimSize, monitor=self.currentMon) #allow user to type in values if autoMode == 'semi': inputDlg = GammaLumValsDlg(lumLevels, parent=self) lumsPre = inputDlg.show() #will be [] if user cancels inputDlg.Destroy() #fit the gamma curves if len(lumsPre) > 1: self.onCopyCalib(1) #create a new dated calibration self.currentMon.setLumsPre(lumsPre) #save for future self.currentMon.setLevelsPre(lumLevels) #save for future self.btnPlotGamma.Enable(True) #do the fits self.doGammaFits(lumLevels, lumsPre) else: log.warning('No lum values captured/entered')
def show(self): """Presents the dialog and waits for the user to press either OK or CANCEL. This function returns nothing. When they do, dlg.OK will be set to True or False (according to which button they pressed. If OK==True then dlg.data will be populated with a list of values coming from each of the input fields created. """ #add buttons for OK and Cancel buttons = wx.BoxSizer(wx.HORIZONTAL) OK = wx.Button(self, wx.ID_OK, " OK ") OK.SetDefault() buttons.Add(OK) CANCEL = wx.Button(self, wx.ID_CANCEL, " Cancel ") buttons.Add(CANCEL) self.sizer.Add(buttons,1,flag=wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM,border=5) self.SetSizerAndFit(self.sizer) if self.ShowModal() == wx.ID_OK: self.data=[] #get data from input fields for n in range(len(self.inputFields)): thisName = self.inputFieldNames[n] thisVal = self.inputFields[n].GetValue() thisType= self.inputFieldTypes[n] #try to handle different types of input from strings log.debug("%s: %s" %(self.inputFieldNames[n], unicode(thisVal))) if thisType in [tuple,list,float,int]: #probably a tuple or list exec("self.data.append("+thisVal+")")#evaluate it elif thisType==numpy.ndarray: exec("self.data.append(numpy.array("+thisVal+"))") elif thisType in [str,unicode,bool]: self.data.append(thisVal) else: log.warning('unknown type:'+self.inputFieldNames[n]) self.data.append(thisVal) self.OK=True else: self.OK=False self.Destroy()
def onCalibGammaBtn(self, event): if NO_MEASUREMENTS: #recalculate from previous measure lumsPre = self.currentMon.getLumsPre() lumLevels = self.currentMon.getLevelsPre() else: #present a dialogue to get details for calibration calibDlg = GammaDlg(self, self.currentMon) if calibDlg.ShowModal()!=wx.ID_OK: calibDlg.Destroy() return 1 nPoints = int(calibDlg.ctrlNPoints.GetStringSelection()) stimSize = float(calibDlg.ctrlStimSize.GetValue()) useBits = calibDlg.ctrlUseBits.GetValue() calibDlg.Destroy() autoMode = calibDlg.methodChoiceBx.GetStringSelection() #run the calibration itself lumLevels=monitors.DACrange(nPoints) lumsPre = monitors.getLumSeries(photometer=self.photom, lumLevels=lumLevels, useBits=useBits, autoMode=autoMode, winSize=self.currentMon.getSizePix(), stimSize=stimSize, monitor=self.currentMon) #allow user to type in values if autoMode=='semi': inputDlg = GammaLumValsDlg(lumLevels, parent=self) lumsPre = inputDlg.show()#will be [] if user cancels inputDlg.Destroy() #fit the gamma curves if len(lumsPre)>1: self.onCopyCalib(1)#create a new dated calibration self.currentMon.setLumsPre(lumsPre)#save for future self.currentMon.setLevelsPre(lumLevels)#save for future self.btnPlotGamma.Enable(True) self.choiceLinearMethod.Enable() #do the fits self.doGammaFits(lumLevels,lumsPre) else: log.warning('No lum values captured/entered')
def measure(self, timeOut=30.0): """Make a measurement with the device. For a PR650 the device is instructed to make a measurement and then subsequent commands are issued to retrieve info about that measurement """ t1 = time.clock() reply = self.sendMessage('m0\n', timeOut) #measure and hold data #using the hold data method the PR650 we can get interogate it #several times for a single measurement if reply==self.codes['OK']: raw = self.sendMessage('d2') xyz = raw.split(',')#parse into words self.lastQual = str(xyz[0]) if self.codes[self.lastQual]=='OK': self.lastLum = float(xyz[3]) else: self.lastLum = 0.0 else: log.warning("Didn't collect any data (extend timeout?)")
def measure(self, timeOut=30.0): """Make a measurement with the device. For a PR650 the device is instructed to make a measurement and then subsequent commands are issued to retrieve info about that measurement """ t1 = time.clock() reply = self.sendMessage('m0\n', timeOut) #measure and hold data #using the hold data method the PR650 we can get interogate it #several times for a single measurement if reply == self.codes['OK']: raw = self.sendMessage('d2') xyz = raw.split(',') #parse into words self.lastQual = str(xyz[0]) if self.codes[self.lastQual] == 'OK': self.lastLum = float(xyz[3]) else: self.lastLum = 0.0 else: log.warning("Didn't collect any data (extend timeout?)")
def __init__( self, win, contrast=1.0, gamma=[1.0, 1.0, 1.0], nEntries=256, bitsType='bits++', ): self.win = win self.contrast = contrast self.nEntries = nEntries self.bitsType = bitsType self.method = 'fast' if len(gamma) > 2: # [Lum,R,G,B] or [R,G,B] self.gamma = gamma[-3:] else: self.gamma = [gamma, gamma, gamma] if init(): setVideoMode(NOGAMMACORRECT | VIDEOENCODEDCOMMS) self.initialised = True log.debug('found and initialised bits++') else: self.initialised = False log.warning("couldn't initialise bits++") #do the processing self._HEADandLUT = numpy.zeros((524, 1, 3), numpy.uint8) self._HEADandLUT[:12, :, 0] = numpy.asarray( [36, 63, 8, 211, 3, 112, 56, 34, 0, 0, 0, 0]).reshape([12, 1]) #R self._HEADandLUT[:12, :, 1] = numpy.asarray( [106, 136, 19, 25, 115, 68, 41, 159, 0, 0, 0, 0]).reshape([12, 1]) #G self._HEADandLUT[:12, :, 2] = numpy.asarray( [133, 163, 138, 46, 164, 9, 49, 208, 0, 0, 0, 0]).reshape([12, 1]) #B self.LUT = numpy.zeros((256, 3), 'd') #just a place holder self.setLUT() #this will set self.LUT and update self._LUTandHEAD
def rgb2dklCart(picture, conversionMatrix=None): """convert an RGB image into Cartesian DKL space""" #Turn the picture into an array so we can do maths picture = numpy.array(picture) #Find the original dimensions of the picture origShape = picture.shape #this is the inversion of the dkl2rgb conversion matrix if conversionMatrix == None: conversionMatrix = numpy.asarray([\ #LUMIN->%L-M->L+M-S [ 0.25145542, 0.64933633, 0.09920825], [ 0.78737943, -0.55586618, -0.23151325], [ 0.26562825, 0.63933074, -0.90495899]]) log.warning( 'This monitor has not been color-calibrated. Using default DKL conversion matrix.' ) else: conversionMatrix = numpy.linalg.inv(conversionMatrix) #Reshape the picture so that it can multiplied by the conversion matrix red = picture[:, :, 0] green = picture[:, :, 1] blue = picture[:, :, 2] dkl = numpy.asarray( [red.reshape([-1]), green.reshape([-1]), blue.reshape([-1])]) #Multiply the picture by the conversion matrix dkl = numpy.dot(conversionMatrix, dkl) #Reshape the picture so that it's back to it's original shape dklPicture = numpy.reshape(numpy.transpose(dkl), origShape) return dklPicture
def rush(value=True): """Raise the priority of the current thread/process using - sched_setscheduler NB for rush() to work on (debian-based?) linux requires that the script is run using a copy of python that is allowed to change priority, eg: sudo setcap cap_sys_nice=eip <sys.executable>, and maybe restart PsychoPy. If <sys.executable> is the system python, its important to restore it back to normal to avoid possible side-effects. Alternatively, use a different python executable, and change its cap_sys_nice. For RedHat-based systems, 'sudo chrt ...' at run-time might be needed instead, not sure. see http://rt.et.redhat.com/wiki/images/8/8e/Rtprio.pdf """ if importCtypesFailed: return False if value: #set to RR with max priority schedParams = _SchedParams() schedParams.sched_priority = c.sched_get_priority_max(SCHED_RR) err = c.sched_setscheduler(0, SCHED_RR, ctypes.byref(schedParams)) if err == -1: #returns 0 if OK log.warning( """Failed to raise thread priority with sched_setscheduler. To enable rush(), if you are using a debian-based linux, try this in a terminal window: 'sudo setcap cap_sys_nice=eip %s' [NB: You may need to install 'setcap' first.] If you are using the system's python (eg /usr/bin/python2.x), its highly recommended to change cap_sys_nice back to normal afterwards: 'sudo setcap cap_sys_nice= %s'""" % (sys.executable, sys.executable)) else: #set to RR with normal priority schedParams = _SchedParams() schedParams.sched_priority = c.sched_get_priority_min(SCHED_NORMAL) err = c.sched_setscheduler(0, SCHED_NORMAL, ctypes.byref(schedParams)) if err == -1: #returns 0 if OK log.warning( """Failed to set thread priority back to normal level with sched_setscheduler. Try: 'sudo setcap cap_sys_nice= %s'""" % (sys.executable)) return True
def installZipFile(self, zfile, v=None): """If v is provided this will be used as new version number, otherwise try and retrieve a version number from zip file name """ info=""#return this at the end if type(zfile) in [str, unicode] and os.path.isfile(zfile):#zfile is filename not an actual file if v==None: #try and deduce it zFilename = os.path.split(zfile)[-1] searchName = re.search('[0-9]*\.[0-9]*\.[0-9]*.', zFilename) if searchName!=None: v=searchName.group(0)[:-1] else:log.warning("Couldn't deduce version from zip file: %s" %zFilename) f=open(zfile) zfile=zipfile.ZipFile(f) else:#assume here that zfile is a ZipFile pass#todo: error checking - is it a zipfile? currPath=self.app.prefs.paths['psychopy'] #any commands that are successfully executed may need to be undone if a later one fails undoString = "" #depending on install method, needs diff handling #if path ends with 'psychopy' then move it to 'psychopy-version' and create a new 'psychopy' folder for new version versionLabelsInPath = re.findall('PsychoPy-.*/',currPath)#does the path contain any version number? if len(versionLabelsInPath)==0:#e.g. the mac standalone app, no need to refer to new versino number unzipTarget=currPath try: #to move existing PsychoPy os.rename(currPath, "%s-%s" %(currPath, psychopy.__version__)) undoString += 'os.rename("%s-%s" %(currPath, psychopy.__version__),currPath)\n' except: if sys.platform=='win32' and int(sys.getwindowsversion()[1])>5: msg = "Right-click the app and 'Run as admin' to upgrade)" else: msg = "Could not move existing PsychoPy installation (permissions error?)" return msg else:#setuptools-style installation #generate new target path unzipTarget=currPath for thisVersionLabel in versionLabelsInPath: pathVersion=thisVersionLabel[:-1]#remove final slash from the re.findall unzipTarget=unzipTarget.replace(pathVersion, "PsychoPy-%s" %v) # find the .pth file that specifies the python dir #create the new installation directory BEFORE changing pth file nUpdates, newInfo = self.updatePthFile(pathVersion, "PsychoPy-%s" %v) if nUpdates==-1:#there was an error (likely permissions) undoString += 'self.updatePthFile(unzipTarget, currPath)\n' exec(undoString)#undo previous changes return newInfo try: os.makedirs(unzipTarget)#create the new installation directory AFTER renaming existing dir undoString += 'os.remove(%s)\n' %unzipTarget except: #revert path rename and inform user exec(undoString)#undo previous changes if sys.platform=='win32' and int(sys.getwindowsversion()[1])>5: msg = "Right-click the app and 'Run as admin'):\n%s" %unzipTarget else: msg = "Failed to create directory for new version (permissions error?):\n%s" %unzipTarget return msg #do the actual extraction for name in zfile.namelist():#for each file within the zip #check that this file is part of the psychopy (not metadata or docs) if name.count('/psychopy/')<1: continue try: targetFile = os.path.join(unzipTarget, name.split('/psychopy/')[1]) targetContainer=os.path.split(targetFile)[0] if not os.path.isdir(targetContainer): os.makedirs(targetContainer)#make the containing folder if targetFile.endswith('/'): os.makedirs(targetFile)#it's a folder else: outfile = open(targetFile, 'wb') outfile.write(zfile.read(name)) outfile.close() except: exec(undoString)#undo previous changes print 'failed to unzip file:', name print sys.exc_info()[0] info += 'Success. \nChanges to PsychoPy will be completed when the application is next run' self.cancelBtn.SetDefault() self.installBtn.Disable() return info
def installZipFile(self, zfile, v=None): """If v is provided this will be used as new version number, otherwise try and retrieve a version number from zip file name """ info = "" #return this at the end if type(zfile) in [ str, unicode ] and os.path.isfile(zfile): #zfile is filename not an actual file if v == None: #try and deduce it zFilename = os.path.split(zfile)[-1] searchName = re.search('[0-9]*\.[0-9]*\.[0-9]*.', zFilename) if searchName != None: v = searchName.group(0)[:-1] else: log.warning("Couldn't deduce version from zip file: %s" % zFilename) f = open(zfile) zfile = zipfile.ZipFile(f) else: #assume here that zfile is a ZipFile pass #todo: error checking - is it a zipfile? currPath = self.app.prefs.paths['psychopy'] #any commands that are successfully executed may need to be undone if a later one fails undoString = "" #depending on install method, needs diff handling #if path ends with 'psychopy' then move it to 'psychopy-version' and create a new 'psychopy' folder for new version versionLabelsInPath = re.findall( 'PsychoPy-.*/', currPath) #does the path contain any version number? if len( versionLabelsInPath ) == 0: #e.g. the mac standalone app, no need to refer to new versino number unzipTarget = currPath try: #to move existing PsychoPy os.rename(currPath, "%s-%s" % (currPath, psychopy.__version__)) undoString += 'os.rename("%s-%s" %(currPath, psychopy.__version__),currPath)\n' except: if sys.platform == 'win32' and int( sys.getwindowsversion()[1]) > 5: msg = "Right-click the app and 'Run as admin' to upgrade)" else: msg = "Could not move existing PsychoPy installation (permissions error?)" return msg else: #setuptools-style installation #generate new target path unzipTarget = currPath for thisVersionLabel in versionLabelsInPath: pathVersion = thisVersionLabel[: -1] #remove final slash from the re.findall unzipTarget = unzipTarget.replace(pathVersion, "PsychoPy-%s" % v) # find the .pth file that specifies the python dir #create the new installation directory BEFORE changing pth file nUpdates, newInfo = self.updatePthFile(pathVersion, "PsychoPy-%s" % v) if nUpdates == -1: #there was an error (likely permissions) undoString += 'self.updatePthFile(unzipTarget, currPath)\n' exec(undoString) #undo previous changes return newInfo try: os.makedirs( unzipTarget ) #create the new installation directory AFTER renaming existing dir undoString += 'os.remove(%s)\n' % unzipTarget except: #revert path rename and inform user exec(undoString) #undo previous changes if sys.platform == 'win32' and int(sys.getwindowsversion()[1]) > 5: msg = "Right-click the app and 'Run as admin'):\n%s" % unzipTarget else: msg = "Failed to create directory for new version (permissions error?):\n%s" % unzipTarget return msg #do the actual extraction for name in zfile.namelist(): #for each file within the zip #check that this file is part of the psychopy (not metadata or docs) if name.count('/psychopy/') < 1: continue try: targetFile = os.path.join(unzipTarget, name.split('/psychopy/')[1]) targetContainer = os.path.split(targetFile)[0] if not os.path.isdir(targetContainer): os.makedirs(targetContainer) #make the containing folder if targetFile.endswith('/'): os.makedirs(targetFile) #it's a folder else: outfile = open(targetFile, 'wb') outfile.write(zfile.read(name)) outfile.close() except: exec(undoString) #undo previous changes print 'failed to unzip file:', name print sys.exc_info()[0] info += 'Success. \nChanges to PsychoPy will be completed when the application is next run' self.cancelBtn.SetDefault() self.installBtn.Disable() return info
from psychopy import log #create a log that gets replaced every run and stores all the details detailedLog = log.LogFile('complete.log', 'w', #'a' will append to previous file, 'w' will overwrite level=log.INFO) #set the level of the console log log.console.setLevel(log.WARNING) #set the level of the log at site-packages/psychopy/psychopy.log log.psychopyLog.setLevel(log.ERROR) log.warning('a shot across the bows') log.error('just a test error message') log.info('this will only get sent to the detailed log file')
def setLUT(self,newLUT=None, gammaCorrect=True, LUTrange=1.0): """Sets the LUT to a specific range of values. Note that, if you leave gammaCorrect=True then any LUT values you supply will automatically be gamma corrected. If BitsBox setMethod is 'fast' then the LUT will take effect on the next ``Window.update()`` If the setMethod is 'slow' then the update will take place over the next 1-4secs down the USB port. **Examples:** ``bitsBox.setLUT()`` builds a LUT using bitsBox.contrast and bitsBox.gamma ``bitsBox.setLUT(newLUT=some256x1array)`` (NB array should be float 0.0:1.0) Builds a luminance LUT using newLUT for each gun (actually array can be 256x1 or 1x256) ``bitsBox.setLUT(newLUT=some256x3array)`` (NB array should be float 0.0:1.0) Allows you to use a different LUT on each gun (NB by using BitsBox.setContr() and BitsBox.setGamma() users may not need this function!?) """ #choose endpoints LUTrange=numpy.asarray(LUTrange) if LUTrange.size==1: startII = int(round((0.5-LUTrange/2.0)*255.0)) endII = int(round((0.5+LUTrange/2.0)*255.0))+1 #+1 because python ranges exclude last value elif LUTrange.size==2: multiplier=1.0 if LUTrange[1]<=1: multiplier=255.0 startII= int(round(LUTrange[0]*multiplier)) endII = int(round(LUTrange[1]*multiplier))+1 #+1 because python ranges exclude last value stepLength = 2.0/(endII-startII-1) if newLUT is None: #create a LUT from scratch (based on contrast and gamma) #rampStep = 2.0/(self.nEntries-1) ramp = numpy.arange(-1.0,1.0+stepLength, stepLength) ramp = (ramp*self.contrast+1.0)/2.0 #self.LUT will be stored as 0.0:1.0 (gamma-corrected) self.LUT[startII:endII,0] = copy(ramp) self.LUT[startII:endII,1] = copy(ramp) self.LUT[startII:endII,2] = copy(ramp) elif type(newLUT) in [float, int] or (newLUT.shape==()): self.LUT[startII:endII,0]= newLUT self.LUT[startII:endII,1]= newLUT self.LUT[startII:endII,2]= newLUT elif len(newLUT.shape) == 1: #one dimensional LUT #replicate LUT to other channels #check range is 0:1 if newLUT>1.0: log.warning('newLUT should be float in range 0.0:1.0') self.LUT[startII:endII,0]= copy(newLUT.flat) self.LUT[startII:endII,1]= copy(newLUT.flat) self.LUT[startII:endII,2]= copy(newLUT.flat) elif len(newLUT.shape) == 2: #one dimensional LUT #use LUT as is #check range is 0:1 if max(max(newLUT))>1.0: raise AttributeError, 'newLUT should be float in range 0.0:1.0' self.LUT[startII:endII,:]= newLUT else: log.warning('newLUT can be None, nx1 or nx3') #do gamma correction if necessary if gammaCorrect==True: gamma=self.gamma if hasattr(self.win.monitor, 'lineariseLums'): self.LUT[startII:endII, : ] = self.win.monitor.lineariseLums(self.LUT[startII:endII, : ], overrideGamma=gamma) #update the bits++ box with new LUT if self.method=='fast': #get bits into correct order, shape and add to header ramp16 = (self.LUT*(2**16-1)).astype(numpy.uint16) #go from ubyte to uint16 ramp16 = numpy.reshape(ramp16,(256,1,3)) #set most significant bits self._HEADandLUT[12::2,:,:] = (ramp16[:,:,:]>>8).astype(numpy.uint8) #set least significant bits self._HEADandLUT[13::2,:,:] = (ramp16[:,:,:]&255).astype(numpy.uint8) self._HEADandLUTstr = self._HEADandLUT.tostring()
import glob from psychopy import core, log, hardware log.console.setLevel(log.DEBUG) pr655 = hardware.findPhotometer(device="PR655") if pr655 == None: log.warning("no device found") else: print "type:", pr655.type print "SN:", pr655.getDeviceSN() pr655.measure() print "lum", pr655.lastLum print "uv", pr655.lastUV print "xy", pr655.lastXY print "tristim", pr655.lastTristim nm, spec = pr655.getLastSpectrum() print "nm", nm print "spec", spec print "temperature", pr655.lastColorTemp print "DONE"
from psychopy import log #create a log that gets replaced every run and stores all the details detailedLog = log.LogFile( 'complete.log', 'w', #'a' will append to previous file, 'w' will overwrite level=log.INFO) #set the level of the console log log.console.setLevel(log.WARNING) #set the level of the log at site-packages/psychopy/psychopy.log log.psychopyLog.setLevel(log.ERROR) log.warning('a shot across the bows') log.error('just a test error message') log.info('this will only get sent to the detailed log file')
"""Deprecated - use the monitors package rather than psychopy.calib """ # Part of the PsychoPy library # Copyright (C) 2010 Jonathan Peirce # Distributed under the terms of the GNU General Public License (GPL). from psychopy import log log.warning("psychopy.calib is deprecated - use monitors package instead") from monitors import *
def setLUT(self, newLUT=None, gammaCorrect=True, LUTrange=1.0): """Sets the LUT to a specific range of values. Note that, if you leave gammaCorrect=True then any LUT values you supply will automatically be gamma corrected. If BitsBox setMethod is 'fast' then the LUT will take effect on the next ``Window.update()`` If the setMethod is 'slow' then the update will take place over the next 1-4secs down the USB port. **Examples:** ``bitsBox.setLUT()`` builds a LUT using bitsBox.contrast and bitsBox.gamma ``bitsBox.setLUT(newLUT=some256x1array)`` (NB array should be float 0.0:1.0) Builds a luminance LUT using newLUT for each gun (actually array can be 256x1 or 1x256) ``bitsBox.setLUT(newLUT=some256x3array)`` (NB array should be float 0.0:1.0) Allows you to use a different LUT on each gun (NB by using BitsBox.setContr() and BitsBox.setGamma() users may not need this function!?) """ #choose endpoints LUTrange = numpy.asarray(LUTrange) if LUTrange.size == 1: startII = int(round((0.5 - LUTrange / 2.0) * 255.0)) endII = int(round( (0.5 + LUTrange / 2.0) * 255.0)) + 1 #+1 because python ranges exclude last value elif LUTrange.size == 2: multiplier = 1.0 if LUTrange[1] <= 1: multiplier = 255.0 startII = int(round(LUTrange[0] * multiplier)) endII = int(round( LUTrange[1] * multiplier)) + 1 #+1 because python ranges exclude last value stepLength = 2.0 / (endII - startII - 1) if newLUT is None: #create a LUT from scratch (based on contrast and gamma) #rampStep = 2.0/(self.nEntries-1) ramp = numpy.arange(-1.0, 1.0 + stepLength, stepLength) ramp = (ramp * self.contrast + 1.0) / 2.0 #self.LUT will be stored as 0.0:1.0 (gamma-corrected) self.LUT[startII:endII, 0] = copy(ramp) self.LUT[startII:endII, 1] = copy(ramp) self.LUT[startII:endII, 2] = copy(ramp) elif type(newLUT) in [float, int] or (newLUT.shape == ()): self.LUT[startII:endII, 0] = newLUT self.LUT[startII:endII, 1] = newLUT self.LUT[startII:endII, 2] = newLUT elif len(newLUT.shape) == 1: #one dimensional LUT #replicate LUT to other channels #check range is 0:1 if newLUT > 1.0: log.warning('newLUT should be float in range 0.0:1.0') self.LUT[startII:endII, 0] = copy(newLUT.flat) self.LUT[startII:endII, 1] = copy(newLUT.flat) self.LUT[startII:endII, 2] = copy(newLUT.flat) elif len(newLUT.shape) == 2: #one dimensional LUT #use LUT as is #check range is 0:1 if max(max(newLUT)) > 1.0: raise AttributeError, 'newLUT should be float in range 0.0:1.0' self.LUT[startII:endII, :] = newLUT else: log.warning('newLUT can be None, nx1 or nx3') #do gamma correction if necessary if gammaCorrect == True: gamma = self.gamma if hasattr(self.win.monitor, 'lineariseLums'): self.LUT[startII:endII, :] = self.win.monitor.lineariseLums( self.LUT[startII:endII, :], overrideGamma=gamma) #update the bits++ box with new LUT if self.method == 'fast': #get bits into correct order, shape and add to header ramp16 = (self.LUT * (2**16 - 1)).astype( numpy.uint16) #go from ubyte to uint16 ramp16 = numpy.reshape(ramp16, (256, 1, 3)) #set most significant bits self._HEADandLUT[12::2, :, :] = (ramp16[:, :, :] >> 8).astype( numpy.uint8) #set least significant bits self._HEADandLUT[13::2, :, :] = (ramp16[:, :, :] & 255).astype( numpy.uint8) self._HEADandLUTstr = self._HEADandLUT.tostring()
10:DEBUG So setting to DEBUG level will include all possible messages, setting to ERROR will include only the absolutely essential messages. """ globalClock = core.Clock()#if this isn't provided the log times will reflect secs since python started log.setDefaultClock(globalClock)#use this for log.console.setLevel(log.DEBUG)#set the console to receive nearly all messges logDat = log.LogFile('logLastRun.log', filemode='w',#if you set this to 'a' it will append instead of overwriting level=log.WARNING)#errors, data and warnings will be sent to this logfile #the following will go to any files with the appropriate minimum level set log.info('Something fairly unimportant') log.data('Something about our data. Data is likely very important!') log.warning('Handy while building your experiment - highlights possible flaws in code/design') log.error("You might have done something that PsychoPy can't handle! But hopefully this gives you some idea what.") #some things should be logged timestamped on the next video frame #For instance the time of a stimulus appearing is related to the flip: win = visual.Window([400,400]) for n in range(5): win.logOnFlip('frame %i occured' %n, level=log.EXP) if n in [2,4]: win.logOnFlip('an even frame occured', level=log.EXP) win.flip() #LogFiles can also simply receive direct input from the write() method #messages using write() will be sent immediately, and are often not #in correct chronological order with logged messages logDat.write("Testing\n\n")
"""Deprecated - use the monitors package rather than psychopy.calib """ # Part of the PsychoPy library # Copyright (C) 2011 Jonathan Peirce # Distributed under the terms of the GNU General Public License (GPL). from psychopy import log log.warning("psychopy.calib is deprecated - use monitors package instead") from monitors import *
""" globalClock = core.Clock( ) #if this isn't provided the log times will reflect secs since python started log.setDefaultClock(globalClock) #use this for log.console.setLevel(log.DEBUG) #set the console to receive nearly all messges logDat = log.LogFile( 'logLastRun.log', filemode='w', #if you set this to 'a' it will append instead of overwriting level=log.WARNING) #errors, data and warnings will be sent to this logfile #the following will go to any files with the appropriate minimum level set log.info('Something fairly unimportant') log.data('Something about our data. Data is likely very important!') log.warning( 'Handy while building your experiment - highlights possible flaws in code/design' ) log.error( "You might have done something that PsychoPy can't handle! But hopefully this gives you some idea what." ) #some things should be logged timestamped on the next video frame #For instance the time of a stimulus appearing is related to the flip: win = visual.Window([400, 400]) for n in range(5): win.logOnFlip('frame %i occured' % n, level=log.EXP) if n in [2, 4]: win.logOnFlip('an even frame occured', level=log.EXP) win.flip() #LogFiles can also simply receive direct input from the write() method