How to make local classification process parallel

Hi,

I ran into a lot of problem of installing Omero server on Mint(Ubuntu)
So far I have to stick with Windows orbit local

I wrote the following code to classify images in a directory and save output labeled images.
If I only classify one image with pre-trained omo model, the classification appears to use only one CPU thread. I am not sure if I could make this process parallel (pixel level parallel).

Also another approach is to make multiple images process at the same time in parallel (file level parallel).

I have 32 core processor, so parallel computation could save quite some time.

I don’t have strong background in java. Need a little bit help to make current code run faster in parallel.

Thanks

/*
Usage: batch process files in a directory using pretrained model
Need to change:
    -dir
    -OrbitModel.LoadFromFile("*.omo")
*/
// load a local image, apply a model (from local file) and save a low-res classification image to disk

// for load image
import com.actelion.research.orbit.beans.RawDataFile
import com.actelion.research.orbit.imageAnalysis.components.RecognitionFrame
import com.actelion.research.orbit.imageAnalysis.dal.DALConfig
import com.actelion.research.orbit.imageAnalysis.dal.ImageProviderLocal
// for model
import com.actelion.research.orbit.imageAnalysis.models.OrbitModel
import com.actelion.research.orbit.imageAnalysis.utils.OrbitHelper

import com.actelion.research.mapReduceGeneric.utils.KeyValue
import com.actelion.research.orbit.imageAnalysis.utils.ClassificationResult
// for saving
import com.actelion.research.orbit.imageAnalysis.utils.ClassImageRenderer
import com.actelion.research.orbit.imageAnalysis.utils.OrbitTiledImage2
import com.actelion.research.orbit.imageAnalysis.utils.TiledImagePainter
import javax.media.jai.TiledImage
import java.awt.image.BufferedImage
// for image
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
import javax.imageio.ImageReader
// import javax.imageio.ImageInputStream
// for file list
import groovy.io.FileType

def list = []
def dir = new File("D:\\images") // !!! CHANGE ME
dir.eachFileRecurse (FileType.FILES) { file ->
    list << file
}

list.each {
    // -------------- main process --------------
    RawDataFile rdf = ((ImageProviderLocal)DALConfig.imageProvider).registerFile(new File(it.path),0)
    OrbitModel model = OrbitModel.LoadFromFile("D:\\model.omo") // !!! CHANGE ME

    // classify the image
    RecognitionFrame rf = new RecognitionFrame(rdf)
    ClassificationResult res = OrbitHelper.Classify(rdf, rf, null, model, null, -1, null, true) // last boolean parameter indicates to stare the classification map

    // saves a downscaled classification image to disk. Similar to "Tools->Save classification image" functionality.

    def fn = it.path.replaceAll("(i\\d+j\\d+)", "out_\$1");
    println fn

    final TiledImage classImg = rf.getClassImage().getImage();

    int width = (int) classImg.getWidth(); //Harry 2020/09/30
    int height = (int) classImg.getHeight(); //Harry 2020/09/30

    OrbitTiledImage2 mainImgTmp = rf.bimg.getImage();
    for (TiledImagePainter tip: rf.bimg.getMipMaps()) {
        // find a good resolution size
        if (tip.getWidth()>width)
            mainImgTmp = tip.getImage();
    }
    final OrbitTiledImage2 mainImg = mainImgTmp;
    ClassImageRenderer renderer = new ClassImageRenderer();

    println("start saving classification image to disk");
    BufferedImage bi = renderer.downsample(classImg, mainImg, width, height);
    renderer.saveToDisk(bi, fn);
    println("classification image saved");

    // and (optional) output the results
    String resStr = rdf.fileName;
    List<KeyValue<String, Double>> norm = res.normalizeRatio();
    (0..model.getClassShapes().size()-1).each {
        resStr += "\t" + norm.get(it).value;
    }
    println resStr;
    DALConfig.getImageProvider().close();  // only close if not executed within Orbit
}

Dear @jena,
the easiest method for this is to process the files in parallel. Basically you csn use gpars for this and replace your list.each with a .eachParallel, e.g. see example here https://github.com/mstritt/orbit-image-analysis/blob/53e25de84199d77b99a46eda0e7b2a3dc76aceaf/src/main/groovy/com/actelion/research/orbit/imageAnalysis/scripts/ClassificationDemo3.groovy

cheers,
Manuel

Hi Manuel.
Thanks for the reply.

