QuPath v0.2.0-m5 now available

The fifth milestone on the way to QuPath v0.2.0 is now available here, with many improvements to the pixel classifier, ROIs, annotations, scripting and more.

Don’t be put off by the ‘path’ if you don’t work in pathology: QuPath is designed not just for whole slide images and pathology, but also for other kinds of bioimage analysis.

More details about the latest update in this blog post.


Indeed, here is a quick gif of performing clustering/cell density analysis on a time lapse! Converted to a movie in FIJI. And with that newfangled Svidro2 color map (colors represent nearby neighbor count).


“Dark Mode” is awesome :boom::100:, thank you.


Glad it is updated so quickly with another set of amazing tools! I love QuPath so much. I think it is one of my favorite software program I have ever used. Easy to learn for a nonprogrammer like myself. I think I am using only some basic tools now, but I wish to learn to use the AI part of the program, soon. Million thanks to Dr. Pete Bankhead and your team.


Glad to see the pixel classifier is up and running quite well! Now that we can save the classifier, is there also a way to load the classifier and convert to annotations by script or is it only possible through the GUI so far?

1 Like

No, that’s still on the list of things to do: https://petebankhead.github.io/qupath/2019/11/02/fifth-milestone.html#limitations--plans

Actually, after doing some spelunking into the source code I came up with this script which seems to get the job done!

import qupath.lib.gui.ml.PixelClassifierTools

//Need a full image annotation to begin with
def annotations = getAnnotationObjects()

//Define pixel classifier
def project = getProject()
def classifier = project.getPixelClassifiers().get('2019-11-04 Pixel Model')

//Define image data
def imageData = getCurrentImageData()

//Convert pixel classifier to annotations
//Not sure if the smallest annotations/holes is in pixels or microns....
PixelClassifierTools.createAnnotationsFromPixelClassifier(imageData, classifier, annotations, 500, 500, false, true)

//Remove our starting annotation
removeObjects(annotations, true)

Great work as always Pete!

I’m really looking forward to diving into the new scripting. Since I’m utilizing QuPath from a GUI viewed within the microscope eyepiece while the user is viewing a slide, QPEx looks like a much more friendly way to utilize QuPath classes without needing a different button for each individual algorithm.

I know how I’m spending my weekend :grinning:

1 Like

13 posts were split to a new topic: Question about Positive Cell Detection

Hi, there, I have run this script but mine shows error saying that ‘PixelClassifierTools’ is not found.
Do you know why?
Thanks a lot

The default settings for QuPath M9 should allow this script to run. Could you elaborate?

I can run the above script successfully on the image in which I defined the pixel classifier (using simple thresholder), but I get the below errors when I try to run it on any other image (in same project):

ERROR: Error requesting classified tile
    at qupath.lib.color.ColorModelFactory.getIndexedClassificationColorModel(ColorModelFactory.java:63)
    at qupath.opencv.ml.pixel.SimplePixelClassifier.getColorModel(SimplePixelClassifier.java:96)
    at qupath.opencv.ml.pixel.SimplePixelClassifier.applyClassification(SimplePixelClassifier.java:76)
    at qupath.lib.classifiers.pixel.PixelClassificationImageServer.readTile(PixelClassificationImageServer.java:209)
    at qupath.lib.images.servers.AbstractTileableImageServer.getTile(AbstractTileableImageServer.java:158)
    at qupath.lib.images.servers.AbstractTileableImageServer.readBufferedImage(AbstractTileableImageServer.java:209)
    at qupath.lib.images.servers.AbstractTileableImageServer.readBufferedImage(AbstractTileableImageServer.java:35)
    at qupath.lib.gui.ml.PixelClassifierTools.lambda$createObjectsFromPixelClassifier$2(PixelClassifierTools.java:364)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.copyInto(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
    at java.base/java.util.stream.ReduceOps$ReduceTask.doLeaf(Unknown Source)
    at java.base/java.util.stream.ReduceOps$ReduceTask.doLeaf(Unknown Source)
    at java.base/java.util.stream.AbstractTask.compute(Unknown Source)
    at java.base/java.util.concurrent.CountedCompleter.exec(Unknown Source)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(Unknown Source)
    at java.base/java.util.concurrent.ForkJoinTask.doInvoke(Unknown Source)
    at java.base/java.util.concurrent.ForkJoinTask.invoke(Unknown Source)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateParallel(Unknown Source)
    at java.base/java.util.stream.AbstractPipeline.evaluate(Unknown Source)
    at java.base/java.util.stream.ReferencePipeline.collect(Unknown Source)
    at qupath.lib.gui.ml.PixelClassifierTools.createObjectsFromPixelClassifier(PixelClassifierTools.java:409)
    at qupath.lib.gui.ml.PixelClassifierTools.createObjectsFromPixelClassifier(PixelClassifierTools.java:314)
    at qupath.lib.gui.ml.PixelClassifierTools.createAnnotationsFromPixelClassifier(PixelClassifierTools.java:298)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.base/java.lang.reflect.Method.invoke(Unknown Source)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
    at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrap.invoke(StaticMetaMethodSite.java:131)
    at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.call(StaticMetaMethodSite.java:89)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
    at Script31.run(Script31.groovy:17)
    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:317)
    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:155)
    at qupath.lib.gui.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:800)
    at qupath.lib.gui.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:734)
    at qupath.lib.gui.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:714)
    at qupath.lib.gui.scripting.DefaultScriptEditor$2.run(DefaultScriptEditor.java:1130)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)

Hi @erindiel, that looks like it may be related to this bug: https://github.com/qupath/qupath/issues/403

I fixed the code last week and it’ll be in the next release.

1 Like

Sorry to revive an old thread but I tried running this script above by dstevens in M11 to apply a pixel classifier to a batch and it could not find the PixelClassiferTools class.

This is the error message:

ERROR: It looks like you have tried to import a class 'qupath.lib.gui.ml.PixelClassifierTools' that doesn't exist!

I have previously used the script successfully in M9, but it does not seem to work in M11 now.

Making the pixel classifier properly scriptable is what I’m working on right now (between forum visits) :slight_smile:https://github.com/qupath/qupath/issues/463
Any short-term scripting solution will break again, but I hope to have an ‘official’, improved way to do it available this week.


Thanks @petebankhead, I look forward to it!