简体   繁体   English

在 OpenCV 中将 `BufferedImage` 转换为 `Mat`

[英]Converting `BufferedImage` to `Mat` in OpenCV

How can I convert a BufferedImage to a Mat in OpenCV ?如何在OpenCV中将BufferedImage转换为Mat

I'm using the JAVA wrapper for OpenCV (not JavaCV ).我正在使用OpenCV的 JAVA 包装器(不是JavaCV )。 As I am new to OpenCV I have some problems understanding how Mat works.由于我是OpenCV新手,我在理解Mat工作原理时遇到了一些问题。

I want to do something like this.我想做这样的事情。 (Based on Ted W. reply): (基于 Ted W. 回复):

BufferedImage image = ImageIO.read(b.getClass().getResource("Lena.png"));

int rows = image.getWidth();
int cols = image.getHeight();
int type = CvType.CV_16UC1;
Mat newMat = new Mat(rows, cols, type);

for (int r = 0; r < rows; r++) {
    for (int c = 0; c < cols; c++) {
        newMat.put(r, c, image.getRGB(r, c));
    }
}

Highgui.imwrite("Lena_copy.png", newMat);

This doesn't work.这不起作用。 Lena_copy.png is just a black picture with the correct dimensions. Lena_copy.png只是一张尺寸正确的黑色图片。

I also was trying to do the same thing, because of need to combining image processed with two libraries.我也试图做同样的事情,因为需要将处理过的图像与两个库结合起来。 And what I've tried to do is to put byte[] in to Mat instead of RGB value.我试图做的是将byte[]放入Mat而不是 RGB 值。 And it worked!它奏效了! So what I did was:所以我所做的是:

1.Converted BufferedImage to byte array with: 1.Converted BufferedImage到字节数组:

byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();

2. Then you can simply put it to Mat if you set type to CV_8UC3 2.如果你把type设置为CV_8UC3,你可以简单地把它放在Mat上

image_final.put(0, 0, pixels);

Edit: Also you can try to do the inverse as on this answer编辑:你也可以尝试按照这个答案做相反的事情

Don't want to deal with big pixel array?不想处理大像素阵列? Simply use this简单地使用这个

BufferedImage to Mat缓冲图像到垫子

public static Mat BufferedImage2Mat(BufferedImage image) throws IOException {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    ImageIO.write(image, "jpg", byteArrayOutputStream);
    byteArrayOutputStream.flush();
    return Imgcodecs.imdecode(new MatOfByte(byteArrayOutputStream.toByteArray()), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);
}

Mat to BufferedImage垫到缓冲图像

public static BufferedImage Mat2BufferedImage(Mat matrix)throws IOException {
    MatOfByte mob=new MatOfByte();
    Imgcodecs.imencode(".jpg", matrix, mob);
    return ImageIO.read(new ByteArrayInputStream(mob.toArray()));
}

Note , Though it's very negligible.注意,虽然它非常微不足道。 However, in this way, you can get a reliable solution but it uses encoding + decoding.但是,通过这种方式,您可以获得可靠的解决方案,但它使用编码+解码。 So you lose some performance.所以你会失去一些性能。 It's generally 10 to 20 milliseconds.一般为 10 到 20 毫秒。 JPG encoding loses some image quality also it's slow (may take 10 to 20ms). JPG编码会损失一些图像质量,而且速度很慢(可能需要 10 到 20 毫秒)。 BMP is lossless and fast (1 or 2 ms) but requires little more memory (negligible). BMP无损且快速(1 或 2 毫秒),但只需要很少的内存(可以忽略不计)。 PNG is lossless but a little more time to encode than BMP. PNG是无损的,但编码时间比 BMP 多一点。 Using BMP should fit the most cases I think.使用BMP应该适合我认为的大多数情况。

This one worked fine for me, and it takes from 0 to 1 ms to be performed.这个对我来说效果很好,执行时间为 0 到 1 毫秒。

public static Mat bufferedImageToMat(BufferedImage bi) {
  Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3);
  byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
  mat.put(0, 0, data);
  return mat;
}

I use following code in my program.我在我的程序中使用以下代码。