Another issue is the saved jpg has rather poor quality.
This affect my next step processing and create a lot of “noise”.
For example, the brown color bleeds over the yellow color and the blue color has noisy variation within (instead of pure solid color).


BufferedImage bi = renderer.downsample(classImg, mainImg, width, height);

Is there a way not to downsample or save classification image as bmp or tiff at the best quality?

Thanks!

Hi @jena,

yes, don’t call downsample :wink:
But then you have to find a way to save the full image (here: classImg) on your own, e.g. create a tiled tiff.

However, my gut feeling is that this is not really what you want. What es the goal of your analysis - what are you trying to answer?

Regards,
Manuel

But then you have to find a way to save the full image (here: classImg) on your own

Could you help to modify my script? should be just a couple lines. I am really not good at java.
Thanks!

My goal is to save the classification image (solid color label maps) at its full resolution as jpg or tiff.
This way I can use color based classification of Orbit and use label maps in MATLAB.

I tried to set up IntelliJ and downloaded your full code from github (in previous post), the code wouldn’t compile successfully. Finding dependencies and how the code works is too hard for me.

Hi @jena,

would it help to use

BufferedImage bi = renderer.downsample(classImg, mainImg, width, height);

with a higher width and height values? (simply replace the variables with the desired size)

Because even if you create a tiled, pyramidal tiff output I guess matlab cannot make use of it.

Regards,
Manuel

No, it doesn’t work.
I tried the higher res (like 3000x3000) for 1000x1000 images.
It’s marginally better and still have color variation problem.

BTW,
int width = (int) classImg.getWidth(); //Harry 2020/09/30
int height = (int) classImg.getHeight(); //Harry 2020/09/30
My code was using full with and height as input for downs ample function.

It appears to be either downsample function or jpg compression tissue that distorted the color.
What I need is raw image data in tiff or in 100% quality jpg. I am sure MATLAB can read both.

Thanks!

Perhaps the following code may be of help? It’s a Groovy script that I used to output a specific layer as a tiff file. I think you could use the code from the ColorModel line (ColorModel cm2 = orbitImage.getColorModel():wink: onwards to export your classImg as a giant tiff.

import com.actelion.research.orbit.imageAnalysis.components.ImageFrame
import com.actelion.research.orbit.imageAnalysis.components.OrbitImageAnalysis
import com.actelion.research.orbit.imageAnalysis.imaging.TileSizeWrapper
import com.actelion.research.orbit.imageAnalysis.models.FeatureDescription
import com.actelion.research.orbit.imageAnalysis.utils.OrbitImagePlanar
import com.actelion.research.orbit.imageAnalysis.utils.OrbitTiledImageIOrbitImage
import com.actelion.research.orbit.imageAnalysis.utils.TiledImagePainter
import javax.imageio.ImageIO;

import java.awt.Rectangle
import java.awt.Graphics2D
import java.awt.image.BufferedImage
import java.awt.image.ColorModel
import javax.media.jai.PlanarImage


final OrbitImageAnalysis OIA = OrbitImageAnalysis.getInstance();
final ImageFrame iFrame = OIA.getIFrame();

TileSizeWrapper tileSizeWrapper = new TileSizeWrapper(
        new OrbitImagePlanar(iFrame.getRecognitionFrame().bimg.getImage(), ""),
        512,
        512);

OrbitTiledImageIOrbitImage orbitImage = new OrbitTiledImageIOrbitImage(tileSizeWrapper);
ColorModel cm2 = orbitImage.getColorModel()

TiledImagePainter mipMap = iFrame.getRecognitionFrame().bimg.getMipMaps()[4]
println mipMap.getHeight()
println mipMap.getWidth()
//final ColorModel colorModel_RGB = new BufferedImage(1,1,BufferedImage.TYPE_INT_RGB).getColorModel();

ColorModel cm = iFrame.getRecognitionFrame().getColorModel()
cm.createCompatibleWritableRaster(1,2)
java.awt.Rectangle rect = new Rectangle(mipMap.getWidth(),mipMap.getHeight())
FeatureDescription fd = new FeatureDescription()
BufferedImage bim = new BufferedImage(cm2, mipMap.getData(rect, fd).createCompatibleWritableRaster(), false, null)
Graphics2D g2d = bim.createGraphics()
PlanarImage pim = mipMap.getModifiedImage(fd)

g2d.drawImage(pim.getAsBufferedImage(),0,0, null);
g2d.dispose();

ImageIO.write(bim, "tiff", new File("D:/tmp/test.tiff"))
println "done"