Search in sources :

Example 31 with TMACoreObject

use of qupath.lib.objects.TMACoreObject in project qupath by qupath.

the class FindConvexHullDetectionsPlugin method getParentObjects.

@Override
protected Collection<? extends PathObject> getParentObjects(PluginRunner<T> runner) {
    PathObjectHierarchy hierarchy = getHierarchy(runner);
    PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
    if (selected instanceof TMACoreObject)
        return Collections.singleton(selected);
    if (hierarchy.getTMAGrid() != null)
        return hierarchy.getTMAGrid().getTMACoreList();
    else
        return Collections.emptyList();
}
Also used : PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) PathObject(qupath.lib.objects.PathObject) TMACoreObject(qupath.lib.objects.TMACoreObject)

Example 32 with TMACoreObject

use of qupath.lib.objects.TMACoreObject in project qupath by qupath.

the class TMACommands method createAugmentedTMAGrid.

/**
 * Add a new row or column to a TMA grid.
 *
 * @param hierarchy
 * @param selectedCore
 * @param type
 * @return
 */
private static TMAGrid createAugmentedTMAGrid(final PathObjectHierarchy hierarchy, final TMACoreObject selectedCore, final TMAAddType type) {
    TMAGrid grid = hierarchy.getTMAGrid();
    // Convert to easier form
    boolean addAfter = type == TMAAddType.COLUMN_AFTER || type == TMAAddType.ROW_AFTER;
    boolean addColumn = type == TMAAddType.COLUMN_AFTER || type == TMAAddType.COLUMN_BEFORE;
    // Try to identify the row/column that we want
    int row = -1;
    int col = -1;
    if (selectedCore != null) {
        for (int y = 0; y < grid.getGridHeight(); y++) {
            for (int x = 0; x < grid.getGridWidth(); x++) {
                if (grid.getTMACore(y, x) == selectedCore) {
                    if (addAfter) {
                        row = y + 1;
                        col = x + 1;
                    } else {
                        row = y;
                        col = x;
                    }
                    break;
                }
            }
        }
    }
    // If we don't have a row or column, choose based on the add type
    if (row < 0) {
        switch(type) {
            case COLUMN_AFTER:
                col = grid.getGridWidth();
                break;
            case COLUMN_BEFORE:
                col = 0;
                break;
            case ROW_AFTER:
                row = grid.getGridHeight();
                break;
            case ROW_BEFORE:
                row = 0;
                break;
            default:
                break;
        }
    }
    // Compute the width of the new grid
    int newWidth = addColumn ? grid.getGridWidth() + 1 : grid.getGridWidth();
    int newHeight = addColumn ? grid.getGridHeight() : grid.getGridHeight() + 1;
    // Loop through cores, getting mean widths, heights & displacements
    RunningStatistics statsWidth = new RunningStatistics();
    RunningStatistics statsHeight = new RunningStatistics();
    RunningStatistics statsDx = new RunningStatistics();
    RunningStatistics statsDy = new RunningStatistics();
    for (int r = 0; r < grid.getGridHeight(); r++) {
        TMACoreObject coreColBefore = null;
        for (int c = 0; c < grid.getGridWidth(); c++) {
            TMACoreObject core = grid.getTMACore(r, c);
            if (!core.hasROI())
                continue;
            statsWidth.addValue(core.getROI().getBoundsWidth());
            statsHeight.addValue(core.getROI().getBoundsHeight());
            if (coreColBefore != null && coreColBefore.hasROI()) {
                statsDx.addValue(core.getROI().getCentroidX() - coreColBefore.getROI().getCentroidX());
            }
            if (r > 0) {
                TMACoreObject coreRowBefore = grid.getTMACore(r - 1, c);
                if (coreRowBefore != null && coreRowBefore.hasROI()) {
                    statsDy.addValue(core.getROI().getCentroidY() - coreRowBefore.getROI().getCentroidY());
                }
            }
            coreColBefore = core;
        }
    }
    double meanWidth = statsWidth.getMean();
    double meanHeight = statsHeight.getMean();
    double meanDx = statsDx.getMean();
    double meanDy = statsDy.getMean();
    double diameter = (meanWidth + meanHeight) / 2;
    // Create a new list of cores, adding where necessary
    List<TMACoreObject> coresNew = new ArrayList<>();
    for (int r = 0; r < newHeight; r++) {
        for (int c = 0; c < newWidth; c++) {
            // Copy existing rows & columns, or create new cores if required
            if (addColumn) {
                if (c < col) {
                    coresNew.add(grid.getTMACore(r, c));
                } else if (c > col) {
                    coresNew.add(grid.getTMACore(r, c - 1));
                } else if (c == col) {
                    // Try to get average x & y coordinates between surrounding columns
                    double x1, x2, y;
                    if (col == 0) {
                        x2 = grid.getTMACore(r, c).getROI().getCentroidX();
                        x1 = x2 - meanDx * 2;
                        y = grid.getTMACore(r, c).getROI().getCentroidY();
                    } else if (col == grid.getGridWidth()) {
                        x1 = grid.getTMACore(r, c - 1).getROI().getCentroidX();
                        x2 = x1 + meanDx * 2;
                        y = grid.getTMACore(r, c - 1).getROI().getCentroidY();
                    } else {
                        x1 = grid.getTMACore(r, c - 1).getROI().getCentroidX();
                        x2 = grid.getTMACore(r, c).getROI().getCentroidX();
                        y = (grid.getTMACore(r, c - 1).getROI().getCentroidY() + grid.getTMACore(r, c).getROI().getCentroidY()) / 2;
                    }
                    TMACoreObject coreNew = PathObjects.createTMACoreObject((x1 + x2) / 2, y, diameter, true);
                    coresNew.add(coreNew);
                }
            } else {
                if (r < row) {
                    coresNew.add(grid.getTMACore(r, c));
                } else if (r > row) {
                    coresNew.add(grid.getTMACore(r - 1, c));
                } else if (r == row) {
                    // Try to get average x & y coordinates between surrounding columns
                    double x, y1, y2;
                    if (row == 0) {
                        y2 = grid.getTMACore(r, c).getROI().getCentroidY();
                        y1 = y2 - meanDy * 2;
                        x = grid.getTMACore(r, c).getROI().getCentroidX();
                    } else if (row == grid.getGridHeight()) {
                        y1 = grid.getTMACore(r - 1, c).getROI().getCentroidY();
                        y2 = y1 + meanDy * 2;
                        x = grid.getTMACore(r - 1, c).getROI().getCentroidX();
                    } else {
                        y1 = grid.getTMACore(r - 1, c).getROI().getCentroidY();
                        y2 = grid.getTMACore(r, c).getROI().getCentroidY();
                        x = (grid.getTMACore(r - 1, c).getROI().getCentroidX() + grid.getTMACore(r, c).getROI().getCentroidX()) / 2;
                    }
                    TMACoreObject coreNew = PathObjects.createTMACoreObject(x, (y1 + y2) / 2, diameter, true);
                    coresNew.add(coreNew);
                }
            }
        }
    }
    // Update with a new TMAGrid
    return DefaultTMAGrid.create(coresNew, newWidth);
}
Also used : TMACoreObject(qupath.lib.objects.TMACoreObject) DefaultTMAGrid(qupath.lib.objects.hierarchy.DefaultTMAGrid) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) ArrayList(java.util.ArrayList) RunningStatistics(qupath.lib.analysis.stats.RunningStatistics)

