def test3(): """ Abandoned!!! """ # _, color = ColorPicker(unit='deg').newcolor(theta=90) color = ColorPicker().Crgb newR = np.array([color[0] - 1.0, color[1], color[2]]) # should be visible on 8-bit display newG = np.array([color[0], color[1] + 1.0, color[2]]) newB = np.array([color[0], color[1], color[2] + 1.0]) testR = np.array([color[0] - 0.5, color[1], color[2]]) # should be only visible on 10-bit display testG = np.array([color[0], color[1] + 0.5, color[2]]) testB = np.array([color[0], color[1], color[2] + 0.5]) allcolor = np.stack([newR, newG, newB, testR, testG, testB]) convertrgb = allcolor / 255 * 2 - 1 # convert from [0, 255] to [-1, 1] convert1023 = allcolor / 255 * 1023 Crgb = list(ColorPicker().Crgb / 255 * 2 - 1) win = visual.Window(fullscr=True, color=Crgb, colorSpace='rgb', unit='pix') # need bpc=(bit, bit, bit), depthBits=bit? size = 0.3 for idx in range(3): colorRect = visual.Rect(win, width=size, height=size, pos=[-0.3, (idx - 1) * 0.3], fillColor=color / 255 * 2 - 1, lineColor=Crgb) newRect = visual.Rect(win, width=size, height=size, pos=[0.3, (idx - 1) * 0.3], fillColor=convertrgb[idx], lineColor=Crgb) testRect = visual.Rect(win, width=size, height=size, pos=[0, (idx - 1) * 0.3], fillColor=convertrgb[idx + 3], lineColor=Crgb) colorRect.draw() newRect.draw() testRect.draw() win.flip() if event.waitKeys(): win.close() return
def test4(): """ Abandoned!!! Temporal changes of colors: should be only visible on 10-bit display """ from psychopy.hardware import keyboard import time Crgb = ColorPicker().Crgb _, color = ColorPicker(unit='deg').newcolor(theta=90) testR = np.array([color[0] - 0.5, color[1], color[2]]) # should be only visible on 10-bit display testG = np.array([color[0], color[1] + 0.5, color[2]]) testB = np.array([color[0], color[1], color[2] + 0.5]) allcolor = np.stack([color, testR, testG, testB]) kb = keyboard.Keyboard() win = visual.Window(unit='pix', size=[800, 800], allowGUI=True, fullscr=True, colorSpace="rgb255", color=Crgb) while True: nowcolor = allcolor[int(np.random.choice(4, 1, replace=False))] rect = visual.Rect(win, width=0.5, height=0.5, pos=[0, 0], fillColorSpace='rgb255', lineColorSpace='rgb255', lineColor=list(Crgb)) rect.fillColor = nowcolor text = visual.TextStim(win, text=str(nowcolor), pos=[0, -0.8], height=0.05) win.mouseVisible = False rect.draw() text.draw() win.flip() kb.clock.reset() if kb.getKeys(): # press any key to quit core.quit() else: time.sleep(1) # change every 3 sec
def rand_color(self, theta, sigma, npatch): # generate color noise noise = np.random.normal(theta, sigma, npatch) color = [ ColorPicker.newcolor(theta, self.param['dlum']) for n in noise ] sml, rgb = zip(*color) return sml, rgb
def __init__(self, subject, par_file, cfg_file, res_dir, priors_file_path): self.subject = subject self.idx = time.strftime("%Y%m%dT%H%M", time.localtime()) # add the current date if not res_dir: res_dir = 'data/' self.res_dir = res_dir self.priors_file_path = priors_file_path self.cfg_file = cfg_file self.cfg = config_tools.read_yml(cfg_file) self.par_file = par_file self.param = config_tools.read_yml(par_file) self.patch_nmb = self.cfg['patch_nmb'] self.trial_nmb = self.cfg['trial_nmb'] self.trial_dur = self.cfg['trial_dur'] self.depthBits = self.cfg['depthBits'] self.ColorPicker = ColorPicker(c=self.param['c'], sscale=self.param['sscale'], unit='deg', depthBits=self.depthBits, subject=self.subject) self.ColorSpace = self.ColorPicker.colorSpace hue_list_path = 'config/colorlist/' + self.subject if not os.path.exists(hue_list_path): self.ColorPicker.gencolorlist(0.2) self.hue_list = hue_list_path + '/hue-list-10bit-res0.2-sub-' + self.subject + '.npy' self.Csml = self.ColorPicker.Csml self.Crgb = self.ColorPicker.Crgb self.mon = monitors.Monitor(name=self.cfg['monitor']['name'], width=self.cfg['monitor']['width'], distance=self.cfg['monitor']['distance']) self.mon.setSizePix((self.cfg['monitor']['size'])) self.win = visual.Window(monitor=self.mon, unit='deg', colorSpace=self.ColorSpace, color=self.Crgb, allowGUI=True, fullscr=True, bpc=(self.depthBits, self.depthBits, self.depthBits), depthBits=self.depthBits)
def run_scrsaver(depthBits): mon = monitors.Monitor(name='VIEWPixx LITE', width=38, distance=57) mon.setSizePix((1920, 1200)) mon.save() # if the monitor info is not saved win = visual.Window(fullscr=True, mouseVisible=False, bpc=(depthBits, depthBits, depthBits), depthBits=depthBits, monitor=mon) kb = keyboard.Keyboard() if depthBits == 8: colorSpace = 'rgb255' elif depthBits == 10: colorSpace = 'rgb' else: raise ValueError("Invalid color depth!") while True: num = np.random.randint(5, high=10) rect = visual.ElementArrayStim(win, units='norm', nElements=num**2, elementMask=None, elementTex=None, sizes=(2 / num, 2 / num), colorSpace=colorSpace) rect.xys = [(x, y) for x in np.linspace(-1, 1, num, endpoint=False) + 1 / num for y in np.linspace(-1, 1, num, endpoint=False) + 1 / num] rect.colors = [ ColorPicker(depthBits=depthBits, unit='deg').newcolor(x)[1] for x in np.random.randint(0, high=360, size=num**2) ] rect.draw() win.mouseVisible = False win.flip() kb.clock.reset() if kb.getKeys(): # press any key to quit core.quit() else: time.sleep(3) # change every 3 sec
class Exp: """ Class for performing the experiment. """ def __init__(self, subject, par_file, cfg_file, res_dir, priors_file_path): self.subject = subject self.idx = time.strftime("%Y%m%dT%H%M", time.localtime()) # add the current date if not res_dir: res_dir = 'data/' self.res_dir = res_dir self.priors_file_path = priors_file_path self.cfg_file = cfg_file self.cfg = config_tools.read_yml(cfg_file) self.par_file = par_file self.param = config_tools.read_yml(par_file) self.patch_nmb = self.cfg['patch_nmb'] self.trial_nmb = self.cfg['trial_nmb'] self.trial_dur = self.cfg['trial_dur'] self.depthBits = self.cfg['depthBits'] self.ColorPicker = ColorPicker(c=self.param['c'], sscale=self.param['sscale'], unit='deg', depthBits=self.depthBits, subject=self.subject) self.ColorSpace = self.ColorPicker.colorSpace hue_list_path = 'config/colorlist/' + self.subject if not os.path.exists(hue_list_path): self.ColorPicker.gencolorlist(0.2) self.hue_list = hue_list_path + '/hue-list-10bit-res0.2-sub-' + self.subject + '.npy' self.Csml = self.ColorPicker.Csml self.Crgb = self.ColorPicker.Crgb self.mon = monitors.Monitor(name=self.cfg['monitor']['name'], width=self.cfg['monitor']['width'], distance=self.cfg['monitor']['distance']) self.mon.setSizePix((self.cfg['monitor']['size'])) self.win = visual.Window(monitor=self.mon, unit='deg', colorSpace=self.ColorSpace, color=self.Crgb, allowGUI=True, fullscr=True, bpc=(self.depthBits, self.depthBits, self.depthBits), depthBits=self.depthBits) """stimulus features""" def patch_ref(self, theta): # reference patches ref = visual.Circle(win=self.win, units='deg', radius=self.cfg['ref_size'], fillColorSpace=self.ColorSpace, lineColorSpace=self.ColorSpace) ref.fillColor = self.ColorPicker.newcolor(theta, self.param['dlum'])[1] ref.lineColor = ref.fillColor return ref def patch_stim(self): # standard and test stimuli patch = visual.ElementArrayStim(win=self.win, units='deg', fieldSize=self.cfg['field_size'], nElements=self.patch_nmb, elementMask='circle', elementTex=None, sizes=self.cfg['patch_size'], colorSpace=self.ColorSpace) return patch def patch_pos(self, xlim, ylim): # position of standard and test stimuli n = int(np.sqrt(self.patch_nmb)) pos = [[x, y] for x in np.linspace(xlim[0], xlim[1], n) for y in np.linspace(ylim[0], ylim[1], n)] return pos """color noise & noise conditions""" def rand_color(self, theta, sigma, npatch): # generate color noise noise = np.random.normal(theta, sigma, npatch) color = [ ColorPicker.newcolor(theta, self.param['dlum']) for n in noise ] sml, rgb = zip(*color) return sml, rgb def choose_con(self, standard, test): # choose noise condition sColor = None tColor = None if self.param['noise_condition'] == 'L-L': # low - low noise sColor = self.ColorPicker.newcolor(standard, self.param['dlum'])[1] tColor = self.ColorPicker.newcolor(test, self.param['dlum'])[1] elif self.param[ 'noise_condition'] == 'L-H': # low - high noise: only test stimulus has high noise sColor = self.ColorPicker.newcolor(standard, self.param['dlum'])[1] tColor = self.rand_color(test, self.param['sigma'], self.patch_nmb)[1] elif self.param['noise_condition'] == 'H-H': # high - high noise sColor = self.rand_color(standard, self.param['sigma'], self.patch_nmb)[1] tColor = self.rand_color(test, self.param['sigma'], self.patch_nmb)[1] else: print("No noise condition corresponds to the input!") return sColor, tColor """tool fucntion""" def take_closest(self, arr, val): """ Assumes arr is sorted. Returns closest value to val (could be itself). If two numbers are equally close, return the smallest number. """ pos = bisect_left(arr, val) if pos == 0: return arr[0] if pos == len(arr): return arr[-1] before = arr[pos - 1] after = arr[pos] if after - val < val - before: return after else: return before """main experiment""" def run_trial(self, rot, cond, count): # set two reference left = cond['leftRef'] right = cond['rightRef'] leftRef = self.patch_ref(left) leftRef.pos = self.cfg['leftRef.pos'] rightRef = self.patch_ref(right) rightRef.pos = self.cfg['rightRef.pos'] # set colors of two stimuli standard = cond['standard'] # standard should be fixed test = standard + rot sPatch = self.patch_stim() tPatch = self.patch_stim() sPatch.colors, tPatch.colors = self.choose_con(standard, test) # randomly assign patch positions: upper (+) or lower (-) patchpos = [self.cfg['standard.ylim'], self.cfg['test.ylim']] rndpos = patchpos.copy() np.random.shuffle(rndpos) sPatch.xys = self.patch_pos(self.cfg['standard.xlim'], rndpos[0]) tPatch.xys = self.patch_pos(self.cfg['test.xlim'], rndpos[1]) # fixation cross fix = visual.TextStim(self.win, text="+", units='deg', pos=[0, 0], height=0.4, color='black', colorSpace=self.ColorSpace) # number of trial num = visual.TextStim(self.win, text="trial " + str(count), units='deg', pos=[12, -10], height=0.4, color='black', colorSpace=self.ColorSpace) trial_time_start = time.time() # first present references for 0.5 sec fix.draw() num.draw() leftRef.draw() rightRef.draw() self.win.flip() core.wait(1.0) # then present the standard and the test stimuli as well for fix.draw() num.draw() leftRef.draw() rightRef.draw() sPatch.draw() tPatch.draw() self.win.flip() if self.trial_dur: # show stimuli for some time core.wait(self.trial_dur) # refresh the window, clear references and stimuli num.draw() self.win.flip() # get response judge = None while judge is None: allkeys = event.waitKeys() for key in allkeys: if (key == 'left' and rot * rndpos[0][0] > 0) or ( key == 'right' and rot * rndpos[0][0] < 0): judge = 1 # correct thiskey = key elif (key == 'left' and rot * rndpos[0][0] < 0) or ( key == 'right' and rot * rndpos[0][0] > 0): judge = 0 # incorrect thiskey = key elif key == 'escape': breakinfo = 'userbreak' # xrl.add_break(breakinfo) config_tools.write_xrl(self.subject, break_info='userbreak') core.quit() trial_time = time.time() - trial_time_start return judge, thiskey, trial_time def run_session(self): path = os.path.join(self.res_dir, self.subject) if not os.path.exists(path): os.makedirs(path) # welcome msg = visual.TextStim(self.win, 'Welcome!' + '\n' + ' Press any key to start this session :)', color='black', units='deg', pos=(0, 0), height=0.8) msg.draw() self.win.mouseVisible = False self.win.flip() event.waitKeys() # read staircase parameters conditions = [ dict({'stimulus': key}, **value) for key, value in self.param.items() if key.startswith('stimulus') ] if conditions[0]['stairType'] == 'simple': stairs = data.MultiStairHandler(stairType='simple', conditions=conditions, nTrials=self.trial_nmb, method='sequential') elif conditions[0]['stairType'] == 'quest': stairs = [] for cond in conditions: if self.priors_file_path: prior_file = self.priors_file_path + cond[ 'label'] + '.psydat' print(prior_file) prior_handler = misc.fromFile(prior_file) else: prior_handler = None cur_handler = data.QuestHandler(cond['startVal'], cond['startValSd'], pThreshold=cond['pThreshold'], nTrials=self.trial_nmb, minVal=cond['min_val'], maxVal=cond['max_val'], staircase=prior_handler, extraInfo=cond) stairs.append(cur_handler) elif conditions[0]['stairType'] == 'psi': stairs = [] for cond in conditions: if self.priors_file_path: prior_file = self.priors_file_path + cond['label'] + '.npy' else: prior_file = None print(prior_file) cur_handler = data.PsiHandler(nTrials=self.trial_nmb, intensRange=[1, 10], alphaRange=[1, 10], betaRange=[0.01, 10], intensPrecision=0.1, alphaPrecision=0.1, betaPrecision=0.01, delta=0.01, extraInfo=cond, prior=prior_file, fromFile=(prior_file is not None)) stairs.append(cur_handler) # write configuration files xpp = config_tools.WriteXpp(self.subject, self.idx) xpp_file = xpp.head(self.cfg_file, self.par_file) config_tools.write_xrl(self.subject, cfg_file=self.cfg_file, par_file=self.par_file, xpp_file=xpp_file) xlsname = path + '/' + self.idx + self.param[ 'noise_condition'] + '.xlsx' """ running staircase """ if isinstance(stairs, data.MultiStairHandler): # start running the staircase using the MultiStairHandler for the up-down method count = 0 for rot, cond in stairs: count += 1 direction = (-1)**(cond['label'].endswith('m') ) # direction as -1 if for minus stim rot = rot * direction # rotation for this trial judge, thiskey, trial_time = self.run_trial(rot, cond, count) # check whether the theta is valid - if not, the rotation given by staircase should be corrected by # realizable values valid_theta = np.round(np.load(self.hue_list), decimals=1) disp_standard = self.take_closest( valid_theta, cond['standard']) # theta actually displayed stair_test = cond[ 'standard'] + stairs._nextIntensity * direction if stair_test < 0: stair_test += 360 disp_test = self.take_closest(valid_theta, stair_test) disp_intensity = disp_test - disp_standard if disp_intensity > 300: disp_intensity = (disp_test + disp_standard) - 360 stairs.addResponse(judge, abs(disp_intensity)) xpp.task(count, cond, rot, float(disp_intensity), judge, trial_time) event.waitKeys(keyList=[ thiskey ]) # press the response key again to start the next trial config_tools.write_xrl(self.subject, xls_file=xlsname) stairs.saveAsExcel(xlsname) # save results psydat_file_path = os.path.join( path, "psydat", self.idx + self.param['condition'] + '.psydat') # save the handler into a psydat-file misc.toFile(psydat_file_path, stairs) elif isinstance(stairs, list): # start running the staircase using custom interleaving stairs for the quest and psi methods count = 0 rot_all = [] rot_all_disp = [] judge_all = [] estimates = {s.extraInfo['label']: [] for s in stairs} for trial_n in range(self.trial_nmb): for handler_idx, cur_handler in enumerate(stairs): count += 1 direction = (-1)**( cur_handler.extraInfo['label'].endswith('m') ) # direction as -1 if for minus stim rot = next( cur_handler) * direction # rotation for this trial if len(rot_all) <= handler_idx: rot_all.append([]) rot_all[handler_idx].append(rot) cond = cur_handler.extraInfo judge, thiskey, trial_time = self.run_trial( rot, cond, count) if len(judge_all) <= handler_idx: judge_all.append([]) judge_all[handler_idx].append(judge) valid_theta = np.round(np.load(self.hue_list), decimals=1) disp_standard = self.take_closest(valid_theta, cond['standard']) stair_test = cond[ 'standard'] + direction * cur_handler._nextIntensity # calculated test hue for this trial - although it is called nextIntensity if stair_test < 0: stair_test += 360 disp_test = self.take_closest( valid_theta, stair_test) # actual displayed test hue for this trial disp_intensity = disp_test - disp_standard # actual displayed hue difference if disp_intensity > 300: disp_intensity = (disp_test + disp_standard) - 360 cur_handler.addResponse( judge, abs(disp_intensity) ) # only positive number is accepted by addResponse if len(rot_all_disp ) <= handler_idx: # add displayed intensities rot_all_disp.append([]) rot_all_disp[handler_idx].append(disp_intensity) if isinstance(cur_handler, data.PsiHandler): estimates[cur_handler.extraInfo['label']].append([ cur_handler.estimateLambda()[0], # location cur_handler.estimateLambda768()[1], # slope cur_handler.estimateThreshold(0.75) ]) elif isinstance(cur_handler, data.QuestHandler): estimates[cur_handler.extraInfo['label']].append([ cur_handler.mean(), cur_handler.mode(), cur_handler.quantile(0.5) ]) xpp.task(count, cond, rot, float(disp_intensity), judge, trial_time) event.waitKeys(keyList=[ thiskey ]) # press the response key again to start the next trial config_tools.write_xrl(self.subject, xls_file=xlsname) # save results in xls-file workbook = xlsxwriter.Workbook(xlsname) for handler_idx, cur_handler in enumerate(stairs): worksheet = workbook.add_worksheet( cur_handler.extraInfo['label']) worksheet.write('A1', 'Reversal Intensities') worksheet.write('B1', 'Reversal Indices') worksheet.write('C1', 'All Intensities') worksheet.write('D1', 'All Responses') for i in range(len(rot_all[handler_idx])): # worksheet.write('C' + str(i + 2), rot_all[handler_idx][i]) worksheet.write('C' + str(i + 2), rot_all_disp[handler_idx][i]) worksheet.write('D' + str(i + 2), judge_all[handler_idx][i]) workbook.close() # print resulting parameters and estimates for each step res_file_path = os.path.join(path, self.idx + '_estimates.csv') res_writer = csv.writer(open(res_file_path, 'w')) for res_stim, res_vals in estimates.items(): for res_val_id, res_val in enumerate(res_vals): res_writer.writerow([ res_stim, res_val_id, res_val[0], res_val[1], res_val[2] ]) # save each handler into a psydat-file and save posterior into a numpy-file for cur_handler in stairs: file_name = os.path.join( path, self.idx + self.param['noise_condition'] + cur_handler.extraInfo['label']) misc.toFile(file_name + '.psydat', cur_handler) if isinstance(cur_handler, data.PsiHandler): cur_handler.savePosterior(file_name + '.npy')
def test2(): """ Abandoned!!! """ _, color = ColorPicker().newcolor(theta=90, unit='deg') newR = np.array([color[0] - 1.0, color[1], color[2]]) # should be visible on 8-bit display newG = np.array([color[0], color[1] + 1.0, color[2]]) newB = np.array([color[0], color[1], color[2] + 1.0]) testR = np.array([color[0] - 0.5, color[1], color[2]]) # should be only visible on 10-bit display testG = np.array([color[0], color[1] + 0.5, color[2]]) testB = np.array([color[0], color[1], color[2] + 0.5]) allcolor = np.stack([newR, newG, newB, testR, testG, testB]) convertrgb = allcolor / 255 * 2 - 1 # convert from [0, 255] to [-1, 1] convert1023 = allcolor / 255 * 1023 Crgb = list(ColorPicker().Crgb / 255 * 2 - 1) win = visual.Window( [1000, 1000], color=Crgb, colorSpace='rgb') # need bpc=(bit, bit, bit), depthBits=bit? for idx in range(3): colorRect = visual.Rect(win, width=0.2, height=0.2, pos=[-0.6, (idx - 1) * 0.5], fillColor=color / 255 * 2 - 1, lineColor=Crgb) colorText = visual.TextStim(win, text=str(np.round(color, decimals=2)), pos=[-0.6, (idx - 1) * 0.5 + 0.2], height=0.05) colorText1023 = visual.TextStim(win, text=str( np.round(color / 255 * 1023, decimals=2)), pos=[-0.6, (idx - 1) * 0.5 + 0.3], height=0.05) newRect = visual.Rect(win, width=0.2, height=0.2, pos=[0.6, (idx - 1) * 0.5], fillColor=convertrgb[idx], lineColor=Crgb) newText = visual.TextStim(win, text=str(np.round(allcolor[idx], decimals=2)), pos=[0.6, (idx - 1) * 0.5 + 0.2], height=0.05) newText1023 = visual.TextStim(win, text=str( np.round(convert1023[idx], decimals=2)), pos=[0.6, (idx - 1) * 0.5 + 0.3], height=0.05) testRect = visual.Rect(win, width=0.2, height=0.2, pos=[0, (idx - 1) * 0.5], fillColor=convertrgb[idx + 3], lineColor=Crgb) testText = visual.TextStim(win, text=str( np.round(allcolor[idx + 3], decimals=2)), pos=[0, (idx - 1) * 0.5 + 0.2], height=0.05) testText1023 = visual.TextStim(win, text=str( np.round(convert1023[idx + 3], decimals=2)), pos=[0, (idx - 1) * 0.5 + 0.3], height=0.05) colorRect.draw() colorText.draw() colorText1023.draw() newRect.draw() newText.draw() newText1023.draw() testRect.draw() testText.draw() testText1023.draw() win.flip() if event.waitKeys(): win.close() return
def test6_pyglet(bit): """ Abandoned!!! Not dynamic yet!!! Same test as test6, but using pyglet directly instead of Psychopy """ import pyglet from pyglet.gl import gl from psychopy.hardware import keyboard import time kb = keyboard.Keyboard() # colors def changegun(c, d): new = c.astype(float) new[0] = new[0] + d # R new[1] = new[1] - d # G new[2] = new[2] - d # B return new Crgb = ColorPicker().Crgb color = Crgb.astype(int) newcolor1 = changegun(color, 1) newcolor2 = changegun(color, -1) color1_1 = [color, color, color, newcolor1, newcolor1, newcolor1] # upper in condition 1 color1_2 = [color, color, color, newcolor2, newcolor2, newcolor2] # upper in condition 2 color2_1 = [ changegun(color, 0.), changegun(color, 0.2), changegun(color, 0.4), changegun(color, 0.6), changegun(color, 0.8), changegun(color, 1.0) ] color2_2 = [ changegun(color, 0.), changegun(color, -0.2), changegun(color, -0.4), changegun(color, -0.6), changegun(color, -0.8), changegun(color, -1.0) ] # convert to [0, 1] Crgb = Crgb / (2**8 - 1) rgb1_1 = [x / (2**8 - 1) for x in color1_1] # upper in condition 1 rgb1_2 = [x / (2**8 - 1) for x in color1_2] # upper in condition 2 rgb2_1 = [x / (2**8 - 1) for x in color2_1] rgb2_2 = [x / (2**8 - 1) for x in color2_2] background = (Crgb[0], Crgb[1], Crgb[2], 1) # RGB and alpha value # set up context and window # platform = pyglet.window.get_platform() # display = platform.get_default_display() # screen = display.get_default_screen() # template = pyglet.gl.Config(red_size=bit, green_size=bit, blue_size=bit) # config = screen.get_best_config(template) # context = config.create_context(None) # config = pyglet.gl.Config(red_size=bit, green_size=bit, blue_size=bit) config = pyglet.gl.Config(buffer_size=bit * 3) winsize = 1900 window = pyglet.window.Window(caption='OpenGL', resizable=True, config=config, fullscreen=True) frameN = 0 while True: if frameN % 2: rgb1 = rgb1_1 rgb2 = rgb2_1 color1 = color1_1 color2 = color2_1 else: rgb1 = rgb1_2 rgb2 = rgb2_2 color1 = color1_2 color2 = color2_2 @window.event def on_draw(): # clears the background with the background color gl.glClearColor(*background) gl.glClear(gl.GL_COLOR_BUFFER_BIT) # draw in a loop boundary = winsize - 100 gap = (winsize - boundary) / 2 i_width = boundary / len(rgb1) i_height = boundary / 2 # the first line for idx, rgb in enumerate(rgb1): gl.glColor3f(*rgb) gl.glBegin( gl.GL_QUADS ) # start drawing a rectangle in counter-clockwise (CCW) order gl.glVertex2f(gap + idx * i_width, gap + i_height) # bottom left point gl.glVertex2f(gap + (idx + 1) * i_width, gap + i_height) # bottom right point gl.glVertex2f(gap + (idx + 1) * i_width, gap + boundary) # top right point gl.glVertex2f(gap + idx * i_width, gap + boundary) # top left point gl.glEnd() label = pyglet.text.Label(str(color1[idx]), font_size=7, x=gap + idx * i_width, y=gap + boundary + 20) label.draw() # # # the second line for idx, rgb in enumerate(rgb2): gl.glColor3f(*rgb) gl.glBegin( gl.GL_QUADS ) # start drawing a rectangle in counter-clockwise (CCW) order gl.glVertex2f(gap + idx * i_width, gap) # bottom left point gl.glVertex2f(gap + (idx + 1) * i_width, gap) # bottom right point gl.glVertex2f(gap + (idx + 1) * i_width, gap + i_height) # top right point gl.glVertex2f(gap + idx * i_width, gap + i_height) # top left point gl.glEnd() label = pyglet.text.Label(str(color2[idx]), font_size=7, x=gap + idx * i_width, y=gap - 20) label.draw() frameN += 1 pyglet.app.run() kb.clock.reset() if kb.getKeys(): # press any key to quit core.quit() else: time.sleep(1) # change every 1 sec
def test5_pyglet(bit): """ Same test as test5, but using pyglet directly instead of Psychopy TODO: adjust the size on VIEWPixx """ import pyglet from pyglet.gl import gl # colors def changegun(c, d): new = c.astype(float) new[0] = new[0] + d # R new[1] = new[1] - d # G new[2] = new[2] - d # B return new Crgb = ColorPicker().Crgb color = Crgb.astype(int) color1 = [ color, color, color, changegun(color, 1.), changegun(color, 1.), changegun(color, 1.) ] color2 = [ color, changegun(color, .2), changegun(color, .4), changegun(color, .6), changegun(color, .8), changegun(color, 1.) ] # convert to [0, 1] Crgb = Crgb / (2**8 - 1) rgb1 = [x / (2**8 - 1) for x in color1] rgb2 = [x / (2**8 - 1) for x in color2] background = (Crgb[0], Crgb[1], Crgb[2], 1) # RGB and alpha value # set up context and window # config = pyglet.gl.Config(red_size=bit, gre""" rewrite the test5 with pyglet"""en_size=bit, blue_size=bit) config = pyglet.gl.Config(buffer_size=bit * 4) winsize = 1200 window = pyglet.window.Window(caption='OpenGL', resizable=True, config=config, fullscreen=True) @window.event def on_draw(): # clears the background with the background color gl.glClearColor(*background) gl.glClear(gl.GL_COLOR_BUFFER_BIT) # draw in a loop boundary = winsize - 200 gap = (winsize - boundary) / 2 i_width = boundary / len(rgb1) i_height = boundary / 2 # the first line for idx, rgb in enumerate(rgb1): gl.glColor3f(*rgb) gl.glBegin( gl.GL_QUADS ) # start drawing a rectangle in counter-clockwise (CCW) order gl.glVertex2f(gap + idx * i_width, gap + i_height) # bottom left point gl.glVertex2f(gap + (idx + 1) * i_width, gap + i_height) # bottom right point gl.glVertex2f(gap + (idx + 1) * i_width, gap + boundary) # top right point gl.glVertex2f(gap + idx * i_width, gap + boundary) # top left point gl.glEnd() label = pyglet.text.Label(str(color1[idx]), font_size=10, x=gap + idx * i_width, y=gap + boundary + 20) label.draw() # # # the second line for idx, rgb in enumerate(rgb2): gl.glColor3f(*rgb) gl.glBegin( gl.GL_QUADS ) # start drawing a rectangle in counter-clockwise (CCW) order gl.glVertex2f(gap + idx * i_width, gap) # bottom left point gl.glVertex2f(gap + (idx + 1) * i_width, gap) # bottom right point gl.glVertex2f(gap + (idx + 1) * i_width, gap + i_height) # top right point gl.glVertex2f(gap + idx * i_width, gap + i_height) # top left point gl.glEnd() label = pyglet.text.Label(str(color2[idx]), font_size=10, x=gap + idx * i_width, y=gap - 20) label.draw() pyglet.app.run()
def test6(bit, diff=1): """ Dynamic version of test5. :param bit: 8 or 10 :param diff: difference in RGB255 scale :return: """ from psychopy.hardware import keyboard import time # mon = monitors.Monitor(name='VIEWPixx LITE', width=38, distance=57) # color = ColorPicker().Crgb color = color.astype(int) def changegun(c, d): new = c.astype(float) new[0] = new[0] + d # R new[1] = new[1] - d # G new[2] = new[2] - d # B return new newcolor1 = changegun(color, diff) newcolor2 = changegun(color, -diff) color1_1 = [color, color, color, newcolor1, newcolor1, newcolor1] # upper in condition 1 color1_2 = [color, color, color, newcolor2, newcolor2, newcolor2] # upper in condition 2 color2_1 = [ changegun(color, 0.), changegun(color, 0.2), changegun(color, 0.4), changegun(color, 0.6), changegun(color, 0.8), changegun(color, 1.0) ] color2_2 = [ changegun(color, 0.), changegun(color, -0.2), changegun(color, -0.4), changegun(color, -0.6), changegun(color, -0.8), changegun(color, -1.0) ] # convert to [-1, 1] Crgb = ColorPicker().Crgb / (2**8 - 1) * 2 - 1 rgb1_1 = [x / (2**8 - 1) * 2 - 1 for x in color1_1] # upper in condition 1 rgb1_2 = [x / (2**8 - 1) * 2 - 1 for x in color1_2] # upper in condition 2 rgb2_1 = [x / (2**8 - 1) * 2 - 1 for x in color2_1] rgb2_2 = [x / (2**8 - 1) * 2 - 1 for x in color2_2] win = visual.Window(fullscr=True, color=Crgb, colorSpace='rgb', bpc=(bit, bit, bit), depthBits=bit, units='norm') kb = keyboard.Keyboard() boundary = 0.8 num = len(color1_1) colorbar1 = visual.ElementArrayStim(win, units='norm', nElements=num, elementMask=None, elementTex=None, sizes=(boundary * 2 / num, boundary / 2), colorSpace='rgb') colorbar2 = visual.ElementArrayStim(win, units='norm', nElements=num, elementMask=None, elementTex=None, sizes=(boundary * 2 / num, boundary / 2), colorSpace='rgb') colorbar1.xys = [ (x, boundary / 4) for x in np.linspace(-boundary, boundary, num, endpoint=False) + boundary / num ] colorbar2.xys = [ (x, -boundary / 4) for x in np.linspace(-boundary, boundary, num, endpoint=False) + boundary / num ] frameN = 0 while True: if frameN % 2: rgb1 = rgb1_1 rgb2 = rgb2_1 color1 = color1_1 color2 = color2_1 else: rgb1 = rgb1_2 rgb2 = rgb2_2 color1 = color1_2 color2 = color2_2 colorbar1.colors = rgb1 colorbar2.colors = rgb2 colorbar1.draw() colorbar2.draw() for idx, x in enumerate( np.linspace(-boundary, boundary, num, endpoint=False) + boundary / num): text1 = visual.TextStim( win, text=str(color1[idx]), pos=(x, 0.7), height=0.028) # position set in weird way but works text2 = visual.TextStim(win, text=str(color2[idx]), pos=(x, -0.7), height=0.028) text1.draw() text2.draw() win.flip() frameN += 1 kb.clock.reset() if kb.getKeys(): # press any key to quit core.quit() else: time.sleep(1) # change every 1 sec
def test5(bit, diff=1): """ Show static 6 x 2 colored patches: - 1st row with 1-bit step in RGB255 - 2nd row with 0.2-bit step -- should be distinguishable on 10-bit :param bit: 8 or 10 :param diff: difference in RGB255 scale :return: """ color = ColorPicker().Crgb color = color.astype(int) def changegun(c, d): new = c.astype(float) new[0] = new[0] + d # R new[1] = new[1] - d # G new[2] = new[2] - d # B return new newcolor = changegun(color, diff) color1 = [color, color, color, newcolor, newcolor, newcolor] # upper row color2 = [ changegun(color, 0.), changegun(color, 0.2), changegun(color, 0.4), changegun(color, 0.6), changegun(color, 0.8), changegun(color, 1.0) ] # lower row # convert to [-1, 1] Crgb = ColorPicker().Crgb / (2**8 - 1) * 2 - 1 rgb1 = [x / (2**8 - 1) * 2 - 1 for x in color1] rgb2 = [x / (2**8 - 1) * 2 - 1 for x in color2] win = visual.Window(fullscr=True, color=Crgb, colorSpace='rgb', bpc=(bit, bit, bit), depthBits=bit) boundary = 0.8 num = len(color1) colorbar1 = visual.ElementArrayStim(win, units='norm', nElements=num, elementMask=None, elementTex=None, sizes=(boundary * 2 / num, boundary / 2), colorSpace='rgb') colorbar2 = visual.ElementArrayStim(win, units='norm', nElements=num, elementMask=None, elementTex=None, sizes=(boundary * 2 / num, boundary / 2), colorSpace='rgb') colorbar1.xys = [ (x, boundary / 4) for x in np.linspace(-boundary, boundary, num, endpoint=False) + boundary / num ] colorbar2.xys = [ (x, -boundary / 4) for x in np.linspace(-boundary, boundary, num, endpoint=False) + boundary / num ] colorbar1.colors = rgb1 colorbar2.colors = rgb2 print(colorbar2.colors) colorbar1.draw() colorbar2.draw() for idx, x in enumerate( np.linspace(-boundary, boundary, num, endpoint=False) + boundary / num): text1 = visual.TextStim( win, text=str(color1[idx]), pos=(x, 0.7), height=0.028) # position set in weird way but works text2 = visual.TextStim(win, text=str(color2[idx]), pos=(x, -0.7), height=0.028) text1.draw() text2.draw() win.flip() if event.waitKeys(): win.close() return
def test1(bit): """ Abandoned!!! for test1(8), color should change every 3 steps; for test1(10), color should change every step """ # visual.backends.getBackend(win=self, # bpc=bpc, # depthBits=depthBits, # stencilBits=stencilBits, # *args, **kwargs) # bpc: # array_like or int Bits per color for the back buffer. # Valid values depend on the output color depth of the display. # By default, it is assumed the display has 8 - bits per color(8, 8, 8) # depthBits: # int, Back buffer depth bits. Default is 8. # stencilBits: # int Back buffer stencil bits. Default is 8. rlist = np.linspace(0.5, 0.6, 100, endpoint=True) # each step is 0.001 in [0, 1] scale; # so we expect color changes every step for 10-bit (1/1023 = 0.0009), but changes every 3 steps for 8-bit (1/255 = 0.0039) glist = np.linspace(0.4, 0.5, 100, endpoint=True) blist = np.linspace(0.8, 0.9, 100, endpoint=True) rgb = np.squeeze(np.dstack((rlist, glist, blist))) colorspace = None Crgb = ColorPicker().Crgb / 255 if bit == 10: colorspace = 'rgb' rgb = rgb * 2 - 1 # converted to [-1, 1] Crgb = Crgb * 2 - 1 elif bit == 8: colorspace = 'rgb255' rgb = rgb * 255 # converted to [0, 255] Crgb = Crgb * 255 win = visual.Window([600, 600], color=list(Crgb), colorSpace=colorspace, bpc=(bit, bit, bit), depthBits=bit) text = visual.TextStim(win, text=str(bit) + ' bit', pos=[-0.7, 0.95], height=0.03) text.draw() num = 40 selrgb = rgb[0:num] boundary = 0.8 colorbar = visual.ElementArrayStim(win, units='norm', nElements=num, elementMask=None, elementTex=None, sizes=(boundary * 2 / num, boundary), colorSpace=colorspace) colorbar.xys = [ (x, 0) for x in np.linspace(-boundary, boundary, num, endpoint=False) + boundary / num ] colorbar.colors = selrgb colorbar.draw() win.flip() if event.waitKeys(): win.close() return