Last active
December 7, 2020 11:32
-
-
Save oeway/7a5313eb4fb7ed09a5f6d60adb561d59 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<config lang="json"> | |
{ | |
"name": "MicroManagerControl", | |
"type": "native-python", | |
"version": "0.1.0", | |
"description": "Microscope control with MicroManager(pymmcore)", | |
"tags": [], | |
"ui": "", | |
"cover": "", | |
"inputs": null, | |
"outputs": null, | |
"flags": [], | |
"icon": "extension", | |
"api_version": "0.1.8", | |
"env": [{"type": "binder", "spec": "imjoy-team/micro-manager-imjoy/master", "skip_requirements": true}], | |
"permissions": [], | |
"requirements": ["repo:https://github.com/imjoy-team/micro-manager-imjoy", "pip:-r micro-manager-imjoy/requirements.txt"], | |
"dependencies": [] | |
} | |
</config> | |
<script lang="python"> | |
import time | |
from imjoy import api | |
import numpy as np | |
import pymmcore | |
import os.path | |
import os | |
import re | |
class DotDict(dict): | |
__getattr__ = dict.__getitem__ | |
__setattr__ = dict.__setitem__ | |
__delattr__ = dict.__delitem__ | |
def to_camel_case(snake_str): | |
components = snake_str.split('_') | |
# We capitalize the first letter of each component except the first one | |
# with the 'title' method and join them together. | |
return components[0] + ''.join(x.title() for x in components[1:]) | |
class MMCoreWrapper(): | |
''' | |
make a wrapper to mmcore so the function calls are more pythonic | |
meaning, all the camel case are converted into snake case | |
for example: mmc.setExposure are converted into mmc.set_exposure | |
''' | |
def __init__(self, obj): | |
self._wrapped_obj = obj | |
def get_tagged_image(self): | |
img = self.get_image() | |
return DotDict({"pix": img, "tags": {"Height": img.shape[0], "Width": img.shape[1]}}) | |
def __getattr__(self, attr): | |
if attr in self.__dict__: | |
return getattr(self, attr) | |
attr = to_camel_case(attr) | |
return getattr(self._wrapped_obj, attr) | |
class MyMicroscope(): | |
async def setup(self): | |
MM_DIR = "./mmcore" | |
MM_CONFIG_FILE = os.path.join(MM_DIR, "MMConfig_demo.cfg") | |
if not os.path.exists(MM_DIR) or not os.path.exists(MM_CONFIG_FILE): | |
MM_DIR = await api.prompt("Please input the root path for your micro-manager installation:", './mmcore') | |
if not os.path.exists(MM_DIR): | |
await api.alert("Invalid micromanager folder.") | |
return | |
else: | |
MM_CONFIG_FILE = await api.prompt("Please input the microscope configuration", os.path.join(MM_DIR, "MMConfig_demo.cfg")) | |
mmc = pymmcore.CMMCore() | |
mmc.setDeviceAdapterSearchPaths([MM_DIR]) | |
mmc.loadSystemConfiguration(MM_CONFIG_FILE) | |
self._core = MMCoreWrapper(mmc) | |
exposure = self._core.get_exposure() | |
api.showMessage('MMcore loaded, exposure: ' + str(exposure)) | |
def snap_image(self): | |
if self._core.is_sequence_running(): | |
self._core.stop_sequence_acquisition() | |
self._core.snap_image() | |
tagged_image = self._core.get_tagged_image() | |
image_array = np.reshape(tagged_image.pix, newshape=[-1, tagged_image.tags['Height'], tagged_image.tags['Width']]) | |
image_array = (image_array/image_array.max()*255).astype('uint8') | |
return image_array | |
def get_image(self): | |
# we can also check remaining with getRemainingImageCount() | |
tagged_image = self._core.get_tagged_image() | |
image_array = np.reshape(tagged_image.pix, newshape=[-1, tagged_image.tags['Height'], tagged_image.tags['Width']]) | |
image_array = (image_array/image_array.max()*255).astype('uint8') | |
return image_array | |
def get_device_properties(self): | |
core = self._core | |
devices = core.get_loaded_devices() | |
if not isinstance(devices, tuple): | |
devices = [devices.get(i) for i in range(devices.size())] | |
device_items = [] | |
for device in devices: | |
props = core.get_device_property_names(device) | |
if not isinstance(props, tuple): | |
props = [props.get(i) for i in range(props.size())] | |
property_items = [] | |
for prop in props: | |
value = core.get_property(device, prop) | |
is_read_only = core.is_property_read_only(device, prop) | |
if core.has_property_limits(device, prop): | |
lower = core.get_property_lower_limit(device, prop) | |
upper = core.get_property_upper_limit(device, prop) | |
allowed = {"type": "range", "min": lower, "max": upper, "readOnly": is_read_only} | |
else: | |
allowed = core.get_allowed_property_values(device, prop) | |
if not isinstance(allowed, tuple): | |
allowed = [allowed.get(i) for i in range(allowed.size())] | |
allowed = {"type": "enum", "options": allowed, "readOnly": is_read_only} | |
property_items.append({"device": device, "name": prop, "value": value, "allowed": allowed}) | |
# print('===>', device, prop, value, allowed) | |
if len(property_items) > 0: | |
device_items.append({"name": device, "value": "{} properties".format(len(props)), "items": property_items}) | |
return device_items | |
async def run(self, ctx): | |
mmcore_api = { | |
"_rintf": True, | |
"snapImage": self.snap_image, | |
"getImage": self.get_image, | |
"getDeviceProperties": self.get_device_properties, | |
"getCameraDevice": self._core.get_camera_device, | |
"setCameraDevice": self._core.set_camera_device, | |
"startContinuousSequenceAcquisition": self._core.start_continuous_sequence_acquisition, | |
"stopSequenceAcquisition": self._core.stop_sequence_acquisition, | |
"setExposure": self._core.set_exposure, | |
"getExposure": self._core.get_exposure, | |
"setProperty": self._core.set_property, | |
"getProperty": self._core.get_property | |
} | |
viewer = await api.createWindow(src="https://gist.github.com/oeway/f59c1d1c49c94a831e5e21ba4c6111dd", data={'mmcore': mmcore_api}) | |
api.export(MyMicroscope()) | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment