Image Viewer Example

This SightLab example demonstrates how to present images from a local folder in a virtual environment, either in random or sequential order, with gaze tracking and experiment summary logging.
Overview
Participants view a series of images placed in resources/images/. Each image is displayed for a fixed duration or until a key or trigger is pressed, and is automatically logged for later analysis. The order can be randomized or cycled sequentially.
Prerequisites
- A folder
resources/images/containing.jpg,.png, or.jpegfiles
Configuration Constants
| Constant | Description | Default |
|---|---|---|
IMAGE_POSITION |
Position of image quad in 3D space (x, y, z) | [0, 1.0, 1.0] |
DESKTOP_POSITION |
Position on desktop mirror view | [0, 1.65, 1.1] |
IMAGE_TIME |
Duration (seconds) each image is displayed | 1.5 |
RANDOMIZE |
If True, images are chosen at random; otherwise cycled sequentially |
True |
ENVIRONMENT_OBJECT |
Path to the environment .osgb file |
"resources/environments/whiteroom.osgb" |
USE_PASSTHROUGH |
Enable device-specific passthrough (e.g. Meta Quest) for augmented reality | False |
TRIAL_COUNT |
Total number of trials (images to display) | 12 |
Code Example
import sightlab_utils.sightlab as sl
from sightlab_utils.settings import *
import random
import os
IMAGE_POSITION = [0,1.0,1.0]
#Desktop
DESKTOP_POSITION = [0,1.65,1.1]
IMAGE_TIME = 1.5
RANDOMIZE = True
ENVIRONMENT_OBJECT = "resources/environments/whiteroom.osgb"
USE_PASSTHROUGH = False
TRIAL_COUNT = 12
sightlab = sl.SightLab(gui=False)
if not USE_PASSTHROUGH:
env = vizfx.addChild(ENVIRONMENT_OBJECT)
else:
env = vizfx.addChild('sightlab_resources/environments/empty.osgb')
sightlab.setEnvironment(env)
sightlab.setTrialCount(TRIAL_COUNT)
# Get all image files from the resources/images/ directory
image_folder = "resources/images/"
image_files = [os.path.join(image_folder, f) for f in os.listdir(image_folder) if f.endswith(('.jpg', '.png', '.jpeg'))]
image_index = 0 # Initialize index for sequential selection
def sightLabExperiment():
global image_index # Allow modification of global index
yield viztask.waitEvent(EXPERIMENT_START)
for trial in range(sightlab.getTrialCount()):
yield sightlab.startTrial(startExperimentText="Press Trigger to Start", textContinueEvent="triggerPress")
# Randomly choose an image and position
if RANDOMIZE:
selected_image = random.choice(image_files)
else:
selected_image = image_files[image_index]
image_index = (image_index + 1) % len(image_files) # Loop back after last image
selected_filename = os.path.basename(selected_image) # Extract only the filename
if sightlab.getConfig()in "Desktop":
selected_position = DESKTOP_POSITION
sightlab.setAvatarRightHand(
rightHand=vizfx.addChild(AVATAR_HANDS_RESOURCE_PATH + "/empty.osgb")
)
else:
selected_position = IMAGE_POSITION
if USE_PASSTHROUGH:
import openxr
xr = openxr.getClient()
if sightlab.getConfig() in[ "Meta Quest Pro","Meta Quest 3"]:
passthrough = xr.getPassthroughFB()
elif sightlab.getConfig() == "Varjo":
passthrough = xr.getPassthroughVarjo()
elif sightlab.getConfig() == 'Vive Focus Vision':
passthrough = xr.getPassthroughHTC()
viz.clearcolor(viz.BLACK, 0.0)
if passthrough:
passthrough.setEnabled(True)
# Save data to experiment summary
sightlab.setExperimentSummaryData('image_file', selected_filename)
sightlab.setExperimentSummaryData('image_position', selected_position)
# Display instructions image
pic = viz.addTexture(selected_image)
instructionsImageQuad = viz.addTexQuad(texture=pic, pos=selected_position)
instructionsImageQuad.drawOrder(125)
# Get texture dimensions
tex_w, tex_h, _ = pic.getSize()
# Calculate aspect-ratio-preserving dimensions
target_height = 1.0 # choose whatever height makes sense in meters
if tex_h > 0: # Prevent division by zero
target_width = target_height * (tex_w / float(tex_h))
else:
target_width = target_height # Fallback to square if height is 0
instructionsImageQuad.setScale(target_width, target_height, 1)
# Add the image quad to be tracked in SightLab
sightlab.addSceneObject('image_quad', instructionsImageQuad, gaze=True)
yield viztask.waitTime(IMAGE_TIME)
yield sightlab.endTrial(endExperimentText="Thank You")
instructionsImageQuad.visible(viz.OFF)
viztask.schedule(sightlab.runExperiment)
viztask.schedule(sightLabExperiment)
viz.callback(viz.getEventID('ResetPosition'), sightlab.resetViewPoint)
How It Works
- Initialization: Create a
SightLabinstance and load a.osgbenvironment into the scene. - Trial Loop: Wait for the experiment start event, then iterate through the number of trials.
- Image Selection: Choose an image randomly or in sequence from the specified folder.
- Display & Tracking: Add a textured quad at the appropriate position, register it with SightLab for gaze tracking (
addSceneObject), and display for a fixed duration. - Data Logging: Use
setExperimentSummaryDatato record which image was shown and where. - Cleanup: Hide the quad and proceed to the next trial.
Customization Options
- Timing: Change
IMAGE_TIMEor usetextContinueEventto wait for user input. - Order: Toggle
RANDOMIZEor implement custom ordering logic. - Interactive Events: Add grab tracking by setting
grab=TrueinaddSceneObject(see Code Reference) fileciteturn0file9. - Ratings & Inputs: Insert
sightlab.showRatings()after a trial to collect responses (see Rating Scale example)
Running the Example
- Place your image files in
resources/images/. - Adjust constants at the top of the script to suit your experiment.
- Run in Vizard: open with Vizard 7/8 or use the SightLab GUI for integration.