web-dev-qa-db-ja.com

opencvでBufferedImageをMatに変換する

OpenCVでBufferedImageをマットに変換するにはどうすればよいですか? OpenCV(JavaCVではなく)のJavaラッパー)を使用しています。OpenCVを初めて使用するとき、Matの動作を理解するのに問題があります。

このようなことをしたいです。 (テッド・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);

これは機能しません。 「Lena_copy.png」は、正しいサイズの単なる黒い画像です。

28
Jompa234

2つのライブラリで処理された画像を組み合わせる必要があるため、同じことをしようとしていました。そして、私がやろうとしたことは、byte[] in RGB値の代わりにMatに。そしてそれはうまくいきました!だから私がやったことは:

1. BufferedImageをバイト配列に変換:

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

2.次に、タイプをCV_8UC3に設定すると、単純にMatに配置できます

image_final.put(0, 0, pixels);

Edit:また、 this answer のように逆を行うこともできます

25
andriy

これは私にとっては問題なく機能し、実行するには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;
}
18
Jorge Mardones

大きなピクセル配列を扱いたくないですか?単にこれを使用する

マットにバッファリングされた画像

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

、それはごくわずかですが。ただし、この方法では、信頼できるソリューションを得ることができますが、エンコード+デコードを使用します。そのため、パフォーマンスが低下します。通常は10〜20ミリ秒です。 [〜#〜] jpg [〜#〜]エンコードは画質をいくらか低下させますが、速度も遅くなります(10〜20msかかります)。 [〜#〜] bmp [〜#〜]はロスレスで高速(1または2ミリ秒)ですが、メモリをほとんど必要としません(無視できます)。 [〜#〜] png [〜#〜]はロスレスですが、BMPよりもエンコードに少し時間がかかります。 [〜#〜] bmp [〜#〜]を使用すると、ほとんどの場合に当てはまるはずです。

14
Ultraviolet

私は解決策を見つけました こちら 。ソリューションは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
Jompa234

私は自分のプログラムで次のコードを使用します。

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

参照: here

2
Karthik N G

1つの簡単な方法は、新しい

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

次に、BufferedImageからピクセル値を取得し、newMatに入れます

newMat.put(row, col, pixel);
1
Ted W.