Viewing many super-pixels at one time

Method
I used SLIC super-pixels to slice up my image. I then applied a pixel classifier to “trim off” the white space from the background. I then ended up with a data frame/spreadsheet containing super-pixel data. The size of my images varied and I would export anywhere from 12,000 to 160,000 super-pixels. I then randomized the rows (super-pixel data needs to remain attached to class) and selected exactly 250 pixels from each of my 50 images. All of the steps after exporting the data frame/spreadsheet was done in Python.

My Issue
In order to validate my findings, I wanted to go back into QuPath and look at the 250 SLIC super-pixels taken from each image, matching them by Centroid X and Y values but was unable to do so without manually finding each one in the dataframe. Scripting has been recommended to me but I wanted to see if anyone else had encountered a similar issue and, if so, the workaround you applied.

Just out of curiosity, why subsample rather than use them all once they are in a data sheet? Total area by superpixel class has been a pretty common way of comparing classes (or merging them into annotations).

You can also count your superpixels by adding a number as a measurement.


Code used is:

i=1
getDetectionObjects().each{
    it.getMeasurementList().putMeasurement("Count",i)
    i++
}

To pick out a specific object (they are ordered top to bottom, left to right, so clicking around isn’t too bad), you can use a selection script.

selectObjects {
   //Some criteria here
   return it.getPathClass() == getPathClass("531")
}
2 Likes

And as a side note, you could use similar selection criteria via the XY coordinates, or create a list of coordinates, but I think the counts will be easier.

2 Likes

Thank you so much! I used your first solution but instead of i as iterative, I used the random integer function and my code looked like the following and seems to work reasonably well:

Random random=new Random()
getDetectionObjects().each{
    i=random.nextInt()
    it.getMeasurementList().putMeasurement("Count", i)
}

To answer your question why I did not use all of the data, the short answer is that one of my species has larger tissue samples and would have biased my SVM unless I adjusted the weight. I had hoped to avoid that during my preliminary testing although I am sure, by the time I am in the end-game, I will be using all of the data.

Again, I really appreciate your help.

1 Like

Not sure random is a good idea if you want to pick out specific objects, but if it is working for you…

Two small suggestions:

  • you might want to seed your random number generator (here).
  • in QuPath it’s generally preferable to call it.getMeasurementList().close() once you’re done modifying the list (see here) - shouldn’t do any harm and may improve performance
2 Likes

I am definitely at risk of overwriting the random number associated with each super-pixel so I will always check the XY values to ensure they, too, line up before highlighting for viewing.

Great point on seeding the RNG, I will include that. Additionally, I updated my code including it.getMeasurementList().close() this time and it seems to have improved run-time slightly. I appreciate you both immensely!

1 Like

Good! Actually just realised you should also use something like

int n = getDetectionObjects().size()
def rand = new Random()
// As required....
int value = rand.nextInt(n)

to constrain the values. Or alternatively put them in a list and use Collections.shuffle to avoid repeats

def detections = new ArrayList<>(getDetectionObjects())
Collections.shuffle(detections, rand)

and then extract the first entries.

2 Likes

Everything looks (and runs) much better now. Thank you both for your help!

1 Like