Search in sources :

Example 11 with Montage

use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.

the class Loader method importGrid.

/**
 * Import a grid of images and put them in the layer. If the directory (@param dir) is null, it'll be asked for.
 */
public Bureaucrat importGrid(final Layer layer, String dir) {
    try {
        String file = null;
        if (null == dir) {
            final String[] dn = Utils.selectFile("Select first image");
            if (null == dn)
                return null;
            dir = dn[0];
            file = dn[1];
        }
        // char digit digit
        String convention = "cdd";
        boolean chars_are_columns = true;
        // examine file name
        /*
		if (file.matches("\\A[a-zA-Z]\\d\\d.*")) { // one letter, 2 numbers
			//means:
			//	\A		- beggining of input
			//	[a-zA-Z]	- any letter upper or lower case
			//	\d\d		- two consecutive digits
			//	.*		- any row of chars
			ini_grid_convention = true;
		}
		*/
        // ask for chars->rows, numbers->columns or viceversa
        final GenericDialog gd = new GenericDialog("Conventions");
        gd.addStringField("file_name_contains:", "");
        gd.addNumericField("base_x: ", 0, 3);
        gd.addNumericField("base_y: ", 0, 3);
        gd.addMessage("Use: x(any), c(haracter), d(igit)");
        gd.addStringField("convention: ", convention);
        final String[] cr = new String[] { "columns", "rows" };
        gd.addChoice("characters are: ", cr, cr[0]);
        gd.addMessage("[File extension ignored]");
        // as asked by Joachim Walter
        gd.addNumericField("bottom-top overlap: ", 0, 3);
        gd.addNumericField("left-right overlap: ", 0, 3);
        gd.addCheckbox("link_images", false);
        gd.addCheckbox("montage with phase correlation", false);
        gd.addCheckbox("homogenize_contrast", true);
        final Component[] c = { (Component) gd.getSliders().get(gd.getSliders().size() - 2), (Component) gd.getNumericFields().get(gd.getNumericFields().size() - 2), (Component) gd.getSliders().get(gd.getSliders().size() - 1), (Component) gd.getNumericFields().get(gd.getNumericFields().size() - 1), (Component) gd.getChoices().get(gd.getChoices().size() - 1) };
        // enable the checkbox to control the slider and its associated numeric field:
        Utils.addEnablerListener((Checkbox) gd.getCheckboxes().get(gd.getCheckboxes().size() - 1), c, null);
        // gd.addCheckbox("Apply non-linear deformation", false);
        gd.showDialog();
        if (gd.wasCanceled()) {
            return null;
        }
        // collect data
        // filter away files not containing this tag
        final String regex = gd.getNextString();
        // the base x,y of the whole grid
        final double bx = gd.getNextNumber();
        final double by = gd.getNextNumber();
        // if (!ini_grid_convention) {
        convention = gd.getNextString().toLowerCase();
        // }
        if (/*!ini_grid_convention && */
        (null == convention || convention.equals("") || -1 == convention.indexOf('c') || -1 == convention.indexOf('d'))) {
            // TODO check that the convention has only 'cdx' chars and also that there is an island of 'c's and of 'd's only.
            Utils.showMessage("Convention '" + convention + "' needs both c(haracters) and d(igits), optionally 'x', and nothing else!");
            return null;
        }
        chars_are_columns = (0 == gd.getNextChoiceIndex());
        final double bt_overlap = gd.getNextNumber();
        final double lr_overlap = gd.getNextNumber();
        final boolean link_images = gd.getNextBoolean();
        final boolean stitch_tiles = gd.getNextBoolean();
        final boolean homogenize_contrast = gd.getNextBoolean();
        // start magic
        // get ImageJ-openable files that comply with the convention
        final File images_dir = new File(dir);
        if (!(images_dir.exists() && images_dir.isDirectory())) {
            Utils.showMessage("Something went wrong:\n\tCan't find directory " + dir);
            return null;
        }
        final String[] file_names = images_dir.list(new ImageFileFilter(regex, convention));
        if (null == file && file_names.length > 0) {
            // the 'selected' file
            file = file_names[0];
        }
        Utils.showStatus("Adding " + file_names.length + " patches.", false);
        if (0 == file_names.length) {
            Utils.log("Zero files match the convention '" + convention + "'");
            return null;
        }
        // How to: select all files, and order their names in a double array as they should be placed in the Display. Then place them, displacing by offset, and resizing if necessary.
        // gather image files:
        final Montage montage = new Montage(convention, chars_are_columns);
        montage.addAll(file_names);
        // an array of Object[] arrays, of unequal length maybe, each containing a column of image file names
        final ArrayList<String[]> cols = montage.getCols();
        // !@#$%^&*
        final String dir_ = dir;
        final double bt_overlap_ = bt_overlap;
        final double lr_overlap_ = lr_overlap;
        final String file_ = file;
        return Bureaucrat.createAndStart(new Worker.Task("Insert grid", true) {

            @Override
            public void exec() {
                StitchingTEM.PhaseCorrelationParam pc_param = null;
                if (stitch_tiles) {
                    pc_param = new StitchingTEM.PhaseCorrelationParam();
                    pc_param.setup(layer);
                }
                insertGrid(layer, dir_, file_, file_names.length, cols, bx, by, bt_overlap_, lr_overlap_, link_images, stitch_tiles, homogenize_contrast, pc_param, this);
            }
        }, layer.getProject());
    } catch (final Exception e) {
        IJError.print(e);
    }
    return null;
}
Also used : ImageFileFilter(ini.trakem2.io.ImageFileFilter) IOException(java.io.IOException) FormatException(loci.formats.FormatException) GenericDialog(ij.gui.GenericDialog) Montage(ini.trakem2.utils.Montage) Worker(ini.trakem2.utils.Worker) Component(java.awt.Component) File(java.io.File)

