use of ini.trakem2.imaging.filters.IFilter 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.imaging.filters.IFilter 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.imaging.filters.IFilter in project TrakEM2 by trakem2.
the class Patch method exportXML.
/**
* Opens and closes the tag and exports data. The image is saved in the directory provided in @param any as a String.
*/
@Override
public void exportXML(final StringBuilder sb_body, final String indent, final XMLOptions options) {
// TODO the Loader should handle the saving of images, not this class.
final String in = indent + "\t";
String path = null;
String path2 = null;
if (options.export_images) {
path = options.patches_dir + title;
// save image without overwriting, and add proper extension (.zip)
path2 = project.getLoader().exportImage(this, path, false);
// path2 will be null if the file exists already
}
sb_body.append(indent).append("<t2_patch\n");
String rel_path = null;
if (null != path && path.equals(path2)) {
// this happens when a DB project is exported. It may be a different path when it's a FS loader
// Utils.log2("p id=" + id + " path==path2");
rel_path = path2;
// TrakEM2 uses paths that always have '/' and never '\', so using java.io.File.separatorChar would be an error.
int i_slash = rel_path.lastIndexOf('/');
if (i_slash > 0) {
i_slash = rel_path.lastIndexOf('/', i_slash - 1);
if (-1 != i_slash) {
rel_path = rel_path.substring(i_slash + 1);
}
}
} else {
// Utils.log2("Setting rel_path to " + path2);
rel_path = path2;
}
// For FSLoader projects, saving a second time will save images as null unless calling it
if (null == rel_path) {
// Utils.log2("path2 was null");
final Object ob = project.getLoader().getPath(this);
path2 = null == ob ? null : (String) ob;
if (null == path2) {
// Utils.log2("ERROR: No path for Patch id=" + id + " and title: " + title);
// at least some clue for recovery
rel_path = title;
} else {
rel_path = path2;
}
}
// Utils.log("Patch path is: " + rel_path);
super.exportXML(sb_body, in, options);
final String[] RGB = Utils.getHexRGBColor(color);
int type = this.type;
if (-1 == this.type) {
Utils.log2("Retrieving type for p = " + this);
final ImagePlus imp = project.getLoader().fetchImagePlus(this);
if (null != imp)
type = imp.getType();
}
sb_body.append(in).append("type=\"").append(type).append("\"\n").append(in).append("file_path=\"").append(rel_path).append("\"\n").append(in).append("style=\"fill-opacity:").append(alpha).append(";stroke:#").append(RGB[0]).append(RGB[1]).append(RGB[2]).append(";\"\n").append(in).append("o_width=\"").append(o_width).append("\"\n").append(in).append("o_height=\"").append(o_height).append("\"\n");
if (null != original_path) {
sb_body.append(in).append("original_path=\"").append(original_path).append("\"\n");
}
sb_body.append(in).append("min=\"").append(min).append("\"\n");
sb_body.append(in).append("max=\"").append(max).append("\"\n");
final String pps = getPreprocessorScriptPath();
if (null != pps)
sb_body.append(in).append("pps=\"").append(project.getLoader().makeRelativePath(pps)).append("\"\n");
sb_body.append(in).append("mres=\"").append(meshResolution).append("\"\n");
if (hasCoordinateTransform()) {
sb_body.append(in).append("ct_id=\"").append(ct_id).append("\"\n");
}
if (hasAlphaMask()) {
sb_body.append(in).append("alpha_mask_id=\"").append(alpha_mask_id).append("\"\n");
}
sb_body.append(indent).append(">\n");
if (hasCoordinateTransform()) {
if (options.include_coordinate_transform) {
// Write an XML entry for the CoordinateTransform
char[] ct_chars = null;
try {
ct_chars = readCoordinateTransformFile();
} catch (final Exception e) {
IJError.print(e);
}
if (null != ct_chars) {
sb_body.append(ct_chars).append('\n');
} else {
Utils.log("ERROR: could not write the CoordinateTransform to the XML file!");
}
}
}
if (null != filters && filters.length > 0) {
// specify their own line termination
for (final IFilter f : filters) sb_body.append(f.toXML(in));
}
super.restXML(sb_body, in, options);
sb_body.append(indent).append("</t2_patch>\n");
}
use of ini.trakem2.imaging.filters.IFilter in project TrakEM2 by trakem2.
the class TMLHandler method endElement.
public void endElement(String namespace_URI, String local_name, String qualified_name) {
if (null == loader)
return;
if (skip) {
// reset
skip = false;
return;
}
String orig_qualified_name = qualified_name;
// Utils.log2("endElement: " + qualified_name);
// iterate over all open things and find the one that matches the qualified_name, and set it closed (pop it out of the list):
qualified_name = qualified_name.toLowerCase().trim();
if (0 == qualified_name.indexOf("t2_")) {
qualified_name = qualified_name.substring(3);
}
for (int i = al_open.size() - 1; i > -1; i--) {
Thing thing = al_open.get(i);
if (thing.getType().toLowerCase().equals(qualified_name)) {
al_open.remove(i);
break;
}
}
if (null != last_annotation && null != last_displayable) {
last_displayable.setAnnotation(last_annotation.toString().trim().replaceAll("<", "<"));
last_annotation = null;
}
// terminate non-single clause objects
if (orig_qualified_name.equals("t2_node")) {
// Remove one node from the stack
nodes.removeLast();
taggables.removeLast();
} else if (orig_qualified_name.equals("t2_connector")) {
if (null != last_connector) {
tree_root_nodes.put(last_connector, last_root_node);
last_root_node = null;
last_connector = null;
last_tree = null;
nodes.clear();
}
last_displayable = null;
} else if (orig_qualified_name.equals("t2_area_list")) {
last_area_list = null;
last_displayable = null;
} else if (orig_qualified_name.equals("t2_area")) {
if (null != reca) {
if (null != last_area_list) {
// it's local
last_area_list.addArea(last_area_list_layer_id, reca.getArea());
} else {
((AreaTree.AreaNode) nodes.getLast()).setData(reca.getArea());
}
reca = null;
}
} else if (orig_qualified_name.equals("ict_transform_list")) {
ct_list_stack.remove(ct_list_stack.size() - 1);
} else if (orig_qualified_name.equals("t2_patch")) {
if (last_patch_filters.size() > 0) {
last_patch.setFilters(last_patch_filters.toArray(new IFilter[last_patch_filters.size()]));
}
if (null != last_ct) {
last_patch.setCoordinateTransformSilently(last_ct);
last_ct = null;
} else if (!last_patch.checkCoordinateTransformFile()) {
Utils.log("ERROR: could not find a file for the coordinate transform #" + last_patch.getCoordinateTransformId() + " of Patch #" + last_patch.getId());
}
if (!last_patch.checkAlphaMaskFile()) {
Utils.log("ERROR: could not find a file for the alpha mask #" + last_patch.getAlphaMaskId() + " of Patch #" + last_patch.getId());
}
last_patch = null;
last_patch_filters.clear();
last_displayable = null;
} else if (orig_qualified_name.equals("t2_ball")) {
last_ball = null;
last_displayable = null;
} else if (orig_qualified_name.equals("t2_dissector")) {
last_dissector = null;
last_displayable = null;
} else if (orig_qualified_name.equals("t2_treeline")) {
if (null != last_treeline) {
// old format:
if (null == last_root_node && null != last_treeline_data && last_treeline_data.length() > 0) {
last_root_node = parseBranch(Utils.trim(last_treeline_data));
last_treeline_data = null;
}
// new
tree_root_nodes.put(last_treeline, last_root_node);
last_root_node = null;
// always:
last_treeline = null;
last_tree = null;
nodes.clear();
}
last_displayable = null;
} else if (orig_qualified_name.equals("t2_areatree")) {
if (null != last_areatree) {
tree_root_nodes.put(last_areatree, last_root_node);
last_root_node = null;
last_areatree = null;
last_tree = null;
// the absence of this line would have made the nodes list grow with all nodes of all areatrees, which is ok but consumes memory
nodes.clear();
}
last_displayable = null;
} else if (orig_qualified_name.equals("t2_stack")) {
if (null != last_ict) {
last_stack.setInvertibleCoordinateTransformSilently(last_ict);
last_ict = null;
}
last_stack = null;
last_displayable = null;
} else if (in(orig_qualified_name, all_displayables)) {
last_displayable = null;
}
}
use of ini.trakem2.imaging.filters.IFilter in project TrakEM2 by trakem2.
the class Loader method preProcess.
protected final void preProcess(final Patch p, ImagePlus imp, final long image_n_bytes) {
if (null == p)
return;
try {
final String path = preprocessors.get(p);
boolean update = false;
if (null != path) {
final File f = new File(path);
if (!f.exists()) {
Utils.log("ERROR: preprocessor script file does NOT exist: " + path);
return;
} else if (!f.canRead()) {
Utils.log("ERROR: can NOT read preprocessor script file at: " + path);
return;
}
if (null == imp) {
// uninitialized: the script may generate its data
imp = new ImagePlus();
} else {
// Prepare image for pre-processing
// for 8-bit and RGB images, your problem: setting min and max will expand the range.
imp.getProcessor().setMinAndMax(p.getMin(), p.getMax());
}
// Free 10 times the memory taken by the image, as a gross estimate of memory consumption by the script
releaseToFit(Math.min(10 * image_n_bytes, MAX_MEMORY / 4));
// Run the script
ini.trakem2.scripting.PatchScript.run(p, imp, path);
// Update Patch image properties:
if (null != imp.getProcessor() && null != imp.getProcessor().getPixels() && imp.getWidth() > 0 && imp.getHeight() > 0) {
update = true;
} else {
Utils.log("ERROR: preprocessor script failed to create a valid image:" + "\n ImageProcessor: " + imp.getProcessor() + "\n pixel array: " + (null == imp.getProcessor() ? null : imp.getProcessor().getPixels()) + "\n width: " + imp.getWidth() + "\n height: " + imp.getHeight());
}
}
// Now apply the Patch filters, if any
final IFilter[] fs = p.getFilters();
if (null != fs && fs.length > 0) {
ImageProcessor ip = imp.getProcessor();
for (final IFilter filter : fs) {
ip = filter.process(ip);
}
if (ip != imp.getProcessor()) {
imp.setProcessor(ip);
}
update = true;
}
// Now apply intensity correction if available
update |= mapIntensities(p, imp);
if (update) {
// 1: Tag the ImagePlus as altered (misuses fileFormat field, which is unused in any case)
final FileInfo fi = imp.getOriginalFileInfo();
// otherwise, the null original FileInfo is a valid tag by itself in the persistence.Cache
if (null != fi)
fi.fileFormat = Loader.PREPROCESSED;
// 2: cache
cache(p, imp);
// 3: update properties of the Patch
p.updatePixelProperties(imp);
}
} catch (final Exception e) {
IJError.print(e);
}
}
Aggregations