本文主要用于记录自己在学习CRF过程中遇到的一些问题。
两个论文截图
CRF模型
B
=
f
(
V
(
t
?
L
)
)
B=f(V( t\cdot L))
B=f(V(t?L)) 其中
B
B
B为相机灰度值brightness,
L
L
L为环境中radiance,
t
t
t为曝光时间,
V
V
V为相机镜头参数,
f
f
f为相机响应函数CRF 。
有些论文中认为相机镜头参数是线性的不考虑,但有些考虑了衰减即靠近图像边缘亮度会暗一些,但没有看到二者同时计算的,如果同时计算两个非线性的函数,我觉得可能会有不确定性,在这里还请教一下了解的朋友。
控制相机曝光
首先要确定其中曝光时长
t
t
t。由于采用的是V4L2的USB相机,调整过程中遇到了一些列问题。详细记录在这里:V4L相机使用记录。
利用OpenCV获取HDR图像
首先了解如何用多张图合成HDR图像,主要参考:learnopencv网站
伪代码:
images.push_back(src);
const vector<float> times = {1/30.0f, 0.25, 2.5, 15.0};
Mat responseDebevec;
Ptr<CalibrateDebevec> calibrateDebevec = createCalibrateDebevec();
calibrateDebevec->process(images, responseDebevec, times);
Mat hdr;
Ptr<MergeDebevec> mergeDebevec = createMergeDebevec();
mergeDebevec->process(images, hdr, times, responseDebevec);
Mat ldr;
Ptr<Tonemap> tonemap = createTonemap(2.2f);
tonemap->process(hdr, ldr);
Ptr<MergeMertens> mergeMertens = createMergeMertens();
Mat mm_img;
mergeMertens->process(images, mm_img);
注意:所有数据格式采用float或32FC1/32FC3格式,这个坑了我半天。
计算CRF
上面出现的responseDebevec 就是CRF。这里把尝试把它画出来:
const int width_scale = 3, height_scale = 20;
const int width = 255 * width_scale, height = 40 * height_scale;
Mat img = Mat::zeros(Size(width, height), CV_8UC3);
Point b_old = Point(0, height);
Point g_old = Point(0, height);
Point r_old = Point(0, height);
for (int i = 0; i < 255; ++i){
Vec3f v3f = responseDebevec.at<Vec3f>(i, 0);
float ib = v3f[0];
float ig = v3f[1];
float ir = v3f[2];
Point b_new = Point(i * width_scale, height - ib * height_scale);
Point g_new = Point(i * width_scale, height - ig * height_scale);
Point r_new = Point(i * width_scale, height - ir * height_scale);
line(img, b_old, b_new, Scalar(255, 0, 0));
line(img, g_old, g_new, Scalar(0, 255, 0));
line(img, r_old, r_new, Scalar(0, 0, 255));
b_old = b_new;
g_old = g_new;
r_old = r_new;
}
imshow("crf", img);
但遇到了一个问题,就是我用相机拍摄不同图像时,计算出的CRF是不一样的。趋势可能接近,但数值相差很多。我也不知道为啥,猜测可能和opencv通过V4L设置曝光时间时存在问题?但大致上都符合exp指数形式,那就认为差不都吧。
通过CRF推算Irradiance
知道CRF、曝光后,可以通过图像灰度值推算对应场景的irradiance 。
由于我每次测得的CRF不一样,但基本符合指数形式,故采用:
B
=
a
?
e
x
p
(
b
?
L
?
t
)
+
c
B=a\cdot exp(b\cdot L \cdot t)+c
B=a?exp(b?L?t)+c 方式推算。这个方程也是我自己瞎凑的,给定
B
=
0
,
L
=
0
B=0, L=0
B=0,L=0 和
B
=
255
,
L
=
1
B=255, L=1
B=255,L=1两个边界,假设
a
=
1
a=1
a=1 ,计算反推:
inline double calInverseCRF(uchar intensity){
const float maxIrradiance = 1;
const float a = 1.0f;
const float b = (log(maxIrradiance + 1) - log(a)) / 255;
return a * exp(b * intensity) - 1;
}
Mat testImg;
cvtColor(images[1], testImg, COLOR_BGR2GRAY);
assert(testImg.type() == CV_8UC1);
imshow("test", testImg);
Mat irradiance = Mat::zeros(testImg.size(), CV_32FC1);
for(int i=0; i<testImg.rows; ++i){
for(int j=0; j<testImg.cols; ++j){
float value = testImg.at<uchar>(i, j);
irradiance.at<float>(i, j) = calInverseCRF(value);
}
}
const double exposureTime = times[1];
Mat intensity = irradiance / exposureTime;
normalize(intensity, intensity, 1.0, 0.0, NORM_MINMAX);
imshow("dst", intensity);
结果:
遇到的问题总结
- CRF是三通道的,我尝试转成灰度图算一个CRF,计算的总是错误。
|