java - 如何匹配BufferedImage和Mat的颜色模型?

标签 java image opencv

我正在尝试转换 BufferedImage Mat 对于从 Internet 下载的具有不同文件类型的大量图像。因为我是从网站上抓取图片,所以我无法控制文件格式。我可以轻松地将它们加载到 BufferedImage不知道格式,但将它们转换为 Mat ,我需要知道图像类型。不幸的是,CvType 之间似乎没有很好的对应关系。和 BufferedImage类型。

CvType表示格式为 CV_<bit-depth>{U|S|F}C<number_of_channels> 的图像类型其中 U是无符号字符,S是有符号的字符,F是 float 的。

BufferedImage类型在表示上有更多变化,包括对称 channel ( TYPE_4BYTE_ABGR )、不同数量的位 ( TYPE_BYTE_BINARY ),以及任何索引字节图像 ( TYPE_BYTE_INDEXED )。

根据文档,我尝试完成自己的通信。

BufferedImage imgBuffer = ImageIO.read(new File("example.gif"));

//Save file as reference
File outputfile = new File("temp/image.png");
ImageIO.write(imgBuffer, "png", outputfile);

//My correspondance
int curCVtype = -1;
switch (imgBuffer.getType()) {
case BufferedImage.TYPE_3BYTE_BGR:
    curCVtype = CvType.CV_8UC3;
    break;
case BufferedImage.TYPE_BYTE_GRAY:
    curCVtype = CvType.CV_8UC1;
    break;
case BufferedImage.TYPE_INT_BGR:
case BufferedImage.TYPE_INT_RGB:
    curCVtype = CvType.CV_8SC3;
    break;
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
    curCVtype = CvType.CV_8SC4;
    break;
default:
//  The types not handled by my correspondence
//                  BufferedImage.TYPE_BYTE_BINARY;
//                  BufferedImage.TYPE_USHORT_GRAY;
//                  BufferedImage.TYPE_4BYTE_ABGR;
//                  BufferedImage.TYPE_4BYTE_ABGR_PRE;
//                  BufferedImage.TYPE_BYTE_INDEXED;
//                  BufferedImage.TYPE_CUSTOM;

    System.out.println("Unsupported format:" + imgBuffer.getType());
    //Here I choose a default type
    curCVtype = CvType.CV_8SC3;
}

//Convert to Mat
byte[] pixels = ((DataBufferByte) imgBuffer.getRaster().getDataBuffer()).getData();
Mat img = new Mat(imgBuffer.getHeight(), imgBuffer.getWidth(), curCVtype);
img.put(0, 0, pixels);

//Write the output to compare
Imgcodecs.imwrite("temp/image_mat.png", img);

问题

  1. 我做的正确吗?或者有更好的方法吗?
  2. 在我的默认情况下,类型的正确对应是什么?

例子

输入
Input example gif

BufferedImage 转换为 PNG
Reference BufferedImage

转换为Mat后输出PNG。 BufferedImage类型是 TYPE_BYTE_INDEXED转换为 CvType.CV_8SC3
Mat output

转换为Mat后输出PNG。 BufferedImage类型是 TYPE_BYTE_INDEXED转换为 CvType.CV_8UC3
Mat output

资源:

我的起始代码来自Converting BufferedImage to Mat in opencv .

我对 CvTypes 的了解来自 What's the difference between cvtype values in OPENCV? .

最佳答案

感谢 Miki 和 haraldK 提供的有用评论。

我针对未知图像类型的解决方案以 RGB 格式检索像素,并将它们放入 CvType.CV_8UC4Mat 中。最后,使用 Core.mixChannels 对 channel 重新排序到 OpenCV 首选顺序:BGR(A)。

此示例仅对未知图像类型的 channel 进行重新排序,但所有非 BGR 图像类型都需要重新排序。

BufferedImage imgBuffer = ImageIO.read(new File("example.gif"));

//Save image as reference
File outputfile = new File("temp/image.png");
ImageIO.write(imgBuffer, "png", outputfile);

//My correspondance

int curCVtype = CvType.CV_8UC4; //Default type
boolean supportedType = true;

switch (imgBuffer.getType()) {
case BufferedImage.TYPE_3BYTE_BGR:
    curCVtype = CvType.CV_8UC3;
    break;
case BufferedImage.TYPE_BYTE_GRAY:
case BufferedImage.TYPE_BYTE_BINARY:
    curCVtype = CvType.CV_8UC1;
    break;
case BufferedImage.TYPE_INT_BGR:
case BufferedImage.TYPE_INT_RGB:
    curCVtype = CvType.CV_32SC3;
    break;
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
    curCVtype = CvType.CV_32SC4;
    break;
case BufferedImage.TYPE_USHORT_GRAY:
    curCVtype = CvType.CV_16UC1;
    break;
case BufferedImage.TYPE_4BYTE_ABGR:
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
    curCVtype = CvType.CV_8UC4;
    break;
default:
    // BufferedImage.TYPE_BYTE_INDEXED;
    // BufferedImage.TYPE_CUSTOM;
    System.out.println("Unsupported format:" + imgBuffer.getType());
    supportedType = false;
}

//Convert to Mat
Mat img = new Mat(imgBuffer.getHeight(), imgBuffer.getWidth(), curCVtype);
if (supportedType) {
    // Insert pixel buffer directly
    byte[] pixels = ((DataBufferByte) imgBuffer.getRaster().getDataBuffer()).getData();
    img.put(0, 0, pixels);
} else {
    // Convert to RGB first
    int height = imgBuffer.getHeight();
    int width = imgBuffer.getWidth();
    int[] pixels = imgBuffer.getRGB(0, 0, width - 1, height - 1, null, 0, width);

    // Convert ints to bytes
    ByteBuffer byteBuffer = ByteBuffer.allocate(pixels.length * 4);
    IntBuffer intBuffer = byteBuffer.asIntBuffer();
    intBuffer.put(pixels);

    byte[] pixelBytes = byteBuffer.array();

    img.put(0, 0, pixelBytes);

    // Reorder the channels for Opencv BGRA format from
    // BufferedImage ARGB format
    Mat imgMix = img.clone();
    ArrayList<Mat> imgSrc = new ArrayList<Mat>();
    imgSrc.add(imgMix);

    ArrayList<Mat> imgDest = new ArrayList<Mat>();
    imgDest.add(img);

    int[] fromTo = { 0, 3, 1, 2, 2, 1, 3, 0 }; //Each pair is a channel swap
    Core.mixChannels(imgSrc, imgDest, new MatOfInt(fromTo));
}

//Save output image
Imgcodecs.imwrite("temp/image_mat.png", img);

新的输出图像
Output image

关于java - 如何匹配BufferedImage和Mat的颜色模型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33403526/

相关文章:

javascript - 无法加载使用 webpack-image-loader 动态导入并从 JSON 文件调用的图像

android:ImageView高度宽度与源图像拟合

python - 如何使用 OpenCV (Python) 捕获视频流

opencv - 如何比较二值图案图像的两个轮廓?

javascript - OpenCV.js - 检测多尺度 "This Exception cannot be caught"

java - 线形角到角

java - 从 java jtextfield 中读取 double

java - 使用 GWT ScriptInjector 加载脚本时如何设置 CacheHeaders?

java - Java 中的 SNMP,具体为 JMX 适配器

html - 如何水平对齐不同 div 中的图像