Auto-fluorescence correction (spectral unmixing) using ImageJ Ops

I’m looking for a flexible way to correct for auto-fluorescence in images from confocal microscopy (e.g. the nematode C. elegans is known to contain auto-fluorescent material interfering with the emission spectrum of green fluorescent protein, GFP).

Consider images acquired simultaneously with a two-camera setup:

  • using a band-pass filter for GFP in channel 1, and
  • a long-pass filter recording the auto-fluorescence in channel 2.

I am aware of the Spectral Unmixing plugin, but was interested in alternative (and possibly more automatable) ways to separate the two fluorophores in case of auto-fluorescence. (The plugin requires selection of ROIs known to have signal originating from single fluorophores, whereas I suppose that the characteristics of auto-fluorescence could likely also be automatically detected from a 2D histogram of the two channels.)


My intended workflow would be something along these lines:

  • Get a 2D histogram (I don’t think there’s an op for it yet, is there?):

    #@ Dataset input
    #@ OpService ops
    
    ch1 = ops.transform().hyperSliceView(input, 2, 0)
    ch2 = ops.transform().hyperSliceView(input, 2, 1)
    
    import net.imglib2.histogram.Integer1dBinMapper
    import net.imglib2.histogram.HistogramNd
    
    ch1mapper = new Integer1dBinMapper(0, 512, false)
    ch2mapper = new Integer1dBinMapper(0, 512, false)
    
    histogram = new HistogramNd([ch1, ch2], [ch1mapper, ch2mapper])
    
  • In the histogram image (since HistogramNd implements Img<LongType>), we can select a region (manually or semi-automatically) that corresponds to our auto-fluorescent (= colocalizing) signal.
    This is where I see some overlap with the coloc ops (like determining thresholds for both channels), right? @etadobson, @ctrueden

  • From the selected region in the histogram, we should be able to fit a (linear?) function (how can we do this?)

  • In the original image, using the derived function, we subtract (using ops) the auto-fluorescence from the GFP signal, which gives us the (single) channel of interest. (with image.equation? or using a sequence of math.multiply and math.subtract?)


Does this workflow make sense? Does anybody have different solutions (scriptable or not)?
I’d be happy to see what others think.

1 Like

Nope, I don’t think so. Would be nice to have, though.

I’ll defer to @etadobson here.

Here are the fitting packages based on ImgLib2 that I know about:

Nothing exists in Ops core yet as far as I know.

Are you looking for something similar to ImageJ 1.x’s CurveFitter? We could port that code over to ImgLib2 Algorithm if it’s useful. But it may also make sense to lean on a third party library. Apache Commons Math can do linear regressions.

The eval op, which uses Parsington, is intended for this: writing an expression that is decomposed into op executions. The parser itself is robust. On the Ops side, though, it would really benefit from the scijava-ops redesign because right now, eval uses ops.run which is fundamentally broken because there is no differentiation between function vs computer vs inplace. We need to update eval: 1) initially, only invoke functions; 2) later, performance could be improved by reusing buffers with computers; 3) more thought needed for how inplace fits into eval, if at all.

1 Like