QuPath: saving filtered DetectionTable with MeasurementExporter for current image only?

Hi,

Is there a way to use QuPath MeasurementExporter for the current image only ?
I want to save only selected columns of the detection table, into (optionally) separated files for each image ?

This is important as the whole pipeline includes manual annotation, and I want to be able to run it on selected images from a project.

I tried to use

// ======== Save Results =============
import qupath.lib.gui.tools.MeasurementExporter
import qupath.lib.objects.PathCellObject

// Get the list of all images in the current project
def project = getProject()
def entry = getProjectEntry()
def outputPath = buildFilePath(PROJECT_BASE_DIR, "results")
mkdirs(outputPath)
def imageData = entry.readImageData()
    
// Separate each measurement value in the output file with a tab ("\t")
def separator = ","

// Choose the columns that will be included in the export
def columnsToInclude = new String[]{"Image", "Name", "Class", "Nucleus: Green mean", "Nucleus: Green sum", "Cell: Green mean", "Cell: Green sum", "Cytoplasm: Green mean", "Cytoplasm: Green sum", "Nucleus/Cell area ratio", "Distance to annotation with TumorInverse µm", "Smoothed: 100 µm: Nearby detection counts"}

def exportType = PathCellObject.class

def name1 = entry.getImageName() +'_CellMeasurements.csv'
def outputFile = buildFilePath(outputPath, name1)

// Create the measurementExporter and start the export
def exporter  = new MeasurementExporter()
                  .imageList(entry)            // Images from which measurements will be exported
                  .separator(separator)                 // Character that separates values
                  .includeOnlyColumns(columnsToInclude) // Columns are case-sensitive
                  .exportType(exportType)               // Type of objects to export
                  .exportMeasurements(outputFile)        // Start the export process

and get the following error code

WARN: Openslide: Property 'openslide.level[0].tile-width' not available, will return default value 256.0
WARN: Openslide: Property 'openslide.level[0].tile-height' not available, will return default value 256.0
ERROR: MissingMethodException at line 48: No signature of method: qupath.lib.gui.tools.MeasurementExporter.imageList() is applicable for argument types: (qupath.lib.projects.DefaultProject$DefaultProjectImageEntry) values: [inj9 arg_diet M7.mrxs]
Possible solutions: imageList(java.util.List), getImageList()

Also:
Is there a scripted way to save the detection table only for Positive Cells
Can this be done with the MeasurementExporter ?

Thanks
Ofra

Here is the quick fix to get the single image to export:

// ======== Save Results =============
import qupath.lib.gui.tools.MeasurementExporter
import qupath.lib.objects.PathCellObject

// Get the list of all images in the current project
def project = getProject()
def entry = getProjectEntry()
entryList = []
entryList << getProjectEntry()

def outputPath = buildFilePath(PROJECT_BASE_DIR, "results")
mkdirs(outputPath)
def imageData = entry.readImageData()
    
// Separate each measurement value in the output file with a tab ("\t")
def separator = ","

// Choose the columns that will be included in the export
def columnsToInclude = new String[]{"Image", "Name", "Class", "Nucleus: Green mean", "Nucleus: Green sum", "Cell: Green mean", "Cell: Green sum", "Cytoplasm: Green mean", "Cytoplasm: Green sum", "Nucleus/Cell area ratio", "Distance to annotation with TumorInverse µm", "Smoothed: 100 µm: Nearby detection counts"}

def exportType = PathCellObject.class

def name1 = entry.getImageName() +'_CellMeasurements.csv'
//need a file here
def outputFile = new File( buildFilePath(outputPath, name1))

// Create the measurementExporter and start the export
def exporter  = new MeasurementExporter()
                  .imageList(entryList)            // Images from which measurements will be exported
                  .separator(separator)                 // Character that separates values
                  .includeOnlyColumns(columnsToInclude) // Columns are case-sensitive
                  .exportType(exportType)               // Type of objects to export
                  .exportMeasurements(outputFile)        // Start the export process
                  
print "Done"

The two main changes were sending a List to the list of images (entryList) that it expects, and creating a file for the output. It looks like it does not want a string, but an actual file, see the new line for “outputFile” similar to the example on readthedocs.

To make this all work for a single class, the quickest hack I could come up with is removing and then re-adding all other cells.

// ======== Save Results =============
import qupath.lib.gui.tools.MeasurementExporter
import qupath.lib.objects.PathCellObject

//New User Defined Entry
exportClass = getPathClass("PD1 (Opal 650)")


// Get the list of all images in the current project
def project = getProject()
def entry = getProjectEntry()
entryList = []
entryList << getProjectEntry()

def outputPath = buildFilePath(PROJECT_BASE_DIR, "results")
mkdirs(outputPath)


//NEW CODE
removedObjects = getCellObjects().findAll{it.getPathClass() != exportClass}
removeObjects(removedObjects, true)
fireHierarchyUpdate()
getProjectEntry().saveImageData(getCurrentImageData())
imageData = entry.readImageData()
    
// Separate each measurement value in the output file with a tab ("\t")
def separator = ","

// Choose the columns that will be included in the export
def columnsToInclude = new String[]{"Image", "Name", "Class", "Nucleus: Green mean", "Nucleus: Green sum", "Cell: Green mean", "Cell: Green sum", "Cytoplasm: Green mean", "Cytoplasm: Green sum", "Nucleus/Cell area ratio", "Distance to annotation with TumorInverse µm", "Smoothed: 100 µm: Nearby detection counts"}

def exportType = PathCellObject.class

def name1 = entry.getImageName() +'_CellMeasurements.csv'
//need a file here
def outputFile = new File( buildFilePath(outputPath, name1))

// Create the measurementExporter and start the export
def exporter  = new MeasurementExporter()
                  .imageList(entryList)            // Images from which measurements will be exported
                  .separator(separator)                 // Character that separates values
                  .includeOnlyColumns(columnsToInclude) // Columns are case-sensitive
                  .exportType(exportType)               // Type of objects to export
                  .exportMeasurements(outputFile)        // Start the export process

//Put stuff back in place!
addObjects(removedObjects)
getProjectEntry().saveImageData(getCurrentImageData())
fireHierarchyUpdate()
print "Done"

This could be altered a bit to use .contains for multiplexing if you wanted to get all classes that contained a certain subclass, but this should get you started, hopefully.

1 Like

There may be a better, cleaner way, and I would defer to @melvingelbard on that.

Thanks @Research_Associate ,
That was what I tried to do, unsuccessfully, for a while.

Nico

1 Like