{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Track spot-like objects using TrackMate\n", "\n", "This notebook shows how to track objects using [TrackMate](https://imagej.net/TrackMate) on an image stored in OMERO.\n", "\n", "Fiji has been installed with few other plugins including the omero_ij plugin to allow to connect to an OMERO server." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Description\n", "\n", "The following section shows:\n", " * how to connect to OMERO\n", " * how to open an OMERO image using Bio-Formats\n", " * how to create a TrackMate tracker using its API\n", " * how to convert the generated ROIs into ROIs that can be stored in OMERO\n", " * how to save the converted ROIs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup: start the [desktop](../../desktop) if it is not already up\n", "The link should open in a different window. If you see an error message try refreshing the window." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup: Add plugins to Classpath\n", "First we had Fiji and the plugins to the classpath." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "//Add dependencies to the classpath\n", "%classpath add jar /srv/conda/vnc/Fiji.app/jars/*\n", "%classpath add jar /srv/conda/vnc/Fiji.app/plugins/*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Enter the credentials. Do not re-run this cell." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "7239c457-7f5d-47ae-aa73-69b018e8071a", "version_major": 2, "version_minor": 0 }, "method": "display_data" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "g = new EasyForm(\"Enter credentials and continue to the next cell. Do not re-run this cell\")\n", "g.addTextField(\"Server\").onInit({g['Server'] = \"wss://workshop.openmicroscopy.org/omero-ws\"})\n", "g.addTextField(\"UserName\")\n", "g.addPasswordField(\"Password\")\n", "g" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Select the Image. Do not re-run this cell." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "beae173a-0494-426e-a72c-d89b281124ba", "version_major": 2, "version_minor": 0 }, "method": "display_data" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ga = new EasyForm(\"Select the Image to analyze\")\n", "ga.addTextField(\"ImageID\")\n", "ga" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Collect parameters" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "-1" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "HOST = g['Server']\n", "USERNAME = g['UserName'].trim()\n", "PASSWORD = g['Password'].trim()\n", "PORT = 443\n", "\n", "image_id = ga['ImageID'].toLong()\n", "group_id = -1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Connect to OMERO" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "connecting...\n", "connected...\n" ] }, { "data": { "text/plain": [ "null" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import omero.gateway.Gateway\n", "import omero.gateway.LoginCredentials\n", "import omero.log.SimpleLogger\n", "\n", "// Method to connect to OMERO\n", "def connect_to_omero() {\n", " \"Connect to OMERO\"\n", " credentials = new LoginCredentials()\n", " credentials.getServer().setHostname(HOST)\n", " credentials.getUser().setUsername(USERNAME)\n", " credentials.getUser().setPassword(PASSWORD)\n", " simpleLogger = new SimpleLogger()\n", " gateway = new Gateway(simpleLogger)\n", " gateway.connect(credentials)\n", " return gateway\n", "}\n", "\n", "// Connect to OMERO\n", "println \"connecting...\"\n", "gateway = connect_to_omero()\n", "println \"connected...\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Open the image using Bio-Formats" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "ename": "java.lang.NoSuchMethodError", "evalue": " ij.IJ.isJava18()Z", "output_type": "error", "traceback": [ "\u001b[1;31mjava.lang.NoSuchMethodError: ij.IJ.isJava18()Z\u001b[0;0m", "\u001b[1;31m\tat loci.plugins.util.LibraryChecker.checkJava(LibraryChecker.java:109)\u001b[0;0m", "\u001b[1;31m\tat loci.plugins.LociImporter.run(LociImporter.java:72)\u001b[0;0m", "\u001b[1;31m\tat ij.IJ.runUserPlugIn(IJ.java:199)\u001b[0;0m", "\u001b[1;31m\tat ij.IJ.runPlugIn(IJ.java:163)\u001b[0;0m", "\u001b[1;31m\tat ij.IJ.runPlugIn(IJ.java:152)\u001b[0;0m", "\u001b[1;31m\tat ij.IJ$runPlugIn.call(Unknown Source)\u001b[0;0m", "\u001b[1;31m\tat script1592252216124.open_image_plus(script1592252216124:20)\u001b[0;0m", "\u001b[1;31m\tat script1592252216124$open_image_plus.callCurrent(Unknown Source)\u001b[0;0m", "\u001b[1;31m\tat this cell line 23\u001b[0;0m", "\u001b[0;31m\tat com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.runScript(GroovyCodeRunner.java:94)\u001b[0;0m", "\u001b[0;31m\tat com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.call(GroovyCodeRunner.java:59)\u001b[0;0m", "\u001b[0;31m\tat com.twosigma.beakerx.groovy.evaluator.GroovyCodeRunner.call(GroovyCodeRunner.java:32)\u001b[0;0m" ] } ], "source": [ "import ij.IJ\n", "\n", "def open_image_plus(host, username, port, password, group_id, image_id) {\n", " \"Open the image using the Bio-Formats Importer\"\n", " StringBuilder options = new StringBuilder()\n", " options.append(\"location=[OMERO] open=[omero:server=\")\n", " options.append(host)\n", " options.append(\"\\nuser=\")\n", " options.append(username.trim())\n", " options.append(\"\\nport=\")\n", " options.append(port)\n", " options.append(\"\\npass=\")\n", " options.append(password.trim())\n", " options.append(\"\\ngroupID=\")\n", " options.append(group_id)\n", " options.append(\"\\niid=\")\n", " options.append(image_id)\n", " options.append(\"] \")\n", " options.append(\"windowless=true view=Hyperstack \")\n", " IJ.runPlugIn(\"loci.plugins.LociImporter\", options.toString())\n", "}\n", "\n", "println \"Image opening...\"\n", "open_image_plus(HOST, USERNAME, PORT, PASSWORD, String.valueOf(group_id), String.valueOf(image_id))\n", "println \"Image opened\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create the TrackMate model" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import ij.IJ\n", "import fiji.plugin.trackmate.Settings\n", "import fiji.plugin.trackmate.Model\n", "import fiji.plugin.trackmate.SelectionModel\n", "import fiji.plugin.trackmate.TrackMate\n", "import fiji.plugin.trackmate.detection.DetectorKeys\n", "import fiji.plugin.trackmate.detection.LogDetectorFactory\n", "import fiji.plugin.trackmate.tracking.sparselap.SparseLAPTrackerFactory\n", "import fiji.plugin.trackmate.tracking.LAPUtils\n", "import fiji.plugin.trackmate.visualization.hyperstack.HyperStackDisplayer\n", "import fiji.plugin.trackmate.features.spot.SpotContrastAndSNRAnalyzerFactory\n", "import fiji.plugin.trackmate.features.spot.SpotIntensityAnalyzerFactory\n", "import fiji.plugin.trackmate.features.track.TrackSpeedStatisticsAnalyzer\n", "\n", "\n", "def create_tracker(imp) {\n", " \"Create the trackmate model for the specified ImagePlus object\"\n", " // Instantiate model object\n", " model = new Model()\n", "\n", " // Prepare settings object\n", " settings = new Settings()\n", " settings.setFrom(imp)\n", " // Configure detector\n", " settings.detectorFactory = new LogDetectorFactory()\n", " settings.detectorSettings.put(DetectorKeys.KEY_DO_SUBPIXEL_LOCALIZATION, true)\n", " settings.detectorSettings.put(DetectorKeys.KEY_RADIUS, new Double(2.5))\n", " settings.detectorSettings.put(DetectorKeys.KEY_TARGET_CHANNEL, 1)\n", " settings.detectorSettings.put(DetectorKeys.KEY_THRESHOLD, new Double(5.0))\n", " settings.detectorSettings.put(DetectorKeys.KEY_DO_MEDIAN_FILTERING, false)\n", " // Configure tracker\n", " settings.trackerFactory = new SparseLAPTrackerFactory()\n", " settings.trackerSettings = LAPUtils.getDefaultLAPSettingsMap()\n", " settings.trackerSettings['LINKING_MAX_DISTANCE'] = new Double(10.0)\n", " settings.trackerSettings['GAP_CLOSING_MAX_DISTANCE'] = new Double(10.0)\n", " settings.trackerSettings['MAX_FRAME_GAP'] = 3\n", "\n", " // Add the analyzers for some spot features\n", " settings.addSpotAnalyzerFactory(new SpotIntensityAnalyzerFactory())\n", " settings.addSpotAnalyzerFactory(new SpotContrastAndSNRAnalyzerFactory())\n", "\n", " // Add an analyzer for some track features, such as the track mean speed.\n", " settings.addTrackAnalyzer(new TrackSpeedStatisticsAnalyzer())\n", " settings.initialSpotFilterValue = 1\n", "\n", " // Instantiate trackmate\n", " trackmate = new TrackMate(model, settings)\n", " ok = trackmate.checkInput()\n", " if (!ok) {\n", " print(str(trackmate.getErrorMessage()))\n", " return null\n", " }\n", "\n", " ok = trackmate.process()\n", " if (!ok) {\n", " print(str(trackmate.getErrorMessage()))\n", " return null\n", " }\n", " return model\n", "}\n", "\n", "imp = IJ.getImage()\n", "trackmate_model = create_tracker(imp)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Convert the tracks into OMERO ROIs" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import java.util.ArrayList\n", "\n", "\n", "import omero.gateway.model.EllipseData\n", "import omero.gateway.model.PolylineData\n", "import omero.gateway.model.ROIData\n", "import omero.model.PolylineI\n", "import static omero.rtypes.rstring\n", "\n", "import fiji.plugin.trackmate.Spot\n", "\n", "def convert_tracks(model, dx, dy) {\n", " \"Convert the tracks into OMERO objects\"\n", " rois = new ArrayList()\n", " tracks = model.getTrackModel().trackIDs(true)\n", " tracks.each() { track_id ->\n", " track = model.getTrackModel().trackSpots(track_id)\n", " roi = new ROIData()\n", " rois.add(roi)\n", " points = \"\"\n", " track.each() { spot ->\n", " sid = spot.ID()\n", " // Fetch spot features directly from spot.\n", " x = spot.getFeature('POSITION_X')/dx\n", " y = spot.getFeature('POSITION_Y')/dy\n", " r = spot.getFeature('RADIUS')\n", " z = spot.getFeature('POSITION_Z')\n", " t = spot.getFeature('FRAME')\n", " // Save spot as Point in OMERO\n", " ellipse = new EllipseData(x, y, r, r)\n", " ellipse.setZ((int) z)\n", " ellipse.setT((int) t)\n", " // set trackmate track ID and spot ID for later\n", " ellipse.setText(track_id+':'+sid)\n", " // set a default color\n", " settings = ellipse.getShapeSettings()\n", " settings.setStroke(java.awt.Color.RED)\n", " roi.addShapeData(ellipse)\n", " points = points + x + ',' + y + ' '\n", " }\n", " // Convert the track\n", " points = points.trim()\n", " polyline = new PolylineI()\n", " polyline.setPoints(rstring(points))\n", " pl = new PolylineData(polyline)\n", " // set a default color\n", " settings = pl.getShapeSettings()\n", " settings.setStroke(java.awt.Color.YELLOW)\n", " roi.addShapeData(pl)\n", " }\n", " return rois\n", "}\n", "\n", "\n", "dx = imp.getCalibration().pixelWidth\n", "dy = imp.getCalibration().pixelHeight\n", "omero_rois = convert_tracks(trackmate_model, dx, dy)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Save the converted ROIs" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import omero.gateway.facility.ROIFacility\n", "import omero.gateway.SecurityContext\n", "\n", "def save_rois(gateway, rois, image_id) {\n", " roi_facility = gateway.getFacility(ROIFacility)\n", " user = gateway.getLoggedInUser()\n", " ctx = new SecurityContext(user.getGroupId())\n", " results = roi_facility.saveROIs(ctx, image_id, user.getId(), rois)\n", "}\n", "\n", "save_rois(gateway, omero_rois, image_id)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### License (BSD 2-Clause)\n", "\n", "Copyright (c) 2021, University of Dundee All rights reserved.\n", "\n", "Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n", "\n", "Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n", "Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n", "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ] } ], "metadata": { "kernelspec": { "display_name": "Groovy", "language": "groovy", "name": "groovy" }, "language_info": { "codemirror_mode": "groovy", "file_extension": ".groovy", "mimetype": "", "name": "Groovy", "nbconverter_exporter": "", "version": "2.5.6" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": false, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": false, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 4 }