Search in sources :

Example 1 with ImageChannel

use of qupath.lib.images.servers.ImageChannel in project qupath by qupath.

the class CreateChannelTrainingImagesCommand method run.

@Override
public void run() {
    var project = qupath.getProject();
    var imageData = qupath.getImageData();
    var entry = project != null && imageData != null ? project.getEntry(imageData) : null;
    if (entry == null) {
        Dialogs.showErrorMessage(title, "This command requires an open image within a project!");
        return;
    }
    var channels = new ArrayList<>(imageData.getServer().getMetadata().getChannels());
    var list = new CheckListView<ImageChannel>();
    list.getItems().setAll(channels);
    list.getCheckModel().checkAll();
    list.setCellFactory(v -> new CheckBoxListCell<>(item -> list.getItemBooleanProperty(item)) {

        @Override
        public void updateItem(ImageChannel item, boolean empty) {
            super.updateItem(item, empty);
            if (item == null || empty) {
                setText(null);
                return;
            }
            setText(item.getName());
        }
    });
    var label = new Label("Create duplicate images for each of the following channels?");
    if (channels.size() == 1)
        label.setText("Create a duplicate image for the one and only channel?");
    var labelName = new Label("Root name");
    var tfName = new TextField(entry.getImageName().trim());
    labelName.setLabelFor(tfName);
    String namePrompt = "Enter root image name for duplicate images";
    tfName.setPromptText(namePrompt);
    tfName.setTooltip(new Tooltip(namePrompt));
    var cbInitializePoints = new CheckBox("Initialize Points annotations");
    var pane = new GridPane();
    int row = 0;
    PaneTools.addGridRow(pane, row++, 0, null, label, label);
    PaneTools.addGridRow(pane, row++, 0, namePrompt, labelName, tfName);
    PaneTools.addGridRow(pane, row++, 0, "Channels to duplicate", list, list);
    PaneTools.addGridRow(pane, row++, 0, "Create Points annotations for the corresponding channel", cbInitializePoints, cbInitializePoints);
    PaneTools.setFillWidth(Boolean.TRUE, label, tfName, list, cbInitializePoints);
    PaneTools.setHGrowPriority(Priority.ALWAYS, label, tfName, list, cbInitializePoints);
    PaneTools.setVGrowPriority(Priority.ALWAYS, list);
    PaneTools.setMaxWidth(Double.MAX_VALUE, label, tfName, list, cbInitializePoints);
    list.setPrefHeight(240);
    pane.setHgap(5.0);
    pane.setVgap(5.0);
    if (!Dialogs.showConfirmDialog(title, pane))
        return;
    var name = tfName.getText().trim();
    boolean initializePoints = cbInitializePoints.isSelected();
    try {
        for (var channel : list.getCheckModel().getCheckedItems()) {
            var entry2 = project.addDuplicate(entry, true);
            String channelName = channel.getName();
            entry2.setImageName(name.trim() + " - " + channelName);
            if (initializePoints) {
                var imageData2 = entry2.readImageData();
                imageData2.getHierarchy().addPathObjects(Arrays.asList(PathObjects.createAnnotationObject(ROIs.createPointsROI(ImagePlane.getDefaultPlane()), PathClassFactory.getPathClass(channelName, channel.getColor())), PathObjects.createAnnotationObject(ROIs.createPointsROI(ImagePlane.getDefaultPlane()), PathClassFactory.getPathClass(PathClassFactory.StandardPathClasses.IGNORE))));
                entry2.saveImageData(imageData2);
            }
        }
        project.syncChanges();
    } catch (Exception e) {
        Dialogs.showErrorMessage(title, e);
    }
    qupath.refreshProject();
}
Also used : Arrays(java.util.Arrays) TextField(javafx.scene.control.TextField) Label(javafx.scene.control.Label) CheckBoxListCell(javafx.scene.control.cell.CheckBoxListCell) PathObjects(qupath.lib.objects.PathObjects) CheckBox(javafx.scene.control.CheckBox) ImageChannel(qupath.lib.images.servers.ImageChannel) PathClassFactory(qupath.lib.objects.classes.PathClassFactory) ArrayList(java.util.ArrayList) Dialogs(qupath.lib.gui.dialogs.Dialogs) CheckListView(org.controlsfx.control.CheckListView) Priority(javafx.scene.layout.Priority) ROIs(qupath.lib.roi.ROIs) ImagePlane(qupath.lib.regions.ImagePlane) Tooltip(javafx.scene.control.Tooltip) GridPane(javafx.scene.layout.GridPane) QuPathGUI(qupath.lib.gui.QuPathGUI) PaneTools(qupath.lib.gui.tools.PaneTools) GridPane(javafx.scene.layout.GridPane) Tooltip(javafx.scene.control.Tooltip) ArrayList(java.util.ArrayList) Label(javafx.scene.control.Label) CheckListView(org.controlsfx.control.CheckListView) CheckBox(javafx.scene.control.CheckBox) ImageChannel(qupath.lib.images.servers.ImageChannel) TextField(javafx.scene.control.TextField)

