use of ini.trakem2.display.Coordinate in project TrakEM2 by trakem2.
the class FSLoader method generateMipMaps.
/**
* Given an image and its source file name (without directory prepended), generate
* a pyramid of images until reaching an image not smaller than 32x32 pixels.
* <p>
* Such images are stored as jpeg 85% quality in a folder named trakem2.mipmaps.
* </p>
* <p>
* The Patch id and the right extension will be appended to the filename in all cases.
* </p>
* <p>
* Any equally named files will be overwritten.
* </p>
*/
protected boolean generateMipMaps(final Patch patch) {
Utils.log2("mipmaps for " + patch);
final String path = getAbsolutePath(patch);
if (null == path) {
Utils.log("generateMipMaps: null path for Patch " + patch);
cannot_regenerate.add(patch);
return false;
}
if (hs_unloadable.contains(patch)) {
FilePathRepair.add(patch);
return false;
}
synchronized (gm_lock) {
try {
if (null == dir_mipmaps)
createMipMapsDir(null);
if (null == dir_mipmaps || isURL(dir_mipmaps))
return false;
} catch (Exception e) {
IJError.print(e);
}
}
/**
* Record Patch as modified
*/
touched_mipmaps.add(patch);
/**
* Remove serialized features, if any
*/
removeSerializedFeatures(patch);
/**
* Remove serialized pointmatches, if any
*/
removeSerializedPointMatches(patch);
/**
* Alpha mask: setup to check if it was modified while regenerating.
*/
final long alpha_mask_id = patch.getAlphaMaskId();
final int resizing_mode = patch.getProject().getMipMapsMode();
try {
ImageProcessor ip;
ByteProcessor alpha_mask = null;
ByteProcessor outside_mask = null;
int type = patch.getType();
// Aggressive cache freeing
releaseToFit(patch.getOWidth() * patch.getOHeight() * 4 + MIN_FREE_BYTES);
// Obtain an image which may be coordinate-transformed, and an alpha mask.
Patch.PatchImage pai = patch.createTransformedImage();
if (null == pai || null == pai.target) {
Utils.log("Can't regenerate mipmaps for patch " + patch);
cannot_regenerate.add(patch);
return false;
}
ip = pai.target;
// can be null
alpha_mask = pai.mask;
// can be null
outside_mask = pai.outside;
pai = null;
// Old style:
// final String filename = new StringBuilder(new File(path).getName()).append('.').append(patch.getId()).append(mExt).toString();
// New style:
final String filename = createMipMapRelPath(patch, mExt);
int w = ip.getWidth();
int h = ip.getHeight();
// sigma = sqrt(2^level - 0.5^2)
// where 0.5 is the estimated sigma for a full-scale image
// which means sigma = 0.75 for the full-scale image (has level 0)
// prepare a 0.75 sigma image from the original
double min = patch.getMin(), max = patch.getMax();
// (The -1,-1 are flags really for "not set")
if (-1 == min && -1 == max) {
switch(type) {
case ImagePlus.COLOR_RGB:
case ImagePlus.COLOR_256:
case ImagePlus.GRAY8:
patch.setMinAndMax(0, 255);
break;
// Find and flow through to default:
case ImagePlus.GRAY16:
((ij.process.ShortProcessor) ip).findMinAndMax();
patch.setMinAndMax(ip.getMin(), ip.getMax());
break;
case ImagePlus.GRAY32:
((FloatProcessor) ip).findMinAndMax();
patch.setMinAndMax(ip.getMin(), ip.getMax());
break;
}
// may have changed
min = patch.getMin();
max = patch.getMax();
}
// Set for the level 0 image, which is a duplicate of the one in the cache in any case
ip.setMinAndMax(min, max);
// ImageJ no longer stretches the bytes for ByteProcessor with setMinAndmax
if (ByteProcessor.class == ip.getClass()) {
if (0 != min && 255 != max) {
final byte[] b = (byte[]) ip.getPixels();
final double scale = 255 / (max - min);
for (int i = 0; i < b.length; ++i) {
final int val = b[i] & 0xff;
if (val < min)
b[i] = 0;
else
b[i] = (byte) Math.min(255, ((val - min) * scale));
}
}
}
// Proper support for LUT images: treat them as RGB
if (ip.isColorLut() || type == ImagePlus.COLOR_256) {
ip = ip.convertToRGB();
type = ImagePlus.COLOR_RGB;
}
final int first_mipmap_level_saved = patch.getProject().getFirstMipMapLevelSaved();
if (Loader.AREA_DOWNSAMPLING == resizing_mode) {
long t0 = System.currentTimeMillis();
final ImageBytes[] b = DownsamplerMipMaps.create(patch, type, ip, alpha_mask, outside_mask);
long t1 = System.currentTimeMillis();
for (int i = 0; i < b.length; ++i) {
if (i < first_mipmap_level_saved) {
// Ignore level i
if (null != b[i])
CachingThread.storeForReuse(b[i].c);
} else {
boolean written = mmio.save(getLevelDir(dir_mipmaps, i) + filename, b[i].c, b[i].width, b[i].height, 0.85f);
if (!written) {
Utils.log("Failed to save mipmap with area downsampling at level=" + i + " for patch " + patch);
cannot_regenerate.add(patch);
break;
}
}
}
long t2 = System.currentTimeMillis();
System.out.println("MipMaps with area downsampling: creation took " + (t1 - t0) + "ms, saving took " + (t2 - t1) + "ms, total: " + (t2 - t0) + "ms\n");
} else if (Loader.GAUSSIAN == resizing_mode) {
if (ImagePlus.COLOR_RGB == type) {
// TODO releaseToFit proper
releaseToFit(w * h * 4 * 10);
final ColorProcessor cp = (ColorProcessor) ip;
final FloatProcessorT2 red = new FloatProcessorT2(w, h, 0, 255);
cp.toFloat(0, red);
final FloatProcessorT2 green = new FloatProcessorT2(w, h, 0, 255);
cp.toFloat(1, green);
final FloatProcessorT2 blue = new FloatProcessorT2(w, h, 0, 255);
cp.toFloat(2, blue);
FloatProcessorT2 alpha;
final FloatProcessorT2 outside;
if (null != alpha_mask) {
alpha = new FloatProcessorT2(alpha_mask);
} else {
alpha = null;
}
if (null != outside_mask) {
outside = new FloatProcessorT2(outside_mask);
if (null == alpha) {
alpha = outside;
alpha_mask = outside_mask;
}
} else {
outside = null;
}
final String target_dir0 = getLevelDir(dir_mipmaps, 0);
if (Thread.currentThread().isInterrupted())
return false;
// Generate level 0 first:
if (0 == first_mipmap_level_saved) {
boolean written;
if (null == alpha) {
written = mmio.save(cp, target_dir0 + filename, 0.85f, false);
} else {
written = mmio.save(target_dir0 + filename, P.asRGBABytes((int[]) cp.getPixels(), (byte[]) alpha_mask.getPixels(), null == outside ? null : (byte[]) outside_mask.getPixels()), w, h, 0.85f);
}
if (!written) {
Utils.log("Failed to save mipmap for COLOR_RGB, 'alpha = " + alpha + "', level = 0 for patch " + patch);
cannot_regenerate.add(patch);
}
}
// Generate all other mipmap levels
// TODO: for best performance, it should start from a direct Gaussian downscaling at the first level to write.
// the scale level. Proper scale is: 1 / pow(2, k)
int k = 0;
do {
if (Thread.currentThread().isInterrupted())
return false;
// 1 - Prepare values for the next scaled image
k++;
// 2 - Check that the target folder for the desired scale exists
final String target_dir = getLevelDir(dir_mipmaps, k);
if (null == target_dir)
break;
// 3 - Blur the previous image to 0.75 sigma, and scale it
// will resize 'red' FloatProcessor in place.
final byte[] r = gaussianBlurResizeInHalf(red);
// idem
final byte[] g = gaussianBlurResizeInHalf(green);
// idem
final byte[] b = gaussianBlurResizeInHalf(blue);
// idem
final byte[] a = null == alpha ? null : gaussianBlurResizeInHalf(alpha);
if (null != outside) {
final byte[] o;
if (alpha != outside)
// idem
o = gaussianBlurResizeInHalf(outside);
else
o = a;
// If there was no alpha mask, alpha is the outside itself
for (int i = 0; i < o.length; i++) {
// TODO I am sure there is a bitwise operation to do this in one step. Some thing like: a[i] &= 127;
if ((o[i] & 0xff) != 255)
a[i] = 0;
}
}
w = red.getWidth();
h = red.getHeight();
// 4 - Compose ColorProcessor
if (first_mipmap_level_saved < k) {
// Skip saving this mipmap level
continue;
}
if (null == alpha) {
// 5 - Save as jpeg
if (!mmio.save(target_dir + filename, new byte[][] { r, g, b }, w, h, 0.85f)) {
Utils.log("Failed to save mipmap for COLOR_RGB, 'alpha = " + alpha + "', level = " + k + " for patch " + patch);
cannot_regenerate.add(patch);
break;
}
} else {
if (!mmio.save(target_dir + filename, new byte[][] { r, g, b, a }, w, h, 0.85f)) {
Utils.log("Failed to save mipmap for COLOR_RGB, 'alpha = " + alpha + "', level = " + k + " for patch " + patch);
cannot_regenerate.add(patch);
break;
}
}
} while (// not smaller than 32x32
w >= 32 && h >= 32);
} else {
long t0 = System.currentTimeMillis();
// Greyscale:
releaseToFit(w * h * 4 * 10);
if (Thread.currentThread().isInterrupted())
return false;
final FloatProcessorT2 fp = new FloatProcessorT2((FloatProcessor) ip.convertToFloat());
if (ImagePlus.GRAY8 == type) {
// for 8-bit, the min,max has been applied when going to FloatProcessor
// just set it
fp.setMinMax(0, 255);
} else {
fp.setMinAndMax(patch.getMin(), patch.getMax());
}
// fp.debugMinMax(patch.toString());
FloatProcessorT2 alpha, outside;
if (null != alpha_mask) {
alpha = new FloatProcessorT2(alpha_mask);
} else {
alpha = null;
}
if (null != outside_mask) {
outside = new FloatProcessorT2(outside_mask);
if (null == alpha) {
alpha = outside;
alpha_mask = outside_mask;
}
} else {
outside = null;
}
// the scale level. Proper scale is: 1 / pow(2, k)
int k = 0;
do {
if (Thread.currentThread().isInterrupted())
return false;
if (0 != k) {
// not doing so at the end because it would add one unnecessary blurring
gaussianBlurResizeInHalf(fp);
if (null != alpha) {
gaussianBlurResizeInHalf(alpha);
if (alpha != outside && outside != null) {
gaussianBlurResizeInHalf(outside);
}
}
}
w = fp.getWidth();
h = fp.getHeight();
// 1 - check that the target folder for the desired scale exists
final String target_dir = getLevelDir(dir_mipmaps, k);
if (null == target_dir)
break;
if (k < first_mipmap_level_saved) {
// Skip saving this mipmap level
k++;
continue;
}
if (null != alpha) {
// If there was no alpha mask, alpha is the outside itself
if (!mmio.save(target_dir + filename, new byte[][] { fp.getScaledBytePixels(), P.merge(alpha.getBytePixels(), null == outside ? null : outside.getBytePixels()) }, w, h, 0.85f)) {
Utils.log("Failed to save mipmap for GRAY8, 'alpha = " + alpha + "', level = " + k + " for patch " + patch);
cannot_regenerate.add(patch);
break;
}
} else {
// 3 - save as 8-bit jpeg
if (!mmio.save(target_dir + filename, new byte[][] { fp.getScaledBytePixels() }, w, h, 0.85f)) {
Utils.log("Failed to save mipmap for GRAY8, 'alpha = " + alpha + "', level = " + k + " for patch " + patch);
cannot_regenerate.add(patch);
break;
}
}
// 4 - prepare values for the next scaled image
k++;
} while (// not smaller than 32x32
fp.getWidth() >= 32 && fp.getHeight() >= 32);
long t1 = System.currentTimeMillis();
System.out.println("MipMaps took " + (t1 - t0));
}
} else {
Utils.log("ERROR: unknown image resizing mode for mipmaps: " + resizing_mode);
}
return true;
} catch (Throwable e) {
Utils.log("*** ERROR: Can't generate mipmaps for patch " + patch);
IJError.print(e);
cannot_regenerate.add(patch);
return false;
} finally {
// flush any cached tiles
flushMipMaps(patch.getId());
// flush any cached layer screenshots
if (null != patch.getLayer()) {
try {
patch.getLayer().getParent().removeFromOffscreens(patch.getLayer());
} catch (Exception e) {
IJError.print(e);
}
}
// gets executed even when returning from the catch statement or within the try/catch block
synchronized (gm_lock) {
regenerating_mipmaps.remove(patch);
}
// Has the alpha mask changed?
if (patch.getAlphaMaskId() != alpha_mask_id) {
Utils.log2("Alpha mask changed: resubmitting mipmap regeneration for " + patch);
regenerateMipMaps(patch);
}
}
}
use of ini.trakem2.display.Coordinate in project TrakEM2 by trakem2.
the class DistortionCorrectionTask method run.
public static final void run(final CorrectDistortionFromSelectionParam p, final List<Patch> patches, final Displayable active, final Layer layer, final Worker worker) {
/* no multiple inheritance, so p cannot be an Align.ParamOptimize, working around legacy by copying data into one ... */
final Align.ParamOptimize ap = new Align.ParamOptimize();
ap.sift.set(p.sift);
ap.desiredModelIndex = p.desiredModelIndex;
ap.expectedModelIndex = p.expectedModelIndex;
ap.maxEpsilon = p.maxEpsilon;
ap.minInlierRatio = p.minInlierRatio;
ap.rod = p.rod;
ap.identityTolerance = p.identityTolerance;
ap.lambda = p.lambdaRegularize;
ap.maxIterations = p.maxIterationsOptimize;
ap.maxPlateauwidth = p.maxPlateauwidthOptimize;
ap.minNumInliers = p.minNumInliers;
ap.regularize = p.regularize;
ap.regularizerModelIndex = p.regularizerIndex;
ap.rejectIdentity = p.rejectIdentity;
/**
* Get all patches that will be affected.
*/
final List<Patch> allPatches = new ArrayList<Patch>();
for (final Layer l : layer.getParent().getLayers().subList(p.firstLayerIndex, p.lastLayerIndex + 1)) for (final Displayable d : l.getDisplayables(Patch.class)) allPatches.add((Patch) d);
/**
* Unset the coordinate transforms of all patches if desired.
*/
if (p.clearTransform) {
if (worker != null)
worker.setTaskName("Clearing present transforms");
setCoordinateTransform(allPatches, null, Runtime.getRuntime().availableProcessors());
Display.repaint();
}
if (worker != null)
worker.setTaskName("Establishing SIFT correspondences");
final List<AbstractAffineTile2D<?>> tiles = new ArrayList<AbstractAffineTile2D<?>>();
final List<AbstractAffineTile2D<?>> fixedTiles = new ArrayList<AbstractAffineTile2D<?>>();
final List<Patch> fixedPatches = new ArrayList<Patch>();
if (active != null && active instanceof Patch)
fixedPatches.add((Patch) active);
Align.tilesFromPatches(ap, patches, fixedPatches, tiles, fixedTiles);
final List<AbstractAffineTile2D<?>[]> tilePairs = new ArrayList<AbstractAffineTile2D<?>[]>();
if (p.tilesAreInPlace)
AbstractAffineTile2D.pairOverlappingTiles(tiles, tilePairs);
else
AbstractAffineTile2D.pairTiles(tiles, tilePairs);
AbstractAffineTile2D<?> fixedTile = null;
if (fixedTiles.size() > 0)
fixedTile = fixedTiles.get(0);
else
fixedTile = tiles.get(0);
Align.connectTilePairs(ap, tiles, tilePairs, p.maxNumThreadsSift, p.multipleHypotheses);
/**
* Shift all local coordinates into the original image frame
*/
for (final AbstractAffineTile2D<?> tile : tiles) {
final Rectangle box = tile.getPatch().getCoordinateTransformBoundingBox();
for (final PointMatch m : tile.getMatches()) {
final double[] l = m.getP1().getL();
final double[] w = m.getP1().getW();
l[0] += box.x;
l[1] += box.y;
w[0] = l[0];
w[1] = l[1];
}
}
if (Thread.currentThread().isInterrupted())
return;
final List<Set<Tile<?>>> graphs = AbstractAffineTile2D.identifyConnectedGraphs(tiles);
if (graphs.size() > 1)
Utils.log("Could not interconnect all images with correspondences. ");
final List<AbstractAffineTile2D<?>> interestingTiles;
/**
* Find largest graph.
*/
Set<Tile<?>> largestGraph = null;
for (final Set<Tile<?>> graph : graphs) if (largestGraph == null || largestGraph.size() < graph.size())
largestGraph = graph;
interestingTiles = new ArrayList<AbstractAffineTile2D<?>>();
for (final Tile<?> t : largestGraph) interestingTiles.add((AbstractAffineTile2D<?>) t);
if (Thread.currentThread().isInterrupted())
return;
Utils.log("Estimating lens model:");
/* initialize with pure affine */
Align.optimizeTileConfiguration(ap, interestingTiles, fixedTiles);
/* measure the current error */
double e = 0;
int n = 0;
for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) {
e += pm.getDistance();
++n;
}
e /= n;
double dEpsilon_i = 0;
double epsilon_i = e;
double dEpsilon_0 = 0;
NonLinearTransform lensModel = null;
Utils.log("0: epsilon = " + e);
/* Store original point locations */
final HashMap<Point, Point> originalPoints = new HashMap<Point, Point>();
for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) originalPoints.put(pm.getP1(), pm.getP1().clone());
/* ad hoc conditions to terminate iteration:
* small improvement ( 1/1000) relative to first iteration
* less than 20 iterations
* at least 2 iterations */
for (int i = 1; i < 20 && (i < 2 || dEpsilon_i <= dEpsilon_0 / 1000); ++i) {
if (Thread.currentThread().isInterrupted())
return;
/* Some data shuffling for the lens correction interface */
final List<PointMatchCollectionAndAffine> matches = new ArrayList<PointMatchCollectionAndAffine>();
for (final AbstractAffineTile2D<?>[] tilePair : tilePairs) {
final AffineTransform a = tilePair[0].createAffine();
a.preConcatenate(tilePair[1].getModel().createInverseAffine());
final Collection<PointMatch> commonMatches = new ArrayList<PointMatch>();
tilePair[0].commonPointMatches(tilePair[1], commonMatches);
final Collection<PointMatch> originalCommonMatches = new ArrayList<PointMatch>();
for (final PointMatch pm : commonMatches) originalCommonMatches.add(new PointMatch(originalPoints.get(pm.getP1()), originalPoints.get(pm.getP2())));
matches.add(new PointMatchCollectionAndAffine(a, originalCommonMatches));
}
if (worker != null)
worker.setTaskName("Estimating lens distortion correction");
lensModel = Distortion_Correction.createInverseDistortionModel(matches, p.dimension, p.lambda, (int) fixedTile.getWidth(), (int) fixedTile.getHeight());
/* update local points */
for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) {
final Point currentPoint = pm.getP1();
final Point originalPoint = originalPoints.get(currentPoint);
final double[] l = currentPoint.getL();
final double[] lo = originalPoint.getL();
l[0] = lo[0];
l[1] = lo[1];
lensModel.applyInPlace(l);
}
/* re-optimize */
Align.optimizeTileConfiguration(ap, interestingTiles, fixedTiles);
/* measure the current error */
e = 0;
n = 0;
for (final AbstractAffineTile2D<?> t : interestingTiles) for (final PointMatch pm : t.getMatches()) {
e += pm.getDistance();
++n;
}
e /= n;
dEpsilon_i = e - epsilon_i;
epsilon_i = e;
if (i == 1)
dEpsilon_0 = dEpsilon_i;
Utils.log(i + ": epsilon = " + e);
Utils.log(i + ": delta epsilon = " + dEpsilon_i);
}
if (lensModel != null) {
if (p.visualize) {
if (Thread.currentThread().isInterrupted())
return;
if (worker != null)
worker.setTaskName("Visualizing lens distortion correction");
lensModel.visualizeSmall(p.lambda);
}
if (worker != null)
worker.setTaskName("Applying lens distortion correction");
appendCoordinateTransform(allPatches, lensModel, Runtime.getRuntime().availableProcessors());
Utils.log("Done.");
} else
Utils.log("No lens model found.");
}
use of ini.trakem2.display.Coordinate in project TrakEM2 by trakem2.
the class AreaUtils method singularInterpolation.
/**
* Extract the Area of the image for the given pixel value.
* ThresholdToSelection is way faster than this, just use it.
* It's BROKEN do not use.
*/
/*
static public final Area extractArea(final ImageProcessor ip, final float val) {
final int height = ip.getHeight();
final int width = ip.getWidth();
final Area area = new Area();
final ArrayList<Area> segments = new ArrayList<Area>();
final Rectangle box = new Rectangle(0, 0, 1, 1);
for (int y=0; y<height; y++) {
float prev = ip.getPixelValue(0, y);
box.x = 0;
box.y = y;
box.width = val == prev ? 1 : 0;
for (int x=1; x<width; x++) {
float pix = ip.getPixelValue(x, y);
if (val == pix) {
if (pix == prev) {
box.width++;
continue;
}
// Else, add previous one
segments.add(new Area(box));
// ... and start a new box
box.x = x;
box.y = y;
box.width = 1;
prev = pix;
}
}
// At end of line, add the last
segments.add(new Area(box));
// Join a few
if (segments.size() > 32) {
final Area a = new Area(segments.get(0));
final int len = segments.size();
for (int i=1; i<len; i++) a.add(segments.get(i));
area.add(a);
segments.clear();
}
}
if (segments.size() > 0) {
final Area a = new Area(segments.get(0));
final int len = segments.size();
for (int i=1; i<len; i++) a.add(segments.get(i));
area.add(a);
}
return area;
}
*/
/**
* Interpolate areas only if they are made of a single shape each.
* Assumes that areas are in the same coordinate system.
* @throws Exception
*/
public static final Area[] singularInterpolation(final Area a1, final Area a2, final int nInterpolates) throws Exception {
if (!a1.isSingular() || !a2.isSingular()) {
return null;
}
final VectorString2D vs1 = M.asVectorString2D(M.getPolygons(a1).iterator().next(), 0);
final VectorString2D vs2 = M.asVectorString2D(M.getPolygons(a2).iterator().next(), 1);
final Editions ed = new Editions(vs1, vs2, Math.min(vs1.getAverageDelta(), vs2.getAverageDelta()), true);
final double[][][] d = SkinMaker.getMorphedPerimeters(vs1, vs2, nInterpolates, ed);
final Area[] a = new Area[d.length];
for (int i = 0; i < d.length; i++) {
final double[] x = d[i][0];
final double[] y = d[i][1];
final int[] xi = new int[x.length];
final int[] yi = new int[y.length];
for (int k = 0; k < x.length; k++) {
xi[k] = (int) x[k];
yi[k] = (int) y[k];
}
a[i] = new Area(new Polygon(xi, yi, xi.length));
}
return a;
}
use of ini.trakem2.display.Coordinate in project TrakEM2 by trakem2.
the class Search method createCoordinate.
private Coordinate<Displayable> createCoordinate(final Displayable d) {
Rectangle r = d.getBoundingBox();
Layer la = d instanceof ZDisplayable ? ((ZDisplayable) d).getFirstLayer() : d.getLayer();
if (null == la) {
Display display = Display.getFront(d.getProject());
if (null == display)
la = d.getProject().getRootLayerSet().getLayer(0);
else
la = display.getLayer();
}
return new Coordinate<Displayable>(r.x + r.width / 2, r.y + r.height / 2, la, d);
}
use of ini.trakem2.display.Coordinate in project TrakEM2 by trakem2.
the class Project method saveTask.
public Bureaucrat saveTask(final String command) {
return Bureaucrat.createAndStart(new Worker.Task("Saving") {
public void exec() {
if (command.equals("Save")) {
save();
} else if (command.equals("Save as...")) {
XMLOptions options = new XMLOptions();
options.overwriteXMLFile = false;
options.export_images = false;
options.include_coordinate_transform = true;
options.patches_dir = null;
// Will open a file dialog
loader.saveAs(project, options);
restartAutosaving();
//
} else if (command.equals("Save as... without coordinate transforms")) {
YesNoDialog yn = new YesNoDialog("WARNING", "You are about to save an XML file that lacks the information for the coordinate transforms of each image.\n" + "These transforms are referred to with the attribute 'ct_id' of each 't2_patch' entry in the XML document,\n" + "and the data for the transform is stored in an individual file under the folder 'trakem2.cts/'.\n" + " \n" + "It is advised to keep a complete XML file with all coordinate transforms included along with this new copy.\n" + "Please check NOW that you have such a complete XML copy.\n" + " \n" + "Proceed?");
if (!yn.yesPressed())
return;
saveWithoutCoordinateTransforms();
//
} else if (command.equals("Delete stale files...")) {
setTaskName("Deleting stale files");
GenericDialog gd = new GenericDialog("Delete stale files");
gd.addMessage("You are about to remove all files under the folder 'trakem2.cts/' which are not referred to from the\n" + "currently loaded project. If you have sibling XML files whose 't2_patch' entries (the images) refer,\n" + "via 'ct_id' attributes, to coordinate transforms in 'trakem2.cts/' that this current XML doesn't,\n" + "they may be LOST FOREVER. Unless you have a version of the XML file with the coordinate transforms\n" + "written in it, as can be obtained by using the 'Project - Save' command.\n" + " \n" + "The same is true for the .zip files that store alpha masks, under folder 'trakem2.masks/'\n" + "and which are referred to from the 'alpha_mask_id' attribute of 't2_patch' entries.\n" + " \n" + "Do you have such complete XML file? Check *NOW*.\n" + " \n" + "Proceed with deleting:");
gd.addCheckbox("Delete stale coordinate transform files", true);
gd.addCheckbox("Delete stale alpha mask files", true);
gd.showDialog();
if (gd.wasCanceled())
return;
project.getLoader().deleteStaleFiles(gd.getNextBoolean(), gd.getNextBoolean());
}
}
}, project);
}
Aggregations