Scripts and modules to control spatial light modulators (SLMs) using Python.
Note that our convention for dimension order is (channels, height, width).
The main goal of this repository is to provide a common API for different SLMs, allowing them to be used interchangeably for different applications.
Generally speaking there are two different kinds of SLMs depending on the property of the wavefront that one wishes to modulate: amplitude and phase. Note that there do exist SLMs that are able to modulate both. Currently the project supports three different SLM devices.
Amplitude SLMs:
(Note that the amplitude SLMs below are obtained by isolating the LCD layer of off-the-shelf components.)
- Adafruit 1.8" TFT LCD (RGB): wiring instructions here.
- Nokia 5110 LCD (Monochrome): wiring instructions here.
Phase SLMs:
- Holoeye LC 2012: connected via HDMI as an external display. See provided manual.
Generally speaking, phase SLMs can also be used to modulate amplitude when being used in conjunction with an appropriate polarizer/analyzer pair.
For all of the above SLMs, if anything goes wrong with the communication with those devices, the
SLM mask is simply plotted to the screen using matplotlib
instead of being
shown on the devices themselves.
The supported platforms for the different SLMs are summarized below:
- Adafruit 1.8" TFT LCD: Raspberry Pi
- Nokia 5110 LCD: Raspberry Pi
- Holoeye LC 2012: Windows
After cloning this repository, you can install the library and the necessary dependencies with the following commands:
# just for Raspberry Pi!
sudo apt-get -y install libatlas-base-dev
sudo apt-get install fonts-dejavu # previous name of package is `ttf-dejavu`
# installation in a virtual environment is recommended
python3.9 -m venv slm_controller_env # require >= 3.9
source slm_controller_env/bin/activate
pip install -e .
# to run examples
pip install click
You can still try out some features of this library! You won't be able to run any example programs on the physical SLMs but the results will be plotted to your screen instead, as mentioned earlier.
The SDK needed for Holoeye LC
2012 is only supported on Windows operating systems!
Hence using a Raspberry Pi directly is not currently supported, and a device with a live Windows instance is needed to use the Holoeye SLM. In the
future we will check if Windows running inside a container on a Raspberry Pi is
a possibility.
Additionally, you need to perform some manual installation steps, explained in the next section, after having run the installation script above.
In order to use the Holoeye LC 2012 SLM, you will need to manually download Holoeye's SLM Display
SDK and
install it. Note that this step is
not a requirement for the other SLMs to work. As a reminder, unfortunately, only Windows operating systems are currently supported by the SLM Display SDK!
Just
follow the installation instructions. At runtime of this project's code, a
script inside slm_controller/holoeye_sdk
automatically determines the specific path
of your SDK installation.
In examples
you can find various example scripts that show how to control the
supported SLMs.
First, activate the virtual environment:
source slm_controller_env/bin/activate
You can exit the virtual environment by running deactivate
.
This script controls the SLM isolated from the Adafruit 1.8" TFT LCD. It either allows to show an image specified by its path or a random mask. By default RGB is used but you can also use monochrome images instead. A flag allows to define how the aspect ratio is handled. Finally, a last flag gives the option to show a preview of the mask before it is sent to the SLM.
Note that SPI needs to be enabled on the Raspberry Pi.
$ python examples/adafruit_slm.py --help
Usage: adafruit_slm.py [OPTIONS]
Options:
--file_path TEXT Path to image to display, create random mask if None.
--monochrome Show monochrome image, otherwise use RGB.
--not_original_ratio Reshape which can distort the image, otherwise scale
and crop to match original aspect ratio.
--show_preview Show a preview of the mask on the screen.
--help Show this message and exit.
To display a randomly generated grayscale image:
python examples/adafruit_slm.py --monochrome
For a randomly generated RGB image:
python examples/adafruit_slm.py
For an image, you can pass the file path:
python examples/adafruit_slm.py --filepath images/blinka.jpg
The original image will be rescaled and cropped to match the original aspect ratio.
This script controls the Nokia 5110 LCD SLM. Like before, it either allows to show an image specified by its path or a random mask. Note that this SLM only supports monochrome values. A flag allows to define how the aspect ratio is handled and another flag gives the option to show a preview of the mask before it is sent to the SLM.
$ python examples/nokia_slm.py --help
Usage: nokia_slm.py [OPTIONS]
Options:
--file_path TEXT Path to image to display, create random mask if None.
--not_original_ratio Reshape which can distort the image, otherwise scale
and crop to match original aspect ratio.
--show_preview Show a preview of the mask on the screen.
--help Show this message and exit.
This script controls the Holoeye LC 2012 SLM. Again, it either allows to show an image specified by its path or a random mask. Note that only monochrome values are supported by this SLM. A flag allows to define how the aspect ratio is handled. Another float argument permits to set how long the mask is shown for (which is useful in Camera-In-The-Loop applications for mask design). Finally, a last flag gives the option to show a preview of the mask before it is sent to the SLM.
$ python examples/holoeye_slm.py --help
Usage: holoeye_slm.py [OPTIONS]
Options:
--file_path TEXT Path to image to display, create random mask if None.
--not_original_ratio Reshape which can distort the image, otherwise scale
and crop to match original aspect ratio.
--show_time FLOAT Time to show the mask on the SLM, show indefinitely if
None. In that case the user has to kill the script
manually.
--show_preview Show a preview of the mask on the screen.
--help Show this message and exit.
In order to add support for a new SLM, a few steps need to be taken. These are done to avoid hard-coded values, but rather have global variables/definitions that are accessible throughout the whole code base.
- Add SLM configuration in
slm_controller/hardware.py:slm_devices
. - Define a new class in
slm_controller/slm.py
for interfacing with the new SLM component (set parameters, masks, etc.). - Add to factory method
create
inslm_controller/slm.py
for a conveniently one-liner to instantiate an object of the new SLM component.
Currently, we aren't aware of any issues. If you should find any, please let us know.
Here, we list features and directions we want to explore in future work.
- Check if Windows can be run in a container on a Raspberry Pi.