我需要在java中进行一些图像处理。我正在移植python代码,它使用带有cols,rows,channels维度的numpy数组;这些都是浮点数。我知道如何从BufferedImage中获取RGB以及如何将其放回去;这个问题是关于如何布置生成的浮动图像。
以下是一些选项:
float[][][] img = new float[cols][rows][channels];
float[][][] img = new float[channels][cols][rows];
float[] img = new float[rows*cols*channels];
img[ i * cols * channels + j * channels + k ] = ...;
选项1的优点是它与原始代码的读取相同;但对Java而言似乎并非惯用,可能并不快。
如果我理解Java N维数组如何工作,那么选项2应该更快;以看起来有些奇怪为代价。这似乎分配channels*cols
大小为rows
的数组,而不是选项1,它分配rows*cols
大小为channels
的数组(非常大量的微小数组=大开销)
选项3似乎最接近AWT和其他Java代码所做的事情;但它需要绕过维度(它们没有内置到数组中)并且很容易使索引编写错误(特别是在进行其他索引算法时)。
哪个更好,为什么?其他一些优点和缺点是什么?还有更好的方法吗?
更新
我对选项1和2进行了基准测试,这是一个非常重要的图像处理示例,它运行四种不同的算法(在10x循环中,因此VM可以预热)。这是在Ubuntu,Intel i5 cpu上的OpenJDK 7上。令人惊讶的是,没有太多的速度差异:选项2比选项1慢约6%。垃圾收集的内存量存在很大差异(使用java -verbose:gc
):选项1在整个运行期间收集1.32 GB的内存,而选项2仅收集0.87 GB(不是一半,但是并非所有使用的图像都是彩色)。我想知道Dalvik会有多大差异?
答案 0 :(得分:1)
你是对的,选项3的内存占用量更小。
至于哪个表现更好,您必须对选项进行分析和/或基准测试。
鉴于你的声明行和列数很大,我会选择选项3,但将数组包装在一个知道维度的类中,例如:叫Image
。
答案 1 :(得分:1)
选项3由Java中的BufferedImage使用。安德烈亚斯说,它对记忆有益,但对于图像处理和信息连续性而言,它并不是最佳的。 最实际的是:
float[][] img = new float[channels][cols*rows];
这样,通道是分开的,因此可以独立处理。如果您想调用本机代码,这种表示将是最佳的。
答案 2 :(得分:1)
BoofCV具有浮动图像类型,原始像素数据可以直接操作。请参阅tutorial。
BoofCV提供了几个例程,用于将BufferedImage快速转换为不同的BoofCV图像类型。使用BoofCV例程转换为BufferedImages或从BufferedImages转换非常快。
使用BoofCV将BufferedImage转换为多光谱浮点型图像:
MultiSpectral<ImageFloat32> image =
ConvertBufferedImage.convertFromMulti(image,null,true,ImageFloat32.class);
从浮动图像数组中访问像素值:
float value = image.getBand(i).data[ image.startIndex + y*image.stride + x];
另一种获取和设置像素值的方法:
float f = image.getBand(i).get(x, y);
...
image.getBand(i).set(x, y, f);
i 表示颜色通道的索引。
将BoofCV图像转换回BufferedImage:
BufferedImage bufferedImage =
new BufferedImage(image.width, image.height, BufferedImage.TYPE_4BYTE_ABGR);
BufferedImage bufferedImage = ConvertBufferedImage.convertTo(
image, bufferedImage, true);