protected Mat img2Mat(BufferedImage in) {
        Mat out;
        byte[] data;
        int r, g, b;

        if (in.getType() == BufferedImage.TYPE_INT_RGB) {
            out = new Mat(in.getHeight(), in.getWidth(), CvType.CV_8UC3);
            data = new byte[in.getWidth() * in.getHeight() * (int) out.elemSize()];
            int[] dataBuff = in.getRGB(0, 0, in.getWidth(), in.getHeight(), null, 0, in.getWidth());
            for (int i = 0; i < dataBuff.length; i++) {
                data[i * 3] = (byte) ((dataBuff[i] >> 0) & 0xFF);
                data[i * 3 + 1] = (byte) ((dataBuff[i] >> 8) & 0xFF);
                data[i * 3 + 2] = (byte) ((dataBuff[i] >> 16) & 0xFF);
            }
        } else {
            out = new Mat(in.getHeight(), in.getWidth(), CvType.CV_8UC1);
            data = new byte[in.getWidth() * in.getHeight() * (int) out.elemSize()];
            int[] dataBuff = in.getRGB(0, 0, in.getWidth(), in.getHeight(), null, 0, in.getWidth());
            for (int i = 0; i < dataBuff.length; i++) {
                r = (byte) ((dataBuff[i] >> 0) & 0xFF);
                g = (byte) ((dataBuff[i] >> 8) & 0xFF);
                b = (byte) ((dataBuff[i] >> 16) & 0xFF);
                data[i] = (byte) ((0.21 * r) + (0.71 * g) + (0.07 * b));
            }
        }
        out.put(0, 0, data);
        return out;
    }

Reference: here参考: 这里

I found a solution here .我在这里找到了解决方案。 The solution is similar to Andriys.解决方案类似于 Andriys。

Camera c;
c.Connect();
c.StartCapture();
Image f2Img, cf2Img;
c.RetrieveBuffer(&f2Img);
f2Img.Convert( FlyCapture2::PIXEL_FORMAT_BGR, &cf2Img );
unsigned int rowBytes = (double)cf2Img.GetReceivedDataSize()/(double)cf2Img.GetRows();

cv::Mat opencvImg = cv::Mat( cf2Img.GetRows(), cf2Img.GetCols(), CV_8UC3, cf2Img.GetData(),rowBytes );

One simple way would be to create a new using一种简单的方法是创建一个新的使用

Mat newMat = Mat(rows, cols, type);

then get the pixel values from your BufferedImage and put into newMat using然后从您的 BufferedImage 获取像素值并使用

newMat.put(row, col, pixel);

To convert from BufferedImage to Mat I use the method below:要将 BufferedImage 转换为 Mat 我使用以下方法:

    public static Mat img2Mat(BufferedImage image) {
        image = convertTo3ByteBGRType(image);
        byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
        mat.put(0, 0, data);
        return mat;
    }

Before converting into Mat, I change the type of bufferedImage to TYPE_3BYTE_BGR, because to some types BufferedImages the method ((DataBufferByte) image.getRaster().getDataBuffer()).getData();在转换为 Mat 之前,我将 bufferedImage 的类型更改为 TYPE_3BYTE_BGR,因为对于某些类型的 BufferedImages 方法((DataBufferByte) image.getRaster().getDataBuffer()).getData(); may return int[] and that would break the code.可能会返回int[]并且会破坏代码。

Below is the method for converting to TYPE_3BYTE_BGR.下面是转换为 TYPE_3BYTE_BGR 的方法。

    private static BufferedImage convertTo3ByteBGRType(BufferedImage image) {
        BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(),
                BufferedImage.TYPE_3BYTE_BGR);
        convertedImage.getGraphics().drawImage(image, 0, 0, null);
        return convertedImage;
    }

When you use as JavaCP wrapper bytedeco library (version 1.5.3) then you can use Java2DFrameUtils .当您使用 JavaCP 包装器bytedeco 库(版本 1.5.3)时,您可以使用Java2DFrameUtils

Simple usage is:简单的用法是:

import org.bytedeco.javacv.Java2DFrameUtils;
...
BufferedImage img = ImageIO.read(new File("some/image.jpg");
Mat mat = Java2DFrameUtils.toMat(img);

Note: don't mix different wrappers, bytedeco Mat is different than opencv Mat.注意:不要混合不同的包装器, bytedeco Mat 与opencv Mat 不同。

You can do it in OpenCV as follows:您可以在 OpenCV 中执行如下操作:

File f4 = new File("aa.png");
Mat mat = Highgui.imread(f4.getAbsolutePath());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM