从全景 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;
}
是否有一些非常简单和基本的代码来预览 HDR 图像(比如获取 2D BufferedImage
输出或其他)?
我正在使用 this HDR 图像。
我尝试了 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
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;
}