Example 33 with TMACoreObject

use of qupath.lib.objects.TMACoreObject in project qupath by qupath.

the class TMACommands method promptToAddTMARowOrColumn.

/**
 * Add a new row or column to a TMA grid.
 *
 * @param imageData
 * @param type
 * @return
 */
private static boolean promptToAddTMARowOrColumn(final ImageData<?> imageData, final TMAAddType type) {
    String NAME = type.commandName();
    if (imageData == null) {
        Dialogs.showNoImageError(NAME);
        return false;
    }
    if (imageData.getHierarchy().getTMAGrid() == null) {
        Dialogs.showErrorMessage(NAME, "No image with dearrayed TMA cores selected!");
        return false;
    }
    PathObjectHierarchy hierarchy = imageData.getHierarchy();
    PathObject selected = hierarchy.getSelectionModel().getSelectedObject();
    TMACoreObject selectedCore = null;
    if (selected != null)
        selectedCore = PathObjectTools.getAncestorTMACore(selected);
    TMAGrid gridNew = createAugmentedTMAGrid(hierarchy, selectedCore, type);
    double w = imageData.getServer().getWidth();
    double h = imageData.getServer().getHeight();
    // Check if the core centroids all fall within the image or not
    int outsideCores = 0;
    for (TMACoreObject core : gridNew.getTMACoreList()) {
        // Shouldn't happen...
        if (!core.hasROI())
            continue;
        // Check if the centroid for any *new* core falls within the image
        // (don't fail if an existing core is outside)
        double x = core.getROI().getCentroidX();
        double y = core.getROI().getCentroidY();
        if (x < 0 || x >= w || y < 0 || y >= h) {
            if (!hierarchy.getTMAGrid().getTMACoreList().contains(core)) {
                outsideCores++;
            }
        // throw new IllegalArgumentException("Cannot update TMA grid - not enough space within image");
        }
    }
    if (outsideCores > 0) {
        String label = outsideCores == 1 ? "core" : "cores";
        if (!Dialogs.showConfirmDialog("Add to TMA Grid", "Not enough space within image to store " + outsideCores + " new " + label + " - proceed anyway?"))
            return false;
    }
    // If we got this far, update the grid
    hierarchy.setTMAGrid(gridNew);
    // Prompt for relabelling
    TMACommands.promptToRelabelTMAGrid(imageData);
    return true;
}
Also used : PathObjectHierarchy(qupath.lib.objects.hierarchy.PathObjectHierarchy) PathObject(qupath.lib.objects.PathObject) TMACoreObject(qupath.lib.objects.TMACoreObject) DefaultTMAGrid(qupath.lib.objects.hierarchy.DefaultTMAGrid) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid)

