An example of a single process Region of Interest (ROI) detection pipeline written in Myriad, using a previously-saved ROI detection model. The major steps in the processing pipeline:

  1. A single local file is read.
  2. A Gaussian Pyramid operation is performed for scale invariance: the ROI model looks at the data at several different scales.
  3. For each step in the Gaussian Pyramid, a Sliding Window moves across the data performing Sobel edge detection.
  4. For each window in the Sliding Window, the ROI model scans for ROI. If found, the ROI is appended to a List.
  5. When ROI scanning is complete, the positions of each ROI relative to the original input data are reported.
/*
 * Copyright (c) 2016 Emphysic LLC.  All rights reserved.
 */

package com.emphysic.myriad.core.examples;

import com.emphysic.myriad.core.data.io.Dataset;
import com.emphysic.myriad.core.data.io.IODataset;
import com.emphysic.myriad.core.data.ops.GaussianBlur;
import com.emphysic.myriad.core.data.ops.GaussianPyramidOperation;
import com.emphysic.myriad.core.data.ops.SlidingWindowOperation;
import com.emphysic.myriad.core.data.ops.SobelOperation;
import com.emphysic.myriad.core.data.roi.AdaptiveSGDROIFinder;
import com.emphysic.myriad.core.data.roi.ROI;
import com.emphysic.myriad.core.data.util.DatasetUtils;
import com.emphysic.myriad.core.data.util.FileSniffer;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Demonstrates a single-process ROI processing pipeline.
 *
 * 1. Ingest data
 * 2. Run a Gaussian Pyramid operation on the input for scale invariance
 * 2a. (Optional) perform any preprocessing desired on each step in the pyramid in 2
 * 3. For each step in the pyramid in 2(a), run a sliding window operation
 * 4. For each sliding window in 3, ask an ROI detector whether the window contains ROI or not
 * 5. Compile the results
 */
@Slf4j
public class PipelineDemo {
    public static void main(String[] args) throws Exception {
        IODataset dataset = null;
        File inputFile;
        if (args == null || args.length != 1) {
            URL sampleData = Thread.currentThread().getContextClassLoader().getResource("data/io/sampledata/140.csv");
            inputFile = new File(sampleData.getPath());
        } else {
            inputFile = new File(args[0]);
        }
        Date start = new Date();
        int windowSize = 15; // Size of dimension in window and model i.e. both are 15x15

        // 1.  Data ingestor
        assert (inputFile.exists());
        System.out.println("Reading input file " + inputFile.getAbsolutePath());
        dataset = FileSniffer.read(inputFile, true);
        System.out.println("Input data " + dataset.getWidth() + "x" + dataset.getHeight() + "\n");

        // 2.  Pyramid
        System.out.println("Creating pyramid operation of radius 1\n");
        GaussianPyramidOperation po = new GaussianPyramidOperation(new GaussianBlur(1));

        // Read the trained model - in this case, an adaptive Stochastic Gradient Descent (SGD) model trained to detect
        // indications of structural damage in ultrasonic sensor data
        System.out.println("Reading pre-trained model\n");
        URL earl = Thread.currentThread().getContextClassLoader().getResource("models/pa_ultrasonic_cscan/model.myr");
        File modelFile = new File(earl.getPath());
        assert (modelFile.exists());
        AdaptiveSGDROIFinder sgdFlawFinder = new AdaptiveSGDROIFinder();
        sgdFlawFinder.load(modelFile);

        // This particular model uses Sobel edge detection
        System.out.println("Creating edge detector\n");
        SobelOperation sobelOperation = new SobelOperation();

        // Run Gaussian Pyramid over current dataset
        int step = 0;
        Dataset current = dataset;
        List foundROIs = new ArrayList<>();
        System.out.println("Running pyramid");
        do {
            System.out.println("\tPyramid step " + step + " " + current.getWidth() + "x" + current.getHeight());
            // 3.  Sliding Window - same size as model 15x15; overlap slightly to make sure we look at everything
            // We'll also do the Sobel edge detection here rather than globally
            SlidingWindowOperation slidingWindow = new SlidingWindowOperation(5, windowSize, sobelOperation);
            Dataset window;
            int win = 0;
            // Run Sliding Window across current step in pyramid
            while ((window = slidingWindow.run(current)) != null) {
                System.out.println("\t\twindow " + win + " position (" + slidingWindow.getXoffset() + ", "
                        + slidingWindow.getYoffset() + ")");
                // 4.  ROI Finder
                try {
                    boolean isFlaw = sgdFlawFinder.isROI(window);
                    if (isFlaw) {
                        ROI newROI = new ROI(window, slidingWindow.getXoffset(), slidingWindow.getYoffset());
                        // Store the step in the metadata
                        newROI.setMetadata(Integer.toString(step));
                        foundROIs.add(newROI);
                    }
                } catch (ArithmeticException ae) {
                    System.out.println("Model returned NaN, skipping");
                }
                win++;
            }
            step++;
        } while ((current = po.run(current)) != null);
        System.out.println("Completed.\n");

        if (foundROIs.size() > 0) {
            int scaler = po.getScaleFactor();

            System.out.println("Found flaws:");
            for (ROI roi : foundROIs) {
                // Coordinates of ROI are relative to their input - need to upscale to the original data dimensions
                List origin = roi.getOrigin();
                int upScale = scaler * Integer.parseInt(roi.getMetadata());
                int lowX = DatasetUtils.safeIdx(upScale * origin.get(0), dataset.getWidth());
                int lowY = DatasetUtils.safeIdx(upScale * origin.get(1), dataset.getHeight());
                int highX = DatasetUtils.safeIdx(lowX + upScale * windowSize, dataset.getWidth());
                int highY = DatasetUtils.safeIdx(lowY + upScale * windowSize, dataset.getHeight());
                System.out.println("\tROI bounding box: (" + lowX + ", " + lowY + ") - (" + highX + "," + highY + ")");
            }
        }
        Date end = new Date();
        Long elapsed = end.getTime() - start.getTime();
        System.out.println("Elapsed time " + (elapsed / 1000 / 60) + " minutes");
    }
}