Example 12 with Montage

use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.

the class StitchingTEM method montageWithPhaseCorrelation.

/**
 * Perform montage based on phase correlation
 * @param col collection of patches
 * @param param phase correlation parameters
 */
public static void montageWithPhaseCorrelation(final Collection<Patch> col, final PhaseCorrelationParam param) {
    if (null == col || col.size() < 1)
        return;
    final ArrayList<Patch> al = new ArrayList<Patch>(col);
    final ArrayList<AbstractAffineTile2D<?>> tiles = new ArrayList<AbstractAffineTile2D<?>>();
    final ArrayList<AbstractAffineTile2D<?>> fixed_tiles = new ArrayList<AbstractAffineTile2D<?>>();
    for (final Patch p : al) {
        // Pre-check: just a warning
        final int aff_type = p.getAffineTransform().getType();
        switch(p.getAffineTransform().getType()) {
            case AffineTransform.TYPE_IDENTITY:
            case AffineTransform.TYPE_TRANSLATION:
                // ok
                break;
            default:
                Utils.log2("WARNING: patch with a non-translation transform: " + p);
                break;
        }
        // create tiles
        final TranslationTile2D tile = new TranslationTile2D(new TranslationModel2D(), p);
        tiles.add(tile);
        if (p.isLocked2()) {
            Utils.log("Added fixed (locked) tile " + p);
            fixed_tiles.add(tile);
        }
    }
    // Get acceptable values
    double cc_scale = param.cc_scale;
    if (cc_scale < 0 || cc_scale > 1) {
        Utils.log("Unacceptable cc_scale of " + param.cc_scale + ". Using 1 instead.");
        cc_scale = 1;
    }
    float overlap = param.overlap;
    if (overlap < 0 || overlap > 1) {
        Utils.log("Unacceptable overlap of " + param.overlap + ". Using 1 instead.");
        overlap = 1;
    }
    for (int i = 0; i < al.size(); i++) {
        final Patch p1 = al.get(i);
        final Rectangle r1 = p1.getBoundingBox();
        // find overlapping, add as connections
        for (int j = i + 1; j < al.size(); j++) {
            if (Thread.currentThread().isInterrupted())
                return;
            final Patch p2 = al.get(j);
            final Rectangle r2 = p2.getBoundingBox();
            if (r1.intersects(r2)) {
                // Skip if it's a diagonal overlap
                final int dx = Math.abs(r1.x - r2.x);
                final int dy = Math.abs(r1.y - r2.y);
                if (dx > r1.width / 2 && dy > r1.height / 2) {
                    // skip diagonal match
                    Utils.log2("Skipping diagonal overlap between " + p1 + " and " + p2);
                    continue;
                }
                p1.getProject().getLoader().releaseToFit((long) (p1.getWidth() * p1.getHeight() * 25));
                final double[] R;
                if (1 == overlap) {
                    R = correlate(p1, p2, overlap, cc_scale, TOP_BOTTOM, 0, 0, param.min_R);
                    if (SUCCESS == R[2]) {
                        addMatches(tiles.get(i), tiles.get(j), R[0], R[1]);
                    }
                } else {
                    switch(getClosestOverlapLocation(p1, p2)) {
                        case // p1 overlaps p2 from the left
                        0:
                            R = correlate(p1, p2, overlap, cc_scale, LEFT_RIGHT, 0, 0, param.min_R);
                            if (SUCCESS == R[2]) {
                                addMatches(tiles.get(i), tiles.get(j), R[0], R[1]);
                            }
                            break;
                        case // p1 overlaps p2 from the top
                        1:
                            R = correlate(p1, p2, overlap, cc_scale, TOP_BOTTOM, 0, 0, param.min_R);
                            if (SUCCESS == R[2]) {
                                addMatches(tiles.get(i), tiles.get(j), R[0], R[1]);
                            }
                            break;
                        case // p1 overlaps p2 from the right
                        2:
                            R = correlate(p2, p1, overlap, cc_scale, LEFT_RIGHT, 0, 0, param.min_R);
                            if (SUCCESS == R[2]) {
                                addMatches(tiles.get(j), tiles.get(i), R[0], R[1]);
                            }
                            break;
                        case // p1 overlaps p2 from the bottom
                        3:
                            R = correlate(p2, p1, overlap, cc_scale, TOP_BOTTOM, 0, 0, param.min_R);
                            if (SUCCESS == R[2]) {
                                addMatches(tiles.get(j), tiles.get(i), R[0], R[1]);
                            }
                            break;
                        default:
                            Utils.log("Unknown overlap direction!");
                            continue;
                    }
                }
            }
        }
    }
    if (param.remove_disconnected || param.hide_disconnected) {
        for (final Iterator<AbstractAffineTile2D<?>> it = tiles.iterator(); it.hasNext(); ) {
            final AbstractAffineTile2D<?> t = it.next();
            if (null != t.getMatches() && t.getMatches().isEmpty()) {
                if (param.hide_disconnected)
                    t.getPatch().setVisible(false);
                else if (param.remove_disconnected)
                    t.getPatch().remove(false);
                it.remove();
            }
        }
    }
    // Optimize tile configuration by removing bad matches
    optimizeTileConfiguration(tiles, fixed_tiles, param);
    for (final AbstractAffineTile2D<?> t : tiles) t.getPatch().setAffineTransform(t.getModel().createAffine());
    try {
        Display.repaint(al.get(0).getLayer());
    } catch (final Exception e) {
    }
}
Also used : TranslationTile2D(mpicbg.trakem2.align.TranslationTile2D) AbstractAffineTile2D(mpicbg.trakem2.align.AbstractAffineTile2D) ArrayList(java.util.ArrayList) Rectangle(java.awt.Rectangle) Point(mpicbg.models.Point) TranslationModel2D(mpicbg.models.TranslationModel2D) Patch(ini.trakem2.display.Patch)

