use of ini.trakem2.display.Patch in project TrakEM2 by trakem2.
the class ExportARGB method makeFlatImageARGBFromOriginals.
/**
* Limited to 2GB arrays for the requested image.
*
* @param patches
* @param roi
* @param backgroundValue
* @param scale
* @return
*/
public static final Pair<ColorProcessor, ByteProcessor> makeFlatImageARGBFromOriginals(final List<Patch> patches, final Rectangle roi, final double backgroundValue, final double scale) {
final ColorProcessor target = new ColorProcessor((int) (roi.width * scale), (int) (roi.height * scale));
target.setInterpolationMethod(ImageProcessor.BILINEAR);
final ByteProcessor targetMask = new ByteProcessor(target.getWidth(), target.getHeight());
targetMask.setInterpolationMethod(ImageProcessor.NEAREST_NEIGHBOR);
for (final Patch patch : patches) {
final Patch.PatchImage pai = patch.createTransformedImage();
final ColorProcessor fp = (ColorProcessor) pai.target.convertToRGB();
final ByteProcessor alpha;
System.out.println("IMAGE:" + patch.getTitle());
System.out.println("mask: " + pai.mask);
System.out.println("outside: " + pai.outside);
if (null == pai.mask) {
if (null == pai.outside) {
alpha = new ByteProcessor(fp.getWidth(), fp.getHeight());
// fully opaque
Arrays.fill((byte[]) alpha.getPixels(), (byte) 255);
} else {
alpha = pai.outside;
}
} else {
alpha = pai.mask;
}
// The affine to apply
final AffineTransform atc = new AffineTransform();
atc.scale(scale, scale);
atc.translate(-roi.x, -roi.y);
final AffineTransform at = new AffineTransform();
at.preConcatenate(atc);
at.concatenate(patch.getAffineTransform());
final AffineModel2D aff = new AffineModel2D();
aff.set(at);
final CoordinateTransformMesh mesh = new CoordinateTransformMesh(aff, patch.getMeshResolution(), fp.getWidth(), fp.getHeight());
final TransformMeshMappingWithMasks<CoordinateTransformMesh> mapping = new TransformMeshMappingWithMasks<CoordinateTransformMesh>(mesh);
fp.setInterpolationMethod(ImageProcessor.BILINEAR);
// no interpolation
alpha.setInterpolationMethod(ImageProcessor.NEAREST_NEIGHBOR);
mapping.map(fp, alpha, target, targetMask);
}
return new Pair<ColorProcessor, ByteProcessor>(target, targetMask);
}
use of ini.trakem2.display.Patch in project TrakEM2 by trakem2.
the class ExportUnsignedShort method exportTiles.
/**
* Create constant size tiles that carpet the areas of the {@code layer} where there are images;
* these tiles are returned in a lazy sequence of {@link Callable} objects that create a tripled
* consisting of the {@link ShortProcessor} and the X and Y pixel coordinates of that tile.
*
* @param layer The layer to export images for
* @param tileWidth The width of the tiles to export
* @param tileHeight
* @return A lazy sequence of {@link Callable} instances, each holding a {@link Triple} that specifies the ShortProcessor,
* the X and the Y (both in world pixel uncalibrated coordinates).
*/
public static final Iterable<Callable<ExportedTile>> exportTiles(final Layer layer, final int tileWidth, final int tileHeight, final boolean visible_only) {
final ArrayList<Displayable> patches = layer.getDisplayables(Patch.class, visible_only);
// If the Layer lacks images, return an empty sequence.
if (patches.isEmpty()) {
return Collections.emptyList();
}
/* calculate intensity transfer */
final ArrayList<PatchIntensityRange> patchIntensityRanges = new ArrayList<PatchIntensityRange>();
double min_ = Double.MAX_VALUE;
double max_ = -Double.MAX_VALUE;
for (final Displayable d : patches) {
final Patch patch = (Patch) d;
final PatchIntensityRange pir = new PatchIntensityRange(patch);
if (pir.min < min_)
min_ = pir.min;
if (pir.max > max_)
max_ = pir.max;
patchIntensityRanges.add(pir);
}
final double min = min_;
final double max = max_;
/* Create lazy sequence that creates Callable instances. */
final Rectangle box = layer.getMinimalBoundingBox(Patch.class, visible_only).intersection(layer.getParent().get2DBounds());
final int nCols = (int) Math.ceil(box.width / (double) tileWidth);
final int nRows = (int) Math.ceil(box.height / (double) tileHeight);
final double minI = -min * 65535.0 / (max - min);
final double maxI = (1.0 - min) * 65535.0 / (max - min);
return new Iterable<Callable<ExportedTile>>() {
@Override
public Iterator<Callable<ExportedTile>> iterator() {
return new Iterator<Callable<ExportedTile>>() {
// Internal state
private int row = 0, col = 0, x0 = box.x, y0 = box.y;
private final ArrayList<PatchIntensityRange> ps = new ArrayList<PatchIntensityRange>();
{
// Constructor body. Prepare to be able to answer "hasNext()"
findNext();
}
private final void findNext() {
// Iterate until finding a tile that intersects one or more patches
ps.clear();
while (true) {
if (nRows == row) {
// End of domain
break;
}
x0 = box.x + col * tileWidth;
y0 = box.y + row * tileHeight;
final Rectangle tileBounds = new Rectangle(x0, y0, tileWidth, tileHeight);
for (final PatchIntensityRange pir : patchIntensityRanges) {
if (pir.patch.getBoundingBox().intersects(tileBounds)) {
ps.add(pir);
}
}
// Prepare next iteration
col += 1;
if (nCols == col) {
col = 0;
row += 1;
}
if (ps.size() > 0) {
// Ready for next iteration
break;
}
}
}
@Override
public boolean hasNext() {
return ps.size() > 0;
}
@Override
public Callable<ExportedTile> next() {
// Capture state locally
final ArrayList<PatchIntensityRange> pirs = new ArrayList<PatchIntensityRange>(ps);
final int x = x0;
final int y = y0;
// Advance
findNext();
return new Callable<ExportedTile>() {
@Override
public ExportedTile call() throws Exception {
final ShortProcessor sp = new ShortProcessor(tileWidth, tileHeight);
sp.setMinAndMax(minI, maxI);
for (final PatchIntensityRange pir : pirs) {
map(new PatchTransform(pir), x, y, mapIntensities(pir, min, max), sp);
}
return new ExportedTile(sp, x, y, minI, maxI);
}
};
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
};
}
use of ini.trakem2.display.Patch in project TrakEM2 by trakem2.
the class ExportUnsignedShort method exportTEST.
public static final void exportTEST(final Layer layer, final int tileWidth, final int tileHeight) {
/* calculate intensity transfer */
final ArrayList<Displayable> patches = layer.getDisplayables(Patch.class);
final ArrayList<PatchIntensityRange> patchIntensityRanges = new ArrayList<PatchIntensityRange>();
double min = Double.MAX_VALUE;
double max = -Double.MAX_VALUE;
for (final Displayable d : patches) {
final Patch patch = (Patch) d;
final PatchIntensityRange pir = new PatchIntensityRange(patch);
if (pir.min < min)
min = pir.min;
if (pir.max > max)
max = pir.max;
patchIntensityRanges.add(pir);
}
/* render tiles */
/* TODO Do not render them into a stack but save them as files */
final ImageStack stack = new ImageStack(tileWidth, tileHeight);
ImagePlus imp = null;
final double minI = -min * 65535.0 / (max - min);
final double maxI = (1.0 - min) * 65535.0 / (max - min);
// ij.IJ.log("min, max: " + min + ", " + max + ", minI, maxI: " + minI + ", " + maxI);
final int nc = (int) Math.ceil(layer.getLayerWidth() / tileWidth);
final int nr = (int) Math.ceil(layer.getLayerHeight() / tileHeight);
for (int r = 0; r < nr; ++r) {
final int y0 = r * tileHeight;
for (int c = 0; c < nc; ++c) {
final int x0 = c * tileWidth;
final Rectangle box = new Rectangle(x0, y0, tileWidth, tileHeight);
final ShortProcessor sp = new ShortProcessor(tileWidth, tileHeight);
sp.setMinAndMax(minI, maxI);
for (final PatchIntensityRange pir : patchIntensityRanges) {
if (pir.patch.getBoundingBox().intersects(box))
map(new PatchTransform(pir), x0, y0, mapIntensities(pir, min, max), sp);
}
stack.addSlice(r + ", " + c, sp);
if (null == imp && stack.getSize() > 1) {
imp = new ImagePlus("tiles", stack);
imp.show();
}
if (null != imp) {
imp.setSlice(stack.getSize());
imp.updateAndDraw();
}
}
}
if (null == imp) {
// single-slice, non-StackWindow
new ImagePlus("tiles", stack).show();
}
}
use of ini.trakem2.display.Patch in project TrakEM2 by trakem2.
the class MatchIntensities method run.
/**
* @param layers
* @param radius
* @param scale
* @param numCoefficients
* @param lambda1
* @param lambda2
* @param neighborWeight
* @param roi
*/
public <M extends Model<M> & Affine1D<M>> void run(final List<Layer> layers, final int radius, final double scale, final int numCoefficients, final double lambda1, final double lambda2, final double neighborWeight, final Rectangle roi) throws InterruptedException, ExecutionException {
final int firstLayerIndex = layerset.getLayerIndex(layers.get(0).getId());
final int lastLayerIndex = layerset.getLayerIndex(layers.get(layers.size() - 1).getId());
// final PointMatchFilter filter = new RansacRegressionFilter();
final PointMatchFilter filter = new RansacRegressionReduceFilter();
/* collect patches */
Utils.log("Collecting patches ... ");
final ArrayList<Patch> patches = new ArrayList<Patch>();
for (final Layer layer : layers) patches.addAll((Collection) layer.getDisplayables(Patch.class, roi));
/* delete existing intensity coefficients */
Utils.log("Clearing existing intensity maps ... ");
for (final Patch p : patches) p.clearIntensityMap();
/* generate coefficient tiles for all patches
* TODO consider offering alternative models */
final HashMap<Patch, ArrayList<Tile<? extends M>>> coefficientsTiles = (HashMap) generateCoefficientsTiles(patches, new InterpolatedAffineModel1D<InterpolatedAffineModel1D<AffineModel1D, TranslationModel1D>, IdentityModel>(new InterpolatedAffineModel1D<AffineModel1D, TranslationModel1D>(new AffineModel1D(), new TranslationModel1D(), lambda1), new IdentityModel(), lambda2), numCoefficients * numCoefficients);
/* completed patches */
final HashSet<Patch> completedPatches = new HashSet<Patch>();
/* collect patch pairs */
Utils.log("Collecting patch pairs ... ");
final ArrayList<ValuePair<Patch, Patch>> patchPairs = new ArrayList<ValuePair<Patch, Patch>>();
for (final Patch p1 : patches) {
completedPatches.add(p1);
final Rectangle box1 = p1.getBoundingBox().intersection(roi);
final ArrayList<Patch> p2s = new ArrayList<Patch>();
/* across adjacent layers */
final int layerIndex = layerset.getLayerIndex(p1.getLayer().getId());
for (int i = Math.max(firstLayerIndex, layerIndex - radius); i <= Math.min(lastLayerIndex, layerIndex + radius); ++i) {
final Layer layer = layerset.getLayer(i);
if (layer != null)
p2s.addAll((Collection) layer.getDisplayables(Patch.class, box1));
}
for (final Patch p2 : p2s) {
/*
* if this patch had been processed earlier, all matches are
* already in
*/
if (completedPatches.contains(p2))
continue;
patchPairs.add(new ValuePair<Patch, Patch>(p1, p2));
}
}
final int numThreads = Integer.parseInt(layerset.getProperty("n_mipmap_threads", Integer.toString(Runtime.getRuntime().availableProcessors())));
Utils.log("Matching intensities using " + numThreads + " threads ... ");
final ExecutorService exec = Executors.newFixedThreadPool(numThreads);
final ArrayList<Future<?>> futures = new ArrayList<Future<?>>();
for (final ValuePair<Patch, Patch> patchPair : patchPairs) {
futures.add(exec.submit(new Matcher(roi, patchPair, (HashMap) coefficientsTiles, filter, scale, numCoefficients)));
}
for (final Future<?> future : futures) future.get();
/* connect tiles within patches */
Utils.log("Connecting coefficient tiles in the same patch ... ");
for (final Patch p1 : completedPatches) {
/* get the coefficient tiles */
final ArrayList<Tile<? extends M>> p1CoefficientsTiles = coefficientsTiles.get(p1);
for (int y = 1; y < numCoefficients; ++y) {
final int yr = numCoefficients * y;
final int yr1 = yr - numCoefficients;
for (int x = 0; x < numCoefficients; ++x) {
identityConnect(p1CoefficientsTiles.get(yr1 + x), p1CoefficientsTiles.get(yr + x), neighborWeight);
}
}
for (int y = 0; y < numCoefficients; ++y) {
final int yr = numCoefficients * y;
for (int x = 1; x < numCoefficients; ++x) {
final int yrx = yr + x;
identityConnect(p1CoefficientsTiles.get(yrx), p1CoefficientsTiles.get(yrx - 1), neighborWeight);
}
}
}
/* optimize */
Utils.log("Optimizing ... ");
final TileConfiguration tc = new TileConfiguration();
for (final ArrayList<Tile<? extends M>> coefficients : coefficientsTiles.values()) {
// for ( final Tile< ? > t : coefficients )
// if ( t.getMatches().size() == 0 )
// IJ.log( "bang" );
tc.addTiles(coefficients);
}
try {
tc.optimize(0.01f, iterations, iterations, 0.75f);
} catch (final NotEnoughDataPointsException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (final IllDefinedDataPointsException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/* save coefficients */
final double[] ab = new double[2];
final FSLoader loader = (FSLoader) layerset.getProject().getLoader();
final String itsDir = loader.getUNUIdFolder() + "trakem2.its/";
for (final Entry<Patch, ArrayList<Tile<? extends M>>> entry : coefficientsTiles.entrySet()) {
final FloatProcessor as = new FloatProcessor(numCoefficients, numCoefficients);
final FloatProcessor bs = new FloatProcessor(numCoefficients, numCoefficients);
final Patch p = entry.getKey();
final double min = p.getMin();
final double max = p.getMax();
final ArrayList<Tile<? extends M>> tiles = entry.getValue();
for (int i = 0; i < numCoefficients * numCoefficients; ++i) {
final Tile<? extends M> t = tiles.get(i);
final Affine1D<?> affine = t.getModel();
affine.toArray(ab);
/* coefficients mapping into existing [min, max] */
as.setf(i, (float) ab[0]);
bs.setf(i, (float) ((max - min) * ab[1] + min - ab[0] * min));
}
final ImageStack coefficientsStack = new ImageStack(numCoefficients, numCoefficients);
coefficientsStack.addSlice(as);
coefficientsStack.addSlice(bs);
final String itsPath = itsDir + FSLoader.createIdPath(Long.toString(p.getId()), "it", ".tif");
new File(itsPath).getParentFile().mkdirs();
IJ.saveAs(new ImagePlus("", coefficientsStack), "tif", itsPath);
}
/* update mipmaps */
for (final Patch p : patches) p.getProject().getLoader().decacheImagePlus(p.getId());
final ArrayList<Future<Boolean>> mipmapFutures = new ArrayList<Future<Boolean>>();
for (final Patch p : patches) mipmapFutures.add(p.updateMipMaps());
for (final Future<Boolean> f : mipmapFutures) f.get();
Utils.log("Matching intensities done.");
}
use of ini.trakem2.display.Patch in project TrakEM2 by trakem2.
the class Render method main.
public static final void main(final String... args) {
new ImageJ();
final double scale = 0.05;
// final double scale = 1;
final int numCoefficients = 4;
final Project project = Project.openFSProject("/home/saalfeld/tmp/bock-lens-correction/subproject.xml", false);
final Layer layer = project.getRootLayerSet().getLayer(0);
final ArrayList<Patch> patches = (ArrayList) layer.getDisplayables(Patch.class);
final Patch patch1 = patches.get(0);
final Patch patch2 = patches.get(2);
final Rectangle box = patch1.getBoundingBox().intersection(patch2.getBoundingBox());
// final Rectangle box = patch1.getBoundingBox();
final int w = (int) (box.width * scale + 0.5);
final int h = (int) (box.height * scale + 0.5);
final FloatProcessor pixels1 = new FloatProcessor(w, h);
final FloatProcessor weights1 = new FloatProcessor(w, h);
final ColorProcessor coefficients1 = new ColorProcessor(w, h);
final FloatProcessor pixels2 = new FloatProcessor(w, h);
final FloatProcessor weights2 = new FloatProcessor(w, h);
final ColorProcessor coefficients2 = new ColorProcessor(w, h);
render(patch1, numCoefficients, numCoefficients, pixels1, weights1, coefficients1, box.x, box.y, scale);
render(patch2, numCoefficients, numCoefficients, pixels2, weights2, coefficients2, box.x, box.y, scale);
final ImageStack stack = new ImageStack(w, h);
stack.addSlice(pixels1);
stack.addSlice(pixels2);
stack.addSlice(weights1);
stack.addSlice(weights2);
stack.addSlice(coefficients1.convertToFloatProcessor());
stack.addSlice(coefficients2.convertToFloatProcessor());
new ImagePlus("", stack).show();
}
Aggregations