43
43
#include " precomp.hpp"
44
44
#include " opencv2/photo.hpp"
45
45
#include " opencv2/imgproc.hpp"
46
- // #include "opencv2/highgui.hpp"
47
46
#include " hdr_common.hpp"
48
47
49
48
namespace cv
@@ -57,77 +56,104 @@ class CalibrateDebevecImpl : public CalibrateDebevec
57
56
samples (_samples),
58
57
lambda (_lambda),
59
58
random (_random),
60
- w (tringleWeights ())
59
+ w (triangleWeights ())
61
60
{
62
61
}
63
62
64
63
void process (InputArrayOfArrays src, OutputArray dst, InputArray _times)
65
64
{
66
65
CV_INSTRUMENT_REGION ()
67
66
67
+ // check inputs
68
68
std::vector<Mat> images;
69
69
src.getMatVector (images);
70
70
Mat times = _times.getMat ();
71
71
72
72
CV_Assert (images.size () == times.total ());
73
73
checkImageDimensions (images);
74
74
CV_Assert (images[0 ].depth () == CV_8U);
75
+ CV_Assert (times.type () == CV_32FC1);
75
76
77
+ // create output
76
78
int channels = images[0 ].channels ();
77
79
int CV_32FCC = CV_MAKETYPE (CV_32F, channels);
80
+ int rows = images[0 ].rows ;
81
+ int cols = images[0 ].cols ;
78
82
79
83
dst.create (LDR_SIZE, 1 , CV_32FCC);
80
84
Mat result = dst.getMat ();
81
85
82
- std::vector<Point> sample_points;
86
+ // pick pixel locations (either random or in a rectangular grid)
87
+ std::vector<Point> points;
88
+ points.reserve (samples);
83
89
if (random) {
84
90
for (int i = 0 ; i < samples; i++) {
85
- sample_points .push_back (Point (rand () % images[ 0 ]. cols , rand () % images[ 0 ]. rows ));
91
+ points .push_back (Point (rand () % cols, rand () % rows));
86
92
}
87
93
} else {
88
- int x_points = static_cast <int >(sqrt (static_cast <double >(samples) * images[0 ].cols / images[0 ].rows ));
94
+ int x_points = static_cast <int >(sqrt (static_cast <double >(samples) * cols / rows));
95
+ CV_Assert (0 < x_points && x_points <= cols);
89
96
int y_points = samples / x_points;
90
- int step_x = images[ 0 ]. cols / x_points ;
91
- int step_y = images[ 0 ]. rows / y_points ;
92
-
97
+ CV_Assert ( 0 < y_points && y_points <= rows) ;
98
+ int step_x = cols / x_points ;
99
+ int step_y = rows / y_points;
93
100
for (int i = 0 , x = step_x / 2 ; i < x_points; i++, x += step_x) {
94
101
for (int j = 0 , y = step_y / 2 ; j < y_points; j++, y += step_y) {
95
- if ( 0 <= x && x < images[ 0 ]. cols &&
96
- 0 <= y && y < images[ 0 ]. rows )
97
- sample_points. push_back ( Point (x, y));
102
+ if ( 0 <= x && x < cols && 0 <= y && y < rows ) {
103
+ points. push_back ( Point (x, y));
104
+ }
98
105
}
99
106
}
107
+ // we can have slightly less grid points than specified
108
+ // samples = static_cast<int>(points.size());
100
109
}
101
110
111
+ // we need enough equations to ensure a sufficiently overdetermined system
112
+ // (maybe only as a warning)
113
+ // CV_Assert(points.size() * (images.size() - 1) >= LDR_SIZE);
114
+
115
+ // solve for imaging system response function, over each channel separately
102
116
std::vector<Mat> result_split (channels);
103
- for (int channel = 0 ; channel < channels; channel++) {
104
- Mat A = Mat::zeros ((int )sample_points.size () * (int )images.size () + LDR_SIZE + 1 , LDR_SIZE + (int )sample_points.size (), CV_32F);
117
+ for (int ch = 0 ; ch < channels; ch++) {
118
+ // initialize system of linear equations
119
+ Mat A = Mat::zeros ((int )points.size () * (int )images.size () + LDR_SIZE + 1 ,
120
+ LDR_SIZE + (int )points.size (), CV_32F);
105
121
Mat B = Mat::zeros (A.rows , 1 , CV_32F);
106
122
107
- int eq = 0 ;
108
- for (size_t i = 0 ; i < sample_points.size (); i++) {
123
+ // include the data−fitting equations
124
+ int k = 0 ;
125
+ for (size_t i = 0 ; i < points.size (); i++) {
109
126
for (size_t j = 0 ; j < images.size (); j++) {
110
-
111
- int val = images[j].ptr ()[3 *(sample_points[i].y * images[j].cols + sample_points[i].x ) + channel];
112
- A.at <float >(eq, val) = w.at <float >(val);
113
- A.at <float >(eq, LDR_SIZE + (int )i) = -w.at <float >(val);
114
- B.at <float >(eq, 0 ) = w.at <float >(val) * log (times.at <float >((int )j));
115
- eq++;
127
+ // val = images[j].at<Vec3b>(points[i].y, points[i].x)[ch]
128
+ int val = images[j].ptr ()[channels*(points[i].y * cols + points[i].x ) + ch];
129
+ float wij = w.at <float >(val);
130
+ A.at <float >(k, val) = wij;
131
+ A.at <float >(k, LDR_SIZE + (int )i) = -wij;
132
+ B.at <float >(k, 0 ) = wij * log (times.at <float >((int )j));
133
+ k++;
116
134
}
117
135
}
118
- A.at <float >(eq, LDR_SIZE / 2 ) = 1 ;
119
- eq++;
120
-
121
- for (int i = 0 ; i < 254 ; i++) {
122
- A.at <float >(eq, i) = lambda * w.at <float >(i + 1 );
123
- A.at <float >(eq, i + 1 ) = -2 * lambda * w.at <float >(i + 1 );
124
- A.at <float >(eq, i + 2 ) = lambda * w.at <float >(i + 1 );
125
- eq++;
136
+
137
+ // fix the curve by setting its middle value to 0
138
+ A.at <float >(k, LDR_SIZE / 2 ) = 1 ;
139
+ k++;
140
+
141
+ // include the smoothness equations
142
+ for (int i = 0 ; i < (LDR_SIZE - 2 ); i++) {
143
+ float wi = w.at <float >(i + 1 );
144
+ A.at <float >(k, i) = lambda * wi;
145
+ A.at <float >(k, i + 1 ) = -2 * lambda * wi;
146
+ A.at <float >(k, i + 2 ) = lambda * wi;
147
+ k++;
126
148
}
149
+
150
+ // solve the overdetermined system using SVD (least-squares problem)
127
151
Mat solution;
128
152
solve (A, B, solution, DECOMP_SVD);
129
- solution.rowRange (0 , LDR_SIZE).copyTo (result_split[channel ]);
153
+ solution.rowRange (0 , LDR_SIZE).copyTo (result_split[ch ]);
130
154
}
155
+
156
+ // combine log-exposures and take its exponent
131
157
merge (result_split, result);
132
158
exp (result, result);
133
159
}
@@ -161,11 +187,11 @@ class CalibrateDebevecImpl : public CalibrateDebevec
161
187
}
162
188
163
189
protected:
164
- String name;
165
- int samples;
166
- float lambda;
167
- bool random;
168
- Mat w;
190
+ String name; // calibration algorithm identifier
191
+ int samples; // number of pixel locations to sample
192
+ float lambda; // constant that determines the amount of smoothness
193
+ bool random; // whether to sample locations randomly or in a grid shape
194
+ Mat w; // weighting function for corresponding pixel values
169
195
};
170
196
171
197
Ptr<CalibrateDebevec> createCalibrateDebevec (int samples, float lambda, bool random)
0 commit comments