从 HDR 图像中选择亮度(曝光)
Choose luminosity (exposure) from HDR image
我目前卡在图片视频项目上。
问题:
我正在从 UE4 中提取图片,由于错误,在屏幕截图的渲染过程中并未考虑所有灯光。
输出是 HDR 图像。我想得到更好的亮度,因为导出的图片很暗,就像第一次曝光一样。
在 UE4 中使用 "exposure bias" 参数,我能够获得真正好的场景亮度,但无法将此参数应用于屏幕截图渲染:
尝试:
使用 Tonemapper 算法(特别是 cv::TonemapDrago
)我可以获得更好的图像效果:
就我而言,色调映射算法的主要问题是因为全局亮度根据区域的亮度而改变:在第二张图像中,window 添加了大量光线,因此算法低所有光度调整均值。
渲染出来的视频中,光线的变化非常残酷。
我尝试更改 brightness 和饱和度但没有成功。
我修改了 TonemapDrago
的代码,试图对算法的某些 steps 使用常量。
问题:
我想 "choose the exposure time" 来自 HDR 图像。色调图基于同一图像的多个曝光时间,对我而言并不有趣。
欢迎任何其他想法。
编辑:
CV::Mat 深度为 5,类型为 CV_32FC3
cout << mat.step
给我19200
这是我用来尝试解决问题的 2 个示例:
编辑 2 :
无法使用 gimp 打开 .HDR 图片,使用 "explosure blend" 插件。
我能够使用 Photoshop 获得足够好的结果。知道背后的算法吗? OpenCV 的 6 种色调图算法中的任何一种都允许选择曝光校正。
编辑 3:
我已经按照 tuto 中针对 openGL 的算法解释,它为我提供了这个 C+ 代码:
cv::Mat exposureTonemap (cv::Mat m, float gamma = 2.2, float exposure = 1)
{
// Exposure tone mapping
cv::Mat exp;
cv::exp( (-m) * exposure, exp );
cv::Mat mapped = cv::Vec3f(1.0) - exp;
// Gamma correction
cv::pow(exp, 1.0f / gamma, exp);
cv::imshow("exposure tonemap", exp );
cv::waitKey();
return exp;
}
在我的 .HDR 图片上应用此算法,即使对伽马和曝光进行了 1 和 1 的校正,我也得到了非常明亮的结果:
阅读代码,有问题,因为1和1作为参数不应该修改图片。
修复了,答案已发布。非常感谢@user3896254(Ge 在评论中也看到了)
您目前使用的是哪种场景照明?看起来您在灯泡所在的地方使用了点光源,但它们不够亮。在您未渲染的场景中,场景将是全亮度的。在你渲染的场景中,你会变得黑暗。
我可能会推荐至少一个最小的天光,这样你的场景中总是有一些光(除非你有实际黑暗的区域)
考虑使用 Retinex。它使用单个图像作为输入并包含在 GIMP 中,因此很容易玩弄,此外您还可以获得它的源代码(或者自己制作,这很简单)。因为你有渲染而不是照片 - 没有噪音,理论上你可以根据需要调整颜色。
但是正如@mark-ransom 已经说过的,您可能无法从呈现的输出中恢复信息。你说你有 HDR 图像作为渲染输出,但我不确定你的意思。它是单个 RGB 图像吗?每个通道的颜色深度是多少?我已尝试将 retinex 应用于您的样本,但显然它看起来不太好,因为压缩和保存前应用的范围有限。如果您的输出具有高范围且未压缩 - 您将获得更好的结果。
编辑:我已经在你的输入上尝试了 retinex,但结果不是很好——图像的明亮部分 (lamps/windows) 在它们周围引入了丑陋的暗光晕。
在这种情况下,简单的色调映射和伽玛校正看起来好多了。你的代码几乎没问题,你只是有一点错字:
而不是 cv::pow(exp, 1.0f / gamma, exp);
你应该 v::pow(mapped, 1.0f / gamma, exp);
我弄乱了你的代码,发现这种色调映射似乎降低了色彩饱和度。为了克服这个问题,我只在 HSV 图像的 V 通道上执行它。自己比较结果(左 - 完整 space 色调映射,右 - 仅 V):
注意地板颜色、window 中的天空和通过这种方法保留的淡黄色光色。
为了完整起见,这里是完整的代码:
#include <opencv2/opencv.hpp>
using namespace cv;
Mat1f exposureTonemap (Mat1f m, float gamma = 2.2, float exposure = 1) {
// Exposure tone mapping
Mat1f exp;
cv::exp( (-m) * exposure, exp );
Mat1f mapped = 1.0f - exp;
// Gamma correction
cv::pow(mapped, 1.0f / gamma, mapped);
return mapped;
}
Mat3f hsvExposureTonemap(Mat &a) {
Mat3f hsvComb;
cvtColor(a, hsvComb, COLOR_RGB2HSV);
Mat1f hsv[3];
split(hsvComb, hsv);
hsv[2] = exposureTonemap(hsv[2], 2.2, 10);
merge(hsv, 3, hsvComb);
Mat rgb;
cvtColor(hsvComb, rgb, COLOR_HSV2RGB);
return rgb;
}
int main() {
Mat a = imread("first.HDR", -1);
Mat b = imread("withwindow.HDR", -1);
imshow("a", hsvExposureTonemap(a));
imshow("b", hsvExposureTonemap(b));
waitKey();
return 0;
}
cv::Mat exposureTonemap (cv::Mat m, float gamma = 2.2, float exposure = 1)
{
// Exposure tone mapping
cv::Mat exp;
cv::exp( (-m) * exposure, exp );
cv::Mat mapped = cv::Scalar(1.0f, 1.0f, 1.0f) - exp;
// Gamma correction
cv::pow(mapped, 1.0f / gamma, mapped);
/*
cv::imshow("exposure tonemap", mapped );
cv::waitKey();
*/
return mapped;
}
此算法是一个色调映射器,试图模拟 HDR 中的曝光偏差
如果你想在 openCv 3.0 中使用它,不要忘记用 -1 作为 imread cv::Mat img = cv::imread("mypicture.HDR", -1);
的最后一个参数打开
我目前卡在图片视频项目上。
问题:
我正在从 UE4 中提取图片,由于错误,在屏幕截图的渲染过程中并未考虑所有灯光。 输出是 HDR 图像。我想得到更好的亮度,因为导出的图片很暗,就像第一次曝光一样。
在 UE4 中使用 "exposure bias" 参数,我能够获得真正好的场景亮度,但无法将此参数应用于屏幕截图渲染:
尝试:
使用 Tonemapper 算法(特别是 cv::TonemapDrago
)我可以获得更好的图像效果:
就我而言,色调映射算法的主要问题是因为全局亮度根据区域的亮度而改变:在第二张图像中,window 添加了大量光线,因此算法低所有光度调整均值。 渲染出来的视频中,光线的变化非常残酷。
我尝试更改 brightness 和饱和度但没有成功。
我修改了 TonemapDrago
的代码,试图对算法的某些 steps 使用常量。
问题:
我想 "choose the exposure time" 来自 HDR 图像。色调图基于同一图像的多个曝光时间,对我而言并不有趣。
欢迎任何其他想法。
编辑:
CV::Mat 深度为 5,类型为 CV_32FC3
cout << mat.step
给我19200
这是我用来尝试解决问题的 2 个示例:
编辑 2 :
无法使用 gimp 打开 .HDR 图片,使用 "explosure blend" 插件。
我能够使用 Photoshop 获得足够好的结果。知道背后的算法吗? OpenCV 的 6 种色调图算法中的任何一种都允许选择曝光校正。
编辑 3:
我已经按照 tuto 中针对 openGL 的算法解释,它为我提供了这个 C+ 代码:
cv::Mat exposureTonemap (cv::Mat m, float gamma = 2.2, float exposure = 1)
{
// Exposure tone mapping
cv::Mat exp;
cv::exp( (-m) * exposure, exp );
cv::Mat mapped = cv::Vec3f(1.0) - exp;
// Gamma correction
cv::pow(exp, 1.0f / gamma, exp);
cv::imshow("exposure tonemap", exp );
cv::waitKey();
return exp;
}
在我的 .HDR 图片上应用此算法,即使对伽马和曝光进行了 1 和 1 的校正,我也得到了非常明亮的结果:
阅读代码,有问题,因为1和1作为参数不应该修改图片。 修复了,答案已发布。非常感谢@user3896254(Ge 在评论中也看到了)
您目前使用的是哪种场景照明?看起来您在灯泡所在的地方使用了点光源,但它们不够亮。在您未渲染的场景中,场景将是全亮度的。在你渲染的场景中,你会变得黑暗。
我可能会推荐至少一个最小的天光,这样你的场景中总是有一些光(除非你有实际黑暗的区域)
考虑使用 Retinex。它使用单个图像作为输入并包含在 GIMP 中,因此很容易玩弄,此外您还可以获得它的源代码(或者自己制作,这很简单)。因为你有渲染而不是照片 - 没有噪音,理论上你可以根据需要调整颜色。
但是正如@mark-ransom 已经说过的,您可能无法从呈现的输出中恢复信息。你说你有 HDR 图像作为渲染输出,但我不确定你的意思。它是单个 RGB 图像吗?每个通道的颜色深度是多少?我已尝试将 retinex 应用于您的样本,但显然它看起来不太好,因为压缩和保存前应用的范围有限。如果您的输出具有高范围且未压缩 - 您将获得更好的结果。
编辑:我已经在你的输入上尝试了 retinex,但结果不是很好——图像的明亮部分 (lamps/windows) 在它们周围引入了丑陋的暗光晕。
在这种情况下,简单的色调映射和伽玛校正看起来好多了。你的代码几乎没问题,你只是有一点错字:
而不是 cv::pow(exp, 1.0f / gamma, exp);
你应该 v::pow(mapped, 1.0f / gamma, exp);
我弄乱了你的代码,发现这种色调映射似乎降低了色彩饱和度。为了克服这个问题,我只在 HSV 图像的 V 通道上执行它。自己比较结果(左 - 完整 space 色调映射,右 - 仅 V):
为了完整起见,这里是完整的代码:
#include <opencv2/opencv.hpp>
using namespace cv;
Mat1f exposureTonemap (Mat1f m, float gamma = 2.2, float exposure = 1) {
// Exposure tone mapping
Mat1f exp;
cv::exp( (-m) * exposure, exp );
Mat1f mapped = 1.0f - exp;
// Gamma correction
cv::pow(mapped, 1.0f / gamma, mapped);
return mapped;
}
Mat3f hsvExposureTonemap(Mat &a) {
Mat3f hsvComb;
cvtColor(a, hsvComb, COLOR_RGB2HSV);
Mat1f hsv[3];
split(hsvComb, hsv);
hsv[2] = exposureTonemap(hsv[2], 2.2, 10);
merge(hsv, 3, hsvComb);
Mat rgb;
cvtColor(hsvComb, rgb, COLOR_HSV2RGB);
return rgb;
}
int main() {
Mat a = imread("first.HDR", -1);
Mat b = imread("withwindow.HDR", -1);
imshow("a", hsvExposureTonemap(a));
imshow("b", hsvExposureTonemap(b));
waitKey();
return 0;
}
cv::Mat exposureTonemap (cv::Mat m, float gamma = 2.2, float exposure = 1)
{
// Exposure tone mapping
cv::Mat exp;
cv::exp( (-m) * exposure, exp );
cv::Mat mapped = cv::Scalar(1.0f, 1.0f, 1.0f) - exp;
// Gamma correction
cv::pow(mapped, 1.0f / gamma, mapped);
/*
cv::imshow("exposure tonemap", mapped );
cv::waitKey();
*/
return mapped;
}
此算法是一个色调映射器,试图模拟 HDR 中的曝光偏差
如果你想在 openCv 3.0 中使用它,不要忘记用 -1 作为 imread cv::Mat img = cv::imread("mypicture.HDR", -1);