3

我有 13255 张图像,每张 240 x 240 像素宽,最大的 15,412 字节,最小的 839 字节。

我正在尝试遍历将它们中的每一个添加到文件 [] 的文件夹。一旦我有了每个图像的数组,我就将它们放在一个 BufferedImage[] 中,准备循环并绘制到由每个单独的图像组成的更大的单个图像上。

每个图像都以以下形式命名

图像 xy.png

但是,我一直以 java.lang.OutOfMemoryError: Java heap space 错误告终。我不知道为什么。我尝试通过在 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)

任何我出错的想法将不胜感激。

问候,

杰米

4

5 回答 5

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++;
    }
}

这将节省至少一半的内存。

于 2013-05-15T21:05:42.000 回答
1

您需要增加程序的最大内存,而不是我假设不需要更多内存的 eclipse 的最大值。

eclipse中有一个用于更改VM参数的选项(我不知道这是因为我已经很多年没有使用它了)

同样,您需要能够加载所有未压缩的图像。这意味着您至少需要 13225 * 240 * 240 * 4 个字节。这刚刚超过 3 GB。如果您首先加载所有图像,则至少需要加倍。我建议您将堆至少设置为 4 - 8 GB。

于 2013-05-15T21:02:52.160 回答
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");
}
于 2013-05-15T21:54:59.207 回答
0

尝试使用 -Xmx1024m 或更大的值运行 JVM。该值是堆大小。

java -Xmx1024m -jar app.jar

此外,您可以在 IDE 中增加此值。

于 2013-05-15T21:03:17.803 回答
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。

问候

杰米

于 2013-05-15T21:33:41.860 回答