Ask Your Question
1

Proper(fast) way to extract pixel data from Mat in Java

asked 2013-08-02 12:42:49 -0600

Anniepoo gravatar image

Suspect I'm doing evil and want to know the right way.

I'm needing to copy a MAT of type CV_8UC3 into a Java BufferedImage. I was offered some code to do this, but it's taking excessive time - 34msec/frame for 640x480 image on my 8 core i7 The code (below) gets each pixel from the Mat via a get call. commenting out this line reduces conversion time to 3msec. Is there a way to get pixels in bigger batches? I'm new to OpenCV in Java, may be missing something simple.

condensing a bit

public static BufferedImage matToBufferedImage(Mat bgr) {
    int width = bgr.width();
    int height = bgr.height();
    BufferedImage image;
    WritableRaster raster;

        image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        raster = image.getRaster();

        byte[] px = new byte[3];
        int[] rgb = new int[3];

        for (int y=0; y<height; y++) {

            for (int x=0; x<width; x++) {
                // this operation is really inefficient!
                bgr.get(y,x,px);
                rgb[0] = px[2];
                rgb[1] = px[1];
                rgb[2] = px[0];
                raster.setPixel(x,y,rgb);
            }
        }
edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
1

answered 2014-01-14 22:34:59 -0600

Using System.arraycopy is faster than my other answer:

public Image toBufferedImageArrayCopy(Mat m){
        int type = BufferedImage.TYPE_BYTE_GRAY;
        if ( m.channels() > 1 ) {
            type = BufferedImage.TYPE_3BYTE_BGR;
        }
        int bufferSize = m.channels()*m.cols()*m.rows();
        byte [] b = new byte[bufferSize];
        m.get(0,0,b); // get all the pixels
        BufferedImage image = new BufferedImage(m.cols(),m.rows(), type);
        final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        System.arraycopy(b, 0, targetPixels, 0, b.length);  
        return image;

    }
edit flag offensive delete link more
1

answered 2013-12-22 22:29:03 -0600

Hi,

I can't assure you this is the fastest way to do it, but it takes around 2-3 ms per frame (640x480) on a similar computer. General idea is natively inverting BGR -> RGB and using BufferedImage setDataElements.

 public Image toBufferedImageNoEncode(Mat m){
        long time = System.currentTimeMillis();
        int type = BufferedImage.TYPE_BYTE_GRAY;
        if ( m.channels() > 1 ) {
            Mat m2 = new Mat();
            Imgproc.cvtColor(m,m2,Imgproc.COLOR_BGR2RGB);
            type = BufferedImage.TYPE_3BYTE_BGR;
            m = m2;
        }

        byte [] b = new byte[m.channels()*m.cols()*m.rows()];
        m.get(0,0,b); // get all the pixels
        BufferedImage image = new BufferedImage(m.cols(),m.rows(), type);
        image.getRaster().setDataElements(0, 0, m.cols(),m.rows(), b);
        System.out.println("To buffer: " + (System.currentTimeMillis() - time));

        return image;


    }
edit flag offensive delete link more

Question Tools

Stats

Asked: 2013-08-02 12:42:49 -0600

Seen: 3,920 times

Last updated: Jan 14 '14