Conversión de BufferedImage a Mat en opencv


¿Cómo puedo convertir un BufferedImage a un Mat en OpenCV? Estoy usando el java wrapper para OpenCV (no JavaCV). Como soy nuevo en OpenCV tengo algunos problemas para entender cómo funciona Mat.

Quiero hacer algo como esto. (Basado en Ted W. reply):

          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);

Esto no funciona. "Lena_copy.png " es solo una imagen negra con las dimensiones correctas.

Author: Jompa234, 2013-02-19

7 answers

También estaba tratando de hacer lo mismo, debido a la necesidad de combinar la imagen procesada con dos bibliotecas. Y lo que he intentado hacer es poner byte[] en Mat en lugar del valor RGB. ¡Y funcionó! Así que lo que hice fue:

1.Convertido BufferedImage a matriz de bytes con:

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

2. A continuación, simplemente puede ponerlo en Mat si establece type en CV_8UC3

image_final.put(0, 0, pixels);

Editar: También puedes intentar hacer lo contrario como en esta respuesta

 23
Author: andriy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-05 10:12:15

Este funcionó bien para mí, y se necesita de 0 a 1 ms para ser realizado.

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;
}
 17
Author: Jorge Mardones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-15 15:39:49

¿No quieres lidiar con una gran matriz de píxeles? Simplemente use este

Imagen en búfer a 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 a 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()));
}

Nota, Aunque es muy insignificante. Sin embargo, de esta manera, puede obtener una solución confiable, pero utiliza codificación + decodificación. Así que pierdes algo de rendimiento. Generalmente es de 10 a 20 milisegundos. JPG la codificación pierde algo de calidad de imagen y también es lenta (puede tomar de 10 a 20 ms). BMP es sin pérdidas y rápido (1 o 2 ms) pero requiere poco más de memoria (insignificante). PNG es sin pérdidas pero un poco más de tiempo para codificar que BMP. Usar BMP debería encajar en la mayoría de los casos, creo.

 12
Author: Ultraviolet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-09 10:39:06

Encontré una solución aquí. La solución es similar a 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 );
 3
Author: Jompa234,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-11 12:56:22

Una forma sencilla sería crear un nuevo usando

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

Luego obtenga los valores de píxeles de su BufferedImage y colóquelos en newMat usando

newMat.put(row, col, pixel);
 1
Author: Ted W.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-19 13:55:11

Utilizo el siguiente código en mi programa.

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;
    }

Referencia: aquí

 1
Author: Karthik N G,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-03 16:15:34

Puede hacerlo en OpenCV de la siguiente manera:

File f4 = new File("aa.png");
Mat mat = Highgui.imread(f4.getAbsolutePath());
 -6
Author: Ishan Randeniya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-20 19:08:03