1

我试图从我的渲染管道中挤出更多的性能。(到目前为止)最慢的部分是在大图像上执行 java.awt.imaging.LookupOp。

图像大小约为 2048x2048。

我发现在绘图操作中完成过滤器比调用过滤器方法要快得多。然而,这仍然给我们留下了大约 250 毫秒(或 4 fps)的查找操作。有人有任何渲染技巧吗?

这基本上是我们正在做的事情:

public void paint(Graphics g)
{
    if(recalcLUT)
    {
        Graphics2D g2d = (Graphics2D) displayImage.getGraphics();
        g2d.drawImage(srcImage, lut, 0, 0);
    }

    Graphics2D g2d = (Graphics2D) g;
    g2d.clearRect(0, 0, this.getWidth(), this.getHeight());
    AffineTransform at = new AffineTransform();
    at.setToIdentity();
    at.scale(scale, scale);
    g2d.drawImage(displayImage, at, null);
}

lut 变量是 LookupOp 通常是 ShortLookupOp,图像是 16 位灰度图像

谢谢

瑞恩布彻:

我知道还有一些其他明显的性能优化可以在这里完成。但主要问题只是进行 LookupOp 操作,所以我正在寻找这方面的建议。

Lookup Ops 本质上是创建数组的地方,而不是将图像的每个像素渲染为其颜色,而是将颜色用作数组的索引并将颜色渲染为索引中的值。在这个特定的例子中,我用它来做一些简单的亮度/对比度操作。您也可以使用 rescaleOp 来实现这一点,这本质上是一种将线性函数应用于所有像素值的方法。但事实证明这会更慢。

4

2 回答 2

1

我已经有近八年没有使用过 java 了,所以有些语法可能无关紧要。

任何关于循环的性能的关键是将尽可能多的东西推到循环之外。如果你不能,那么只有在它们发生变化时才执行计算。通常最好等到最后一分钟再重新计算,这样您就可以缓存多个更改。

  1. 将所有对象构造移到渲染循环之外。如果您事先知道需要多少个对象,则将它们传递进去;如果您不使用对象池并让工厂在渲染循环之外创建对象。这将为您节省建造/破坏时间。

  2. 仅在比例发生变化时计算您的 AffineTransform。将其推到绘制循环之外并将其传入(作为 const 参考......它们甚至存在于 Java 中吗?我在 C++ 中已经太久了)

  3. 您可能不需要调用 at.setToIdentity() 因为您的 AffineTransform 应该默认为 Identity 矩阵(检查此)

  4. recalcLUT 是否需要每帧调用一次?执行 if 语句后将 recalcLUT 设置为 false 是否有意义?

我不确定 LookupOp 的目标是什么。如果你给我更多关于它在做什么的信息,我可能会提出更多建议。

希望这会有所帮助。

于 2008-11-07T14:38:51.243 回答
0

您是否有能力将此处理推送到 GPU 上?多个硬件管道将显着加快处理速度。

如果你不能,那么你应该考虑在 CPU 上并行化 LookupOp。据我了解,每次查找都可以单独完成。因此,您可以启动多个线程(多少取决于您的 CPU Arch 以及同时发生的其他事情)并让每个线程查找图像的一部分。在每次更新运行时,您都需要一个信号量来等待所有线程完成。

在任何一种情况下,您都应该执行以下操作来权衡没有变化的每一帧的一些内存消耗。除非您的帧速率受到限制,否则您的帧数越多,没有任何变化的机会就越大。这将节省您做不必要的工作。

//Has filter or source image changed?
//   yes, recalculate filter and cache
//   no, render cached image

最后,您是否了解 LookupOp 的实现?它在做什么,是否可以通过自己编写实现来收集任何性能增强(这应该是最后的手段)。

于 2008-11-07T15:23:39.767 回答