use of qupath.opencv.ops.ImageOp in project qupath by qupath.
the class SimpleThresholdCommand method updateClassification.
private void updateClassification() {
// for (var viewer : qupath.getViewers()) {
// var imageData = viewer.getImageData();
// if (imageData == null) {
// selectedOverlay.set(null);
// viewer.resetCustomPixelLayerOverlay();
// }
// }
var channel = selectedChannel.get();
var thresholdValue = threshold.get();
var resolution = selectedResolution.get();
if (channel == null || thresholdValue == null || resolution == null) {
resetOverlays();
return;
}
var feature = selectedPrefilter.get();
double sigmaValue = sigma.get();
PixelClassifier classifier;
List<ImageOp> ops = new ArrayList<>();
if (feature != null && sigmaValue > 0) {
ops.add(feature.buildOp(sigmaValue));
}
ops.add(ImageOps.Threshold.threshold(threshold.get()));
Map<Integer, PathClass> classifications = new LinkedHashMap<>();
classifications.put(0, classificationsBelow.getSelectionModel().getSelectedItem());
classifications.put(1, classificationsAbove.getSelectionModel().getSelectedItem());
var op = ImageOps.Core.sequential(ops);
var transformer = ImageOps.buildImageDataOp(channel).appendOps(op);
classifier = PixelClassifiers.createClassifier(transformer, resolution.getPixelCalibration(), classifications);
// Create classifier
var overlay = PixelClassificationOverlay.create(qupath.getOverlayOptions(), classifier);
overlay.setLivePrediction(true);
var previousOverlay = selectedOverlay.get();
if (previousOverlay != null)
previousOverlay.stop();
selectedOverlay.set(overlay);
this.currentClassifier.set(classifier);
ensureOverlays();
}
use of qupath.opencv.ops.ImageOp 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);
}
use of qupath.opencv.ops.ImageOp in project qupath by qupath.
the class DensityMapDataOp method appendOps.
@Override
public ImageDataOp appendOps(ImageOp... ops) {
if (ops.length == 0)
return this;
ImageOp opNew;
if (ops.length > 1)
opNew = ImageOps.Core.sequential(ops);
else
opNew = ops[0];
var dataOp = new DensityMapDataOp(radius, primaryObjects, allObjects, densityType);
dataOp.op = ImageOps.Core.sequential(dataOp.op, opNew);
dataOp.channels = opNew.getChannels(dataOp.channels);
return dataOp;
}
use of qupath.opencv.ops.ImageOp in project qupath by qupath.
the class OpenCVDnn method createBlobFunction.
private BlobFunction<Mat> createBlobFunction() {
var ops = new ArrayList<ImageOp>();
if (mean != null) {
// TODO: Trim scalar array if needed
double[] scalarArray = new double[4];
mean.get(scalarArray);
ops.add(ImageOps.Core.subtract(scalarArray));
}
if (scale != 1)
ops.add(ImageOps.Core.multiply(scale));
ImageOp preprocess;
if (ops.isEmpty())
preprocess = null;
else if (ops.size() == 1)
preprocess = ops.get(0);
else
preprocess = ImageOps.Core.sequential(ops);
return new DefaultBlobFunction(preprocess, size, crop);
}
Aggregations