【问题标题】:Undo/Redoing adjustments to whole image (Android)撤消/重做整个图像的调整(Android)
【发布时间】:2013-03-25 15:31:12
【问题描述】:

注意:

请多多包涵,这(恕我直言)不是关于在绘画/绘图场景中撤消的十几个问题的重复。

背景:

我一直在使用 Processing for Android 开发一个图像处理应用程序,现在我正在尝试实现一个简单的一步撤消/重做功能。

我最初(撤消友好)的想法是仅将调整应用于下采样的预览图像,保留一系列调整操作,并在保存时将它们应用于原始图像。我不得不放弃这个想法有两个原因:

  • 有些操作需要几秒钟才能完成,如果我们有一些操作,就会使本已缓慢的保存过程变得乏味地慢下来。

  • 当应用于下采样图像而不是全尺寸图像时,某些操作(例如减少彩色噪声)会产生截然不同的(错误)结果。但无论如何,这是一个不太严重的问题......

所以我决定存储之前/之后的图像。

问题:

不幸的是,由于内存限制,无法在内存中缓冲图像。所以我现在正在做的是将之前/之后的图像保存到内部存储中。

但这会造成性能/质量两难:

  • jpeg 速度很快(即在我的 Xperia Arc S 上节省约 500 毫秒),但在两/三次迭代后会降低质量,超出可接受范围。

  • png 当然是无损的,但速度非常慢(保存时间约为 7000 毫秒),因此不切实际。

  • bmp 我想可能会很快,但 android 不编码 bmp(我认为 android 的处理将“file.bmp”保存为 tiff)。

  • tiff 的性能可以接受(约 1500 毫秒保存),但 android 不解码 tiff。

  • 我还尝试使用此函数将 raw 像素数组写入文件:

    void writeData(String filename, int[] data) {
      try {
        DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(openFileOutput(filename, Context.MODE_PRIVATE)));
        for (int i = 0; i < data.length; i++) {
          dos.writeInt(data[i]);
        }
        dos.close();
      }
      catch (IOException e) {
        e.printStackTrace();
      }
    }
    

    但它需要超过 2000 毫秒才能完成,所以我现在放弃了。

问题:

  1. 是否有更快的方法来为此目的写入/读取数据?

  2. ...还是应该回到最初的想法,尽可能地解决它的问题?

  3. 还有其他建议吗?

更新:

我想出了这个写原始数据的方法:

void saveRAW2(String filename) {
  byte[] bytes = new byte[orig.pixels.length*3];
  orig.loadPixels(); //orig = my original PImage, duh!
  int index = 0;
  for (int i = 0; i < bytes.length; i++) {
    bytes[i++] = (byte)((orig.pixels[index] >> 16) & 0xff);
    bytes[i++] = (byte)((orig.pixels[index] >> 8) & 0xff);
    bytes[i] = (byte)((orig.pixels[index]) & 0xff);
    index++;
  }
  saveBytes(filename, bytes);
}

...完成时间不到 1000 毫秒。

如果我将文件写入 SD 卡,它的运行速度会快 3 倍,但我想我不能指望在每部手机上都一样。对吧?

无论如何,我正在使用这种方法将保存的数据读回 orig.pixels:

void loadRAW(String filename) {
  byte[] bytes = loadBytes(filename);
  int index = 0;
  int count = bytes.length/3;
  for (int i = 0; i<count; i++) {
    orig.pixels[i] = 
      0xFF000000 |
      (bytes[index++] & 0xff) << 16 |
      (bytes[index++] & 0xff) << 8 |
      (bytes[index++] & 0xff);
  }
  orig.updatePixels();
}

这需要大约 1500 毫秒才能完成。有什么优化的想法吗?

【问题讨论】:

  • 为什么内存是一个约束?你允许图像有多大?您是在使用平铺,还是这些幼稚的操作(即应用于整个图像)。附加说明:您使用纯 Java 作为处理应用程序的一部分,提出了一个问题,为什么您使用处理而不是使用带有处理的 Java 来处理某些绘图功能(但不是用于您的实际成像算法)
  • @Pomax,图像大约为 1600x1200,具体取决于设备(增量下采样图像直到它不抛出 OOM)。这与内存中的其他内容相结合,很容易达到旧设备的 16MB 限制。我没有使用平铺。
  • 又是@Pomax!我不是真正的程序员,只有处理经验,想尝试一下 android 的处理。渐渐地,我不得不放弃大多数处理方法,并使用纯 java 来实现我的方法……但后来我走得太深,无法从头开始没有处理。 :) 无论如何,我想如果我仍然可以通过这个实现可接受的性能,为什么不完全开发应用程序?

标签: android image-processing processing undo


【解决方案1】:

我建议找出 Android“暂存盘”区域是什么,并将您的图像处理为图块,并将它们缓存在该暂存盘上。这可能比直接使用内存要慢一些,但这意味着您可以在不遇到内存限制的情况下进行图像编辑,并且(如果 Android 的 SDK 具有合理的 API),将图块写入完整文件应该不会花费太多时间.也就是说,您已经从“处理”转移到纯 Java,所以问题不再是关于处理的问题了......我的回答可能不如熟悉 Android SDK 的人好

【讨论】:

  • 但这与我已经描述的我在上面所做的不同吗?...当然除了瓷砖。我已经设法避免在图像编辑时出现 OOM,而且我的图像不是很大。所以我想我不需要经历平铺的麻烦(我有包括模糊等的操作)。而且由于您还建议缓存到磁盘,这就是我正在做的事情,所以我也不需要更多的内存。还是我错过了什么?
  • 更具体地说,我已经在上面的“更新:”中描述了同样的事情(当然除了平铺),即缓存到内部内存/缓存文件夹(暂存盘)。你能告诉我是否有比我已经在做的更快的读取缓存文件的方法吗?
  • 我不能,我对 Android 施加的限制以及影响快速磁盘写入图像的 API 调用的了解几乎为零。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-07
  • 1970-01-01
  • 2012-06-22
  • 1970-01-01
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多