Example 13 with Montage

use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.

the class StitchingTEM method montageWithPhaseCorrelation.

/**
 * @param layers
 * @param worker Optional, the {@link Worker} running this task.
 */
public static void montageWithPhaseCorrelation(final List<Layer> layers, final Worker worker) {
    final PhaseCorrelationParam param = new PhaseCorrelationParam();
    final Collection<Displayable> col = layers.get(0).getDisplayables(Patch.class);
    if (!param.setup(col.size() > 0 ? (Patch) col.iterator().next() : null)) {
        return;
    }
    final int i = 1;
    for (final Layer la : layers) {
        if (Thread.currentThread().isInterrupted() || (null != worker && worker.hasQuitted()))
            return;
        if (null != worker)
            worker.setTaskName("Montage layer " + i + "/" + layers.size());
        final Collection<Patch> patches = (Collection<Patch>) (Collection) la.getDisplayables(Patch.class);
        AlignTask.transformPatchesAndVectorData(patches, new Runnable() {

            @Override
            public void run() {
                montageWithPhaseCorrelation(patches, param);
            }
        });
    }
}
Also used : Displayable(ini.trakem2.display.Displayable) Collection(java.util.Collection) Layer(ini.trakem2.display.Layer) Patch(ini.trakem2.display.Patch) Point(mpicbg.models.Point)

