I want to create a script which takes a .HDR
file and tonemaps it into a .JPG
. I have looked at a few OpenCV tutorials and it seems it should be able to do this.
I have written this script:
import cv2
import numpy as np
filename = "image/gg.hdr"
im = cv2.imread(filename)
cv2.imshow('', im.astype(np.uint8))
cv2.waitKey(0)
tonemapDurand = cv2.createTonemapDurand(2.2)
ldrDurand = tonemapDurand.process(im.copy())
new_filename = filename + ".jpg"
im2_8bit = np.clip(ldrDurand * 255, 0, 255).astype('uint8')
cv2.imwrite(new_filename, ldrDurand)
cv2.imshow('', ldrDurand.astype(np.uint8))
Which according to the tutorials should work. I am getting a black image in the end though. I have verified that the result it saves is .JPG
, as well as that the input image (a 1.6 megapixel HDR envrionment map) is a valid .HDR
.
OpenCV should be able to load .HDR
s according to the documentation.
I have tried reproducing the tutorial linked and that worked correctly, so the issue is in the .HDR
image, anybody know what to do?
Thanks
EDIT: I used this HDR image. Providing a link rather than a direct download due to copyright etc.
You were almost there, except for two small mistakes.
The first mistake is using cv2.imread
to load the HDR image without specifying any flags. Unless you call it with IMREAD_ANYDEPTH
, the data will be downscaled to 8-bit and you lose all that high dynamic range.
When you do specify IMREAD_ANYDEPTH
, the image will be loaded as 32bit floating point format. This would normally have intensities in range [0.0, 1.0], but due to being HDR, the values exceed 1.0 (in this particular case they go up to about 22). This means that you won't be able to visualize it (in a useful way) by simply casting the data to np.uint8
. You could perhaps normalize it first into the nominal range, or use the scale and clip method... whatever you find appropriate. Since the early visualization is not relevant to the outcome, I'll skip it.
The second issue is trivial. You correctly scale and clip the tone-mapped image back to np.uint8
, but then you never use it.
Script
import cv2
import numpy as np
filename = "GoldenGate_2k.hdr"
im = cv2.imread(filename, cv2.IMREAD_ANYDEPTH)
tonemapDurand = cv2.createTonemapDurand(2.2)
ldrDurand = tonemapDurand.process(im)
im2_8bit = np.clip(ldrDurand * 255, 0, 255).astype('uint8')
new_filename = filename + ".jpg"
cv2.imwrite(new_filename, im2_8bit)
Output
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With