【发布时间】:2016-01-28 23:06:30
【问题描述】:
我正在尝试将 BufferedImage 转换为 Mat 以获取从 Internet 下载的具有不同文件类型的大量图像。因为我是从网站上抓取图像,所以我无法控制文件格式。我可以在不知道格式的情况下轻松地将它们加载到BufferedImage,但是要将它们转换为Mat,我需要知道图像类型。不幸的是,CvType 和 BufferedImage 类型之间似乎没有很好的对应关系。
CvType 表示格式为CV_<bit-depth>{U|S|F}C<number_of_channels> 的图像类型,其中U 是无符号字符,S 是有符号字符,F 是浮点数。
BufferedImage 类型的表示形式更加多样,包括对称通道 (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);
问题
- 我这样做正确吗?还是有更好的方法?
- 默认情况下的类型的正确对应关系是什么?
示例
转换为 Mat 后输出 PNG。 BufferedImage 类型被TYPE_BYTE_INDEXED 转换为CvType.CV_8SC3
转换为 Mat 后输出 PNG。 BufferedImage 类型被TYPE_BYTE_INDEXED 转换为CvType.CV_8UC3
资源:
我的起始代码来自 Converting BufferedImage to Mat in opencv 。
我对 CvTypes 的了解来自 What's the difference between cvtype values in OPENCV?。
【问题讨论】:
-
TYPE_INT 应该映射到 CV_32S,而不是 CV_8S。然后 TYPE_BYTE_BINARY 到 CV_8UC1,TYPE_USHORT_GRAY 到 CV_16UC1,TYPE_4BYTE_ABGR 到 CV_8UC4。并默认使用 CV_8UC3
-
@Miki 我最初对 int 类型也有同样的想法,但后来被文档弄糊涂了,上面写着“表示具有 8 位 RGB 颜色分量打包成整数像素的图像”。澄清一下,颜色只需要 8 位,但它们存储为 32 位?
-
打包成整数像素,所以你需要CV_32S。我不知道 BufferedImage,但我认为您可以将所有缓冲图像转换为 RGB。然后你可以转换为 opencv 就好像类型是 TYPE_3BYTE_BGR
-
@Miki 谢谢,我认为你的 cmets 会是一个很好的答案。
-
请注意,
TYPE_CUSTOM不是单一类型,它用于表示不是其他类型之一的所有内容。您可能可以为所有已知类型创建一个直接转换,然后使用getRGB到CV_8UC4或CV_32U的回退(我不认为任何JavaTYPE_INT_xxx应该被视为已签名)这将是速度较慢,但仍完全兼容。