Exporting annotations: getAnnotationObjects() error

If you are saving annotation data, you can use saveAnnotationMeasurements(). Not sure if that is what you are trying to do instead?

Otherwise, it would help to see the script. I am not sure what you are trying to do with the getAnnotationObjects() function. It doesn’t accomplish much on its own.

Version of QuPath and any edits made to the program are important as well.

Version: just updated to 0.2.0-m2, and still same error. No edits to the program.

Can you explain how you would use saveAnnotationMeasurements()? I tried running it in the interpreter and getting yet other No signature of method error.

The way I ran getAnnotationObjects() is either independently, or as a part of scripts, e.g.

In any case, by just running getAnnotationObjects() I expect a list of objects in the output, and I am getting the No signature of method. This means that maybe some import is missing, it should not depend on the context I am running it in or output I expect to get, right?
Here is the screenshot showing that:

  • I have an SVS slide open
  • there is an annotation in the image
  • the commands I am running and No signature of method errors.

19

Ah, that might be it. I have never actually used the interpreter. If you are getting the same thing from the script editor when running something as simple as “annotations = getAnnotationObjects()”, then something is wrong beyond anything I have experience with :slight_smile:

All of the save functions run with the path to the file you want to save as the first argument, then you can specify specific fields afterwards if you want a subset of the data. Pete has a slightly more complex and flexible (builds a path) example of it here. You could use this for TMA cores, or detections as well, with variants of the function name.

It seems helpful. Thank you! I am able to run a script now.
Still it outputs an empty file, even though I have a legitimate annotation, which have been saved in .qdata, and it is in my slide within the selected project (see figure below, I tried it several times, I am sure I am selecting the right project)

02

It looks that for some reason the image is not in its namesake project. I ran with just Run, and got an output.
saveAnnotationMeasurements by no means saves coordinates that I need – it saves some summary stats.
Anyway, we are getting closer.

Any idea how to get actual coordinates? I have been looking in all possible Google group posts and Github issue with no reasonable result. How are ROIs represented internally in groovy? Are they stored as binary masks, RLEs, or vertices?

ROIs are stored as vertices (well, except Ellipses). They can be converted to java.awt.Shape objects, ImageJ ROIs or (in v0.2.0-m2) JTS Geometry objects.

If you like the sound of JTS, I should warn there is a bug (here) that means some complex ROIs don’t convert to JTS Geometry objects properly in v0.2.0-m2. I have a workaround that has survived all my tests so far and should be in the next milestone… along with the option to export ROIs as GeoJSON.

In the meantime, this may be useful: https://github.com/qupath/qupath/issues/95#issuecomment-324421783

I’m not sure how or why you want to export the annotations in the end. If as a binary or labelled image, these two scripts may help:

The reason you had trouble with getAnnotationObjects() in the script interpreter is that it doesn’t auto-import (statically) one of the classes with that method: https://github.com/qupath/qupath/wiki/Writing-custom-scripts#technical-notes

With the script editor, there is an option to auto-import (it’s on by default).

1 Like

It may have to do with how you are opening the image/handling the project. Hard to say from here though.

There are some recent posts here seem to cover that.

This one covers some tricks if you are converting points between pixels and um, though it deals with centroids not outline points.

There are quite a few other posts about the problems with transferring annotations between programs, as there is frequently not a set file format to handle things like holes in annotations.
https://github.com/qupath/qupath/issues/140 for example

  • ran into a problem posting last night with the forum being in read only mode… Looks like Pete has it covered, but finishing posting anyway.

That’s helpful, thank you!

Now I am struggling with importing groovy.json so that I can write the vertex coordinates. I tried using

@Grab("org.codehaus.groovy:groovy-json")
import groovy.json.*

but it hangs

Not sure if it will help, but the second part of this thread is all about using JSON in a script. Though it is also about command line.
https://groups.google.com/forum/#!topic/qupath-users/lE5AJDcxA28

