从全景 HDR 创建简单的 2D 图像预览

Create simple 2D image preview from panoramic HDR

是否有一些非常简单和基本的代码来预览 HDR 图像(比如获取 2D BufferedImage 输出或其他)?

我正在使用 this HDR 图像。

我尝试了 (it uses TwelveMonkeys),但完全没有成功(只是 stuck/frozen 在 ImageReader reader = readers.next();

我像这样对它进行了一些编辑以满足我的需要,测试它在哪里损坏/stuck/frozen...它总是在测试 1 之后发生,即从未达到测试 2,没有 IllegalArgumentException 被抛出 - 如果我删除 if() 部分,则永远不会达到 TEST 3(我使用的是 NetBeansIDE v12.4,Win7 x64):

public BufferedImage hdrToBufferedImage(File hdrFile) throws IOException {
    BufferedImage bi = null;

    // Create input stream
    // I WROTE DOWN THE STRING FOR THIS EXAMPLE, normally it is taken from the hdrFile
    // HDR image size is 23.7MB if it matters at all?
    ImageInputStream input = ImageIO.createImageInputStream(new File("Z:/HDR/spiaggia_di_mondello_4k.hdr"));

    try {
        // Get the reader
        Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
        System.err.println("=====>>> TEST 1");

        if (!readers.hasNext()) {
            throw new IllegalArgumentException("No reader for: " + hdrFile);
        }
        System.err.println("=====>>> TEST 2");

        ImageReader reader = readers.next();
        System.err.println("=====>>> TEST 3");

        try {
            reader.setInput(input);

            // Disable default tone mapping
            HDRImageReadParam param = (HDRImageReadParam) reader.getDefaultReadParam();
            param.setToneMapper(new NullToneMapper());

            // Read the image, using settings from param
            bi = reader.read(0, param);
        } finally {
            // Dispose reader in finally block to avoid memory leaks
            reader.dispose();
        }
    } finally {
        // Close stream in finally block to avoid resource leaks
        input.close();
    }

    // Get float data
    float[] rgb = ((DataBufferFloat) bi.getRaster().getDataBuffer()).getData();

    // Convert the image to something easily displayable
    BufferedImage converted = new ColorConvertOp(null).filter(bi, new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_RGB));

    return converted;
}

好吧,如果你不介意某些颜色偶尔出现极端的致幻过度饱和(我无法解决这个问题 - 如果有人知道如何解决,请随时更新我的​​代码),你可以试试这个(它使用 JavaHDR)+ 我还添加了一点亮度和对比度,因为我测试的所有 HDR 对于预览来说都太暗了,所以如果你不喜欢它,你可以从代码中删除那部分:

public int rgbToInteger(int r, int g, int b) {
    int rgb = r;
    rgb = (rgb << 8) + g;
    rgb = (rgb << 8) + b;
    return rgb;
}

public BufferedImage hdrToBufferedImage(File hdrFile) throws IOException {
    HDRImage hdr = HDREncoder.readHDR(hdrFile, true);
    int width = hdr.getWidth();
    int height = hdr.getHeight();
    BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
            int r = (int) (hdr.getPixelValue(x, y, 0) * 255);
            int g = (int) (hdr.getPixelValue(x, y, 1) * 255);
            int b = (int) (hdr.getPixelValue(x, y, 2) * 255);
            bi.setRGB(x, y, rgbToInteger(r, g, b));
        }
    }

    //***** YOU CAN REMOVE THIS SMALL SECTION IF YOU FEEL THE IMAGE IS TOO BRIGHT FOR YOU
    float brightness = 2f;
    float contrast = 20f;
    RescaleOp rescaleOp = new RescaleOp(brightness, contrast, null);
    rescaleOp.filter(bi, bi);
    //***** 

    return bi;
}

我可以在我的两台 macOS 机器上毫无问题地编译和 运行 你发布的代码(明显改变路径),测试所有 LTS Java 版本(8、11 和 17) .此外,我 运行 代码与此类似,作为我项目 CI/CD 管道的一部分,该管道也在 Windows 和 Linux 上进行测试。我认为您计算机上 IDE 或 Java 的设置有问题。我无法重现您描述的“冻结”情况...

这是 运行 程序的输出(我还打印了结果 BufferedImage 以供验证):

=====>>> TEST 1
=====>>> TEST 2
=====>>> TEST 3
image = BufferedImage@5a42bbf4: type = 1 DirectColorModel: rmask=ff0000 gmask=ff00 bmask=ff amask=0 IntegerInterleavedRaster: width = 1024 height = 512 #Bands = 3 xOff = 0 yOff = 0 dataOffset[0] 0

运行 代码 as-is(带有 NullToneMapper 而没有 post-processing),由于未标准化的值,图像看起来像这样:

运行 default/built-in 色调映射器,或者按照评论中的建议简单地使用 ImageIO.read(hdrFile) 读取图像,图像将如下所示:

最后,使用自定义全局色调映射器对代码进行一些尝试; param.setToneMapper(new DefaultToneMapper(0.75f)),我得到这样的结果:

在与@HaraldK 和他的代码添加进行了长时间的讨论之后,我发布了这个问题的最终正确代码,实际上是 @qraqatit 的混合更新了 @HaraldK 的添加纠正错误的色调映射,这里是:

public int rgbToInteger(int r, int g, int b) {
    int rgb = r;
    rgb = (rgb << 8) + g;
    rgb = (rgb << 8) + b;
    return rgb;
}

public BufferedImage hdrToBufferedImage(File hdrFile) throws IOException {
    HDRImage hdr = HDREncoder.readHDR(hdrFile, true);
    int width = hdr.getWidth();
    int height = hdr.getHeight();
    BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    float colorToneCorrection = 0.75f;
    for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
            float r = hdr.getPixelValue(x, y, 0);
            int red = (int) ((r / (colorToneCorrection + r)) * 255);
            float g = hdr.getPixelValue(x, y, 1);
            int green = (int) ((g / (colorToneCorrection + g)) * 255);
            float b = hdr.getPixelValue(x, y, 2);
            int blue = (int) (int) ((b / (colorToneCorrection + b)) * 255);
            bi.setRGB(x, y, rgbToInteger(red, green, blue));
        }
    }

    //MAKE THE RESULTING IMAGE A BIT BRIGHTER
    float brightness = 1.35f;
    float contrast = 0f;
    RescaleOp rescaleOp = new RescaleOp(brightness, contrast, null);
    rescaleOp.filter(bi, bi);

    return bi;
}