package org.bytedeco.javacv; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.WritableRaster; import org.bytedeco.javacpp.opencv_core.IplImage; import org.bytedeco.javacpp.opencv_core.Mat; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter; /** * Convenience class for performing various conversions between Mat, IplImage, * BufferedImage and Frame objects. Methods are synchronized because the * underlying JavaCV converters aren't safe for concurrent access. * * All created Frame, Mat, IplImages and BufferedImages are cloned internally * after creation so that their memory locations remain valid after the * converters which created them are garbage collected. This is safer for the * called, but may be slower. * * If performance is critical, use the *FrameConverter classes directly, after * reading about the image validity constraints (eg, images data is only valid * until next call to the converter). * * @see <a href="https://groups.google.com/forum/#!topic/javacv/sSgY9e-IDRA">Java2DFrameConverter crashes JVM</a> * @see FrameConverter * * @author Sam West, Joel Wong, Sep 2016. * */ public class Java2DFrameUtils { private static OpenCVFrameConverter.ToIplImage iplConv = new OpenCVFrameConverter.ToIplImage(); private static OpenCVFrameConverter.ToMat matConv = new OpenCVFrameConverter.ToMat(); private static Java2DFrameConverter biConv = new Java2DFrameConverter(); /** * Clones (deep copies the data) of a {@link BufferedImage}. Necessary when * converting to BufferedImages from JavaCV types to avoid re-using the same * memory locations. * * @param image1 * @return */ public static BufferedImage deepCopy(BufferedImage image1){ ColorModel cm = image1.getColorModel(); WritableRaster raster = image1.copyData(image1.getRaster().createCompatibleWritableRaster()); BufferedImage copied = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); return copied; } public synchronized static BufferedImage toBufferedImage(IplImage src) { return deepCopy(biConv.getBufferedImage(iplConv.convert(src).clone())); } public synchronized static BufferedImage toBufferedImage(Mat src) { return deepCopy(biConv.getBufferedImage(matConv.convert(src).clone())); } public synchronized static BufferedImage toBufferedImage(Frame src) { return deepCopy(biConv.getBufferedImage(src.clone())); } public synchronized static IplImage toIplImage(Mat src){ return iplConv.convertToIplImage(matConv.convert(src)).clone(); } public synchronized static IplImage toIplImage(Frame src){ return iplConv.convertToIplImage(src).clone(); } public synchronized static IplImage toIplImage(BufferedImage src){ return iplConv.convertToIplImage(biConv.convert(src)).clone(); } public synchronized static Mat toMat(IplImage src){ return matConv.convertToMat(iplConv.convert(src).clone()); } public synchronized static Mat toMat(Frame src){ return matConv.convertToMat(src).clone(); } public synchronized static Mat toMat(BufferedImage src){ return matConv.convertToMat(biConv.convert(src)).clone(); } public synchronized static Frame toFrame(IplImage src){ return iplConv.convert(src).clone(); } public synchronized static Frame toFrame(Mat src){ return matConv.convert(src).clone(); } public synchronized static Frame toFrame(BufferedImage src){ return biConv.convert(src).clone(); } }