Example 2 with ImageChannel

use of qupath.lib.images.servers.ImageChannel in project qupath by qupath.

the class DensityMapDataOp method buildOpAndChannels.

private void buildOpAndChannels() {
    logger.trace("Building density map op with type {}", densityType);
    String baseChannelName;
    ImageChannel lastChannel = null;
    List<ImageOp> sequentialOps = new ArrayList<>();
    switch(densityType) {
        case GAUSSIAN:
            if (radius > 0) {
                double sigma = radius;
                sequentialOps.add(ImageOps.Filters.gaussianBlur(sigma));
                // Scale so that central value ~1 - this is a closer match to the alternative sum filter
                sequentialOps.add(ImageOps.Core.multiply(2 * Math.PI * sigma * sigma));
            }
            baseChannelName = "Gaussian weighted counts ";
            break;
        case PERCENT:
            int[] extractInds = IntStream.range(0, primaryObjects.size()).toArray();
            if (radius > 0) {
                sequentialOps.add(ImageOps.Filters.sum(radius));
                sequentialOps.add(ImageOps.Core.round());
            }
            if (extractInds.length > 0) {
                // Duplicate the image, then
                // - On the first duplicate, remove the last channel and divide all the other channels by its values
                // - On the second duplicate, extract the last channel (so as to retain its values)
                // Finally merge the last channel back
                // The outcome should be that the last channel is unchanged, while the other channels are divided by the last
                // channel elementwise.
                sequentialOps.addAll(Arrays.asList(ImageOps.Core.splitMerge(ImageOps.Core.sequential(ImageOps.Core.splitDivide(ImageOps.Channels.extract(extractInds), ImageOps.Core.sequential(ImageOps.Channels.extract(extractInds.length), ImageOps.Channels.repeat(extractInds.length))), // Convert to percent
                ImageOps.Core.multiply(100.0)), ImageOps.Channels.extract(extractInds.length))));
            } else {
                // Values will be 1 and NaN (a possibly-zero value being divided by itself)
                sequentialOps.add(ImageOps.Core.splitDivide(null, null));
            }
            baseChannelName = "";
            if (!primaryObjects.isEmpty())
                lastChannel = ImageChannel.getInstance(DensityMaps.CHANNEL_ALL_OBJECTS, null);
            break;
        case SUM:
        default:
            if (radius > 0) {
                sequentialOps.add(ImageOps.Filters.sum(radius));
                sequentialOps.add(ImageOps.Core.round());
            }
            baseChannelName = "";
    }
    var channelNames = primaryObjects.keySet().stream().map(n -> baseChannelName + n).toArray(String[]::new);
    var channels = new ArrayList<>(ImageChannel.getChannelList(channelNames));
    if (lastChannel != null)
        channels.add(lastChannel);
    if (channels.isEmpty())
        this.channels = Collections.singletonList(ImageChannel.getInstance(DensityMaps.CHANNEL_ALL_OBJECTS, null));
    else
        this.channels = Collections.unmodifiableList(channels);
    sequentialOps.add(ImageOps.Core.ensureType(PixelType.FLOAT32));
    this.op = ImageOps.Core.sequential(sequentialOps);
}
Also used : IntStream(java.util.stream.IntStream) Arrays(java.util.Arrays) org.bytedeco.opencv.global.opencv_core(org.bytedeco.opencv.global.opencv_core) LoggerFactory(org.slf4j.LoggerFactory) ImageChannel(qupath.lib.images.servers.ImageChannel) ImageDataOp(qupath.opencv.ops.ImageDataOp) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) ImageOps(qupath.opencv.ops.ImageOps) Point2(qupath.lib.geom.Point2) DensityMapType(qupath.lib.analysis.heatmaps.DensityMaps.DensityMapType) Map(java.util.Map) Mat(org.bytedeco.opencv.opencv_core.Mat) Scalar(org.bytedeco.opencv.opencv_core.Scalar) URI(java.net.URI) DoubleIndexer(org.bytedeco.javacpp.indexer.DoubleIndexer) ImageData(qupath.lib.images.ImageData) Logger(org.slf4j.Logger) BufferedImage(java.awt.image.BufferedImage) RegionRequest(qupath.lib.regions.RegionRequest) PixelType(qupath.lib.images.servers.PixelType) Collection(java.util.Collection) ImageOp(qupath.opencv.ops.ImageOp) IOException(java.io.IOException) Padding(qupath.lib.regions.Padding) Collectors(java.util.stream.Collectors) PathObjectTools(qupath.lib.objects.PathObjectTools) Objects(java.util.Objects) ROI(qupath.lib.roi.interfaces.ROI) List(java.util.List) PathObjectPredicate(qupath.lib.objects.PathObjectPredicates.PathObjectPredicate) Collections(java.util.Collections) ImageOp(qupath.opencv.ops.ImageOp) ImageChannel(qupath.lib.images.servers.ImageChannel) ArrayList(java.util.ArrayList)

