Image loads; Cannot put into array

asked 2015-02-26 07:15:50 -0600

updated 2015-02-26 07:24:20 -0600

This loads just fine:

    private Mat m = Imgcodecs.imread("C:/Users/Link/workspace/G3DExperiment/src/imgres/stone.png");

But for some reason I can't load it into an array:

public void draw(Mat mat, int x, int y) {
    int rows = mat.rows(), cols = mat.cols(), type = CvType.channels(mat.type());
    int[] bgr = new int[rows*cols*type];
    mat.get(0, 0, bgr);
    canvas.setRGB(x, y, cols, rows, bgr, 0, width);
}

canvas is a BufferedImage of type TYPE_3BYTE_BGR and this method MatrixCanvas#draw(Mat, int, int) is used to draw a Mat directly onto the screen by covering the screen in a BufferedImage and setting the pixels on the image.

The full stacktrace reads:

Exception in thread "AWT-EventQueue-0" java.lang.UnsupportedOperationException: Mat data type is not compatible: 16
at org.opencv.core.Mat.get(Mat.java:2599)
at genesis.g2D.MatrixCanvas.draw(MatrixCanvas.java:158)
at g.Main.<init>(Main.java:49)
at g.Main.<init>(Main.java:42)
at g.Main$1.run(Main.java:37)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
edit retag flag offensive close merge delete

Comments

2

try byte[] bgr = new byte[mat.total() * mat.elemSize()]; ( not int)

berak gravatar imageberak ( 2015-02-26 08:10:22 -0600 )edit

Yeah I probably should try byte. int didn't work. It still gives an error.

LinkTheProgrammer gravatar imageLinkTheProgrammer ( 2015-02-26 08:21:43 -0600 )edit
1

hehe, you can do it all in 2 lines:

    BufferedImage image = new BufferedImage(m.cols(),m.rows(), type);
    m.get(0,0,((DataBufferByte)image.getRaster().getDataBuffer()).getData()); // get all the pixels
berak gravatar imageberak ( 2015-02-26 08:26:03 -0600 )edit

Your optimization makes it 1 line for my method. Also, it works! I mean it doesn't draw correctly, but it works! Probably a problem somewhere between types but... it works! Thanks again :)

LinkTheProgrammer gravatar imageLinkTheProgrammer ( 2015-02-26 08:29:25 -0600 )edit

ah ok. i'm cheating, that's 3 lines more :

    int type = BufferedImage.TYPE_BYTE_GRAY;
    if ( m.channels() > 1 ) {
        type = BufferedImage.TYPE_3BYTE_BGR;
    }
berak gravatar imageberak ( 2015-02-26 08:35:50 -0600 )edit
1

now look here - i guess, now you can make a much better answer, than the existing one !

berak gravatar imageberak ( 2015-02-26 08:46:49 -0600 )edit

That is too CPU intensive to run at 60 fps. I need a one-liner that will set the data in a BufferedImage that is the size of the JFrame it is in. Currently, your m.get(0,0,((DataBufferByte)image.getRaster().getDataBuffer()).getData()); works, but it shows up as two rows of pixels rather than an image. I need the fastest way to copy data from a Mat into what is now a TYPE_4BYTE_ABGR. I changed the type to allow alpha. I noticed the method BufferedImage.getRaster().setPixels(x, y, w, h, iArray); which sets a part or the whole thing to some pixels. Simply using setPixels(x, y, Raster) would just copy the pixels in without formation and so that is why it is two lines instead of 16x16.

LinkTheProgrammer gravatar imageLinkTheProgrammer ( 2015-02-26 08:51:10 -0600 )edit

Or something fast enough that it isn't one line, but does not use condition statements. To clarify, the canvas can only be instantiated as new MatrixCanvas() {... TYPE_4BYTE_ABGR ...}

LinkTheProgrammer gravatar imageLinkTheProgrammer ( 2015-02-26 08:52:39 -0600 )edit

if your canvas has to be bgra, then Imgproc.cvtColor(img,img,COLOR_BGR2BGRA); and type = BufferedImage.TYPE_3BYTE_BGRA

berak gravatar imageberak ( 2015-02-26 08:58:25 -0600 )edit

Well, That converts it to BGRA, but if I load the image using Imgcodecs.imread(imgname, Imgcodecs.IMREAD_UNCHANGED), that should load unchanged, as in the actual read in data right? Also, I still need a way to efficiently copy the data in one swift move.

LinkTheProgrammer gravatar imageLinkTheProgrammer ( 2015-02-26 09:05:32 -0600 )edit

hmm, yes, but with a big IF the img data is bgra. (which might not nessecarily be so)

again, i do not see, why you want a bgra canvas for opencv things in the 1st place. alpha is of no relevance in computer-vision, and only relevant for compositing /dtp operations. there's not a single algorithm in opencv, that makes use of it.

berak gravatar imageberak ( 2015-02-26 09:08:50 -0600 )edit

Well, do you know of a way for me to just copy the data using x y w h?

LinkTheProgrammer gravatar imageLinkTheProgrammer ( 2015-02-26 09:11:24 -0600 )edit