use of ini.trakem2.display.Patch in project TrakEM2 by trakem2.
the class ContrastEnhancerWrapper method apply.
public boolean apply(final Collection<Displayable> patches_) {
if (null == patches_)
return false;
// Create appropriate patch list
ArrayList<Patch> patches = new ArrayList<Patch>();
for (final Displayable d : patches_) {
if (d.getClass() == Patch.class)
patches.add((Patch) d);
}
if (0 == patches.size())
return false;
// Check that all images are of the same size and type
Patch firstp = (Patch) patches.get(0);
final int ptype = firstp.getType();
final double pw = firstp.getOWidth();
final double ph = firstp.getOHeight();
for (final Patch p : patches) {
if (p.getType() != ptype) {
// can't continue
Utils.log("Can't homogenize histograms: images are not all of the same type.\nFirst offending image is: " + p);
return false;
}
if (!equalize && 0 == stats_mode && p.getOWidth() != pw || p.getOHeight() != ph) {
Utils.log("Can't homogenize histograms: images are not all of the same size.\nFirst offending image is: " + p);
return false;
}
}
try {
if (equalize) {
for (final Patch p : patches) {
if (Thread.currentThread().isInterrupted())
return false;
p.appendFilters(new IFilter[] { new EqualizeHistogram() });
/*
p.getProject().getLoader().releaseToFit(p.getOWidth(), p.getOHeight(), p.getType(), 3);
ImageProcessor ip = p.getImageProcessor().duplicate(); // a throw-away copy
if (this.from_existing_min_and_max) {
ip.setMinAndMax(p.getMin(), p.getMax());
}
ce.equalize(ip);
p.setMinAndMax(ip.getMin(), ip.getMax());
*/
// submit for regeneration
p.getProject().getLoader().decacheImagePlus(p.getId());
regenerateMipMaps(p);
}
return true;
}
// Else, call stretchHistogram with an appropriate stats object
final ImageStatistics stats;
if (1 == stats_mode) {
// use each image independent stats
stats = null;
} else if (0 == stats_mode) {
// use stack statistics
final ArrayList<Patch> sub = new ArrayList<Patch>();
if (use_full_stack) {
sub.addAll(patches);
} else {
// build stack statistics, ordered by stdDev
final SortedMap<Stats, Patch> sp = Collections.synchronizedSortedMap(new TreeMap<Stats, Patch>());
Process.progressive(patches, new TaskFactory<Patch, Stats>() {
public Stats process(final Patch p) {
if (Thread.currentThread().isInterrupted())
return null;
ImagePlus imp = p.getImagePlus();
p.getProject().getLoader().releaseToFit(p.getOWidth(), p.getOHeight(), p.getType(), 2);
Stats s = new Stats(imp.getStatistics());
sp.put(s, p);
return s;
}
});
if (Thread.currentThread().isInterrupted())
return false;
final ArrayList<Patch> a = new ArrayList<Patch>(sp.values());
final int count = a.size();
if (count < 3) {
sub.addAll(a);
} else if (3 == count) {
// the middle one
sub.add(a.get(1));
} else if (4 == count) {
sub.addAll(a.subList(1, 3));
} else if (count > 4) {
int first = (int) (count / 4.0 + 0.5);
int last = (int) (count / 4.0 * 3 + 0.5);
sub.addAll(a.subList(first, last));
}
}
stats = new StackStatistics(new PatchStack(sub.toArray(new Patch[sub.size()]), 1));
} else {
stats = reference_stats;
}
final Calibration cal = patches.get(0).getLayer().getParent().getCalibrationCopy();
Process.progressive(patches, new TaskFactory<Patch, Object>() {
public Object process(final Patch p) {
if (Thread.currentThread().isInterrupted())
return null;
p.getProject().getLoader().releaseToFit(p.getOWidth(), p.getOHeight(), p.getType(), 3);
// a throw-away copy
ImageProcessor ip = p.getImageProcessor().duplicate();
if (ContrastEnhancerWrapper.this.from_existing_min_and_max) {
ip.setMinAndMax(p.getMin(), p.getMax());
}
ImageStatistics st = stats;
if (null == stats) {
Utils.log2("Null stats, using image's self");
st = ImageStatistics.getStatistics(ip, Measurements.MIN_MAX, cal);
}
ce.stretchHistogram(ip, saturated, st);
// This is all we care about from stretching the histogram:
p.setMinAndMax(ip.getMin(), ip.getMax());
regenerateMipMaps(p);
return null;
}
});
} catch (Exception e) {
IJError.print(e);
return false;
}
return true;
}
use of ini.trakem2.display.Patch in project TrakEM2 by trakem2.
the class FilterEditor method GUI.
public static final void GUI(final Collection<Patch> patches, final Patch reference) {
final ArrayList<FilterWrapper> filters = new ArrayList<FilterWrapper>();
// Find out if all images have the exact same filters
final StringBuilder sb = new StringBuilder();
final Patch ref = (null == reference ? patches.iterator().next() : reference);
final IFilter[] refFilters = ref.getFilters();
if (null != refFilters) {
// makes a copy of the IFilter
for (final IFilter f : refFilters) filters.add(new FilterWrapper(f));
}
//
for (final Patch p : patches) {
if (ref == p)
continue;
final IFilter[] fs = p.getFilters();
// ok
if (null == fs && null == refFilters)
continue;
if ((null != refFilters && null == fs) || (null == refFilters && null != fs) || (null != refFilters && null != fs && fs.length != refFilters.length)) {
sb.append("WARNING: patch #" + p.getId() + " has a different number of filters than reference patch #" + ref.getId());
continue;
}
// Compare each
for (int i = 0; i < refFilters.length; ++i) {
if (fs[i].getClass() != refFilters[i].getClass()) {
sb.append("WARNING: patch #" + p.getId() + " has a different filters than reference patch #" + ref.getId());
break;
}
// Does the filter have the same parameters?
if (!filters.get(i).sameParameterValues(new FilterWrapper(fs[i]))) {
sb.append("WARNING: patch #" + p.getId() + " has filter '" + fs[i].getClass().getSimpleName() + "' with different parameters than the reference patch #" + ref.getId());
}
}
}
if (sb.length() > 0) {
final GenericDialog gd = new GenericDialog("WARNING", null == Display.getFront() ? IJ.getInstance() : Display.getFront().getFrame());
gd.addMessage("Filters are not all the same for all images:");
gd.addTextAreas(sb.toString(), null, 20, 30);
final String[] s = new String[] { "Use the filters of the reference image", "Start from an empty list of filters" };
gd.addChoice("Do:", s, s[0]);
gd.showDialog();
if (gd.wasCanceled())
return;
if (1 == gd.getNextChoiceIndex())
filters.clear();
}
final TableChosenFilters tcf = new TableChosenFilters(filters);
final TableParameters tp = new TableParameters(tcf);
tcf.setupListener(tp);
final TableAvailableFilters taf = new TableAvailableFilters(tcf);
if (filters.size() > 0) {
tcf.getSelectionModel().setSelectionInterval(0, 0);
}
final JFrame frame = new JFrame("Image filters");
final JButton set = new JButton("Set");
final JComboBox pulldown = new JComboBox(new String[] { "Selected images (" + patches.size() + ")", "All images in layer " + (ref.getLayer().getParent().indexOf(ref.getLayer()) + 1), "All images in layer range..." });
final Component[] cs = new Component[] { set, pulldown, tcf, tp, taf };
set.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
if (check(frame, filters)) {
final ArrayList<Patch> ps = new ArrayList<Patch>();
switch(pulldown.getSelectedIndex()) {
case 0:
ps.addAll(patches);
break;
case 1:
for (final Displayable d : ref.getLayer().getDisplayables(Patch.class)) {
ps.add((Patch) d);
}
break;
case 2:
final GenericDialog gd = new GenericDialog("Apply filters");
Utils.addLayerRangeChoices(ref.getLayer(), gd);
gd.addStringField("Image title matches:", "", 30);
gd.addCheckbox("Visible images only", true);
gd.showDialog();
if (gd.wasCanceled())
return;
final String regex = gd.getNextString();
final boolean visible_only = gd.getNextBoolean();
Pattern pattern = null;
if (0 != regex.length()) {
pattern = Pattern.compile(regex);
}
for (final Layer l : ref.getLayer().getParent().getLayers(gd.getNextChoiceIndex(), gd.getNextChoiceIndex())) {
for (final Displayable d : l.getDisplayables(Patch.class, visible_only)) {
if (null != pattern && !pattern.matcher(d.getTitle()).matches()) {
continue;
}
ps.add((Patch) d);
}
}
}
apply(ps, filters, cs, false);
}
}
});
final JPanel buttons = new JPanel();
final JLabel label = new JLabel("Push F1 for help");
final GridBagConstraints c2 = new GridBagConstraints();
final GridBagLayout gb2 = new GridBagLayout();
buttons.setLayout(gb2);
c2.anchor = GridBagConstraints.WEST;
c2.gridx = 0;
gb2.setConstraints(label, c2);
buttons.add(label);
c2.gridx = 1;
c2.weightx = 1;
final JPanel empty = new JPanel();
gb2.setConstraints(empty, c2);
buttons.add(empty);
c2.gridx = 2;
c2.weightx = 0;
c2.anchor = GridBagConstraints.EAST;
final JLabel a = new JLabel("Apply to:");
gb2.setConstraints(a, c2);
buttons.add(a);
c2.gridx = 3;
c2.insets = new Insets(4, 10, 4, 0);
gb2.setConstraints(pulldown, c2);
buttons.add(pulldown);
c2.gridx = 4;
gb2.setConstraints(set, c2);
buttons.add(set);
//
taf.setPreferredSize(new Dimension(350, 500));
tcf.setPreferredSize(new Dimension(350, 250));
tp.setPreferredSize(new Dimension(350, 250));
//
final GridBagLayout gb = new GridBagLayout();
final GridBagConstraints c = new GridBagConstraints();
final JPanel all = new JPanel();
all.setBackground(Color.white);
all.setPreferredSize(new Dimension(700, 500));
all.setLayout(gb);
c.gridx = 0;
c.gridy = 0;
c.anchor = GridBagConstraints.NORTHWEST;
c.fill = GridBagConstraints.BOTH;
c.gridheight = 2;
c.weightx = 0.5;
final JScrollPane p1 = new JScrollPane(taf);
p1.setPreferredSize(taf.getPreferredSize());
gb.setConstraints(p1, c);
all.add(p1);
c.gridx = 1;
c.gridy = 0;
c.gridheight = 1;
c.weighty = 0.7;
final JScrollPane p2 = new JScrollPane(tcf);
p2.setPreferredSize(tcf.getPreferredSize());
gb.setConstraints(p2, c);
all.add(p2);
c.gridx = 1;
c.gridy = 1;
c.weighty = 0.3;
final JScrollPane p3 = new JScrollPane(tp);
p3.setPreferredSize(tp.getPreferredSize());
gb.setConstraints(p3, c);
all.add(p3);
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 2;
c.weightx = 1;
c.weighty = 0;
gb.setConstraints(buttons, c);
all.add(buttons);
final KeyAdapter help = new KeyAdapter() {
@Override
public void keyPressed(final KeyEvent ke) {
if (ke.getKeyCode() == KeyEvent.VK_F1) {
final GenericDialog gd = new GenericDialog("Help :: image filters");
gd.addMessage("In the table 'Available Filters':\n" + " - double-click a filter to add it to the table of 'Chosen Filters'\n \n" + "In the table 'Chosen Filters':\n" + " - double-click a filter to remove it.\n" + " - PAGE UP/DOWN keys move the filter up/down in the list.\n" + " - 'Delete' key removes the selected filter.\n \n" + "In the table of parameter names and values:\n" + " - double-click a value to edit it. Then push enter to set the new value.\n \n" + "What you need to know:\n" + " - filters are set and applied in order, so order matters.\n" + " - filters with parameters for which you entered a value of zero\nwill result in a warning message.\n" + " - when applying the filters, if you choose 'Selected images', these are the images\nthat were selected when the filter editor was opened.\n" + " - when applying the filters, if you want to filter for a regular expression pattern\nin the image name, use the 'All images in layer range...' option,\nwhere a range of one single layer is also possible.");
gd.hideCancelButton();
gd.setModal(false);
gd.showDialog();
}
}
};
taf.addKeyListener(help);
tcf.addKeyListener(help);
tp.addKeyListener(help);
all.addKeyListener(help);
buttons.addKeyListener(help);
empty.addKeyListener(help);
a.addKeyListener(help);
frame.getContentPane().add(all);
frame.pack();
frame.setVisible(true);
}
use of ini.trakem2.display.Patch in project TrakEM2 by trakem2.
the class AlignTask method alignPatches.
/**
* @param patches: the list of Patch instances to align, all belonging to the same Layer.
* @param fixedPatches: the list of Patch instances to keep locked in place, if any.
* @param m: {@link AlignTask#LINEAR_SIFT_CORRESPONDENCES}, {@link AlignTask#LINEAR_PHASE_CORRELATION} or {@link AlignTask#ELASTIC_BLOCK_CORRESPONDENCES}.
*/
public static final void alignPatches(final List<Patch> patches, final Set<Patch> fixedPatches, final int m) throws Exception {
if (patches.size() < 2) {
Utils.log("No images to align.");
return;
}
for (final Patch patch : fixedPatches) {
if (!patches.contains(patch)) {
Utils.log("The list of fixed patches contains at least one Patch not included in the list of patches to align!");
return;
}
}
if (ELASTIC_BLOCK_CORRESPONDENCES == m)
new ElasticMontage().exec(patches, fixedPatches);
else if (LINEAR_PHASE_CORRELATION == m) {
// Montage all given patches, fixedPatches is ignored!
if (!fixedPatches.isEmpty())
Utils.log("Ignoring " + fixedPatches.size() + " fixed patches.");
StitchingTEM.montageWithPhaseCorrelation(patches);
} else if (LINEAR_SIFT_CORRESPONDENCES == m) {
if (!Align.paramOptimize.setup("Montage Selection"))
return;
final GenericDialog gd = new GenericDialog("Montage Selection: Miscellaneous");
gd.addCheckbox("tiles are roughly in place", tilesAreInPlace);
gd.addCheckbox("sloppy overlap test (fast)", sloppyOverlapTest);
gd.addCheckbox("consider largest graph only", largestGraphOnly);
gd.addCheckbox("hide tiles from non-largest graph", hideDisconnectedTiles);
gd.addCheckbox("delete tiles from non-largest graph", deleteDisconnectedTiles);
gd.showDialog();
if (gd.wasCanceled())
return;
tilesAreInPlace = gd.getNextBoolean();
sloppyOverlapTest = gd.getNextBoolean();
largestGraphOnly = gd.getNextBoolean();
hideDisconnectedTiles = gd.getNextBoolean();
deleteDisconnectedTiles = gd.getNextBoolean();
final Align.ParamOptimize p = Align.paramOptimize.clone();
alignPatches(p, patches, fixedPatches, tilesAreInPlace, largestGraphOnly, hideDisconnectedTiles, deleteDisconnectedTiles, sloppyOverlapTest);
} else
Utils.log("Don't know how to align with mode " + m);
}
use of ini.trakem2.display.Patch in project TrakEM2 by trakem2.
the class AlignTask method alignMultiLayerMosaic.
/**
* Align a multi-layer mosaic.
*
* @param l the current layer
*/
public static final void alignMultiLayerMosaic(final Layer l, final Patch nail) {
/* layer range and misc */
final List<Layer> layers = l.getParent().getLayers();
final String[] layerTitles = new String[layers.size()];
for (int i = 0; i < layers.size(); ++i) layerTitles[i] = l.getProject().findLayerThing(layers.get(i)).toString();
final GenericDialog gd1 = new GenericDialog("Align Multi-Layer Mosaic : Layer Range");
gd1.addMessage("Layer Range:");
final int sel = l.getParent().indexOf(l);
gd1.addChoice("first :", layerTitles, layerTitles[sel]);
gd1.addChoice("last :", layerTitles, layerTitles[sel]);
gd1.addMessage("Miscellaneous:");
gd1.addCheckbox("tiles are roughly in place", tilesAreInPlace);
gd1.addCheckbox("consider largest graph only", largestGraphOnly);
gd1.addCheckbox("hide tiles from non-largest graph", hideDisconnectedTiles);
gd1.addCheckbox("delete tiles from non-largest graph", deleteDisconnectedTiles);
gd1.addCheckbox("deform layers", deform);
gd1.showDialog();
if (gd1.wasCanceled())
return;
final int first = gd1.getNextChoiceIndex();
final int last = gd1.getNextChoiceIndex();
final int d = first < last ? 1 : -1;
tilesAreInPlace = gd1.getNextBoolean();
largestGraphOnly = gd1.getNextBoolean();
hideDisconnectedTiles = gd1.getNextBoolean();
deleteDisconnectedTiles = gd1.getNextBoolean();
deform = gd1.getNextBoolean();
if (!Align.paramOptimize.setup("Align Multi-Layer Mosaic : Intra-Layer"))
return;
final Align.ParamOptimize p = Align.paramOptimize.clone();
final Align.ParamOptimize pcp = p.clone();
if (!Align.param.setup("Align Multi-Layer Mosaic : Cross-Layer"))
return;
final Align.Param cp = Align.param.clone();
pcp.desiredModelIndex = cp.desiredModelIndex;
final List<Layer> layerRange = new ArrayList<Layer>();
for (int i = first; i != last + d; i += d) layerRange.add(layers.get(i));
alignMultiLayerMosaicTask(layerRange, nail, cp, p, pcp, tilesAreInPlace, largestGraphOnly, hideDisconnectedTiles, deleteDisconnectedTiles, deform);
}
use of ini.trakem2.display.Patch in project TrakEM2 by trakem2.
the class AlignTask method createTransformPropertiesTable.
/**
* Creates a map only for visible patches that intersect vdata.
* @param src_vdata represents the VectorData instances in original form, of the original project and layer set.
* @param tgt_vdata if not null, it must have the same size as src_data and their elements correspond one-to-one (as in, tgt element a clone of src element at the same index).
* @param lids_to_operate The id of the layers on which any operation will be done
* tgt_data enables transformVectorData to apply the transforms to copies of the src_vdata in another project.
*/
public static final ReferenceData createTransformPropertiesTable(final List<Displayable> src_vdata, final List<Displayable> tgt_vdata, final Set<Long> lids_to_operate) {
if (src_vdata.isEmpty())
return null;
final Map<Long, Patch.TransformProperties> tp = new HashMap<Long, Patch.TransformProperties>();
// A map of Displayable vs a map of Layer id vs list of Patch ids in that Layer that lay under the Patch, sorted by stack index
final Map<Displayable, Map<Long, TreeMap<Integer, Long>>> underlying = new HashMap<Displayable, Map<Long, TreeMap<Integer, Long>>>();
// The set of layers used
final Set<Long> src_layer_lids_used = new HashSet<Long>();
// Parallelize! This operation can be insanely expensive
final int nproc = Runtime.getRuntime().availableProcessors();
final ExecutorService exec = Utils.newFixedThreadPool(nproc, "AlignTask-createTransformPropertiesTable");
final List<Future<?>> dtasks = new ArrayList<Future<?>>();
final List<Future<?>> ltasks = new ArrayList<Future<?>>();
final Thread current = Thread.currentThread();
try {
for (int i = src_vdata.size() - 1; i > -1; i--) {
final Displayable src_d = src_vdata.get(i);
// filter out
if (!(src_d instanceof VectorData))
continue;
// use src_d if tgt_vdata is null
final Displayable tgt_d = null == tgt_vdata ? src_d : tgt_vdata.get(i);
// Some checking
if (!(tgt_d instanceof VectorData)) {
Utils.log("WARNING ignoring provided tgt_vdata " + tgt_d + " which is NOT a VectorData instance!");
continue;
}
if (src_d.getClass() != tgt_d.getClass()) {
Utils.log("WARNING src_d and tgt_d are instances of different classes:\n src_d :: " + src_d + "\n tgt_d :: " + tgt_d);
}
dtasks.add(exec.submit(new Runnable() {
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void run() {
final Map<Long, TreeMap<Integer, Long>> under = new HashMap<Long, TreeMap<Integer, Long>>();
synchronized (underlying) {
underlying.put(tgt_d, under);
}
if (current.isInterrupted())
return;
// Iterate the layers in which this VectorData has any data AND which have to be transformed
for (final Long olid : src_d.getLayerIds()) {
final long lid = olid.longValue();
// layer with id 'lid' is not affected
if (!lids_to_operate.contains(lid))
continue;
final Layer la = src_d.getLayerSet().getLayer(lid);
final Area a = src_d.getAreaAt(la);
if (null == a || a.isEmpty()) {
// does not paint in the layer
continue;
}
// The list of patches that lay under VectorData d, sorted by their stack index in the layer
final TreeMap<Integer, Long> stacked_patch_ids = new TreeMap<Integer, Long>();
synchronized (under) {
under.put(lid, stacked_patch_ids);
}
final boolean[] layer_visited = new boolean[] { false };
// Iterate source patches
for (final Patch patch : (Collection<Patch>) (Collection) la.getDisplayables(Patch.class, a, true)) {
// pick visible patches only
if (current.isInterrupted())
return;
try {
ltasks.add(exec.submit(new Runnable() {
@Override
public void run() {
if (current.isInterrupted())
return;
synchronized (patch) {
Patch.TransformProperties props;
synchronized (tp) {
props = tp.get(patch.getId());
}
if (null == props) {
props = patch.getTransformPropertiesCopy();
// Cache the props
synchronized (tp) {
tp.put(patch.getId(), props);
}
}
// Cache this patch as under the VectorData d
synchronized (stacked_patch_ids) {
// sorted by stack index
stacked_patch_ids.put(la.indexOf(patch), patch.getId());
// Utils.log("Added patch for layer " + la + " with stack index " + la.indexOf(patch) + ", patch " + patch);
}
if (!layer_visited[0]) {
// synch may fail to avoid adding it twice
// but it's ok since it's a Set anyway
layer_visited[0] = true;
synchronized (src_layer_lids_used) {
src_layer_lids_used.add(la.getId());
}
}
}
}
}));
} catch (final Throwable t) {
IJError.print(t);
return;
}
}
}
}
}));
}
Utils.wait(dtasks);
Utils.wait(ltasks);
} catch (final Throwable t) {
IJError.print(t);
} finally {
exec.shutdownNow();
}
return new ReferenceData(tp, underlying, src_layer_lids_used);
}
Aggregations