Select Class by ROI - then set new class; Does not work; & set new class with script possible?

124 views
Skip to first unread message

David Haumann

unread,
Oct 1, 2017, 5:38:38 PM10/1/17
to QuPath users
I have a huge tissue ROI from simple tissue detection.
Inside the tissue are ROI with class, created by tiles to ROI function.
It looks like that: The round structures are ROI with class "islet":

Now I want to create tiles inside the Islets.
To do so, i can use the script
      selectObjects {it.getPathClass() != null}
ROI become activated/yellow:

now I could do tile creation for further segmentation inside Islets.
But as soon as I want to train a classifier, it will not work, because everything inside Islet will be classified as "Islet".   So all tiles become Islets.

The only chance to train a classifier is to set the class of the Islet-ROI to "none".
Is there a way to change the class automatically by a script?

Another point:
If I select all Islet-ROI with the Script
       selectObjects {it.getPathClass() != null}
All ROI are selected. BUT I can NOT change the class! It will gust not work.

If I do rightclick - the function will not appear in the menue.
If I use the buttons on the left:

nothing will happen!.

Only if i go via "Measure" > "Show Annotations measurements" and select all Islets in the table, then the rightclick works and the function appears in the menue:


I am happy I found a way. But that is really hard manual work in case of a lot of files. Not i can delete the class/change the class to "none".
Afterwards I have no means anymore to distinguish between the tissue annotation and the islets annotations. I need to do it manually.

I reach my final goal to create tiles within the islets and classify them.

But I am far away of automation.

Do you have some idea if it is possible with scripts?

Would make me really feel relieved!

Best
David




Auto Generated Inline Image 1
Auto Generated Inline Image 2
Auto Generated Inline Image 3
Auto Generated Inline Image 4
Auto Generated Inline Image 5

Pete

unread,
Oct 1, 2017, 5:51:58 PM10/1/17
to QuPath users
I'm not sure why the option isn't appearing when you right-click, but maybe you can use the 'Set class' button just below the list of classifications?

Anyway, that's still manual and even if it does work that way I agree that a script would be nicer.

If the islets are selected, you should be able to do this:

getSelectedObjects().each {it.setPathClass(null)}
fireHierarchyUpdate()

If they aren't (or might not be) selected, then you could try this:

getAnnotationObjects().each {
    if (it.getPathClass() == getPathClass("Islet"))
        it.setPathClass(null)
}
fireHierarchyUpdate()

I hope one of those can help.

Best wishes,

Pete

David Haumann

unread,
Oct 2, 2017, 5:00:26 AM10/2/17
to QuPath users
Hi Pete,

I tried the second one. It works. Thank you very much for your help again :)

If I want to learn to write this kind of scripting by my own, I need to learn groovy? Or do I need to know more about the insights of QuPath do create good scripts?

Best
David

Pete

unread,
Oct 2, 2017, 2:15:21 PM10/2/17
to QuPath users
Hi David,

You'll need to learn Groovy and also QuPath-specific things.  But probably only a little bit of each to get started, and the rest only when you need it.

There is also a small (unfinished) bit of information on import Java classes used for QuPath objects here.
But the key thing when getting started is to set up IntelliJ with access to the QuPath source code.  That means you can get autocomplete and the ability to delve into the QuPath code quickly.  Often there is further specific documentation or explanation there.

There aren't really any other sources of QuPath information, but there should be various websites and books to help get started with Groovy.

If you prefer, you could also use Java tutorials - if you write valid Java, it's usually valid Groovy.  Java is more strict, which might make it easier to learn... the downside is that it is also more verbose.

In any case, there are usually various different ways to do the same thing.  Reading different scripts and trying things out should help.

For example, the solution above was:

getAnnotationObjects().each {
    if (it.getPathClass() == getPathClass("Islet"))
        it.setPathClass(null)
}
fireHierarchyUpdate()

This takes advantage of the fact that QuPath imports QPEx (or QP) for you automatically, but IntelliJ doesn't know anything about that.  Therefore if you're coding with IntelliJ it's often preferable to import them yourself, so that IntelliJ can offer better help.  With the import written out in full, the code could be:

import qupath.lib.scripting.QPEx

QPEx.getAnnotationObjects().each {
    if (it.getPathClass() == QPEx.getPathClass("Islet"))
        it.setPathClass(null)
}
QPEx.fireHierarchyUpdate()

The each and it parts are specific to Groovy, meaning that each annotation is handled by the code between the braces.  You could replace it with a specific variable name if you wanted like this:

import qupath.lib.scripting.QPEx

QPEx.getAnnotationObjects().each { annotation ->
    if (annotation.getPathClass() == QPEx.getPathClass("Islet"))
        annotation.setPathClass(null)
}
QPEx.fireHierarchyUpdate()


But you could also handle things with a for loop:

import qupath.lib.scripting.QPEx

for (annotation in QPEx.getAnnotationObjects()) {
    if (annotation.getPathClass() == QPEx.getPathClass("Islet"))
        annotation.setPathClass(null)
}
QPEx.fireHierarchyUpdate()

This is closer to valid Java, but still not quite... because Java is strict about giving the type of variables, and also the use of semi colons and the end of lines.  So the Java way would be more like this:

import qupath.lib.scripting.QPEx;
import qupath.lib.objects.PathAnnotationObject;

for (PathAnnotationObject annotation : QPEx.getAnnotationObjects()) {
    if (annotation.getPathClass() == QPEx.getPathClass("Islet"))
        annotation.setPathClass(null);
}
QPEx.fireHierarchyUpdate();

This version runs through QuPath as well.  It's also the way I would have written it a couple of years ago, before I learned more tricks within Groovy to make the code shorter.

Finally, another way to do it with Groovy would be to filter out the annotations you don't want first, and then set the class of whatever is left over.  This can all be done in one line:

getAnnotationObjects().findAll({it.getPathClass() == getPathClass("Islet")}).each({it.setPathClass(null)})
fireHierarchyUpdate()

This is a even shorter than the original version above... but maybe less readable.

Anyway, I suggest looking for a good Groovy tutorial to get started, and then gradually add new ways of doing things along the way as you learn more of the language.

Best wishes,

Pete

micros...@gmail.com

unread,
Oct 2, 2017, 6:28:42 PM10/2/17
to QuPath users
"But as soon as I want to train a classifier, it will not work, because everything inside Islet will be classified as "Islet".   So all tiles become Islets."

If you are only doing one segmentation (I am guessing cell detection of some sort or SLICs?) you can also, after doing the segmentation use the one liner:

resetDetectionClassifications();

Then proceed with your own classification.  This would allow you to keep the annotations classified in case you need them later, or ever have multiple types of annotations you want to keep track of.  You can also access that command through the Classify menu.
Reply all
Reply to author
Forward
0 new messages