不幸的是,在Java中没有建议的即用型缩放可以提供视觉上良好的结果。除其他外,以下是我推荐的缩放方法:
- Lanczos3重采样(通常在视觉上更好,但速度较慢)
- 渐进式降级(通常在视觉上不错,可能很快)
- 单步缩放以进行放大(具有
Graphics2d
双三次快速和良好的结果,通常不如Lanczos3更好)
每种方法的示例都可以在此答案中找到。
视觉比较
这是您使用不同方法/库将图像缩放到96x140
的图像。单击图像以获取完整大小:
- 莫滕·诺贝尔的lib Lanczos3
- Thumbnailator双线性渐进缩放
- Imgscalr ULTRA_QUALTY(1/7步双三次渐进缩放)
- Imgscalr质量(1/2步双三次渐进式缩放)
- Morten Nobel的lib双线性渐进缩放
-
Graphics2d
双三次插值 -
Graphics2d
最近邻插值 - Photoshop CS5双三次参考
不幸的是,单个图像不足以判断缩放算法,您应该测试带有锐利边缘的图标,带有文本的照片等。
Lanczos重采样
据说对扩大规模特别是缩小规模很有好处。不幸的是,当前的JDK中没有本机实现,因此您可以自己实现,也可以使用Morten Nobel的lib之类的库 。一个使用上述lib的简单示例:
ResampleOp resizeOp = new ResampleOp(dWidth, dHeight);
resizeOp.setFilter(ResampleFilters.getLanczos3Filter());
BufferedImage scaledImage = resizeOp.filter(imageToScale, null);
该库发布在maven-central上 ,不幸的是它没有被提及。不利之处在于,如果没有我所知道的任何高度优化或硬件加速的实现,它通常会非常缓慢。 Nobel的实现比使用Graphics2d
的1/2步渐进缩放算法慢大约8倍。 在他的博客上阅读有关此库的更多信息 。
逐步缩放
在Chris Campbell的博客中提到有关 Java 缩放的内容时,渐进缩放基本上就是以较小的步长逐步缩放图像,直到达到最终尺寸为止。坎贝尔将其描述为将宽度/高度减半直至达到目标。这样可以产生良好的结果,并且可以与可以通过硬件加速的Graphics2D
一起使用,因此通常在大多数情况下都具有非常好的性能和可接受的结果。这样做的主要缺点是,如果使用Graphics2D
缩小比例不到一半,则会产生相同的中等结果,因为它只能缩放一次。
这是一个有关其工作原理的简单示例:
以下库结合了基于Graphics2d
的渐进缩放形式:
Thumbnailator v0.4.8
如果目标至少是每个尺寸的一半,则使用渐进式双线性算法,否则使用简单的Graphics2d
双线性缩放和双三次缩放。
Resizer resizer = DefaultResizerFactory.getInstance().getResizer(
new Dimension(imageToScale.getWidth(), imageToScale.getHeight()),
new Dimension(dWidth, dHeight))
BufferedImage scaledImage = new FixedSizeThumbnailMaker(
dWidth, dHeight, false, true).resizer(resizer).make(imageToScale);
与Graphics2d
在我的基准测试中平均获得6.9秒的单步缩放速度一样快或稍快。
imgscalr v4.2
使用渐进式双三次缩放。在“ QUALITY
设置中,它使用Campbell样式算法将每一步的尺寸减半,而ULTRA_QUALITY
具有更精细的步长,将每个增量的大小减小1/7,这通常会生成较柔和的图像,但最小化了仅使用1次迭代的情况。
BufferedImage scaledImage = Scalr.resize(imageToScale, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.FIT_EXACT, dWidth, dHeight, bufferedImageOpArray);
主要缺点是性能。 ULTRA_QUALITY
比其他库慢得多。甚至QUALITY
比Thumbnailator的实现要慢一些。我的简单基准测试分别得出平均26.2秒和11.1秒的结果。
Morten Nobel的lib v0.8.6
还具有用于所有基本Graphics2d
(双线性,双三次和最近邻)的逐步缩放的实现
BufferedImage scaledImage = new MultiStepRescaleOp(dWidth, dHeight, RenderingHints.VALUE_INTERPOLATION_BILINEAR).filter(imageToScale, null);
谈谈JDK缩放方法
当前缩放图像的jdk方法将是这样的
scaledImage = new BufferedImage(dWidth, dHeight, imageType);
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(imageToScale, 0, 0, dWidth, dHeight, null);
graphics2D.dispose();
但无论使用哪种插值法或其他RenderHints
,大多数人都对缩小结果感到非常失望。另一方面,放大似乎可以产生可接受的图像(最好是双三次的)。在以前的JDK版本(我们谈论90年代v1.1)中,引入了Image.getScaledInstance()
,它使用参数SCALE_AREA_AVERAGING
可以提供良好的视觉效果,但是不鼓励您使用它- 请在此处阅读完整说明 。
0
我有10,000张照片需要调整大小,所以我有一个Java程序可以做到这一点。不幸的是,图像质量丢失得很严重,我无法访问未压缩的图像。
我正在使用的图像是这样的:
这是我在Microsoft Paint中完成的手动大小调整:
这是我的程序[bilinear]的输出:
更新:使用
BICUBIC
没有显着差异这是我的程序的输出[bicubic]:
是否有提高程序输出质量的方法,所以我不必手动调整所有照片的大小?
先感谢您!