Example 3 with ImageChannel

use of qupath.lib.images.servers.ImageChannel in project qupath by qupath.

the class WatershedCellDetection method buildParameterList.

private ParameterList buildParameterList(final ImageData<BufferedImage> imageData) {
    ParameterList params = new ParameterList();
    // TODO: Use a better way to determining if pixel size is available in microns
    // params.addEmptyParameter("detectionParameters", "Detection parameters", true);
    String microns = IJ.micronSymbol + "m";
    params.addTitleParameter("Setup parameters");
    String defaultChannel = null;
    List<String> channelNames = new ArrayList<>();
    String[] nucleusGuesses = new String[] { "dapi", "hoechst", "nucleus", "nuclei", "nuclear", "hematoxylin", "haematoxylin" };
    for (ImageChannel channel : imageData.getServer().getMetadata().getChannels()) {
        String name = channel.getName();
        channelNames.add(name);
        if (defaultChannel == null) {
            String lower = name.toLowerCase();
            for (String guess : nucleusGuesses) {
                if (lower.contains(guess))
                    defaultChannel = name;
            }
        }
    }
    if (defaultChannel == null)
        defaultChannel = channelNames.get(0);
    if (channelNames.size() != new HashSet<>(channelNames).size())
        logger.warn("Image contains duplicate channel names! This may be confusing for detection and analysis.");
    params.addChoiceParameter("detectionImage", "Detection channel", defaultChannel, channelNames, "Choose the channel that should be used for nucleus detection (e.g. DAPI)");
    params.addChoiceParameter("detectionImageBrightfield", "Detection image", IMAGE_HEMATOXYLIN, Arrays.asList(IMAGE_HEMATOXYLIN, IMAGE_OPTICAL_DENSITY), "Transformed image to which to apply the detection");
    params.addDoubleParameter("requestedPixelSizeMicrons", "Requested pixel size", .5, microns, "Choose pixel size at which detection will be performed - higher values are likely to be faster, but may be less accurate; set <= 0 to use the full image resolution");
    // params.addDoubleParameter("requestedPixelSize", "Requested downsample factor", 1, "");
    params.addTitleParameter("Nucleus parameters");
    params.addDoubleParameter("backgroundRadiusMicrons", "Background radius", 8, microns, "Radius for background estimation, should be > the largest nucleus radius, or <= 0 to turn off background subtraction");
    params.addDoubleParameter("medianRadiusMicrons", "Median filter radius", 0, microns, "Radius of median filter used to reduce image texture (optional)");
    params.addDoubleParameter("sigmaMicrons", "Sigma", 1.5, microns, "Sigma value for Gaussian filter used to reduce noise; increasing the value stops nuclei being fragmented, but may reduce the accuracy of boundaries");
    params.addDoubleParameter("minAreaMicrons", "Minimum area", 10, microns + "^2", "Detected nuclei with an area < minimum area will be discarded");
    params.addDoubleParameter("maxAreaMicrons", "Maximum area", 400, microns + "^2", "Detected nuclei with an area > maximum area will be discarded");
    params.addDoubleParameter("backgroundRadius", "Background radius", 15, "px", "Radius for background estimation, should be > the largest nucleus radius, or <= 0 to turn off background subtraction");
    params.addDoubleParameter("medianRadius", "Median filter radius", 0, "px", "Radius of median filter used to reduce image texture (optional)");
    params.addDoubleParameter("sigma", "Sigma", 3, "px", "Sigma value for Gaussian filter used to reduce noise; increasing the value stops nuclei being fragmented, but may reduce the accuracy of boundaries");
    params.addDoubleParameter("minArea", "Minimum area", 10, "px^2", "Detected nuclei with an area < minimum area will be discarded");
    params.addDoubleParameter("maxArea", "Maximum area", 1000, "px^2", "Detected nuclei with an area > maximum area will be discarded");
    params.addTitleParameter("Intensity parameters");
    params.addDoubleParameter("threshold", "Threshold", 0.1, null, "Intensity threshold - detected nuclei must have a mean intensity >= threshold");
    // params.addDoubleParameter("threshold", "Threshold", 0.1, null, 0, 2.5,
    // "Intensity threshold - detected nuclei must have a mean intensity >= threshold");
    params.addDoubleParameter("maxBackground", "Max background intensity", 2, null, "If background radius > 0, detected nuclei occurring on a background > max background intensity will be discarded");
    // params.addBooleanParameter("mergeAll", "Merge all", true);
    params.addBooleanParameter("watershedPostProcess", "Split by shape", true, "Split merged detected nuclei based on shape ('roundness')");
    params.addBooleanParameter("excludeDAB", "Exclude DAB (membrane staining)", false, "Set to 'true' if regions of high DAB staining should not be considered nuclei; useful if DAB stains cell membranes");
    params.addTitleParameter("Cell parameters");
    params.addDoubleParameter("cellExpansionMicrons", "Cell expansion", 5, microns, 0, 25, "Amount by which to expand detected nuclei to approximate the full cell area");
    params.addDoubleParameter("cellExpansion", "Cell expansion", 5, "px", "Amount by which to expand detected nuclei to approximate the full cell area");
    // params.addBooleanParameter("limitExpansionByNucleusSize", "Limit cell expansion by nucleus size", false, "If checked, nuclei will not be expanded by more than their (estimated) smallest diameter in any direction - may give more realistic results for smaller, or 'thinner' nuclei");
    params.addBooleanParameter("includeNuclei", "Include cell nucleus", true, "If cell expansion is used, optionally include/exclude the nuclei within the detected cells");
    params.addTitleParameter("General parameters");
    params.addBooleanParameter("smoothBoundaries", "Smooth boundaries", true, "Smooth the detected nucleus/cell boundaries");
    params.addBooleanParameter("makeMeasurements", "Make measurements", true, "Add default shape & intensity measurements during detection");
    return params;
}
Also used : ImageChannel(qupath.lib.images.servers.ImageChannel) ArrayList(java.util.ArrayList) ParameterList(qupath.lib.plugins.parameters.ParameterList) HashSet(java.util.HashSet)

Aggregations

ArrayList (java.util.ArrayList)3 ImageChannel (qupath.lib.images.servers.ImageChannel)3 Arrays (java.util.Arrays)2 BufferedImage (java.awt.image.BufferedImage)1 IOException (java.io.IOException)1 URI (java.net.URI)1 Collection (java.util.Collection)1 Collections (java.util.Collections)1 HashSet (java.util.HashSet)1 LinkedHashMap (java.util.LinkedHashMap)1 List (java.util.List)1 Map (java.util.Map)1 Objects (java.util.Objects)1 Collectors (java.util.stream.Collectors)1 IntStream (java.util.stream.IntStream)1 CheckBox (javafx.scene.control.CheckBox)1 Label (javafx.scene.control.Label)1 TextField (javafx.scene.control.TextField)1 Tooltip (javafx.scene.control.Tooltip)1 CheckBoxListCell (javafx.scene.control.cell.CheckBoxListCell)1