我有13255张图片,每张240 x 240像素宽,最大的15,412字节,最小的839字节。
我正在尝试遍历文件夹,将每个文件夹添加到File []。一旦我有一个每个图像的数组,然后我将它们放在BufferedImage []中,准备好循环并绘制到由每个图像组成的更大的单个图像上。
每张图片都以
的形式命名Image x-y.png
但是,我一直以java.lang.OutOfMemoryError:Java堆空间错误结束。我不知道为什么。我已经尝试通过向Eclipse的目标末尾添加参数来更改JVM可用内存的大小。以下是我的用法:
IDE's\eclipse-jee-juno-SR2-win32-x86_64\eclipse\eclipse.exe -vmargs -Xms64m -Xmx1024m
和
IDE's\eclipse-jee-juno-SR2-win32-x86_64\eclipse\eclipse.exe -vmargs -Xms64m -Xmx4096m
两者都没有效果。我也进入了控制面板 - >程序 - > Java并改变了那里可用的内存量。
这是我写的方法:
public static void merge_images() throws IOException {
int rows = 115;
int cols = 115;
int chunks = rows * cols;
System.out.println(chunks);
int chunkWidth, chunkHeight;
int type;
// fetching image files
File[] imgFiles = new File[chunks];
int count = 0;
for (int j = 1; j <= 115; j++) {
for (int k = 1; k <= 115; k++) {
imgFiles[count] = new File("G:\\Images\\Image " + j
+ "-" + k + ".png");
count++;
}
}
System.out.println(imgFiles.length);
// creating a buffered image array from image files
BufferedImage[] buffImages = new BufferedImage[chunks];
for (int i = 0; i < chunks; i++) {
buffImages[i] = ImageIO.read(imgFiles[i]);
System.out.println(i);
}
type = buffImages[0].getType();
chunkWidth = buffImages[0].getWidth();
chunkHeight = buffImages[0].getHeight();
// Initializing the final image
BufferedImage finalImg = new BufferedImage(chunkWidth * cols,
chunkHeight * rows, type);
int num = 0;
for (int i = 0; i < rows; i++) {
for (int k = 0; k < cols; k++) {
finalImg.createGraphics().drawImage(buffImages[num], null,
chunkWidth * k, chunkHeight * i);
num++;
}
}
System.out.println("Image concatenated.....");
ImageIO.write(finalImg, "png", new File("fusions.png"));
System.out.println("Image Saved, Exiting");
}
在此处的打印行
for (int i = 0; i < chunks; i++) {
buffImages[i] = ImageIO.read(imgFiles[i]);
System.out.println(i);
}
它总是在7320点附近停止。
这是确切的控制台打印输出
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.awt.image.DataBufferByte.<init>(Unknown Source)
at java.awt.image.ComponentSampleModel.createDataBuffer(Unknown Source)
at java.awt.image.Raster.createWritableRaster(Unknown Source)
at javax.imageio.ImageTypeSpecifier.createBufferedImage(Unknown Source)
at javax.imageio.ImageReader.getDestination(Unknown Source)
at com.sun.imageio.plugins.png.PNGImageReader.readImage(Unknown Source)
at com.sun.imageio.plugins.png.PNGImageReader.read(Unknown Source)
at javax.imageio.ImageIO.read(Unknown Source)
at javax.imageio.ImageIO.read(Unknown Source)
at main.merge_images(main.java:48)
at main.main(main.java:19)
我将非常感谢任何我出错的想法。
此致
杰米
答案 0 :(得分:4)
您无需将所有块图像保留在内存中。您可以逐个阅读它们并在最终循环中绘制到最终图像,如下所示:
for (int i = 0; i < rows; i++) {
for (int k = 0; k < cols; k++) {
BufferedImage buffImage = ImageIO.read(imgFiles[num]);
finalImg.createGraphics().drawImage(buffImage, null,
chunkWidth * k, chunkHeight * i);
num++;
}
}
这将节省至少一半的内存。
答案 1 :(得分:1)
你需要增加程序的最大内存,而不是我假设不需要更多内存的最大内存。
在eclipse中有一个选项可以更改VM参数(我不知道它是因为我多年没有使用它)
您需要能够加载所有未压缩的图像。这意味着您至少需要13225 * 240 * 240 * 4个字节。这刚刚超过3 GB。如果先加载所有图像,至少需要加倍。我建议你使堆至少4 - 8 GB。
答案 2 :(得分:1)
看起来每个人都在提供更简单,资源消耗更少的解决方案。让我试试我的:
public static void merge_images() throws IOException {
int rows = 115;
int cols = 115;
System.out.println(rows * cols);
// Initializing the final image
BufferedImage finalImg = null;
for (int i = 0; i < rows; i++) {
for (int k = 0; k < cols; k++) {
BufferedImage bufferedImage = ImageIO.read(new File("G:\\Images\\Image " + i + "-" + k + ".png"));
int chunkWidth = bufferedImage.getWidth();
int chunkHeight = bufferedImage.getHeight();
if (finalImg == null) {
finalImg = new BufferedImage(chunkWidth * cols, chunkHeight * rows, bufferedImage.getType());
}
finalImg.createGraphics().drawImage(bufferedImage, null, chunkWidth * k, chunkHeight * i);
}
}
System.out.println("Image concatenated.....");
ImageIO.write(finalImg, "png", new File("fusions.png"));
System.out.println("Image Saved, Exiting");
}
答案 3 :(得分:0)
尝试使用-Xmx1024m运行JVM或使用更大的值运行JVM。该值是堆大小。
java -Xmx1024m -jar app.jar
此外,您可以在IDE中增加此值。
答案 4 :(得分:0)
正如hoaz指出的那样(非常感谢)我采取了太多步骤。我的解决方案如下:
public static void merge_images() throws IOException {
int rows = 115; // we assume the no. of rows and cols are known and each
// chunk has equal width and height
int cols = 115;
int chunks = rows * cols;
System.out.println(chunks);
// fetching image files
File[] imgFiles = new File[chunks];
int count = 0;
for (int j = 1; j <= 115; j++) {
for (int k = 1; k <= 115; k++) {
imgFiles[count] = new File("G:\\Images\\Image " + j
+ "-" + k + ".png");
count++;
}
}
// Initializing the final image
BufferedImage finalImg = new BufferedImage(240 * cols,
240 * rows, 13);
int num = 0;
for (int i = 0; i < rows; i++) {
for (int k = 0; k < cols; k++) {
BufferedImage buffImage = ImageIO.read(imgFiles[num]);
finalImg.createGraphics().drawImage(buffImage, null,
240 * k, 240 * i);
num++;
}
}
System.out.println("Image concatenated.....");
ImageIO.write(finalImg, "png", new File("fusions.png"));
System.out.println("Image Saved, Exiting");
}
基本上我所做的就是删除BufferedImage [],然后在构建最终图像时,在嵌套for循环期间创建一个新的BufferedImage。我没有使用变量,而是硬编码了图像的边界和每个图像的类型。
感谢你指出我正确的方向hoaz。
此致
杰米