use*_*954 56 java bufferedimage image image-processing
我有10,000张照片需要调整大小,所以我有一个Java程序来做.不幸的是,图像的质量很差,我无法访问未压缩的图像.
import java.awt.Graphics;
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
/**
* This class will resize all the images in a given folder
* @author
*
*/
public class JavaImageResizer {
public static void main(String[] args) throws IOException {
File folder = new File("/Users/me/Desktop/images/");
File[] listOfFiles = folder.listFiles();
System.out.println("Total No of Files:"+listOfFiles.length);
BufferedImage img = null;
BufferedImage tempPNG = null;
BufferedImage tempJPG = null;
File newFilePNG = null;
File newFileJPG = null;
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
System.out.println("File " + listOfFiles[i].getName());
img = ImageIO.read(new File("/Users/me/Desktop/images/"+listOfFiles[i].getName()));
tempJPG = resizeImage(img, img.getWidth(), img.getHeight());
newFileJPG = new File("/Users/me/Desktop/images/"+listOfFiles[i].getName()+"_New");
ImageIO.write(tempJPG, "jpg", newFileJPG);
}
}
System.out.println("DONE");
}
/**
* This function resize the image file and returns the BufferedImage object that can be saved to file system.
*/
public static BufferedImage resizeImage(final Image image, int width, int height) {
int targetw = 0;
int targeth = 75;
if (width > height)targetw = 112;
else targetw = 50;
do {
if (width > targetw) {
width /= 2;
if (width < targetw) width = targetw;
}
if (height > targeth) {
height /= 2;
if (height < targeth) height = targeth;
}
} while (width != targetw || height != targeth);
final BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
final Graphics2D graphics2D = bufferedImage.createGraphics();
graphics2D.setComposite(AlphaComposite.Src);
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.drawImage(image, 0, 0, width, height, null);
graphics2D.dispose();
return bufferedImage;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用的图像是这样的:

这是我在Microsoft Paint中完成的手动调整大小:

这是我的程序[bilinear]的输出:

更新:使用没有显着差异BICUBIC
这是我的程序[bicubic]的输出:

反正是为了提高程序输出的质量,所以我不必手动调整所有照片的大小?
先感谢您!
pat*_*ckf 66
不幸的是,Java中没有推荐的开箱即用的扩展,可以提供视觉上良好的结果.其中,以下是我推荐用于缩放的方法:
Graphics2d双三次快速和良好的结果,通常不如Lanczos3)每个方法的示例都可以在这个答案中找到.
这是96x140使用不同方法/库缩放的图像.点击图片获取完整尺寸:
Graphics2d 双立方插值Graphics2d 最近邻插值不幸的是,单个图像不足以判断缩放算法,您应该测试具有锐边的图标,带有文本的照片等.
据说有利于上升,特别是降尺度.遗憾的是,当前的JDK中没有本机实现,所以你要么自己实现它,要么像Morten Nobel的lib一样使用它.使用所述lib的一个简单示例:
ResampleOp resizeOp = new ResampleOp(dWidth, dHeight);
resizeOp.setFilter(ResampleFilters.getLanczos3Filter());
BufferedImage scaledImage = resizeOp.filter(imageToScale, null);
Run Code Online (Sandbox Code Playgroud)
lib 发布在maven-central上,遗憾的是没有提到.缺点是它通常非常慢,没有任何高度优化或硬件加速的实现.诺贝尔的实现速度比采用1/2步进渐进式缩放算法慢约8倍Graphics2d.在他的博客上阅读有关此lib的更多信息.
在Chris Campbell的博客中提到有关 Java 缩放的问题,渐进式缩放基本上是以较小的步长逐步缩放图像,直到达到最终尺寸.坎贝尔将其描述为将宽度/高度减半,直到达到目标.这产生了良好的结果并且可以与Graphics2D硬件加速一起使用,因此通常具有非常好的性能并且在大多数情况下具有可接受的结果.这样做的主要缺点是如果缩小不到一半使用Graphics2D提供相同的平庸结果,因为它只缩放一次.
这是一个关于它如何工作的简单示例:
以下库包含基于以下内容的渐进式缩放形式Graphics2d:
如果目标是每个维度的至少一半,则使用渐进双线性算法,否则它使用简单的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);
Run Code Online (Sandbox Code Playgroud)
它比一步缩放更快或更快Graphics2d,在我的基准测试中平均得分为6.9秒.
使用渐进式双三次缩放.在QUALITY设置中,它使用Campbell样式算法,每一步都将尺寸减半,同时ULTRA_QUALITY具有更精细的步长,将每个增量的尺寸减小1/7,这会产生通常更柔和的图像,但最小化仅使用1次迭代的实例.
BufferedImage scaledImage = Scalr.resize(imageToScale, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.FIT_EXACT, dWidth, dHeight, bufferedImageOpArray);
Run Code Online (Sandbox Code Playgroud)
主要缺点是表现.ULTRA_QUALITY比其他库慢得多.甚至QUALITY比Thumbnailator的实现慢一点.我的简单基准测试分别为26.2秒和11.1秒平均值.
还有针对所有基本Graphics2d(双线性,双三次和最近邻居)的渐进式缩放的实现
BufferedImage scaledImage = new MultiStepRescaleOp(dWidth, dHeight, RenderingHints.VALUE_INTERPOLATION_BILINEAR).filter(imageToScale, null);
Run Code Online (Sandbox Code Playgroud)
当前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();
Run Code Online (Sandbox Code Playgroud)
但是,无论使用什么插值或其他RenderHints方法,大多数人都对降尺度的结果非常失望.另一方面,放大似乎产生可接受的图像(最好是双三次).在以前的JDK版本(我们说90s v1.1)Image.getScaledInstance()中引入了一个带参数的良好视觉效果,SCALE_AREA_AVERAGING但是你不鼓励使用它 - 请阅读这里的完整说明.
coo*_*ird 38
Thumbnailator是一个编写的库,用于以简单的方式创建高质量的缩略图,并且对现有图像进行批量转换是其用例之一.
例如,要使用Thumbnailator调整您的示例,您应该能够使用以下代码获得类似的结果:
File folder = new File("/Users/me/Desktop/images/");
Thumbnails.of(folder.listFiles())
.size(112, 75)
.outputFormat("jpg")
.toFiles(Rename.PREFIX_DOT_THUMBNAIL);
Run Code Online (Sandbox Code Playgroud)
这将继续并获取images目录中的所有文件并继续逐个处理它们,尝试调整它们以适应112 x 75的尺寸,并且它将尝试保留原始图像的纵横比以防止"翘曲"的形象.
Thumbnailator将继续读取所有文件,无论图像类型如何(只要Java Image IO支持格式,Thumbnailator将处理它),执行调整大小操作并将缩略图输出为JPEG文件,同时添加thumbnail.到开头的文件名.
以下是如果执行上述代码,将如何在缩略图的文件名中使用原始文件名的说明.
images/fireworks.jpg -> images/thumbnail.fireworks.jpg
images/illustration.png -> images/thumbnail.illustration.png
images/mountains.jpg -> images/thumbnail.mountains.jpg
Run Code Online (Sandbox Code Playgroud)
就图像质量而言,正如Marco13的答案中所提到的,Chris Campbell在他的The Perils of Image.getScaledInstance()中描述的技术是在Thumbnailator中实现的,从而产生高质量的缩略图而无需任何复杂的处理.
以下是使用Thumbnailator调整原始问题中显示的烟花图像时生成的缩略图:

上面的图像是使用以下代码创建的:
BufferedImage thumbnail =
Thumbnails.of(new URL("http://i.stack.imgur.com/X0aPT.jpg"))
.height(75)
.asBufferedImage();
ImageIO.write(thumbnail, "png", new File("24745147.png"));
Run Code Online (Sandbox Code Playgroud)
代码显示它也可以接受URL作为输入,并且Thumbnailator也能够创建BufferedImages.
免责声明:我是Thumbnailator库的维护者.
Mar*_*o13 16
给定输入图像,评论中第一个链接中的答案方法(对Chris Campbell的称赞)会产生以下缩略图之一:

(另一个是您使用MS Paint创建的缩略图.很难将其中一个称为"更好"而不是其他...)
编辑:也是指出这一点:原始代码的主要问题是你没有真正按多个步骤缩放图像.您刚刚使用了一个奇怪的循环来"计算"目标大小.关键是您实际上是在多个步骤中执行缩放.
只是为了完整性,MVCE
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
public class ResizeQuality
{
public static void main(String[] args) throws IOException
{
BufferedImage image = ImageIO.read(new File("X0aPT.jpg"));
BufferedImage scaled = getScaledInstance(
image, 51, 75, RenderingHints.VALUE_INTERPOLATION_BILINEAR, true);
writeJPG(scaled, new FileOutputStream("X0aPT_tn.jpg"), 0.85f);
}
public static BufferedImage getScaledInstance(
BufferedImage img, int targetWidth,
int targetHeight, Object hint,
boolean higherQuality)
{
int type =
(img.getTransparency() == Transparency.OPAQUE)
? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = (BufferedImage) img;
int w, h;
if (higherQuality)
{
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
}
else
{
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do
{
if (higherQuality && w > targetWidth)
{
w /= 2;
if (w < targetWidth)
{
w = targetWidth;
}
}
if (higherQuality && h > targetHeight)
{
h /= 2;
if (h < targetHeight)
{
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
return ret;
}
public static void writeJPG(
BufferedImage bufferedImage,
OutputStream outputStream,
float quality) throws IOException
{
Iterator<ImageWriter> iterator =
ImageIO.getImageWritersByFormatName("jpg");
ImageWriter imageWriter = iterator.next();
ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
imageWriteParam.setCompressionQuality(quality);
ImageOutputStream imageOutputStream =
new MemoryCacheImageOutputStream(outputStream);
imageWriter.setOutput(imageOutputStream);
IIOImage iioimage = new IIOImage(bufferedImage, null, null);
imageWriter.write(null, iioimage, imageWriteParam);
imageOutputStream.flush();
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
经过几天的研究,我更喜欢javaxt。
使用javaxt.io.Image该类具有一个类似的构造函数:
public Image(java.awt.image.BufferedImage bufferedImage)
Run Code Online (Sandbox Code Playgroud)
因此您可以执行(another example):
javaxt.io.Image image = new javaxt.io.Image(bufferedImage);
image.setWidth(50);
image.setOutputQuality(1);
Run Code Online (Sandbox Code Playgroud)
这是输出:
我们不应忘记一个十二猴子图书馆
它包含一个非常令人印象深刻的过滤器集合。
用法示例:
BufferedImage input = ...; // Image to resample
int width, height = ...; // new width/height
BufferedImageOp resampler = new ResampleOp(width, height, ResampleOp.FILTER_LANCZOS);
BufferedImage output = resampler.filter(input, null);
Run Code Online (Sandbox Code Playgroud)
小智 5
下面是我自己的渐进式缩放实现,没有使用任何外部库。希望这有帮助。
private static BufferedImage progressiveScaling(BufferedImage before, Integer longestSideLength) {
if (before != null) {
Integer w = before.getWidth();
Integer h = before.getHeight();
Double ratio = h > w ? longestSideLength.doubleValue() / h : longestSideLength.doubleValue() / w;
//Multi Step Rescale operation
//This technique is describen in Chris Campbell’s blog The Perils of Image.getScaledInstance(). As Chris mentions, when downscaling to something less than factor 0.5, you get the best result by doing multiple downscaling with a minimum factor of 0.5 (in other words: each scaling operation should scale to maximum half the size).
while (ratio < 0.5) {
BufferedImage tmp = scale(before, 0.5);
before = tmp;
w = before.getWidth();
h = before.getHeight();
ratio = h > w ? longestSideLength.doubleValue() / h : longestSideLength.doubleValue() / w;
}
BufferedImage after = scale(before, ratio);
return after;
}
return null;
}
private static BufferedImage scale(BufferedImage imageToScale, Double ratio) {
Integer dWidth = ((Double) (imageToScale.getWidth() * ratio)).intValue();
Integer dHeight = ((Double) (imageToScale.getHeight() * ratio)).intValue();
BufferedImage scaledImage = new BufferedImage(dWidth, dHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(imageToScale, 0, 0, dWidth, dHeight, null);
graphics2D.dispose();
return scaledImage;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
65521 次 |
| 最近记录: |