Skip to content

Commit

Permalink
Merge pull request #685 from henrypinkard/acqengpy
Browse files Browse the repository at this point in the history
Python backend + new APIs
  • Loading branch information
henrypinkard authored Sep 7, 2023
2 parents 0a5fd4e + 43ccdfe commit 4121e08
Show file tree
Hide file tree
Showing 75 changed files with 3,912 additions and 962 deletions.
14 changes: 7 additions & 7 deletions docs/source/application_notebooks/PSF_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
import napari
from napari.qt import thread_worker
from magicgui import magicgui
from pycromanager import Acquisition, multi_d_acquisition_events
from pycromanager import JavaBackendAcquisition, multi_d_acquisition_events
# open napari in an extra window, only needed for jupyter notebooks
#%gui qt

Expand Down Expand Up @@ -166,9 +166,9 @@ def acquire_data(z_range):
""" micro-manager data acquisition. Creates acquisition events for z-stack.
This example: use custom events, not multi_d_acquisition because the
z-stage is not run from micro-manager but controlled via external DAQ."""
with Acquisition(directory=None, name=None,
show_display=True,
image_process_fn = grab_image) as acq:
with JavaBackendAcquisition(directory=None, name=None,
show_display=True,
image_process_fn = grab_image) as acq:
events = []
for index, z_um in enumerate(np.linspace(z_range[0], z_range[1], z_range[2])):
evt = {"axes": {"z_ext": index}, "z_ext": z_um}
Expand All @@ -182,9 +182,9 @@ def acquire_multid(z_range):
from micro-manager.
Unless hardware triggering is set up in micro-manager, this will be fairly slow:
micro-manager does not sweep the z-stage, but acquires plane by plane. """
with Acquisition(directory=None, name=None,
show_display=False,
image_process_fn = grab_image) as acq:
with JavaBackendAcquisition(directory=None, name=None,
show_display=False,
image_process_fn = grab_image) as acq:
events = multi_d_acquisition_events(z_start=z_range[0], z_end=z_range[1],
z_step=(z_range[1]-z_range[0])/(z_range[2]-1))
acq.acquire(events)
Expand Down
6 changes: 3 additions & 3 deletions java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.micro-manager.pycro-manager</groupId>
<artifactId>PycroManagerJava</artifactId>
<version>0.43.1</version>
<version>0.44.0</version>
<packaging>jar</packaging>
<name>Pycro-Manager Java</name>
<description>The Java components of Pycro-Manager</description>
Expand Down Expand Up @@ -54,7 +54,7 @@
<dependency>
<groupId>org.micro-manager.acqengj</groupId>
<artifactId>AcqEngJ</artifactId>
<version>0.32.2</version>
<version>0.33.0</version>
</dependency>
<dependency>
<groupId>org.micro-manager.ndviewer</groupId>
Expand All @@ -64,7 +64,7 @@
<dependency>
<groupId>org.micro-manager.ndtiffstorage</groupId>
<artifactId>NDTiffStorage</artifactId>
<version>2.14.0</version>
<version>2.15.1</version>
</dependency>
</dependencies>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ protected ExploreMouseListener createMouseListener() {
return new ExploreMouseListener(acq_, display_, logger_);
}

public void putImage(final TaggedImage taggedImg) {
public Object putImage(final TaggedImage taggedImg) {

String channelName = (String) AcqEngMetadata.getAxes(taggedImg.tags).get("channel");
boolean newChannel = !channelNames_.contains(channelName);
Expand Down Expand Up @@ -399,6 +399,7 @@ public void run() {
}
});
}
return null;
}


Expand Down
10 changes: 6 additions & 4 deletions java/src/main/java/org/micromanager/internal/zmq/ZMQServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class ZMQServer extends ZMQSocketWrapper {
private static Function<Class, Object> classMapper_;
private static ZMQServer mainServer_;
static boolean debug_ = false;
private Consumer<String> debugLogger_;
private static Consumer<String> debugLogger_;

//for testing
// public static void main(String[] args) {
Expand Down Expand Up @@ -76,6 +76,9 @@ public ZMQServer(Collection<ClassLoader> cls, Function<Class, Object> classMappe
public ZMQServer(Collection<ClassLoader> cls, Function<Class, Object> classMapper,
String[] excludePaths, Consumer<String> debugLogger, int port) throws URISyntaxException, UnsupportedEncodingException {
super(SocketType.REP, port);
mainServer_ = this;
debugLogger_ = debugLogger;

classMapper_ = classMapper;
util_ = new ZMQUtil(cls, excludePaths);

Expand All @@ -89,7 +92,6 @@ public ZMQServer(Collection<ClassLoader> cls, Function<Class, Object> classMappe
packages_.addAll(Stream.of(Package.getPackages()).map(p -> p.getName()).collect(Collectors.toList()));
}
}
debugLogger_ = debugLogger;
}

public static ZMQServer getMasterServer() {
Expand Down Expand Up @@ -440,8 +442,8 @@ private JSONObject runMethod(Object obj, JSONObject message, boolean staticMetho
protected JSONObject parseAndExecuteCommand(JSONObject request) throws Exception {
JSONObject reply;
switch (request.getString("command")) {
case "connect": {//Connect to master server
mainServer_ = this;
case "connect": {
// Connect to the server
debug_ = request.getBoolean("debug");
//Called by master process
reply = new JSONObject();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.micromanager.lightsheet;

import java.util.concurrent.BlockingQueue;
import mmcorej.TaggedImage;
import mmcorej.org.json.JSONException;
import mmcorej.org.json.JSONObject;
Expand Down Expand Up @@ -73,7 +74,7 @@ public StackResamplersImageProcessor(int mode, double theta, double cameraPixelS
/**
* For testing purposes only
*/
LinkedBlockingDeque<TaggedImage> getOutputQueue() {
BlockingQueue<TaggedImage> getOutputQueue() {
return sink_;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,10 @@ public RemoteAcquisition createAcquisition(String dir, String name, boolean show
int savingQueueSize, boolean debug) {
RemoteEventSource eventSource = new RemoteEventSource();
RemoteViewerStorageAdapter adapter = null;
if (name != null && dir != null) {
// Saving to disk
adapter = new RemoteViewerStorageAdapter(showViewer, dir, name, false, 0,0,
null, savingQueueSize);

}
adapter = new RemoteViewerStorageAdapter(showViewer, dir, name, false, 0,0,
null, savingQueueSize);

return new RemoteAcquisition(eventSource, adapter, debug);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
package org.micromanager.remote;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
Expand All @@ -30,7 +31,7 @@ public class RemoteImageProcessor implements TaggedImageProcessor {

private ExecutorService pushExecutor_, pullExecutor_;

volatile LinkedBlockingDeque<TaggedImage> source_, sink_;
volatile BlockingQueue<TaggedImage> source_, sink_;

ZMQPushSocket<TaggedImage> pushSocket_;
ZMQPullSocket<TaggedImage> pullSocket_;
Expand Down Expand Up @@ -97,7 +98,7 @@ public void startPush() {
while (true) {
if (source_ != null) {
try {
TaggedImage img = source_.takeFirst();
TaggedImage img = source_.take();
pushSocket_.push(img);
if (img.tags == null && img.pix == null) {
// all images have been pushed
Expand All @@ -124,7 +125,7 @@ public void startPull() {
if (sink_ != null) {
try {
TaggedImage ti = pullSocket_.next();
sink_.putLast(ti);
sink_.put(ti);
if (ti.pix == null && ti.tags == null) {
pullExecutor_.shutdown();
break;
Expand All @@ -146,6 +147,12 @@ public void startPull() {
@Override
public void setAcqAndDequeues(AcquisitionAPI acq,
LinkedBlockingDeque<TaggedImage> source, LinkedBlockingDeque<TaggedImage> sink) {
// This is deprecated, remove in a future version once its taken out of API
}

@Override
public void setAcqAndQueues(AcquisitionAPI acq, BlockingQueue<TaggedImage> source,
BlockingQueue<TaggedImage> sink) {
source_ = source;
sink_ = sink;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
import org.micromanager.acqj.api.AcqNotificationListener;
import org.micromanager.acqj.api.AcquisitionAPI;
import org.micromanager.acqj.main.AcqNotification;
import org.micromanager.acqj.main.Acquisition;
import org.micromanager.internal.zmq.ZMQPushSocket;
import org.micromanager.ndtiffstorage.IndexEntryData;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand Down Expand Up @@ -55,6 +53,8 @@ public void run() {
public void start() {
//constantly poll the socket for more event sequences to submit
executor_.submit(() -> {
boolean eventsFinished = false;
boolean dataSinkFinished = false;
while (true) {
AcqNotification e = null;
try {
Expand All @@ -66,8 +66,14 @@ public void start() {
}

pushSocket_.push(e);
if (e.isAcquisitionFinishedNotification()) {
return;
if (e.isAcquisitionEventsFinishedNotification()) {
eventsFinished = true;
}
if (e.isDataSinkFinishedNotification()) {
dataSinkFinished = true;
}
if (eventsFinished && dataSinkFinished) {
break;
}
}
});
Expand All @@ -80,7 +86,8 @@ public void postNotification(AcqNotification n) {

/**
* Called by the python side to signal that the final shutdown signal has been received
* and that the push socket can be closed
* and that the push socket can be closed. Because otherwise it wouldn't be possible
* to know when the ZMQ push socket has finished doing its thing
*/
public void notificationHandlingComplete() {
executor_.submit(() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* A class that broadcasts information about images that have finsihed saving to disk
* @author henrypinkard
*/
@Deprecated
public class RemoteStorageMonitor implements ImageWrittenListener {

private ZMQPushSocket<IndexEntryData> pushSocket_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import org.micromanager.acqj.api.AcqEngJDataSink;
import org.micromanager.acqj.main.Acquisition;
import org.micromanager.acqj.internal.Engine;
import org.micromanager.ndtiffstorage.IndexEntryData;
import org.micromanager.ndtiffstorage.NDRAMStorage;
import org.micromanager.ndtiffstorage.NDTiffStorage;
import org.micromanager.ndtiffstorage.MultiresNDTiffAPI;
import org.micromanager.ndtiffstorage.NDTiffAPI;
Expand All @@ -34,8 +36,8 @@ class RemoteViewerStorageAdapter implements NDViewerDataSource, AcqEngJDataSink,

private volatile NDViewerAPI viewer_;
private volatile Acquisition acq_;
private volatile MultiresNDTiffAPI storage_;
private final boolean showViewer_, storeData_, xyTiled_;
private volatile NDTiffAPI storage_;
private final boolean showViewer_, xyTiled_;
private final int tileOverlapX_, tileOverlapY_;
private String dir_;
private String name_;
Expand All @@ -58,7 +60,6 @@ public RemoteViewerStorageAdapter(boolean showViewer, String dataStorageLocation
int tileOverlapY,
Integer maxResLevel, int savingQueueSize) {
showViewer_ = showViewer;
storeData_ = dataStorageLocation != null;
xyTiled_ = xyTiled;
dir_ = dataStorageLocation;
name_ = name;
Expand All @@ -71,13 +72,19 @@ public RemoteViewerStorageAdapter(boolean showViewer, String dataStorageLocation
public void initialize(Acquisition acq, JSONObject summaryMetadata) {
acq_ = acq;

if (storeData_) {
if (xyTiled_) {
//tiled datasets have a fixed, acquisition-wide image size
AcqEngMetadata.setWidth(summaryMetadata, (int) Engine.getCore().getImageWidth());
AcqEngMetadata.setHeight(summaryMetadata, (int) Engine.getCore().getImageHeight());
}

if (xyTiled_) {
//tiled datasets have a fixed, acquisition-wide image size
AcqEngMetadata.setWidth(summaryMetadata, (int) Engine.getCore().getImageWidth());
AcqEngMetadata.setHeight(summaryMetadata, (int) Engine.getCore().getImageHeight());
}

if (dir_ == null) {
storage_ = new NDRAMStorage(summaryMetadata);
if (name_ == null) {
name_ = "In RAM acquisition";
}
} else {
storage_ = new NDTiffStorage(dir_, name_,
summaryMetadata, tileOverlapX_, tileOverlapY_,
xyTiled_, maxResLevel_, savingQueueSize_,
Expand All @@ -87,7 +94,6 @@ public void initialize(Acquisition acq, JSONObject summaryMetadata) {
}) : null, true
);
name_ = storage_.getUniqueAcqName();

}

if (showViewer_) {
Expand Down Expand Up @@ -119,32 +125,30 @@ private void createDisplay(JSONObject summaryMetadata) {
viewer_.setReadZMetadataFunction((JSONObject tags) -> AcqEngMetadata.getStageZIntended(tags));
}

public void putImage(final TaggedImage taggedImg) {
public Object putImage(final TaggedImage taggedImg) {
HashMap<String, Object> axes = AcqEngMetadata.getAxes(taggedImg.tags);
final Future added;
final Future<IndexEntryData> added;
if (xyTiled_) {
added = storage_.putImageMultiRes(taggedImg.pix, taggedImg.tags, axes,
added = ((MultiresNDTiffAPI)storage_).putImageMultiRes(taggedImg.pix, taggedImg.tags, axes,
AcqEngMetadata.isRGB(taggedImg.tags),
AcqEngMetadata.getBitDepth(taggedImg.tags),
AcqEngMetadata.getHeight(taggedImg.tags),
AcqEngMetadata.getWidth(taggedImg.tags));
} else {
added = null;
storage_.putImage(taggedImg.pix, taggedImg.tags, axes,
added = storage_.putImage(taggedImg.pix, taggedImg.tags, axes,
AcqEngMetadata.isRGB(taggedImg.tags),
AcqEngMetadata.getBitDepth(taggedImg.tags),
AcqEngMetadata.getHeight(taggedImg.tags),
AcqEngMetadata.getWidth(taggedImg.tags));
}


if (showViewer_) {
//put on different thread to not slow down acquisition
displayCommunicationExecutor_.submit(new Runnable() {
@Override
public void run() {
try {
if (added != null) {
if (xyTiled_) {
// This is needed to make sure multi res data at higher
// resolutions kept up to date I think because lower resolutions
// aren't stored temporarily. This could potentially be
Expand All @@ -165,6 +169,11 @@ public void run() {
}
});
}
try {
return added.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

///////// Data source interface for Viewer //////////
Expand All @@ -177,9 +186,13 @@ public int[] getBounds() {
public TaggedImage getImageForDisplay(HashMap<String, Object> axes, int resolutionindex,
double xOffset, double yOffset, int imageWidth, int imageHeight) {

return storage_.getDisplayImage(
axes, resolutionindex, (int) xOffset, (int) yOffset,
imageWidth, imageHeight);
if (storage_ instanceof MultiresNDTiffAPI) {
return ((MultiresNDTiffAPI) storage_).getDisplayImage(
axes, resolutionindex, (int) xOffset, (int) yOffset,
imageWidth, imageHeight);
} else {
return storage_.getSubImage(axes, (int) xOffset, (int) yOffset, imageWidth, imageHeight);
}
}

@Override
Expand All @@ -189,12 +202,17 @@ public Set<HashMap<String, Object>> getImageKeys() {

@Override
public int getMaxResolutionIndex() {
return storage_.getNumResLevels() - 1;
if (storage_ instanceof MultiresNDTiffAPI) {
return ((MultiresNDTiffAPI) storage_).getNumResLevels() - 1;
}
return 0;
}

@Override
public void increaseMaxResolutionLevel(int newMaxResolutionLevel) {
storage_.increaseMaxResolutionLevel(newMaxResolutionLevel);
if (storage_ instanceof MultiresNDTiffAPI) {
((MultiresNDTiffAPI) storage_).increaseMaxResolutionLevel(newMaxResolutionLevel);
}
}

@Override
Expand Down
Loading

0 comments on commit 4121e08

Please sign in to comment.