Example 34 with TMACoreObject

use of qupath.lib.objects.TMACoreObject in project qupath by qupath.

the class ColorToolsFX method getDisplayedColorARGB.

/**
 * Get the color with which an object should be displayed, as a packaged ARGB integer.
 *
 * This could be stored internally, or obtained from its PathClass.
 *
 * If neither of these produces a result, a default color will be returned based on PathPrefs
 * for the specific (Java) class of the PathObject.
 *
 * Assuming PathPrefs does not contain any nulls, this will therefore not return nulls either.
 *
 * @param pathObject
 * @return
 */
public static Integer getDisplayedColorARGB(final PathObject pathObject) {
    // Check if any color has been set - if so, return it
    Integer color = pathObject.getColorRGB();
    if (color != null)
        return color;
    // Check if any class has been set, if so then use its color
    PathClass pathClass = pathObject.getPathClass();
    if (pathClass != null)
        color = pathClass.getColor();
    if (color != null)
        return color;
    if (pathObject instanceof PathTileObject)
        return PathPrefs.colorTileProperty().getValue();
    if (pathObject instanceof TMACoreObject) {
        if (((TMACoreObject) pathObject).isMissing())
            return PathPrefs.colorTMAMissingProperty().getValue();
        else
            return PathPrefs.colorTMAProperty().getValue();
    }
    return PathPrefs.colorDefaultObjectsProperty().getValue();
}
Also used : PathClass(qupath.lib.objects.classes.PathClass) PathTileObject(qupath.lib.objects.PathTileObject) TMACoreObject(qupath.lib.objects.TMACoreObject)

Example 35 with TMACoreObject

use of qupath.lib.objects.TMACoreObject in project qupath by qupath.

the class TMAExplorer method createAndShowStage.

