package ijopencv.ij; import ij.ImagePlus; import ij.process.ByteProcessor; import ij.process.ColorProcessor; import ij.process.FloatProcessor; import ij.process.ImageProcessor; import ij.process.ShortProcessor; import org.bytedeco.javacpp.BytePointer; import org.bytedeco.javacpp.FloatPointer; import org.bytedeco.javacpp.ShortPointer; import org.bytedeco.javacpp.opencv_core; import org.bytedeco.javacpp.opencv_core.Mat; import org.scijava.Prioritized; import org.scijava.Priority; import org.scijava.convert.AbstractConverter; import org.scijava.convert.Converter; import org.scijava.log.LogService; import org.scijava.plugin.Plugin; /** * @author J. Heras * @author W. Burger */ @Plugin(type = Converter.class, priority = Priority.LOW_PRIORITY) public class ImagePlusMatConverter extends AbstractConverter< ImagePlus, Mat> { @Override public int compareTo(Prioritized o) { return super.compareTo(o); } @Override public LogService log() { return super.log(); } @Override public String getIdentifier() { return super.getIdentifier(); } @Override public < T> T convert(Object o, Class< T> type) { ImagePlus imp = (ImagePlus) o; return (T) toMat(imp.getProcessor()); } @Override public Class< Mat> getOutputType() { return Mat.class; } @Override public Class< ImagePlus> getInputType() { return ImagePlus.class; } // -------------------------------------------------------------------- // ImageJ -> OpenCV (ImageProcessor -> Mat) // -------------------------------------------------------------------- /** * Dispatcher method. Duplicates {@link ImageProcessor} to the corresponding * OpenCV image of type {@link Mat}. TODO: Could be coded more elegantly ;-) * * @param ip The {@link ImageProcessor} to be converted * @return The OpenCV image (of type {@link Mat}) */ public static Mat toMat(ImageProcessor ip) { Mat mat = null; if (ip instanceof ByteProcessor) { mat = toMat((ByteProcessor) ip); } else if (ip instanceof ColorProcessor) { mat = toMat((ColorProcessor) ip); } else if (ip instanceof ShortProcessor) { mat = toMat((ShortProcessor) ip); } else if (ip instanceof FloatProcessor) { mat = toMat((FloatProcessor) ip); } else { throw new IllegalArgumentException("cannot convert to Mat: " + ip); } return mat; } /** * Convert the {@link ImageProcessor} to a given bitDepth and then * to an OpenCV image of type {@link Mat} * * @param ip The {@link ImageProcessor} to be converted * @param bitDepth Target bit depth * @return The OpenCV image (of type {@link Mat}) */ public static Mat toMat(ImageProcessor ip, int bitDepth) { if (bitDepth==8) ip = ip.convertToByteProcessor(); else if (bitDepth==16) ip = ip.convertToShortProcessor(); else if (bitDepth==32) ip = ip.convertToFloatProcessor(); else throw new IllegalArgumentException("bitDepth can only be 8, 16 or 32"); Mat mat = toMat(ip); return mat; } /** * Duplicates {@link ByteProcessor} to the corresponding OpenCV image of * type {@link Mat}. * * @param bp The {@link ByteProcessor} to be converted * @return The OpenCV image (of type {@link Mat}) */ public static Mat toMat(ByteProcessor bp) { final int w = bp.getWidth(); final int h = bp.getHeight(); final byte[] pixels = (byte[]) bp.getPixels(); // version A - copies the pixel data to a new array // Size size = new Size(w, h); // Mat mat = new Mat(size, opencv_core.CV_8UC1); // mat.data().put(bData); // version 2 - reuses the existing pixel array return new Mat(h, w, opencv_core.CV_8UC1, new BytePointer(pixels)); } /** * Duplicates {@link ShortProcessor} to the corresponding OpenCV image of * type {@link Mat}. * * @param sp The {@link ShortProcessor} to be converted * @return The OpenCV image (of type {@link Mat}) */ public static Mat toMat(ShortProcessor sp) { final int w = sp.getWidth(); final int h = sp.getHeight(); final short[] pixels = (short[]) sp.getPixels(); return new Mat(h, w, opencv_core.CV_16UC1, new ShortPointer(pixels)); } /** * Duplicates {@link FloatProcessor} to the corresponding OpenCV image of * type {@link Mat}. * * @param cp The {@link FloatProcessor} to be converted * @return The OpenCV image (of type {@link Mat}) */ public static Mat toMat(FloatProcessor cp) { final int w = cp.getWidth(); final int h = cp.getHeight(); final float[] pixels = (float[]) cp.getPixels(); return new Mat(h, w, opencv_core.CV_32FC1, new FloatPointer(pixels)); } /** * Duplicates {@link ColorProcessor} to the corresponding OpenCV image of * type {@link Mat}. * * @param cp The {@link ColorProcessor} to be converted * @return The OpenCV image (of type {@link Mat}) */ public static Mat toMat(ColorProcessor cp) { final int w = cp.getWidth(); final int h = cp.getHeight(); final int[] pixels = (int[]) cp.getPixels(); byte[] bData = new byte[w * h * 3]; // convert int-encoded RGB values to byte array for (int i = 0; i < pixels.length; i++) { bData[i * 3 + 0] = (byte) ((pixels[i] >> 16) & 0xFF); // red bData[i * 3 + 1] = (byte) ((pixels[i] >> 8) & 0xFF); // grn bData[i * 3 + 2] = (byte) ((pixels[i]) & 0xFF); // blu } return new Mat(h, w, opencv_core.CV_8UC3, new BytePointer(bData)); } /** * Convert an {@link ImagePlus} image to an OpenCV image of type {@link Mat} * * @param imp The {@link ImagePlus} to be converted * @return The OpenCV image (of type {@link Mat}) */ public static Mat toMat(ImagePlus imp) { ImageProcessor ip = imp.getProcessor(); Mat mat = toMat(ip); return mat; } /** * Convert an {@link ImagePlus} image to a different bitDepth and then to an OpenCV image of type {@link Mat} * * @param imp The {@link ImagePlus} to be converted * @param bitDepth The target bitDepth * @return The OpenCV image (of type {@link Mat}) */ public static Mat toMat(ImagePlus imp, int bitDepth) { ImageProcessor ip = imp.getProcessor(); Mat mat = toMat(ip, bitDepth); return mat; } }