我正在使用Java项目,它需要非常高级的图像操作。实际上,我使用OpenCV完成了大部分操作,并且使用JNI包装了我需要的OpenCV函数。我对OpenCV提供的性能非常满意,编写OpenCV代码的人应该为代码赢得极大的赞誉。这与我在Java开发人员编写的代码中的体验形成了鲜明对比。
我一开始对我的编程语言的选择持乐观态度,我的第一次工作迭代工作得很好,但它的性能远远谈不上实时(大约每2秒获得1帧)。我对我的代码做了一些优化,这对我有很大的帮助。我已经能够将帧速率提高到大约每秒10-20帧,这很好,但我发现要做进一步的优化,我必须重写Java代码来做同样的事情,但效率提高了10-20倍。
Java的开发人员很少关注性能,特别是在为Media相关的类编写类时,我对此感到震惊。我已经下载了OpenJDK,并且正在探索我正在使用的函数。例如,在栅格类下有一个名为getPixels(...)的函数它会得到图像的像素。我期望这个函数在源代码中是一个高度优化的函数,并对System.arrayCopy进行多次调用以进一步优化性能。相反,我发现的是非常“经典”的代码,他们调用5-6个不同的类和10-20个不同的方法,只是为了在一行中完成我能做的事情:
for (int i =0; i < n; i++) {
long p = rawFrame[i];
p = (p << 32) >>> 32;
byte red = (byte) ((p >> 16) & 0xff);
byte green = (byte) ((p >> 8) & 0xff);
byte blue = (byte) ((p) & 0xff);
byte val = (byte)(0.212671f * red + 0.715160f * green + 0.072169f * blue);
data[i] = val;
grayFrameData[i] = (val & 0x80) + (val & (0x7f));
}上面的代码将图像转换为灰度,并在大约1-10ms内获得浮点像素数据。如果我想用Java内置函数做同样的事情,转换成灰度本身需要200-300ms,然后抓取浮点像素需要大约50-100ms。这对于实时性能来说是不可接受的。注为了获得加速,我大量使用了按位运算符,而Java开发人员则避免使用这些运算符。
我理解他们需要处理一般情况,但即便如此,他们至少不能给出优化的选项,或者至少警告这段代码可能执行得有多慢。
我的问题是,在开发的后期(我已经有了第一次迭代,而不是我正在进行第二次更实时的迭代),我是应该咬紧牙关切换到C/C++,在那里我可以对事情进行更多的微调,还是应该坚持使用Java,希望事情会变得更加实时友好,这样我就不需要重写已经实现的Java代码来获得加速。
我真的开始对Java的“优雅”和缓慢感到厌恶了。类的数量似乎有点过头了。
发布于 2009-05-22 15:38:42
我用Java做过计算机视觉的工作,我可能会因为这样说而被否决,但它对于计算机视觉和实时的东西是非常有用的,你只需要知道如何使用它。
潜在的优化:
如果您需要优化代码的帮助,我很乐意为您提供帮助--例如,我可以告诉您,通过创建一个方法,您可能会获得性能提升
`public static final int getGrayScale(final int pixelRGB){
return (0.212671f * ((pixelRGB >> 16) & 0xff) + 0.715160f * ((pixelRGB >> 8) & 0xff) + 0.072169f * ((pixelRGB) & 0xff));
}`并在您的for{像素}循环中使用它。通过使用方法调用,JVM可以更多地优化此操作,并且可能还可以更多地优化for循环。
如果要刻录RAM,则可以为所有可能的24位像素颜色创建输出灰度字节的静态最终查找表。这在RAM中大约为16MB,但这样您就不必进行任何浮点运算,只需进行一次数组访问。这可能会更快,这取决于您正在使用的JVM,以及它是否可以优化数组边界检查。
找到类似的、更快的图像处理代码的地方:
我强烈建议您查看ImageJ图像处理应用程序的代码(由于StackOverflow被延迟,无法链接)&它的库,特别是ij.process.TypeConverter。就像您的代码一样,它在很大程度上依赖于直接数组操作,只需少量的和最少的额外数组创建。Java2D库(标准JRE的一部分)和Java Advanced Imaging(JAI)库(由于StackOverflow被延迟而不能链接)提供了其他方法来快速地直接对图像数据进行图像处理,而不必每次都执行自己的操作。对于Java2D,您只需小心使用哪些函数即可。
为什么Java2D库如此间接:
大多数“类”是由于支持多种颜色模型和存储格式(即HSB图像、基于浮点的颜色模型、索引颜色模型)。这种间接性的存在是有原因的,有时实际上会提高性能--在最近的VM中,BufferedImage类(例如)直接挂接到图形内存中,以使某些操作速度更快。间接性让它在很多时候对用户屏蔽了这一点。
发布于 2009-05-21 23:25:27
我的问题是,在开发的后期(我已经有了第一个迭代,而不是我正在进行第二个实时执行的迭代),我是应该咬紧牙关切换到C/C++,在那里我可以对事情进行更多的微调,还是应该坚持使用Java语言,希望事情会变得更加实时友好,这样我就不需要重写已经实现的Java代码来获得加速。
你在问我该不该
切换到一种语言,在这种语言中,我可以使用
可能还有其他选择...但是选项2看起来并不现实,你不能仅仅“希望”代码变得更快:p
有几点需要注意:
可能是值得的
发布于 2009-05-21 23:19:57
我的建议是,这取决于图像操作与整个项目相比有多重要,以及相对于java带来的任何好处。显然,如果需要,您可以用java编写快速代码(正如您所演示的那样)。但是,如果您的项目的80%将包含这样的优化,我肯定会重新考虑将Java作为这里的语言选择。
另一方面,如果这代表了应用程序的20%,另外80%是提供这种转换的用户功能,那么可能不得不做一些工作来完成操作,而不必处理自己的内存管理,并拥有java为用户交互提供的任何其他API (Web、Swing、SWT,无论您正在使用什么)。
由于垃圾收集器的存在,Java的实时能力并不为人所知。这也可能会咬到你,所以要小心。
https://stackoverflow.com/questions/895725
复制相似问题