java中的图像:最有效的浮点表示?

时间:2015-08-24 08:12:53

标签: java image image-processing

我需要在java中进行一些图像处理。我正在移植python代码,它使用带有cols,rows,channels维度的numpy数组;这些都是浮点数。我知道如何从BufferedImage中获取RGB以及如何将其放回去;这个问题是关于如何布置生成的浮动图像。

以下是一些选项:

  1. 直接翻译:
  2. float[][][] img = new float[cols][rows][channels];
    
    1. 首先放置频道:
    2. float[][][] img = new float[channels][cols][rows];
      
      1. 合并索引:
      2. 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会有多大差异?

3 个答案:

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