use of qupath.lib.regions.ImageRegion in project qupath by qupath.
the class SparseImageServer method readTile.
@Override
protected BufferedImage readTile(final TileRequest tileRequest) throws IOException {
WritableRaster raster = null;
for (ImageRegion subRegion : manager.getRegions()) {
if (subRegion.getZ() != tileRequest.getZ() + originZ || subRegion.getT() != tileRequest.getT() + originT)
continue;
double downsample = tileRequest.getRegionRequest().getDownsample();
if (subRegion.intersects(tileRequest.getImageX() + originX, tileRequest.getImageY() + originY, tileRequest.getImageWidth(), tileRequest.getImageHeight())) {
// If we overlap, request the overlapping portion
ImageServer<BufferedImage> serverTemp = manager.getServer(subRegion, downsample);
// Get image coordinates for bounding box of valid region
int x1 = Math.max(tileRequest.getImageX() + originX, subRegion.getX());
int y1 = Math.max(tileRequest.getImageY() + originY, subRegion.getY());
int x2 = Math.min(tileRequest.getImageX() + originX + tileRequest.getImageWidth(), subRegion.getX() + subRegion.getWidth());
int y2 = Math.min(tileRequest.getImageY() + originY + tileRequest.getImageHeight(), subRegion.getY() + subRegion.getHeight());
// Determine request coordinates
// TODO: Test whether sparse images with pyramidal regions work, or images stored as single planes at pre-specified downsamples
int xr = x1 - subRegion.getX();
int yr = y1 - subRegion.getY();
int xr2 = x2 - subRegion.getX();
int yr2 = y2 - subRegion.getY();
double requestDownsample = downsample;
// if (requestDownsample > 1 && serverTemp.nResolutions() == 1) {
// requestDownsample = serverTemp.getDownsampleForResolution(0);
// double scale = requestDownsample / downsample;
// xr = (int)Math.round(xr * scale);
// yr = (int)Math.round(yr * scale);
// xr2 = (int)Math.round(xr2 * scale);
// yr2 = (int)Math.round(yr2 * scale);
// System.err.println(downsample + ", " + scale + ": " + serverTemp.getPath());
// }
RegionRequest requestTemp = RegionRequest.createInstance(serverTemp.getPath(), requestDownsample, xr, yr, xr2 - xr, yr2 - yr, tileRequest.getZ() + originZ, tileRequest.getT() + originT);
BufferedImage imgTemp = null;
synchronized (serverTemp) {
imgTemp = serverTemp.readBufferedImage(requestTemp);
}
if (imgTemp == null)
continue;
// If we don't have an output image yet, create a compatible one
if (raster == null) {
raster = imgTemp.getRaster().createCompatibleWritableRaster(tileRequest.getTileWidth(), tileRequest.getTileHeight());
}
int x = (int) Math.round((x1 - tileRequest.getImageX() - originX) / downsample);
int y = (int) Math.round((y1 - tileRequest.getImageY() - originY) / downsample);
int w = Math.min(imgTemp.getWidth(), raster.getWidth() - x);
int h = Math.min(imgTemp.getHeight(), raster.getHeight() - y);
raster.setDataElements(x, y, w, h, imgTemp.getRaster().getDataElements(0, 0, w, h, null));
}
}
// reusing an existing raster where possible to reduce memory requirements.
if (raster == null) {
return getEmptyTile(tileRequest.getTileWidth(), tileRequest.getTileHeight(), true);
}
// System.err.println(String.format("%.2f - %.2f", (double)tileRequest.getImageHeight()/raster.getHeight(), tileRequest.getDownsample()));
return new BufferedImage(colorModel, raster, false, null);
}
use of qupath.lib.regions.ImageRegion in project qupath by qupath.
the class OMEPyramidWriterCommand method run.
@Override
public void run() {
if (currentTask != null && !currentTask.isDone()) {
if (!Dialogs.showConfirmDialog("OME Pyramid writer", "Do you want to stop the current export?"))
// TODO: Delete exporting file?
return;
else {
currentTask.cancel(true);
}
}
QuPathViewer viewer = qupath.getViewer();
int zPos = viewer.getZPosition();
int tPos = viewer.getTPosition();
ImageData<BufferedImage> imageData = viewer.getImageData();
if (imageData == null) {
Dialogs.showNoImageError("OME Pyramid writer");
return;
}
ImageServer<BufferedImage> server = imageData.getServer();
// Region
PathObject selected = imageData.getHierarchy().getSelectionModel().getSelectedObject();
ImageRegion region = null;
int width, height;
if (selected == null || !selected.hasROI() || !selected.getROI().isArea()) {
width = server.getWidth();
height = server.getHeight();
} else {
region = ImageRegion.createInstance(selected.getROI());
width = region.getWidth();
height = region.getHeight();
}
// Set compression - with a sanity check for validity, defaulting to another comparable method if necessary
CompressionType compression = getDefaultPyramidCompression();
List<String> compatibleCompression = Arrays.stream(CompressionType.values()).filter(c -> c.supportsImage(server)).map(c -> c.toFriendlyString()).collect(Collectors.toList());
if (!compatibleCompression.contains(compression.toFriendlyString()))
compression = CompressionType.DEFAULT;
var params = new ParameterList().addChoiceParameter("compression", "Compression type", compression.toFriendlyString(), compatibleCompression).addIntParameter("scaledDownsample", "Pyramidal downsample", scaledDownsample.get(), "", 1, 8, "Amount to downsample each consecutive pyramidal level; use 1 to indicate the image should not be pyramidal").addIntParameter("tileSize", "Tile size", getDefaultTileSize(), "px", "Tile size for export (should be between 128 and 8192)").addBooleanParameter("parallelize", "Parallelize export", parallelizeTiling.get(), "Export image tiles in parallel - " + "this should be faster, best keep it on unless you encounter export problems").addBooleanParameter("allZ", "All z-slices", allZ.get(), "Include all z-slices in the stack").addBooleanParameter("allT", "All timepoints", allT.get(), "Include all timepoints in the time-series");
boolean singleTile = server.getTileRequestManager().getTileRequests(RegionRequest.createInstance(server)).size() == 1;
params.setHiddenParameters(server.nZSlices() == 1, "allZ");
params.setHiddenParameters(server.nTimepoints() == 1, "allT");
params.setHiddenParameters(singleTile, "tileSize", "parallelize");
if (!Dialogs.showParameterDialog("Export OME-TIFF", params))
return;
compression = CompressionType.fromFriendlyString((String) params.getChoiceParameterValue("compression"));
defaultPyramidCompression.set(compression);
int downsampleScale = params.getIntParameterValue("scaledDownsample");
scaledDownsample.set(downsampleScale);
int tileSize = params.getIntParameterValue("tileSize");
boolean parallelize = params.getBooleanParameterValue("parallelize");
if (!singleTile) {
tileSize = GeneralTools.clipValue(tileSize, 128, 8192);
defaultTileSize.set(tileSize);
parallelizeTiling.set(parallelize);
}
boolean doAllZ = false;
boolean doAllT = false;
if (server.nZSlices() > 1) {
doAllZ = params.getBooleanParameterValue("allZ");
allZ.set(doAllZ);
}
if (server.nTimepoints() > 1) {
doAllT = params.getBooleanParameterValue("allT");
allT.set(doAllT);
}
OMEPyramidWriter.Builder builder = new OMEPyramidWriter.Builder(server);
if (region != null) {
builder = builder.region(region);
} else {
if (server.nZSlices() > 1 && !doAllZ)
builder.zSlice(zPos);
if (server.nTimepoints() > 1 && !doAllT)
builder.timePoint(tPos);
}
builder.compression(compression);
if (downsampleScale <= 1 || Math.max(width, height) / server.getDownsampleForResolution(0) < minSizeForTiling.get())
builder.downsamples(server.getDownsampleForResolution(0));
else
builder.scaledDownsampling(server.getDownsampleForResolution(0), downsampleScale);
// Set tile size; if we just have one tile, use the image width & height
if (singleTile)
builder = builder.tileSize(width, height);
else
builder = builder.tileSize(tileSize).parallelize(parallelize);
if (server.nZSlices() > 1 && doAllZ)
builder.allZSlices();
if (server.nTimepoints() > 1 && doAllT)
builder.allTimePoints();
// Prompt for file
File fileOutput = Dialogs.promptToSaveFile("Write pyramid", null, null, "OME TIFF pyramid", ".ome.tif");
if (fileOutput == null)
return;
String name = fileOutput.getName();
// We can have trouble with only the '.tif' part of the name being included
if (name.endsWith(".tif") && !name.endsWith(".ome.tif"))
fileOutput = new File(fileOutput.getParentFile(), name.substring(0, name.length() - 4) + ".ome.tif");
OMEPyramidSeries writer = builder.build();
if (pool == null) {
pool = Executors.newSingleThreadExecutor(ThreadTools.createThreadFactory("ome-pyramid-export", false));
}
currentTask = pool.submit(new WriterTask(OMEPyramidWriter.createWriter(writer), fileOutput.getAbsolutePath()));
}
Aggregations