Example 14 with Montage

use of ini.trakem2.utils.Montage in project TrakEM2 by trakem2.

the class AlignTask method montageLayers.

@SuppressWarnings({ "rawtypes", "unchecked" })
public static final void montageLayers(final Align.ParamOptimize p, final List<Layer> layers, final boolean tilesAreInPlaceIn, final boolean largestGraphOnlyIn, final boolean hideDisconnectedTilesIn, final boolean deleteDisconnectedTilesIn, final boolean sloppyOverlapTest) {
    int i = 0;
    for (final Layer layer : layers) {
        if (Thread.currentThread().isInterrupted())
            return;
        final Collection<Displayable> patches = layer.getDisplayables(Patch.class, true);
        if (patches.isEmpty())
            continue;
        for (final Displayable patch : patches) {
            if (patch.isLinked() && !patch.isOnlyLinkedTo(Patch.class)) {
                Utils.log("Cannot montage layer " + layer + "\nReason: at least one Patch is linked to non-image data: " + patch);
                continue;
            }
        }
        Utils.log("====\nMontaging layer " + layer);
        Utils.showProgress(((double) i) / layers.size());
        i++;
        alignPatches(p, new ArrayList<Patch>((Collection<Patch>) (Collection) patches), new ArrayList<Patch>(), tilesAreInPlaceIn, largestGraphOnlyIn, hideDisconnectedTilesIn, deleteDisconnectedTilesIn, sloppyOverlapTest);
        Display.repaint(layer);
    }
}
Also used : Displayable(ini.trakem2.display.Displayable) Collection(java.util.Collection) Layer(ini.trakem2.display.Layer) Patch(ini.trakem2.display.Patch) Point(mpicbg.models.Point)

Aggregations

GenericDialog (ij.gui.GenericDialog)7 Patch (ini.trakem2.display.Patch)7 Rectangle (java.awt.Rectangle)6 ArrayList (java.util.ArrayList)6 Worker (ini.trakem2.utils.Worker)5 ImagePlus (ij.ImagePlus)4 File (java.io.File)4 Roi (ij.gui.Roi)3 Project (ini.trakem2.Project)3 NoninvertibleTransformException (java.awt.geom.NoninvertibleTransformException)3 Point (mpicbg.models.Point)3 PolygonRoi (ij.gui.PolygonRoi)2 ShapeRoi (ij.gui.ShapeRoi)2 Displayable (ini.trakem2.display.Displayable)2 Layer (ini.trakem2.display.Layer)2 InspectPatchTrianglesMode (ini.trakem2.display.inspect.InspectPatchTrianglesMode)2 DBObject (ini.trakem2.persistence.DBObject)2 ProjectThing (ini.trakem2.tree.ProjectThing)2 Bureaucrat (ini.trakem2.utils.Bureaucrat)2 Color (java.awt.Color)2