private void createAndShowStage() {
    Project<BufferedImage> project = qupath.getProject();
    entries.clear();
    if (project != null) {
        // Create an output directory for the images
        File dirBaseImageOutput = Projects.getBaseDirectory(project);
        dirBaseImageOutput = new File(dirBaseImageOutput, "TMA");
        dirBaseImageOutput = new File(dirBaseImageOutput, "images");
        if (!dirBaseImageOutput.exists())
            dirBaseImageOutput.mkdirs();
        Map<String, RunningStatistics> statsMap = new HashMap<>();
        for (ProjectImageEntry<BufferedImage> imageEntry : project.getImageList()) {
            // Look for data file
            if (!imageEntry.hasImageData())
                continue;
            File dirImageOutput = new File(dirBaseImageOutput, imageEntry.getImageName());
            if (!dirImageOutput.exists())
                dirImageOutput.mkdirs();
            // Read data
            ImageData<BufferedImage> imageData;
            try {
                imageData = imageEntry.readImageData();
            } catch (IOException e) {
                logger.error("Error reading ImageData for " + imageEntry.getImageName(), e);
                continue;
            }
            TMAGrid tmaGrid = imageData.getHierarchy().getTMAGrid();
            if (tmaGrid == null) {
                logger.warn("No TMA data for {}", imageEntry.getImageName());
                continue;
            }
            // Figure out downsample value
            ImageServer<BufferedImage> server = imageData.getServer();
            double downsample = Math.round(5 / server.getPixelCalibration().getAveragedPixelSizeMicrons());
            // Read the TMA entries
            int counter = 0;
            for (TMACoreObject core : tmaGrid.getTMACoreList()) {
                counter++;
                String name = core.getName();
                if (name == null)
                    name = Integer.toString(counter);
                File fileOutput = new File(dirImageOutput, name + ".jpg");
                if (!fileOutput.exists()) {
                    try {
                        RegionRequest request = RegionRequest.createInstance(server.getPath(), downsample, core.getROI());
                        BufferedImage img = server.readBufferedImage(request);
                        ImageIO.write(img, "jpg", fileOutput);
                    } catch (Exception e) {
                        logger.error("Unable to write {}", fileOutput.getAbsolutePath());
                    }
                }
                var entry = TMAEntries.createDefaultTMAEntry(imageEntry.getImageName(), fileOutput.getAbsolutePath(), null, core.getName(), core.isMissing());
                MeasurementList ml = core.getMeasurementList();
                for (int i = 0; i < ml.size(); i++) {
                    String measurement = ml.getMeasurementName(i);
                    double val = ml.getMeasurementValue(i);
                    entry.putMeasurement(measurement, val);
                    if (!Double.isNaN(val)) {
                        RunningStatistics stats = statsMap.get(measurement);
                        if (stats == null) {
                            stats = new RunningStatistics();
                            statsMap.put(measurement, stats);
                        }
                        stats.addValue(val);
                    }
                }
                entries.add(entry);
            }
            try {
                server.close();
            } catch (Exception e) {
                logger.warn("Problem closing server", e);
            }
        }
        // Loop through all entries and perform outlier count
        double k = 3;
        for (TMAEntry entry : entries) {
            int outlierCount = 0;
            for (Entry<String, RunningStatistics> statsEntry : statsMap.entrySet()) {
                RunningStatistics stats = statsEntry.getValue();
                double val = entry.getMeasurementAsDouble(statsEntry.getKey());
                if (!(val >= stats.getMean() - stats.getStdDev() * k && val <= stats.getMean() + stats.getStdDev() * k))
                    outlierCount++;
            }
            entry.putMeasurement("Outlier count", outlierCount);
        }
    }
    Stage stage = new Stage();
    stage.initOwner(qupath.getStage());
    TMASummaryViewer summaryViewer = new TMASummaryViewer(stage);
    summaryViewer.setTMAEntries(entries);
    summaryViewer.getStage().show();
}
Also used : HashMap(java.util.HashMap) TMACoreObject(qupath.lib.objects.TMACoreObject) MeasurementList(qupath.lib.measurements.MeasurementList) TMAEntry(qupath.lib.gui.tma.TMAEntries.TMAEntry) TMAGrid(qupath.lib.objects.hierarchy.TMAGrid) IOException(java.io.IOException) BufferedImage(java.awt.image.BufferedImage) IOException(java.io.IOException) RunningStatistics(qupath.lib.analysis.stats.RunningStatistics) Stage(javafx.stage.Stage) File(java.io.File) RegionRequest(qupath.lib.regions.RegionRequest)

Aggregations

TMACoreObject (qupath.lib.objects.TMACoreObject)35 PathObject (qupath.lib.objects.PathObject)20 ArrayList (java.util.ArrayList)17 PathObjectHierarchy (qupath.lib.objects.hierarchy.PathObjectHierarchy)15 TMAGrid (qupath.lib.objects.hierarchy.TMAGrid)13 BufferedImage (java.awt.image.BufferedImage)12 PathAnnotationObject (qupath.lib.objects.PathAnnotationObject)12 ROI (qupath.lib.roi.interfaces.ROI)12 IOException (java.io.IOException)9 List (java.util.List)9 RegionRequest (qupath.lib.regions.RegionRequest)9 File (java.io.File)6 ImageServer (qupath.lib.images.servers.ImageServer)6 PathDetectionObject (qupath.lib.objects.PathDetectionObject)6 Collection (java.util.Collection)5 LinkedHashMap (java.util.LinkedHashMap)5 Collectors (java.util.stream.Collectors)5 HashSet (java.util.HashSet)4 Insets (javafx.geometry.Insets)4 Scene (javafx.scene.Scene)4