package ini.trakem2.utils; import java.util.List; import org.scijava.vecmath.Point3f; import ij.ImagePlus; import ij.ImageStack; import ij.measure.Calibration; import ij.process.ByteProcessor; import ij.process.ColorProcessor; import ij.process.ImageProcessor; import ij3d.Volume; import isosurface.Triangulator; import mpicbg.imglib.image.Image; import mpicbg.imglib.type.numeric.RealType; import vib.NaiveResampler; public class MCTriangulator implements Triangulator { @Override public List getTriangles(ImagePlus image, final int threshold, final boolean[] channels, final int resamplingF) { if(resamplingF != 1) image = NaiveResampler.resample(image, resamplingF); // There is no need to zero pad any more. MCCube automatically // scans one pixel more in each direction, assuming a value // of zero outside the image. // zeroPad(image); // create Volume final Volume volume = new Volume(image, channels); volume.setAverage(true); // get triangles final List l = MCCube.getTriangles(volume, threshold); return l; } /** * @param img The {@code Image<? extends RealType>} instance to use. * @param threshold The cut-off (inclusive) of pixel values considered inside. * @param origin The translation of the origin, in 3D. */ public<T extends RealType<T>> List<Point3f> getTriangles(final Image<T> img, final int threshold, final float[] origin) throws Exception { return MCCube.getTriangles(new ImgLibVolume(img, origin), threshold); } static public void zeroPad(final ImagePlus imp) { final ImageStack stack = imp.getStack(); final int w = stack.getWidth(); final int h = stack.getHeight(); final int d = stack.getSize(); final int type = imp.getType(); // create new stack final ImageStack st = new ImageStack(w+2, h+2); // retrieve 1st processor ImageProcessor old = stack.getProcessor(1); // enlarge it and add it as a first slide. ImageProcessor ne = createProcessor(w+2, h+2, type); st.addSlice("", ne); // now do the same for all slices in the old stack for(int z = 0; z < d; z++) { old = stack.getProcessor(z+1); ne = createProcessor(w+2, h+2, type); ne.insert(old, 1, 1); st.addSlice(Integer.toString(z+1), ne); } // now add an empty new slice ne = createProcessor(w+2, h+2, type); st.addSlice(Integer.toString(d+1), ne); imp.setStack(null, st); // update the origin final Calibration cal = imp.getCalibration(); cal.xOrigin -= cal.pixelWidth; cal.yOrigin -= cal.pixelHeight; cal.zOrigin -= cal.pixelDepth; imp.setCalibration(cal); } private static final ImageProcessor createProcessor( final int w, final int h, final int type) { if(type == ImagePlus.COLOR_RGB) return new ColorProcessor(w, h); return new ByteProcessor(w, h); } }