That’s nice but… The fact that there is no integrated package manager makes any scripts I write not portable. And I need it to be portable for other non-programmer people in my institution ;(((

I am not able to include JSON given that description. What it addresses is calling a qupath jar from an external python script, not from the QuPath compiler window

everything I could find on google relates to including groovy packages into web-applications through html / xml specifications. I tried copying the groovy-json-*.jar into the /Applications/QuPath-0.2.0-m2.app/Contents/Java to no avail.

I think you are supposed to copy it into the open QuPath window, it says that should not work in the link where someone tried it.

And have you tried importing it directly as in 140? I realize there have been a lot of links but: https://github.com/qupath/qupath/issues/140
import org.json.*

image

That actually works. Before I was trying to import import groovy.json.* and that failed. Now I need to serialize an qupath.lib.roi.AreaROI object that I get out of annotation.getROI(). All tutorials that I see use either Jackson or flexjson libraries. And here again, I have no idea how to enable / include those libraries into path with the QuPath. Any ideas?

Ah, never heard of those.

Thank you for your help!
If we could extend an qupath.lib.roi.AreaROI with a JSON serializer, it will solve the whole issue of interoperability and save / read the ROIs into JSON (if there is willingness for interoperability from the maintainers of the package).

1 Like

Think the single maintainer of QuPath is a bit busy at the moment between versions and setting up a lab among other things :slight_smile: If you want to create an issue or suggestion on the GitHub Issues page, that would be the best place for him to be able to keep track of requests.

1 Like

In case others need it, leaving here a hack I came up with for now:

// a script for exporting ROIs as vertices and other metadata in JSON format
// to be replaced with proper serialization of qupath.lib.roi.AreaROI

import org.json.*

def serializeArea(roi){
    JSONObject jroi = new JSONObject();
    // serialize the object
    for (prp in ['roiType', 'empty', 'area']){
        jroi.put(prp, roi[prp]);
    }
    
    for (prp in ["geometryType"]){
        jroi.put(prp, roi.geometry[prp]);
    }

    jroi.put("interiorPoint", [roi.geometry.interiorPoint.x, roi.geometry.interiorPoint.y])
    jroi.put("centroid", [roi.centroidX, roi.centroidY])
    jroi.put("boundsStart", [roi.boundsX, roi.boundsY])
    jroi.put("boundsSize", [roi.boundsWidth, roi.boundsHeight])
    // collect vertices per se
    def jvert = new ArrayList<>();;
    for (point in roi.getPolygonPoints()){
        jvert.add([point.x, point.y]);
    }
    jroi.put("vertices", jvert)

    return jroi;
}

// make a file name and directory
def entry = getProjectEntry()
def name = entry.getImageName() + '.txt'
def path = buildFilePath(PROJECT_BASE_DIR, 'annotation')
mkdirs(path)
path = buildFilePath(path, name)
// collect ROIs
JSONArray jstr = new JSONArray();
for (annotation in getAnnotationObjects()) {
    def pathClass = annotation.getPathClass()
    def roi = annotation.getROI()
    jstr.put(serializeArea(roi));
}

File file = new File(path)
file.write jstr.toString();
println jstr;

Groovy JSON isn’t a default part of Groovy, so you need the extra jar.
Copying it to the QuPath application won’t be enough to get it onto QuPath’s classpath. You need to drag it onto QuPath to copy it to the extensions directory to use the jar from scripts.

But you don’t need to do any of that if you use Gson to write JSON, since it’s already there as a dependency and used by QuPath to write JSON.

There’s an example showing the import here.

There have been discussions about interoperability, e.g.:

Serializing to/from JSON can be deceptively tricky and very hard to maintain in evolving software. There are a lot of design decisions to make, and relying on the default serialization from Jackson/Gson will cause problems if (/when…) the internal QuPath representation for ROIs changes. JSON serialization is also very hard to manage with interfaces and subclasses.

For that reason, I recently wrote support to serialize QuPath ROIs and objects to/from GeoJSON. The code is here but not yet in a QuPath release or tested in the real world.

Yeah, that is the problem :slight_smile:
I try to priorities in a vaguely utilitarian way the things that will help the most people or make the biggest difference, but also keeping in mind long-term plans to improve the software more substantially and sustainable.

There’s a position currently advertised here. To help QuPath go faster, please consider either joining me or at least advertising this widely!

1 Like