【问题标题】:diff/patch for images图像的差异/补丁
【发布时间】:2011-09-30 15:05:40
【问题描述】:

我正在编写一个项目,我需要通过网络传输一组相似的图像。为了加快速度,我考虑做大多数电影编解码器所做的事情。拥有关键帧,然后发送更改。

现在,我得到的是一组BufferedImages,所以类似于文本文件,我基本上只想区分它们并发送补丁。 但是,我以前从未真正使用过图像,所以如果我这样做,那将是相当糟糕的。

那么,实现这样的事情的最佳方式是什么,或者已经有这样的事情的良好实现?

我想将图像存储在一个字节数组中并二进制比较它们不会很有效。

编辑:我需要流式传输这些图像。 Edit2:与其说是实现的细节,不如说是:算法最有效的想法是什么。就像只使​​用 5px 块而不忽略 px,如果它的变化很小,眼睛不会注意到(我可以忍受一些质量损失)

【问题讨论】:

  • 也许您可以让现有的压缩算法为您完成工作,方法是将图像打包成一个大图像(并以任何常见格式压缩),或压缩成一个 zip(或类似的)存档。
  • 如果我需要流式传输它们,这不是一个选项。
  • 我们在谈论什么样的流媒体?
  • 从您的问题中删除脏话。这里不欢迎。
  • @Damokles 好吧,当我知道发生了什么变化时,我已经发送了关键帧

标签: java image diff binary-diff


【解决方案1】:

一种简单的方法是对两个图像执行等效的异或运算。这将显示相​​同的像素(将为零)和已更改的像素(非零)。

如果您不关心几乎难以察觉的差异,那么或者,使用“减法”混合然后右移以丢弃一到两位差异。

然后您可以计算边界(可能是一个简单的矩形)并仅传输增量。增量可能包含大量零或最多包含少量最右边差异位的字节 - 即,它将具有低“熵”,这意味着它理论上应该可以使用当代压缩算法进行高度压缩。

在接收端,相反的过程同样简单。给定增量和边界框,解压缩增量,然后将其应用(异或,或左移然后相加)到上一个/现有图像的受影响区域。

如需更复杂、无损的方法,请查看动画 GIF/PNG 的动画效果以及用于计算/编码帧之间的增量信息的算法。例如,请参阅What's the best way to make an animated GIF using an algorithm?

对于更复杂的方法,在处理真实世界的图像时,如果您愿意走有损路线,那么您已经暗示过了。查看视频编解码器如何编码/传输帧,例如MPEG Video Encoding

不言而喻,由于在(编码/解码过程的)复杂性和传输数据大小的减少之间存在权衡,因此您必须决定在任一端增加的计算开销是否值得节省传输费用。

【讨论】:

    【解决方案2】:

    您可以使用getRGB(int x, int y) 遍历 BufferedImage 的所有像素。

    for (int x = 0; x < img.getWidth(); ++x)
    {
        for (int y = 0; y < img.getHeight(); ++y)
        {
            int oldARGB = oldImg.getRGB(x, y);
            int newARGB = img.getRGB(x, y);
            if (oldARGB != newARGB)
            {
                // handle the diffrence
            }
        }
    
    }
    

    【讨论】:

    • handle the diffrence 我认为这才是真正有趣的部分。您需要能够以高效的方式传递差异。
    • 谢谢,但我的问题更多是关于一个好的算法应该是什么样子的。我的意思是我可以忍受一些质量损失。因此,如果 alpha 值改变了 1,我不需要更新像素。这样做最好的方法是什么,比如使用 5x5px 块或其他什么,是的,处理差异是我真正关心的。
    • 您可以创建一个新的 BufferedImage(增量),最初所有像素 100% 透明(或其他一些固定值),然后将所有更改的像素复制到该图像。将其以 PNG 格式发送,并遍历接收端的所有像素,将不透明的像素复制过来。
    • "如果 alpha 值改变了 1,我不需要更新像素。"您可以通过在客户端看到图像时保留图像的服务器端副本来相当有效地处理此问题,并且仅在参考和实际之间的 RGB 差异超过某个阈值时才包含更改的像素,这是一种快乐盒的方法。
    【解决方案3】:

    我有一个想法,其实这很简单。逐个比较像素

    如果像素相等,则保存为 RGBA(0, 0, 0, 0)。然后将差异存储为 PNG。

    这是演示结果。差异非常小。

    stackoverflow 说you need at least 10 reputation to post images。所以我只能在这里发布图片地址。

    http://oi61.tinypic.com/2vs5ifl.jpg

    【讨论】:

      【解决方案4】:

      根据您要投入的工作量,我会建议一个相当简单的解决方案,将这些图像保存为位图并让 7z 压缩它们。然后发送存档。

      【讨论】:

      • 是的,不幸的是,这不是我要找的东西,我真的需要“区分”它们,因为它需要快速。
      【解决方案5】:

      如果您不介意画质有所下降,并且想要在带宽方面真正有效的解决方案,而无需进行大量手动工作,您也可以使用真正的电影编解码器对图像进行编码。特别是你有一个 GPU 来卸载计算,这种方法在计算工作量方面也非常有效。

      【讨论】:

        【解决方案6】:

        您最好将时间花在开发应用程序上,然后在出现问题时评估性能改进。我猜这整件事都会是 YAGNI。

        为了加快速度,我想过做...

        这不是一个要求,只是一个“如果……会不会很酷”。以今天的网络速度,传输几百兆也可以在不到一分钟的时间内完成。

        【讨论】:

        • 我有 2 MBps 的上游。如果糟糕的互联网需要如此复杂的代码,那么简单的解决方案可能是获得更好的互联网包?对不起,如果这个答案不是你想听到的,我只是想提供一个不同的观点。
        猜你喜欢
        • 1970-01-01
        • 2013-04-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多